From b92adbc3c35ec2494160a6c844a1e3e9439b9c96 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Thu, 2 Nov 2017 16:17:27 +0100
Subject: [PATCH] ajout de la calculette des courbes de remous (composants
 CourbeRemousComponent et RemousResultsComponent)

---
 src/app/app.component.ts                      |   3 +-
 src/app/app.module.ts                         |   6 +-
 .../generic/calculator.component.html         |   3 +-
 .../generic/calculator.component.ts           | 148 +++++++++++-
 src/app/calculators/generic/formulaire.ts     |  39 +++-
 .../calculators/remous/remous.component.html  |   2 +
 .../calculators/remous/remous.component.ts    |   8 +
 src/app/calculators/remous/remous.config.json |  90 ++++---
 src/app/calculators/remous/remous.fr.json     |  19 +-
 .../remous-results.component.html             |  42 ++++
 .../remous-results.component.ts               | 221 ++++++++++++++++++
 .../services/formulaire/formulaire.service.ts |  18 +-
 src/app/services/param/param.service.ts       |  47 ++--
 13 files changed, 555 insertions(+), 91 deletions(-)
 create mode 100644 src/app/calculators/remous/remous.component.html
 create mode 100644 src/app/calculators/remous/remous.component.ts
 create mode 100644 src/app/components/remous-results/remous-results.component.html
 create mode 100644 src/app/components/remous-results/remous-results.component.ts

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 1500b3345..4972f2dba 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -16,8 +16,9 @@ import { FormulaireService } from './services/formulaire/formulaire.service';
     <option *ngFor="let l of intlService.languages" [value]=l.code>{{l.label}}</option>
   </select>
 
-  <regime-uniforme></regime-uniforme>
+  <courbe-remous></courbe-remous>
   <!--
+  <regime-uniforme></regime-uniforme>
   <section-param></section-param>
   <lechapt-calmon></lechapt-calmon>
   <cond-distri></cond-distri>
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index e9ec127ae..b3613a86d 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -16,6 +16,7 @@ import { CondDistriComponent } from './calculators/cond_distri/conddistri.compon
 import { LechaptCalmonComponent } from './calculators/lechapt-calmon/lechaptcalmon.component';
 import { SectionParametreeComponent } from './calculators/section-param/section-param.component';
 import { RegimeUniformeComponent } from './calculators/regime-uniforme/regime-uniforme.component';
+import { CourbeRemousComponent } from './calculators/remous/remous.component';
 import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
 import { AppErrorModule } from './error.module';
 import { CalculatorResultsComponent } from './components/calculator-results/calculator-results.component';
@@ -23,6 +24,7 @@ import { SectionResultsComponent } from './components/section-results/section-re
 import { GenericCalculatorComponent } from './calculators/generic/calculator.component';
 import { CalcCanvasComponent } from './components/canvas/canvas.component';
 import { SectionCanvasComponent } from './components/section-canvas/section-canvas.component';
+import { RemousResultsComponent } from './components/remous-results/remous-results.component';
 
 @NgModule({
   imports: [
@@ -40,9 +42,9 @@ import { SectionCanvasComponent } from './components/section-canvas/section-canv
     ParamInputComponent,
     FieldSetComponent,
     ParamFieldLineComponent, SelectFieldLineComponent, CheckFieldLineComponent,
-    CondDistriComponent, LechaptCalmonComponent, SectionParametreeComponent, GenericCalculatorComponent, RegimeUniformeComponent,
+    CondDistriComponent, LechaptCalmonComponent, SectionParametreeComponent, GenericCalculatorComponent, RegimeUniformeComponent, CourbeRemousComponent,
     AlertDialog,
-    CalculatorResultsComponent, SectionResultsComponent,
+    CalculatorResultsComponent, SectionResultsComponent, RemousResultsComponent,
     CalcCanvasComponent, SectionCanvasComponent
   ],
   entryComponents: [AlertDialog],
diff --git a/src/app/calculators/generic/calculator.component.html b/src/app/calculators/generic/calculator.component.html
index 3491a069c..af3fb204b 100644
--- a/src/app/calculators/generic/calculator.component.html
+++ b/src/app/calculators/generic/calculator.component.html
@@ -7,4 +7,5 @@
     <button type="button" class="button_compute" name="Calculer" (click)="doCompute()" i18n="@@hyd_compute">Calculer</button>
 </div>
 <calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
-<section-results [style.display]="getSectionResultsStyleDisplay()"></section-results>
\ No newline at end of file
+<section-results [style.display]="getSectionResultsStyleDisplay()"></section-results>
+<remous-results [style.display]="getRemousResultsStyleDisplay()"></remous-results>
diff --git a/src/app/calculators/generic/calculator.component.ts b/src/app/calculators/generic/calculator.component.ts
index 1291b64c5..abf9a9dc5 100644
--- a/src/app/calculators/generic/calculator.component.ts
+++ b/src/app/calculators/generic/calculator.component.ts
@@ -3,7 +3,7 @@ import { Response } from '@angular/http';
 import { Observable } from "rxjs/Observable";
 import 'rxjs/add/operator/toPromise';
 
-import { ComputeNode, ComputeNodeType, IParamsEquation, Nub, acSection, RegimeUniforme } from "jalhyd";
+import { ComputeNode, ComputeNodeType, ParamsEquation, Nub, acSection, RegimeUniforme, MethodeResolution, CourbeRemousParams, CourbeRemous, cLog } from "jalhyd";
 
 import { ParamService } from '../../services/param/param.service';
 import { HttpService } from '../../services/http/http.service';
@@ -13,6 +13,7 @@ import { FieldSet, InputField, SelectField, FormulaireDefinition, CalculatorType
 import { NgParameter, ParamRadioConfig } from './ngparam';
 import { CalculatorResultsComponent } from '../../components/calculator-results/calculator-results.component';
 import { SectionResultsComponent } from '../../components/section-results/section-results.component';
+import { RemousResultsComponent } from '../../components/remous-results/remous-results.component';
 import { Observer } from '../../services/observer';
 
 @Component({
@@ -54,6 +55,12 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
     @ViewChild(SectionResultsComponent)
     private sectionResultsComponent: SectionResultsComponent;
 
+    /**
+     * composant d'affichage des résultats des section paramétrées
+     */
+    @ViewChild(RemousResultsComponent)
+    private remousResultsComponent: RemousResultsComponent;
+
     /**
      * objet JSON chargé depuis le fichier de traduction
      */
@@ -71,6 +78,11 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
      */
     private _showResultsSection: boolean = false;
 
+    /**
+     * flag d'affichage du composant de résultats du calcul des courbes de remous
+     */
+    private _showResultsRemous: boolean = false;
+
     constructor(private paramService: ParamService, private httpService: HttpService, private intlService: InternationalisationService, private formulaireService: FormulaireService) {
         this.intlService.addObserver(this);
     }
@@ -204,6 +216,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
     private onRadioClick(info: string) {
         this._showResultsFixVar = false;
         this._showResultsSection = false;
+        this._showResultsRemous = false;
 
         let tmp: string[] = info.split("_");
         let symbol: string = tmp[0];
@@ -327,11 +340,11 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
         this.resultsComponent.setVariableResultHeader(computedParam["label"]);
 
         let ssf: SelectField = <SelectField>this._formulaire.getFormulaireElementById("select_section");
-        let typeSect: ComputeNodeType = FormulaireDefinition.getSectionType(ssf.getValue());
+        let typeSect: ComputeNodeType = FormulaireDefinition.getComputeNodeTypeFromSection(ssf.getValue(), CalculatorType.SectionParametree);
 
-        var np: [acSection, IParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.SectionParametree, typeSect);
+        var np: [acSection, ParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.SectionParametree, typeSect);
         let sect: acSection = np[0];
-        let prms: IParamsEquation = np[1];
+        let prms: ParamsEquation = np[1];
 
         let min: number = +varParam.minValue;
         let max: number = +varParam.maxValue;
@@ -364,16 +377,16 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
         }
 
         let ssf: SelectField = <SelectField>this._formulaire.getFormulaireElementById("select_section");
-        let typeSect: ComputeNodeType = FormulaireDefinition.getSectionType(ssf.getValue());
-        var np: [acSection, IParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.SectionParametree, typeSect);
+        let typeSect: ComputeNodeType = FormulaireDefinition.getComputeNodeTypeFromSection(ssf.getValue(), CalculatorType.SectionParametree);
+        var np: [acSection, ParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.SectionParametree, typeSect);
 
         let sect: acSection = np[0];
-        let prms: IParamsEquation = np[1];
+        let prms: ParamsEquation = np[1];
 
         let prec: number = this.getNodeParameterValue(ComputeNodeType.SectionParametree, "Pr"); // précision
         let nDigits = -Math.log10(prec);
 
-        let Y = prms.Y.v; // tirant d'eau original (doit être fourni à acSection.Calc() sous peine d'être modifié par les appels successifs car c'est en même temps un paramètre et une variable temporaire)
+        let Y = prms.map.Y.v; // tirant d'eau original (doit être fourni à acSection.Calc() sous peine d'être modifié par les appels successifs car c'est en même temps un paramètre et une variable temporaire)
 
         // charge spécifique
         let Hs = sect.Calc("Hs", Y);
@@ -447,21 +460,106 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
         this._showResultsSection = true;
     }
 
+    private addRemousResult(x: string, f: number, t: number, nDigits: number) {
+        let flu = f == undefined ? "" : f.toFixed(nDigits);
+        let tor = t == undefined ? "" : f.toFixed(nDigits);
+        this.remousResultsComponent.addResult(x, flu, tor);
+    }
+
+    private doComputeRemous() {
+        this.remousResultsComponent.reset();
+
+        let ssf: SelectField = <SelectField>this._formulaire.getFormulaireElementById("select_section");
+        let typeSect: ComputeNodeType = FormulaireDefinition.getComputeNodeTypeFromSection(ssf.getValue(), CalculatorType.CourbeRemous);
+        var np: [acSection, ParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.CourbeRemous, typeSect, false);
+
+        let sect: acSection = np[0];
+        let prmSect: ParamsEquation = np[1];
+
+        let prec: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "Pr"); // précision
+        let nDigits: number = -Math.log10(prec);
+
+        let Yamont: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "Yamont"); // tirant amont
+        let Yaval: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "Yaval"); // tirant aval
+        let Dx: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "Dx"); // pas de discrétisation
+        let Long: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "Long"); // longueur du bief
+        let If: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "If"); // pente du fond
+        let YB: number = this.getNodeParameterValue(ComputeNodeType.CourbeRemous, "YB"); // hauteur de berge
+        let Yn: number = sect.Calc("Yn"); // hauteur normale
+        let Yc: number = sect.Calc("Yc"); // hauteur critique
+
+        // méthode de résolution
+
+        let msf: SelectField = <SelectField>this._formulaire.getFormulaireElementById("select_resolution");
+        let smeth: string = msf.getValue();
+        let methRes: MethodeResolution;
+        if (smeth == "select_resolution_trap")
+            methRes = MethodeResolution.Trapezes;
+        else if (smeth == "select_resolution_rk4")
+            methRes = MethodeResolution.RungeKutta4;
+        else if (smeth == "select_resolution_euler")
+            methRes = MethodeResolution.EulerExplicite;
+        else
+            throw "GenericCalculatorComponent.doComputeRemous() : type de méthode de résolution '" + smeth + "' inconnu";
+
+        // calcul
+
+        let prmCR: CourbeRemousParams = new CourbeRemousParams(sect, Yamont, Yaval, Long, Dx, methRes);
+        let log: cLog = new cLog();
+        let cr = new CourbeRemous(prmCR, log);
+        let res = cr.calculRemous(undefined);
+
+        // affichage du graphe
+
+        this.remousResultsComponent.setPenteFond(If);
+        this.remousResultsComponent.setLongBief(Long);
+        this.remousResultsComponent.setHauteurBerge(YB);
+        this.remousResultsComponent.setHauteurNormale(Yn);
+        this.remousResultsComponent.setHauteurCritique(Yc);
+
+        // affichage du journal
+
+        for (let l of log.messages)
+            this.remousResultsComponent.addLogEntry(l.toString());
+
+        // affichage des resultats numériques
+
+        let kFlu = Object.keys(res.flu);
+        let kTor = Object.keys(res.tor);
+        for (let i = 0; i < res.trX.length; i++) {
+            let x: string = res.trX[i];
+            // let f = i < kFlu.length ? res.flu[kFlu[i]] : undefined;
+            // let t = i < kTor.length ? res.tor[kTor[i]] : undefined;
+            let f = res.flu[x];
+            let t = res.tor[x];
+            this.addRemousResult(x, f, t, nDigits);
+        }
+
+        this.remousResultsComponent.generateGraph();
+        this._showResultsRemous = true;
+    }
+
     private doCompute() {
         this._showResultsFixVar = false;
         this._showResultsSection = false;
+        this._showResultsRemous = false;
 
         if (this._calculatorType == CalculatorType.SectionParametree) {
             this.doComputeSection();
             return;
         }
 
-        let np: [Nub, IParamsEquation];
+        if (this._calculatorType == CalculatorType.CourbeRemous) {
+            this.doComputeRemous();
+            return;
+        }
+
+        let np: [Nub, ParamsEquation];
         let nub: Nub;
-        let prms: IParamsEquation;
+        let prms: ParamsEquation;
         let rg: boolean = this._calculatorType == CalculatorType.RegimeUniforme;
         if (rg) {
-            let snp: [acSection, IParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.RegimeUniforme, this._nodeType);
+            let snp: [acSection, ParamsEquation] = this.formulaireService.getSectionNubAndParameters(CalculatorType.RegimeUniforme, this._nodeType);
             nub = new RegimeUniforme(snp[0]);
             prms = snp[1];
         }
@@ -518,6 +616,10 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
         return this._showResultsSection ? "block" : "none";
     }
 
+    private getRemousResultsStyleDisplay() {
+        return this._showResultsRemous ? "block" : "none";
+    }
+
     private getFieldsetStyleDisplay(id: string) {
         let isDisplayed: boolean = this._formulaire.isDisplayed(id);
         return isDisplayed ? "block" : "none";
@@ -579,6 +681,30 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
                             this._nodeType = ComputeNodeType.RegimeUniformePuissance;
                             break;
                     }
+                    break;
+
+                case CalculatorType.CourbeRemous:
+                    switch (type) {
+                        case "trapez":
+                            this._nodeType = ComputeNodeType.CourbeRemousTrapeze;
+                            break;
+
+                        case "rect":
+                            this._nodeType = ComputeNodeType.CourbeRemousRectangle;
+                            break;
+
+                        case "circ":
+                            this._nodeType = ComputeNodeType.CourbeRemousCercle;
+                            break;
+
+                        case "puiss":
+                            this._nodeType = ComputeNodeType.CourbeRemousPuissance;
+                            break;
+                    }
+                    break;
+
+                default:
+                    throw "GenericCalculatorComponent.updateSectionType() : section " + val + " / type de calculette " + CalculatorType[this._calculatorType] + " non pris en charge"
             }
         }
     }
diff --git a/src/app/calculators/generic/formulaire.ts b/src/app/calculators/generic/formulaire.ts
index a67ceab36..c3004c012 100644
--- a/src/app/calculators/generic/formulaire.ts
+++ b/src/app/calculators/generic/formulaire.ts
@@ -6,7 +6,7 @@ import { StringMap } from '../../stringmap';
 import { logObject } from '../../util';
 
 export enum CalculatorType {
-    ConduiteDistributrice, LechaptCalmon, SectionParametree, RegimeUniforme
+    ConduiteDistributrice, LechaptCalmon, SectionParametree, RegimeUniforme, CourbeRemous
 }
 
 export class FormulaireDefinition {
@@ -344,6 +344,7 @@ export class FormulaireDefinition {
             }
         }
 
+        // logObject(this._fieldSets, "fieldsets");
         // logObject(this._dependencies, "dependences");
     }
 
@@ -405,17 +406,33 @@ export class FormulaireDefinition {
             console.log(d.toString());
     }
 
-    public static getSectionType(s: string): ComputeNodeType {
-        if (s === "select_section_trapez")
-            return ComputeNodeType.SectionTrapeze;
-        if (s === "select_section_rect")
-            return ComputeNodeType.SectionRectangle;
-        if (s === "select_section_circ")
-            return ComputeNodeType.SectionCercle;
-        if (s === "select_section_puiss")
-            return ComputeNodeType.SectionPuissance;
+    public static getComputeNodeTypeFromSection(sect: string, calc: CalculatorType): ComputeNodeType {
+        switch (calc) {
+            case CalculatorType.SectionParametree:
+                if (sect === "select_section_trapez")
+                    return ComputeNodeType.SectionTrapeze;
+                if (sect === "select_section_rect")
+                    return ComputeNodeType.SectionRectangle;
+                if (sect === "select_section_circ")
+                    return ComputeNodeType.SectionCercle;
+                if (sect === "select_section_puiss")
+                    return ComputeNodeType.SectionPuissance;
+                throw "Formulaire.getSectionType() : type de section '" + sect + "' inconnu pour la calculette " + CalculatorType[calc];
+
+            case CalculatorType.CourbeRemous:
+                if (sect === "select_section_trapez")
+                    return ComputeNodeType.CourbeRemousTrapeze;
+                if (sect === "select_section_rect")
+                    return ComputeNodeType.CourbeRemousRectangle;
+                if (sect === "select_section_circ")
+                    return ComputeNodeType.CourbeRemousCercle;
+                if (sect === "select_section_puiss")
+                    return ComputeNodeType.CourbeRemousPuissance;
+                throw "Formulaire.getSectionType() : type de section '" + sect + "' inconnu pour la calculette " + CalculatorType[calc];
 
-        throw "Formulaire.getSectionType() : type de section '" + s + "' inconnu"
+            default:
+                throw "Formulaire.getSectionType() : type de calculette " + CalculatorType[calc] + " non pris en charge";
+        }
     }
 
     public isDisplayed(id: string) {
diff --git a/src/app/calculators/remous/remous.component.html b/src/app/calculators/remous/remous.component.html
new file mode 100644
index 000000000..add35e051
--- /dev/null
+++ b/src/app/calculators/remous/remous.component.html
@@ -0,0 +1,2 @@
+<h1>Courbe de remous</h1>
+<hydrocalc type="CourbeRemous"></hydrocalc>
\ No newline at end of file
diff --git a/src/app/calculators/remous/remous.component.ts b/src/app/calculators/remous/remous.component.ts
new file mode 100644
index 000000000..eed0dc6d8
--- /dev/null
+++ b/src/app/calculators/remous/remous.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+    selector: 'courbe-remous',
+    templateUrl: "./remous.component.html"
+})
+export class CourbeRemousComponent {
+}
diff --git a/src/app/calculators/remous/remous.config.json b/src/app/calculators/remous/remous.config.json
index 3a14d2db1..0376b0b44 100644
--- a/src/app/calculators/remous/remous.config.json
+++ b/src/app/calculators/remous/remous.config.json
@@ -16,7 +16,7 @@
                         "id": "select_section_circ"
                     },
                     {
-                        "id": "select_section_para"
+                        "id": "select_section_puiss"
                     }
                 ]
             }
@@ -24,11 +24,12 @@
     },
     {
         "id": "fs_section_trapez",
+        "nodeType": "CourbeRemousTrapeze",
         "option": "fix",
         "dep_exist": [
             {
                 "refid": "select_section",
-                "refvalue": "select_section_para"
+                "refvalue": "select_section_trapez"
             }
         ],
         "fields": [
@@ -48,6 +49,7 @@
     },
     {
         "id": "fs_section_rect",
+        "nodeType": "CourbeRemousRectangle",
         "option": "fix",
         "dep_exist": [
             {
@@ -58,7 +60,7 @@
         "fields": [
             {
                 "type": "input",
-                "id": "LargeurFond",
+                "id": "LargeurBerge",
                 "unit": "m",
                 "value": 2.5
             }
@@ -66,6 +68,7 @@
     },
     {
         "id": "fs_section_circ",
+        "nodeType": "CourbeRemousCercle",
         "option": "fix",
         "dep_exist": [
             {
@@ -83,12 +86,13 @@
         ]
     },
     {
-        "id": "fs_section_para",
+        "id": "fs_section_puiss",
+        "nodeType": "CourbeRemousPuissance",
         "option": "fix",
         "dep_exist": [
             {
                 "refid": "select_section",
-                "refvalue": "select_section_para"
+                "refvalue": "select_section_puiss"
             }
         ],
         "fields": [
@@ -100,7 +104,7 @@
             },
             {
                 "type": "input",
-                "id": "B",
+                "id": "LargeurBerge",
                 "unit": "m",
                 "value": 2
             }
@@ -112,10 +116,16 @@
         "fields": [
             {
                 "type": "input",
-                "id": "K",
+                "id": "Ks",
                 "unit": "m1/3s-1",
                 "value": 40
             },
+            {
+                "type": "input",
+                "id": "Long",
+                "unit": "m",
+                "value": 100
+            },
             {
                 "type": "input",
                 "id": "If",
@@ -124,7 +134,7 @@
             },
             {
                 "type": "input",
-                "id": "H",
+                "id": "YB",
                 "unit": "m",
                 "value": 1
             }
@@ -136,7 +146,31 @@
         "fields": [
             {
                 "type": "input",
-                "id": "Pd",
+                "id": "Q",
+                "unit": "m³/s",
+                "value": 2
+            },
+            {
+                "type": "input",
+                "id": "Yaval",
+                "unit": "m",
+                "value": 0.4
+            },
+            {
+                "type": "input",
+                "id": "Yamont",
+                "unit": "m",
+                "value": 0.15
+            }
+        ]
+    },
+    {
+        "id": "fs_param_calc",
+        "option": "fix",
+        "fields": [
+            {
+                "type": "input",
+                "id": "Dx",
                 "unit": "m",
                 "value": 5
             },
@@ -157,7 +191,7 @@
                         "id": "select_resolution_rk4"
                     },
                     {
-                        "id": "select_resolution_trap"
+                        "id": "select_resolution_euler"
                     }
                 ]
             }
@@ -174,55 +208,55 @@
                         "id": "select_target_none"
                     },
                     {
-                        "id": "select_target_hs"
+                        "id": "select_target_Hs"
                     },
                     {
-                        "id": "select_target_hsc"
+                        "id": "select_target_Hsc"
                     },
                     {
-                        "id": "select_target_b"
+                        "id": "select_target_B"
                     },
                     {
-                        "id": "select_target_p"
+                        "id": "select_target_P"
                     },
                     {
-                        "id": "select_target_s"
+                        "id": "select_target_S"
                     },
                     {
-                        "id": "select_target_r"
+                        "id": "select_target_R"
                     },
                     {
-                        "id": "select_target_v"
+                        "id": "select_target_V"
                     },
                     {
-                        "id": "select_target_fr"
+                        "id": "select_target_Fr"
                     },
                     {
-                        "id": "select_target_yc"
+                        "id": "select_target_Yc"
                     },
                     {
-                        "id": "select_target_yn"
+                        "id": "select_target_Yn"
                     },
                     {
-                        "id": "select_target_yf"
+                        "id": "select_target_Yf"
                     },
                     {
-                        "id": "select_target_yt"
+                        "id": "select_target_Yt"
                     },
                     {
-                        "id": "select_target_yco"
+                        "id": "select_target_Yco"
                     },
                     {
-                        "id": "select_target_j"
+                        "id": "select_target_J"
                     },
                     {
-                        "id": "select_target_i_j"
+                        "id": "select_target_I-J"
                     },
                     {
-                        "id": "select_target_imp"
+                        "id": "select_target_Imp"
                     },
                     {
-                        "id": "select_target_tau0"
+                        "id": "select_target_Tau0"
                     }
                 ]
             }
@@ -230,6 +264,6 @@
     },
     {
         "id": "options",
-        "idCal": "J"
+        "nodeType": "CourbeRemous"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/remous/remous.fr.json b/src/app/calculators/remous/remous.fr.json
index fc1192576..ad73abf68 100644
--- a/src/app/calculators/remous/remous.fr.json
+++ b/src/app/calculators/remous/remous.fr.json
@@ -4,26 +4,27 @@
     "select_section_trapez": "Trapézoïdale",
     "select_section_rect": "Rectangulaire",
     "select_section_circ": "Circulaire",
-    "select_section_para": "Parabolique",
+    "select_section_puiss": "Parabolique",
     "fs_section_trapez": "Définition de la section trapézoïdale",
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
     "fs_section_rect": "Définition de la section rectangulaire",
     "fs_section_circ": "Définition de la section circulaire",
     "D": "Diamètre",
-    "fs_section_para": "Définition de la section parabolique",
+    "fs_section_puiss": "Définition de la section puissance",
     "k": "Coefficient",
-    "B": "Largeur de berge",
+    "LargeurBerge": "Largeur de berge",
     "fs_bief": "Caractéristiques du bief",
-    "K": "Coefficient de Strickler",
+    "Ks": "Coefficient de Strickler",
+    "Long": "Longueur du bief",
     "If": "Pente du fond",
-    "H": "Hauteur de berge",
+    "YB": "Hauteur de berge",
     "fs_condlim": "Conditions aux limites",
-    "Q_a": "Débit amont",
-    "Y_a": "Tirant d'eau imposé à l'aval",
-    "Y_A": "Tirant d'eau imposé à l'amont",
+    "Q": "Débit amont",
+    "Yaval": "Tirant d'eau imposé à l'aval",
+    "Yamont": "Tirant d'eau imposé à l'amont",
     "fs_param_calc": "Paramètres de calcul",
-    "Pd": "Pas de discrétisation",
+    "Dx": "Pas de discrétisation",
     "Pr": "Précision de calcul et d'affichage des cotes",
     "select_resolution": "Méthode de résolution",
     "select_resolution_trap": "Intégration par trapèzes",
diff --git a/src/app/components/remous-results/remous-results.component.html b/src/app/components/remous-results/remous-results.component.html
new file mode 100644
index 000000000..2f957c349
--- /dev/null
+++ b/src/app/components/remous-results/remous-results.component.html
@@ -0,0 +1,42 @@
+<div style="width:30%; height: 400px">
+    <chart [type]="graph_type" [data]="graph_data" [options]="graph_options"></chart>
+    <!--
+    <div>
+        <chart style="float: left" [type]="graph_type" [data]="graph_data" [options]="graph_options"></chart>
+-->
+</div>
+<br/>
+<div style="text-align:center;">
+    <!-- journal -->
+    <table style="float: left">
+        <thead>
+            <tr>
+                <th>Journal de calcul</th>
+            </tr>
+        </thead>
+        <tr *ngFor="let r of _logEntries">
+            <td>{{r}}</td>
+        </tr>
+    </table>
+    <br/>
+    <!-- résultats numériques -->
+    <table style="float: left">
+        <thead>
+            <tr>
+                <th></th>
+                <th>Ligne d'eau fluviale</th>
+                <th>Ligne d'eau torrentielle</th>
+            </tr>
+            <tr>
+                <th>Abscisse</th>
+                <th>Tirant d'eau (m)</th>
+                <th>Tirant d'eau (m)</th>
+            </tr>
+        </thead>
+        <tr *ngFor="let r of _results; let i=index" [class]="getResultClass(i)">
+            <td>{{r.abs}}</td>
+            <td>{{r.flu}}</td>
+            <td>{{r.tor}}</td>
+        </tr>
+    </table>
+</div>
\ No newline at end of file
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
new file mode 100644
index 000000000..584950c68
--- /dev/null
+++ b/src/app/components/remous-results/remous-results.component.ts
@@ -0,0 +1,221 @@
+import { Component } from '@angular/core';
+
+@Component({
+    selector: 'remous-results',
+    templateUrl: './remous-results.component.html',
+    styles: [`
+    .result_label {
+        text-align: right;
+        padding-top:10px;
+        padding-bottom:10px;
+        padding-right:10px;   
+    }
+    .result_value {
+        text-align: center;
+        padding-left:30px;   
+        padding-right:30px;   
+    }
+    .result_id_0 {
+        background-color: #f0f0f0;
+    }
+    .result_id_2 {
+        font-weight: bold;
+    }
+    `
+    ]
+})
+export class RemousResultsComponent {
+    // /**
+    //  * tirant imposé à l'amont
+    //  */
+    // private _Yamont: number;
+
+    // /**
+    //  * tirant imposé à l'aval
+    //  */
+    // private _Yaval: number;
+
+    /**
+     * pente du fond
+     */
+    private _penteFond: number;
+
+    /**
+     * hauteur de berge
+     */
+    private _hautBerge: number;
+
+    /**
+     * hauteur normale
+     */
+    private _hautNormale: number;
+
+    /**
+     * hauteur critique
+     */
+    private _hautCritique: number;
+
+    /**
+     * longueur du bief
+     */
+    private _longBief: number;
+
+    /**
+    * journal
+    */
+    private _logEntries: Object[] = [];
+
+    /**
+    * résultats numériques
+    */
+    private _results: Object[] = [];
+
+    /**
+    * tableau de valeurs du graphe des tirants
+    */
+    private _fluvialGraph: any = {};
+    private _torrentGraph: any = {};
+
+    /*
+    * config du graphe
+    */
+    private graph_type = 'line';
+    private graph_data = {};
+    private graph_options = {
+        responsive: true,
+        maintainAspectRatio: true,
+        animation: {
+            duration: 0
+        },
+        legend: {
+            display: false
+        },
+        title: {
+            display: false,
+            text: ""
+        }
+    };
+
+    public reset() {
+        this._results = [];
+        this._logEntries = [];
+        this._fluvialGraph = {};
+        this._torrentGraph = {};
+    }
+
+    /**
+     * transforme une cote en tenant compte du fond
+     * @param x abscisse où se trouve la cote à transformer
+     * @param y cote à transformer
+     */
+    private mapY(x: number, y: number) {
+        let d: number;
+        if (this._penteFond >= 0) {
+            d = this._penteFond * (this._longBief - x);
+        } else {
+            d = -this._penteFond * x;
+        }
+        return y + d;
+    }
+
+    private drawLine(y0: number, ymax: number, color: string, fillColor: string = undefined) {
+        let ys = [];
+        ys.push({ x: 0, y: this.mapY(0, y0) });
+        ys.push({ x: this._longBief, y: this.mapY(this._longBief, ymax) });
+        // return { data: yFond, fill: true, tension: 0, borderColor: "#753F00", backgroundColor: "#753F00", pointRadius: 0 };
+        return { data: ys, fill: fillColor != undefined, tension: 0, borderColor: color, backgroundColor: fillColor, pointRadius: 0 };
+    }
+
+    public generateGraph() {
+        // http://www.chartjs.org/docs/latest/charts/line.html
+
+        let ds: any = [];
+
+        // abscisses
+
+        let labs = [];
+        for (let r of this._results)
+            labs.push(+r["abs"]);
+
+        // ligne de fond
+        ds.push(this.drawLine(0, 0, "#753F00", "#753F00"));
+
+        // ligne de berge
+        ds.push(this.drawLine(this._hautBerge, this._hautBerge, "#C58F50"));
+
+        // hauteur normale
+        ds.push(this.drawLine(this._hautNormale, this._hautNormale, "#A4C537"));
+
+        // hauteur critique
+        ds.push(this.drawLine(this._hautCritique, this._hautCritique, "#FF0000"));
+
+        // lignes d'eau torrentielle et fluviale
+
+        let dataFlu = [];
+        let dataTor = [];
+        for (let r of this._results) {
+            let x: number = +r["abs"];
+            let yFlu: string = r["flu"];
+            let yTor: string = r["tor"];
+            if (yFlu != undefined && yFlu != "")
+                dataFlu.push(this.mapY(x, +yFlu));
+            if (yTor != undefined && yTor != "")
+                dataTor.push(this.mapY(x, +yTor));
+        }
+        ds.push({ data: dataTor, tension: 0, borderColor: "#77A3CD", pointRadius: 5, backgroundColor: "#D1D0D4" });
+        ds.push({ data: dataFlu, tension: 0, borderColor: "#0093BD", pointRadius: 5, backgroundColor: "#D1D0D4" });
+
+        this.graph_data = {
+            labels: labs,
+            datasets: ds
+        };
+    }
+
+    public addResult(x: string, f: string, t: string) {
+        this._results.push({ "abs": x, "flu": f, "tor": t });
+    }
+
+    public addLogEntry(s: string) {
+        this._logEntries.push(s);
+    }
+
+    // public setYamont(v: number) {
+    //     this._Yamont = v;
+    // }
+
+    // public setYaval(v: number) {
+    //     this._Yaval = v;
+    // }
+
+    public setPenteFond(v: number) {
+        this._penteFond = v;
+    }
+
+    public setHauteurBerge(v: number) {
+        this._hautBerge = v;
+    }
+
+    public setHauteurNormale(v: number) {
+        this._hautNormale = v;
+    }
+
+    public setHauteurCritique(v: number) {
+        this._hautCritique = v;
+    }
+
+    public setLongBief(v: number) {
+        this._longBief = v;
+    }
+
+    public addXYFluvial(x: number, y: number) {
+        this._fluvialGraph.push({ x: x, y: y });
+    }
+
+    public addXYTorrent(x: number, y: number) {
+        this._torrentGraph.push({ x: x, y: y });
+    }
+
+    private getResultClass(i: number) {
+        return "result_id_" + String(i & 1);
+    }
+}
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index f8b3d8017..373d07227 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -1,7 +1,7 @@
 import { Injectable } from '@angular/core';
 import { Response } from '@angular/http';
 
-import { ComputeNodeType, IParamsEquation, acSection, Nub, ConduiteDistrib, ConduiteDistribParams } from "jalhyd";
+import { ComputeNodeType, ParamsEquation, acSection, Nub, ConduiteDistrib, ConduiteDistribParams } from "jalhyd";
 import { LechaptCalmon, LechaptCalmonParams, ParamsSectionTrapez, cSnTrapez } from "jalhyd";
 import { ParamsSectionRectang, cSnRectang, ParamsSectionCirc, cSnCirc, ParamsSectionPuiss, cSnPuiss } from "jalhyd";
 
@@ -90,7 +90,7 @@ export class FormulaireService {
         }
     }
 
-    public getNubAndParameters(ct: CalculatorType): [Nub, IParamsEquation] {
+    public getNubAndParameters(ct: CalculatorType): [Nub, ParamsEquation] {
         let f = this.getFormulaire(ct);
         switch (ct) {
             case CalculatorType.ConduiteDistributrice:
@@ -124,7 +124,7 @@ export class FormulaireService {
         }
     }
 
-    public getSectionNubAndParameters(ct: CalculatorType, nt: ComputeNodeType): [acSection, IParamsEquation] {
+    public getSectionNubAndParameters(ct: CalculatorType, nt: ComputeNodeType, getY: boolean = true): [acSection, ParamsEquation] {
         let f: FormulaireDefinition = this.getFormulaire(ct);
 
         // bief
@@ -135,7 +135,10 @@ export class FormulaireService {
 
         // caractéristiques hydro
         let Q: number = f.getParameterValue("Q"); // débit Q
-        let Y: number = f.getParameterValue("Y"); // tirant d'eau
+        if (getY)
+            var Y: number = f.getParameterValue("Y"); // tirant d'eau
+        else
+            Y = undefined;
 
         let Prec = f.getParameterValue("Pr"); // précision calcul/affichage
 
@@ -147,6 +150,7 @@ export class FormulaireService {
         switch (nt) {
             case ComputeNodeType.SectionTrapeze:
             case ComputeNodeType.RegimeUniformeTrapeze:
+            case ComputeNodeType.CourbeRemousTrapeze:
                 {
                     let LargeurFond = f.getNodeParameterValue(nt, "LargeurFond"); // Largeur au fond
                     let Fruit = f.getNodeParameterValue(nt, "Fruit"); // Fruit des berges
@@ -157,6 +161,7 @@ export class FormulaireService {
 
             case ComputeNodeType.SectionRectangle:
             case ComputeNodeType.RegimeUniformeRectangle:
+            case ComputeNodeType.CourbeRemousRectangle:
                 {
                     let LargeurFond = f.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au fond
                     let prms = new ParamsSectionRectang(Y, LargeurFond, Ks, Q, If, Prec, YB);
@@ -166,6 +171,7 @@ export class FormulaireService {
 
             case ComputeNodeType.SectionCercle:
             case ComputeNodeType.RegimeUniformeCercle:
+            case ComputeNodeType.CourbeRemousCercle:
                 {
                     let D = f.getNodeParameterValue(nt, "D"); // Largeur au fond
                     let prms = new ParamsSectionCirc(D, Y, Ks, Q, If, Prec, YB);
@@ -175,6 +181,7 @@ export class FormulaireService {
 
             case ComputeNodeType.SectionPuissance:
             case ComputeNodeType.RegimeUniformePuissance:
+            case ComputeNodeType.CourbeRemousPuissance:
                 {
                     let k = f.getNodeParameterValue(nt, "k"); // coefficient
                     let LargeurBerge = f.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au niveau des berges
@@ -205,6 +212,9 @@ export class FormulaireService {
             case CalculatorType.RegimeUniforme:
                 return "app/calculators/regime-uniforme/regime-uniforme.";
 
+            case CalculatorType.CourbeRemous:
+                return "app/calculators/remous/remous.";
+
             default:
                 throw "FormulaireService.getConfigPathPrefix() : valeur de CalculatorType " + ct + " non implémentée"
         }
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index fce555e49..d952660c1 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -1,4 +1,7 @@
-import { ParamDomain, ComputeNodeType, ComputeNodeParameters, IParamsEquation, ParamsSectionRectang, ParamDefinition, ParamDomainValue, ParamCalculability } from 'jalhyd';
+import {
+    ParamDomain, ComputeNodeType, ComputeNodeParameters, ParamsEquation, ParamsSectionRectang, ParamDefinition,
+    ParamDomainValue, ParamCalculability
+} from 'jalhyd';
 
 import { NgParameter } from "../../calculators/generic/ngparam";
 import { logObject } from '../../util';
@@ -20,10 +23,14 @@ export class ParamService {
         this.addParameters(ComputeNodeType.RegimeUniformeRectangle);
         this.addParameters(ComputeNodeType.RegimeUniformeCercle);
         this.addParameters(ComputeNodeType.RegimeUniformePuissance);
+        this.addParameters(ComputeNodeType.CourbeRemousCercle);
+        this.addParameters(ComputeNodeType.CourbeRemousPuissance);
+        this.addParameters(ComputeNodeType.CourbeRemousRectangle);
+        this.addParameters(ComputeNodeType.CourbeRemousTrapeze);
 
         // précision de calcul
 
-        let d = new ParamDomain(ParamDomainValue.POS, 1e-10, 100);
+        let d = new ParamDomain(ParamDomainValue.INTERVAL, 1e-10, 100);
         let p = new ParamDefinition(ComputeNodeType.LechaptCalmon, 'Pr', d);
         p.calculability = ParamCalculability.FREE;
         this.addParameter(p);
@@ -40,6 +47,10 @@ export class ParamService {
         p.calculability = ParamCalculability.FREE;
         this.addParameter(p);
 
+        p = new ParamDefinition(ComputeNodeType.CourbeRemous, 'Pr', d);
+        p.calculability = ParamCalculability.FREE;
+        this.addParameter(p);
+
         // logObject(this._params);
     }
 
@@ -58,28 +69,10 @@ export class ParamService {
     }
 
     private addParameters(nodeType: ComputeNodeType) {
-        let cdp: IParamsEquation = ComputeNodeParameters.getInstance().getComputeNodeParameters(nodeType);
-        for (let pi in cdp) {
-            /*
-            Langage de m.... !
-            Ici p n'a pas de type déclaré (bien que le type (ParamDefinition) soit connu à l'exécution,
-            le debugger le montre), et on peut quand même l'ajouter à this._params bien que son type soit
-            différent (NgParam[]) !
-
-            let p = cdp[pi];
-            if (!this.hasParameter(p.symbol))
-                this._params.push(p);
-            */
-            /*
-              ce code ne marche pas mais compile sans pb !!
-            
-              let p: ParamDefinition = cdp[pi]; // on peut avoir n'importe quoi dans p malgré son typage
-              if (!this.hasParameter(p.symbol)) 
-                  this._params.push(new NgParameter(p));
-            */
-            let p = cdp[pi]; // on peut écrire let p:ParamDefinition = cdp[pi]; ça ne dérange pas le compilateur
-            if (p instanceof ParamDefinition) // obligatoire car malgré le typage de p, p peut être = constructor ou n'importe quel autre membre
-                this.addParameter(p);
+        let cdp: ParamsEquation = ComputeNodeParameters.getInstance().getComputeNodeParameters(nodeType);
+        for (let pi in cdp.map) {
+            let p: ParamDefinition = cdp.map[pi];
+            this.addParameter(p);
         }
     }
 
@@ -101,6 +94,12 @@ export class ParamService {
             case ComputeNodeType.RegimeUniformeTrapeze:
                 return this.getParameter(ComputeNodeType.RegimeUniforme, symbol);
 
+            case ComputeNodeType.CourbeRemousCercle:
+            case ComputeNodeType.CourbeRemousPuissance:
+            case ComputeNodeType.CourbeRemousRectangle:
+            case ComputeNodeType.CourbeRemousTrapeze:
+                return this.getParameter(ComputeNodeType.CourbeRemous, symbol);
+
             default:
                 return undefined;
         }
-- 
GitLab