From f875f421d4ddedef5b3de972747acf555d4515fe Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Mon, 6 Nov 2017 11:51:20 +0100
Subject: [PATCH] =?UTF-8?q?section=20param=C3=A9tr=C3=A9e=20:=20ajout=20de?=
 =?UTF-8?q?s=20messages=20dans=20le=20journal=20pour=20la=20non=20converge?=
 =?UTF-8?q?nce=20des=20calculs=20par=20la=20m=C3=A9thode=20de=20Newton?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 spec/section_param_rect_conv_newton.spec.ts | 100 ++++++++++++++++++++
 src/section/hauteur.ts                      |  16 ++--
 src/section/newton.ts                       |  15 ++-
 src/section/section_type.ts                 |  62 +++++++++---
 src/util/message.ts                         |  30 ++++++
 5 files changed, 200 insertions(+), 23 deletions(-)
 create mode 100644 spec/section_param_rect_conv_newton.spec.ts

diff --git a/spec/section_param_rect_conv_newton.spec.ts b/spec/section_param_rect_conv_newton.spec.ts
new file mode 100644
index 00000000..d0c632e8
--- /dev/null
+++ b/spec/section_param_rect_conv_newton.spec.ts
@@ -0,0 +1,100 @@
+/// <reference path="../node_modules/@types/jasmine/index.d.ts" />
+
+import { Result } from "../src/base";
+import { precDist, equalEpsilon } from "./nubtest";
+import { ParamsSectionRectang, cSnRectang } from "../src/section/section_rectang";
+import { cLog } from "../src/util/log";
+import { MessageCode } from "../src/util/message";
+
+let paramSection: ParamsSectionRectang;
+let sect: cSnRectang;
+
+function check(val1: number, val2: number) {
+    expect(equalEpsilon(val1, val2)).toBeTruthy("expected " + val2 + ", got " + val1);
+}
+
+describe('Section paramétrée rectangulaire : ', () => {
+    beforeEach(() => {
+        paramSection = new ParamsSectionRectang(0.8, // tirant d'eau
+            2.5, // largeur de fond
+            40, //  Ks=Strickler
+            10,  //  Q=Débit
+            0.001, //  If=pente du fond
+            1e-10, // précision
+            1 // YB= hauteur de berge
+        );
+
+        sect = new cSnRectang(new cLog(), paramSection);
+        sect.newtonMaxIter = 5;
+    });
+
+    describe('non convergence de la méthode de Newton :', () => {
+        it('hauteur critique', () => {
+            sect.Calc("Yc");
+            expect(sect.log.messages.length).toEqual(1);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+        });
+
+        it('hauteur normale', () => {
+            sect.Calc("Yn");
+            expect(sect.log.messages.length).toEqual(2);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[1].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE);
+        });
+
+        it('hauteur normale, pente négative', () => {
+            sect.prms.If.v = -0.001;
+            sect.Calc("Yn");
+            expect(sect.log.messages.length).toEqual(1);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF);
+        });
+
+        it('hauteur fluviale, Y < Yc', () => {
+            sect.Calc("Yf");
+            expect(sect.log.messages.length).toEqual(3);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[1].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[2].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HFLU);
+        });
+
+        it('hauteur fluviale, Y > Yc', () => {
+            sect.prms.Y.v = 2;
+            sect.Calc("Yf");
+            expect(sect.log.messages.length).toEqual(1);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+        });
+
+        it('hauteur torrentielle, Y < Yc', () => {
+            sect.Calc("Yt");
+            expect(sect.log.messages.length).toEqual(1);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+        });
+
+        it('hauteur torrentielle, Y > Yc', () => {
+            sect.prms.Y.v = 2;
+            sect.Calc("Yt");
+            expect(sect.log.messages.length).toEqual(2);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[1].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HTOR);
+        });
+
+        it('hauteur conjuguée, Froude < 1', () => {
+            sect.prms.Y.v = 2;
+            sect.Calc("Yco");
+            console.log(sect.log.toString());
+            expect(sect.log.messages.length).toEqual(3);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[1].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HTOR);
+            expect(sect.log.messages[2].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG);
+        });
+
+        it('hauteur conjuguée, Froude > 1', () => {
+            sect.Calc("Yco");
+            expect(sect.log.messages.length).toEqual(4);
+            expect(sect.log.messages[0].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[1].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+            expect(sect.log.messages[2].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HFLU);
+            expect(sect.log.messages[3].code).toEqual(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG);
+        });
+    });
+});
diff --git a/src/section/hauteur.ts b/src/section/hauteur.ts
index 63d181c1..9a3faa0e 100644
--- a/src/section/hauteur.ts
+++ b/src/section/hauteur.ts
@@ -15,8 +15,8 @@ export class cHautCritique extends acNewton {
          * Constructeur de la classe
          * @param Sn Section sur laquelle on fait le calcul
          */
-        constructor(Sn: acSection, dbg: boolean = false) {
-                super(Sn.prms, dbg);
+        constructor(Sn: acSection, maxIter: number, dbg: boolean = false) {
+                super(Sn.prms, maxIter, dbg);
                 this.Sn = Sn.clone();
         }
 
@@ -77,8 +77,8 @@ export class cHautNormale extends acNewton {
          * Constructeur de la classe
          * @param oSn Section sur laquelle on fait le calcul
          */
-        constructor(Sn: acSection, dbg: boolean = false) {
-                super(Sn.prms, dbg);
+        constructor(Sn: acSection, maxIter: number, dbg: boolean = false) {
+                super(Sn.prms, maxIter, dbg);
                 this.Sn = Sn;
                 this.Q = Sn.prms.Q.v;
                 this.Ks = Sn.prms.Ks.v;
@@ -135,8 +135,8 @@ export class cHautCorrespondante extends acNewton {
          * Constructeur de la classe
          * @param oSn Section sur laquelle on fait le calcul
          */
-        constructor(Sn: acSection, dbg: boolean = false) {
-                super(Sn.prms, dbg);
+        constructor(Sn: acSection, maxIter: number, dbg: boolean = false) {
+                super(Sn.prms, maxIter, dbg);
                 this.Y = Sn.prms.Y.v;
                 this.rS2 = Math.pow(Sn.Calc("S"), -2);
                 this.Sn = Sn;
@@ -186,8 +186,8 @@ export class cHautConjuguee extends acNewton {
          * Constructeur de la classe
          * @param oSn Section sur laquelle on fait le calcul
          */
-        constructor(oSn: acSection, dbg: boolean = false) {
-                super(oSn.prms, dbg);
+        constructor(oSn: acSection, maxIter: number, dbg: boolean = false) {
+                super(oSn.prms, maxIter, dbg);
                 this.rQ2 = Math.pow(oSn.prms.Q.v, 2);
                 this.Sn = oSn;
                 this.rS = oSn.Calc("S");
diff --git a/src/section/newton.ts b/src/section/newton.ts
index fd1d0813..f3b76d66 100644
--- a/src/section/newton.ts
+++ b/src/section/newton.ts
@@ -4,8 +4,8 @@ import { cParamsCanal } from "./section_type"
 export abstract class acNewton extends Debug {
         protected rTol: number;
         protected Dx: number;
-        private iCpt = 0;
-        private readonly iCptMax = 50;
+        private iCpt: number = 0;
+        private iCptMax: number;
         private rRelax = 1; /// Coefficient de relaxation
         private rFnPrec = 0; /// Mémorisation du Fn précédent pour détecter le changement de signe
         private iOscil = 0; /// Nombre de changement de signe de Delta
@@ -14,10 +14,11 @@ export abstract class acNewton extends Debug {
          * Constructeur de la classe
          * @param prms Paramètres supplémentaires (Débit, précision...)
          */
-        constructor(prms: cParamsCanal, dbg: boolean = false) {
+        constructor(prms: cParamsCanal, maxIter: number, dbg: boolean = false) {
                 super(dbg);
                 this.rTol = prms.Prec.v;
                 this.Dx = prms.Prec.v / 10;
+                this.iCptMax = maxIter;
         }
 
         /**
@@ -92,4 +93,12 @@ export abstract class acNewton extends Debug {
                 // Echec de la résolution
                 return undefined;
         }
+
+        /**
+	 * Pour savoir si le Newton a convergé
+	 * @return true si oui, false sinon
+	 */
+        public hasConverged(): boolean {
+                return this.iCpt < this.iCptMax;
+        }
 }
\ No newline at end of file
diff --git a/src/section/section_type.ts b/src/section/section_type.ts
index c898f5d8..4cdf97da 100644
--- a/src/section/section_type.ts
+++ b/src/section/section_type.ts
@@ -1,5 +1,6 @@
 import { XOR } from "../base";
 import { cLog } from "../util/log";
+import { MessageCode, Message } from "../util/message";
 import { ComputeNodeType, ComputeNode, ParamDefinition, ParamDomainValue, ParamCalculability, ParamsEquation } from "../param";
 import { cHautCritique, cHautNormale, cHautCorrespondante, cHautConjuguee } from "./hauteur";
 
@@ -149,10 +150,9 @@ export abstract class acSection extends ComputeNode {
         private Calc_old = {}; /// Mémorisation des données hydrauliques pour calcul intermédiaire
 
         /**
-         * Nombre de points nécessaires pour le dessin de la section (hors point de berge)
-         * Valeur de 1 par défaut pour les sections rectangulaires et trapézoïdales
+         * itérations max pour Newton
          */
-        protected nbDessinPoints = 1;
+        private _newtonMaxIter: number = 50;
 
         /**
          * Construction de la classe.
@@ -188,6 +188,14 @@ export abstract class acSection extends ComputeNode {
                 return Object.create(this);
         }
 
+        public set newtonMaxIter(n: number) {
+                this._newtonMaxIter = n;
+        }
+
+        public get log(): cLog {
+                return this.oLog;
+        }
+
         /**
          * Efface toutes les données calculées pour forcer le recalcul
          * @param bGeo Réinitialise les données de géométrie aussi
@@ -500,8 +508,12 @@ export abstract class acSection extends ComputeNode {
          * @return tirant d'eau critique
          */
         private Calc_Yc(): number {
-                var hautCritique = new cHautCritique(this, this.DBG);
+                let hautCritique = new cHautCritique(this, this._newtonMaxIter, this.DBG);
                 this.HautCritique = hautCritique.Newton(this.prms.YB.v);
+                if (this.HautCritique == undefined || !hautCritique.hasConverged()) {
+                        let m = new Message(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE);
+                        this.oLog.add(m);
+                }
                 return this.HautCritique;
         }
 
@@ -511,11 +523,20 @@ export abstract class acSection extends ComputeNode {
          */
         private Calc_Yn(): number {
                 this.debug("in calc_Yn");
-                if (this.prms.If.v <= 0)
+                if (this.prms.If.v <= 0) {
+                        let m = new Message(MessageCode.ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF);
+                        this.oLog.add(m);
                         return undefined;
+                }
+
+                let oHautNormale = new cHautNormale(this, this._newtonMaxIter, this.DBG);
+                let res = oHautNormale.Newton(this.CalcGeo("Yc"));
+                if (res == undefined || !oHautNormale.hasConverged()) {
+                        let m = new Message(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE);
+                        this.oLog.add(m);
+                }
 
-                var oHautNormale = new cHautNormale(this, this.DBG);
-                return oHautNormale.Newton(this.CalcGeo("Yc"));
+                return res;
         }
 
         /**
@@ -526,8 +547,14 @@ export abstract class acSection extends ComputeNode {
                 if (this.prms.Y.v > this.CalcGeo("Yc"))
                         return this.prms.Y.v;
 
-                var oHautCorrespondante = new cHautCorrespondante(this, this.DBG);
-                return oHautCorrespondante.Newton(this.Calc("Yc") * 2);
+                var oHautCorrespondante = new cHautCorrespondante(this, this._newtonMaxIter, this.DBG);
+                let res = oHautCorrespondante.Newton(this.Calc("Yc") * 2);
+                if (res == undefined || !oHautCorrespondante.hasConverged()) {
+                        let m = new Message(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HFLU);
+                        this.oLog.add(m);
+                }
+
+                return res;
         }
 
         /**
@@ -538,8 +565,14 @@ export abstract class acSection extends ComputeNode {
                 if (this.prms.Y.v < this.CalcGeo("Yc"))
                         return this.prms.Y.v;
 
-                var oHautCorrespondante = new cHautCorrespondante(this, this.DBG);
-                return oHautCorrespondante.Newton(this.CalcGeo("Yc") / 2);
+                var oHautCorrespondante = new cHautCorrespondante(this, this._newtonMaxIter, this.DBG);
+                let res = oHautCorrespondante.Newton(this.CalcGeo("Yc") / 2);
+                if (res == undefined || !oHautCorrespondante.hasConverged()) {
+                        let m = new Message(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HTOR);
+                        this.oLog.add(m);
+                }
+
+                return res;
         }
 
         /**
@@ -548,7 +581,7 @@ export abstract class acSection extends ComputeNode {
          */
         private Calc_Yco(): number {
                 this.Swap(true);
-                var oHautConj = new cHautConjuguee(this, this.DBG);
+                var oHautConj = new cHautConjuguee(this, this._newtonMaxIter, this.DBG);
                 // Choisir une valeur initiale du bon côté de la courbe
                 if (this.Calc("Fr") < 1) {
                         // Ecoulement fluvial, on cherche la conjuguée à partir du tirant d'eau torrentiel
@@ -559,6 +592,11 @@ export abstract class acSection extends ComputeNode {
                         Y0 = this.Calc("Yf");
                 }
                 let Yco = oHautConj.Newton(Y0);
+                if (Yco == undefined || !oHautConj.hasConverged()) {
+                        let m = new Message(MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG);
+                        this.oLog.add(m);
+                }
+
                 this.Swap(false);
                 return Yco;
         }
diff --git a/src/util/message.ts b/src/util/message.ts
index d34afb18..a4ee532a 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -157,6 +157,36 @@ export enum MessageCode {
      * courbe de remous : Condition limite amont > Hauteur critique : pas de calcul possible depuis l'amont
      */
     ERROR_REMOUS_PAS_CALCUL_DEPUIS_AMONT = -510,
+
+    /**
+     * section : Non convergence du calcul de la hauteur critique (Méthode de Newton)
+     */
+    ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE = -600,
+
+    /**
+     * section : Non convergence du calcul de la hauteur normale (Méthode de Newton)
+     */
+    ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE = -601,
+
+    /**
+     * section : Non convergence du calcul de la hauteur conjuguée (Méthode de Newton)
+     */
+    ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG = -602,
+
+    /**
+     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton) pour le calcul de la hauteur fluviale
+     */
+    ERROR_SECTION_NON_CONVERGENCE_NEWTON_HFLU = -603,
+
+    /**
+     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton) pour le calcul de la hauteur torrentielle
+     */
+    ERROR_SECTION_NON_CONVERGENCE_NEWTON_HTOR = -604,
+
+    /**
+     * section : La pente est négative ou nulle, la hauteur normale est infinie
+     */
+    ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF = -605,
 }
 
 /**
-- 
GitLab