From 314768c3eb7989929895a7bd3db8028423e9aa13 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 30 Jul 2019 09:37:31 +0200
Subject: [PATCH 01/11] Update jalhyd_branch

---
 jalhyd_branch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jalhyd_branch b/jalhyd_branch
index 4cc13e7cb..1f7391f92 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-66-integrer-au-modele-un-maximum-d-informations-pour-alleger-la-configuration-des-modules-dans-nghyd
+master
-- 
GitLab


From 68582dbbb89463830e5058c2cacb8870c1e8f68a Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 30 Jul 2019 12:10:22 +0200
Subject: [PATCH 02/11] Work on #246

---
 .../results-graph.component.html              |  4 +-
 .../results-graph/results-graph.component.ts  | 15 ++-
 .../definition/form-compute-fixedvar.ts       |  2 +-
 .../form-compute-section-parametree.ts        |  2 +-
 src/app/results/plottable-data.ts             | 10 +-
 src/app/results/plottable-pab-results.ts      |  8 ++
 src/app/results/remous-results.ts             |  2 +-
 src/app/results/var-results.ts                | 98 +++++++++++++++++--
 src/locale/messages.en.json                   | 10 ++
 src/locale/messages.fr.json                   | 10 ++
 10 files changed, 142 insertions(+), 19 deletions(-)

diff --git a/src/app/components/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html
index 50024d806..d27357a5e 100644
--- a/src/app/components/results-graph/results-graph.component.html
+++ b/src/app/components/results-graph/results-graph.component.html
@@ -26,7 +26,7 @@
 <div class="select-x-y-axis" fxLayout="row wrap" fxLayoutAlign="space-between start">
     <mat-form-field fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
         <mat-select id="selectX" [placeholder]="uitextSelectX" [(value)]="chartX">
-            <mat-option *ngFor="let x of availableChartAxis" [value]="x" [title]="getChartAxisLabel(x)">
+            <mat-option *ngFor="let x of availableXAxis" [value]="x" [title]="getChartAxisLabel(x)">
                 {{ getChartAxisLabel(x) }}
             </mat-option>
         </mat-select>
@@ -36,7 +36,7 @@
 
     <mat-form-field fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
         <mat-select id="selectY" [placeholder]="uitextSelectY" [(value)]="chartY">
-            <mat-option *ngFor="let y of availableChartAxis" [value]="y" [title]="getChartAxisLabel(y)">
+            <mat-option *ngFor="let y of availableYAxis" [value]="y" [title]="getChartAxisLabel(y)">
                 {{ getChartAxisLabel(y) }}
             </mat-option>
         </mat-select>
diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
index 6ea796e94..07f5703a8 100644
--- a/src/app/components/results-graph/results-graph.component.ts
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -96,9 +96,20 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
         }
     }
 
-    public get availableChartAxis() {
+    public get availableXAxis() {
         if (this._results) {
-            return this._results.getAvailableChartAxis();
+            return this._results.getAvailableXAxis();
+        }
+    }
+
+    public get availableYAxis() {
+        if (this._results) {
+            if (this._results.graphType !== GraphType.Scatter) {
+                // do not use real Y axis (that include families), if chart cannot display multiple series
+                return this._results.getAvailableXAxis();
+            } else {
+                return this._results.getAvailableYAxis();
+            }
         }
     }
 
diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
index 2900c66b1..00d5793b3 100644
--- a/src/app/formulaire/definition/form-compute-fixedvar.ts
+++ b/src/app/formulaire/definition/form-compute-fixedvar.ts
@@ -54,7 +54,7 @@ export class FormComputeFixedVar extends FormCompute {
             this.formResult.varResults.calculatedParameter = computedParam;
 
             this.formResult.varResults.result = nub.result;
-            this.formResult.varResults.update(false);
+            this.formResult.varResults.update();
         }
     }
 }
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
index 3e833eed4..a1380b658 100644
--- a/src/app/formulaire/definition/form-compute-section-parametree.ts
+++ b/src/app/formulaire/definition/form-compute-section-parametree.ts
@@ -44,7 +44,7 @@ export class FormComputeSectionParametree extends FormCompute {
             // résultats variés avec tous les résultats complémentaires
             this._varResults.variatedParameters = varParams;
             this._varResults.result = sectNub.result;
-            this._varResults.update(false);
+            this._varResults.update();
         } else {
             // résultats de section (avec le graphique de section)
             this._sectionResults.result = sectNub.result;
diff --git a/src/app/results/plottable-data.ts b/src/app/results/plottable-data.ts
index a5493b94b..687c40273 100644
--- a/src/app/results/plottable-data.ts
+++ b/src/app/results/plottable-data.ts
@@ -24,9 +24,15 @@ export interface PlottableData {
 
     /**
      * Returns a list of plottable parameters / result elements, that can be defined
-     * as X or Y chart axis
+     * as X chart axis
      */
-    getAvailableChartAxis(): string[];
+    getAvailableXAxis(): string[];
+
+    /**
+     * Returns a list of plottable parameters / result elements / families,
+     * that can be defined as Y chart axis
+     */
+    getAvailableYAxis(): string[];
 
     /**
      * Returns the series of values for the required variated parameter / result element
diff --git a/src/app/results/plottable-pab-results.ts b/src/app/results/plottable-pab-results.ts
index 57a4dd318..c75e3f5b3 100644
--- a/src/app/results/plottable-pab-results.ts
+++ b/src/app/results/plottable-pab-results.ts
@@ -50,6 +50,14 @@ export class PlottablePabResults implements PlottableData {
         return [ "x" ].concat(this.pabResults.columns);
     }
 
+    public getAvailableXAxis(): string[] {
+        return this.getAvailableChartAxis();
+    }
+
+    public getAvailableYAxis(): string[] {
+        return this.getAvailableChartAxis();
+    }
+
     // just to implement interface
     public getVariatingParametersSymbols(): string[] {
         return [];
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index 6d6e1f6e1..5610468f5 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -152,7 +152,7 @@ export class RemousResults extends CalculatorResults {
             keys.push(this.extraParamSymbol);
         }
         this._varResults.extraResultKeys = keys;
-        this._varResults.update(true);
+        this._varResults.update();
     }
 
     public get extraParamSymbol(): string {
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index b01195b15..0b43f067b 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -1,7 +1,7 @@
 import { CalculatorResults } from "./calculator-results";
 import { CalculatedParamResults } from "./param-calc-results";
 import { NgParameter } from "../formulaire/ngparam";
-import { ResultElement } from "jalhyd";
+import { ResultElement, ParamFamily } from "jalhyd";
 import { ServiceFactory } from "../services/service-factory";
 import { PlottableData } from "./plottable-data";
 import { GraphType } from "./graph-type";
@@ -30,7 +30,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
     /**
      * type de graphe
      */
-    public graphType: GraphType = GraphType.Scatter;
+    protected _graphType: GraphType = GraphType.Scatter;
 
     /**
      * variated parameter or result displayed as chart's X-axis
@@ -93,6 +93,15 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         return this._extraResultHeaders;
     }
 
+    public get graphType(): GraphType {
+        return this._graphType;
+    }
+
+    public set graphType(gt: GraphType) {
+        this._graphType = gt;
+        this.resetDefaultAxisIfNeeded();
+    }
+
     public getChartAxisLabel(symbol: string): string {
         // 1. calculated param ?
         if (this.calculatedParameter && this.calculatedParameter.symbol === symbol) {
@@ -160,9 +169,9 @@ export class VarResults extends CalculatedParamResults implements PlottableData
 
     /**
      * Returns a list of plottable parameters / result elements, that can be defined
-     * as X or Y chart axis
+     * as X chart axis
      */
-    public getAvailableChartAxis(): string[] {
+    public getAvailableXAxis(): string[] {
         const res: string[] = [];
         if (this.calculatedParameter) {
             res.push(this.calculatedParameter.symbol);
@@ -176,6 +185,71 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         return res;
     }
 
+    /**
+     * Same as X axis, plus results families if graph type is Scatter
+     * (for multi-series comparison)
+     */
+    public getAvailableYAxis(): string[] {
+        const res: string[] = this.getAvailableXAxis();
+        if (this._graphType === GraphType.Scatter) {
+            // add families having more than 1 variable as plottable ordinates
+            const families = this.extractFamilies();
+            console.log("FOUND FAMILIES", families);
+            for (const f in families) {
+                if (families[f].length > 1) {
+                    res.push(f);
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Browses all parameters and results to produce a map of families => list of
+     * symbols in this family
+     */
+    private extractFamilies(): { [key: string]: string[] } {
+        const families: { [key: string]: string[] } = {};
+        if (this.calculatedParameter) {
+            const f = ParamFamily[this.calculatedParameter.paramDefinition.family];
+            console.log(`1 - calcParam: ${this.calculatedParameter.symbol} > ${f}`);
+            if (f !== undefined) {
+                if (! (f in families)) {
+                    console.log("-- init to []");
+                    families[f] = [];
+                }
+                console.log("--- push", this.calculatedParameter.symbol);
+                families[f].push(this.calculatedParameter.symbol);
+            }
+        }
+        for (const v of this._variatedParams) {
+            const f = ParamFamily[v.paramDefinition.family];
+            console.log(`2 - variatedParam: ${v.symbol} > ${f}`);
+            if (f !== undefined) {
+                if (! (f in families)) {
+                    console.log("-- init to []");
+                    families[f] = [];
+                }
+                console.log("--- push", v.symbol);
+                families[f].push(v.symbol);
+            }
+        }
+        for (const erk in this.extraResultKeys) {
+
+            const f = ParamFamily[this.result.sourceNub.extraResultsFamilies[erk]];
+            console.log(`3 - extraResult: ${erk} > ${f}`);
+            if (f !== undefined) {
+                if (! (f in families)) {
+                    console.log("-- init to []");
+                    families[f] = [];
+                }
+                console.log("--- push", erk);
+                families[f].push(erk);
+            }
+        }
+        return families;
+    }
+
     /**
      * Returns the list of variating parameters
      * (used by tooltip functions)
@@ -186,7 +260,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         });
     }
 
-    public update(displaySymbol: boolean) {
+    public update() {
         if (this._variableParamHeaders.length === 0) {
             this._variableParamHeaders = this._variatedParams.map((v) => {
                 return CalculatorResults.paramLabel(v, true);
@@ -244,14 +318,18 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, k)
             );
         }
+        this.resetDefaultAxisIfNeeded();
+    }
 
-        // when variable parameter changes, ensure the X / Y current values are still available
-        // (might be the previous variated parameter, that is not accessible anymore)
-        const aca = this.getAvailableChartAxis();
-        if (! aca.includes(this.chartX)) {
+    /**
+     * When variable parameter or graph type changes, ensure the X / Y current values are still available
+     */
+    public resetDefaultAxisIfNeeded() {
+        console.log("RDAIN");
+        if (! this.getAvailableXAxis().includes(this.chartX)) {
             this.chartX = this.variatedParameters[0].symbol;
         }
-        if (! aca.includes(this.chartY)) {
+        if (! this.getAvailableYAxis().includes(this.chartY)) {
             this.chartY = this.variatedParameters[0].symbol;
         }
     }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 42c454e76..033387261 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -135,6 +135,16 @@
     "INFO_WALL_REMOVED": "Wall #%s removed",
     "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
+    "INFO_LIB_LENGTHS": "Every length",
+    "INFO_LIB_WIDTHS": "Every width",
+    "INFO_LIB_SLOPES": "Every slope",
+    "INFO_LIB_HEIGHTS": "Every height",
+    "INFO_LIB_BASINFALLS": "Every basin fall",
+    "INFO_LIB_TOTALFALLS": "Every total fall",
+    "INFO_LIB_ELEVATIONS": "Every elevation",
+    "INFO_LIB_VOLUMES": "Every volume",
+    "INFO_LIB_FLOWS": "Every flow",
+    "INFO_LIB_DIAMETERS": "Every diameter",
     "INFO_LIB_ABSCISSE_CLOISON": "Wall abscissa",
     "INFO_LIB_ALPHA": "Alpha coefficient",
     "INFO_LIB_ALPHA2": "Half-angle at the apex",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 245c7a820..932338269 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -135,6 +135,16 @@
     "INFO_WALL_REMOVED": "Cloison n°%s supprimée",
     "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
+    "INFO_LIB_LENGTHS": "Toutes les longueurs",
+    "INFO_LIB_WIDTHS": "Toutes les largeurs",
+    "INFO_LIB_SLOPES": "Toutes les pentes",
+    "INFO_LIB_HEIGHTS": "Toutes les hauteurs",
+    "INFO_LIB_BASINFALLS": "Toutes les chutes entre bassins",
+    "INFO_LIB_TOTALFALLS": "Toutes les chutes totales",
+    "INFO_LIB_ELEVATIONS": "Toutes les cotes",
+    "INFO_LIB_VOLUMES": "Tous les volumes",
+    "INFO_LIB_FLOWS": "Tous les débits",
+    "INFO_LIB_DIAMETERS": "Tous les diamètres",
     "INFO_LIB_ABSCISSE_CLOISON": "Abscisse de la cloison",
     "INFO_LIB_ALPHA": "Coefficient alpha",
     "INFO_LIB_ALPHA2": "Demi-angle au sommet",
-- 
GitLab


From e3c41c390e248c63d3003ddc07731dbef6e6c3fc Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 31 Jul 2019 10:53:04 +0200
Subject: [PATCH 03/11] Update jalhyd_branch

---
 jalhyd_branch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jalhyd_branch b/jalhyd_branch
index 1f7391f92..c9cd8896a 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-master
+128-reorganisation-du-stockage-des-resultats-dans-le-nub
-- 
GitLab


From 5cc4596d514aaf809b289ff1fe24297d6988c046 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 31 Jul 2019 17:48:03 +0200
Subject: [PATCH 04/11] Adaptation to jalhyd results  refactoring

---
 .../fixed-results.component.ts                |  2 +-
 .../fixedvar-results.component.ts             |  4 +--
 .../pab-results/pab-results.component.ts      | 28 +++++++++----------
 src/app/results/pab-results.ts                | 18 ++++++------
 src/app/results/param-calc-results.ts         |  2 +-
 5 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index 4a9534654..1a9a0f822 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -91,7 +91,7 @@ export class FixedResultsComponent {
         const res = this._fixedResults.result;
         if (
             res
-            && res.nbResultElements > 0
+            && res.resultElements.length > 0
             && res.resultElement
             && res.extraResults
         ) {
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index d5d9c85cc..87a483a11 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -99,8 +99,8 @@ export class FixedVarResultsComponent implements DoCheck {
     }
 
     private mergeLog(result: Result, log: cLog) {
-        if (result && result.hasLog) {
-            if (result.hasGlobalLog) {
+        if (result && result.hasLog()) {
+            if (result.hasGlobalLog()) {
                 log.addLog(result.globalLog);
             } else {
                 log.addLog(result.log);
diff --git a/src/app/components/pab-results/pab-results.component.ts b/src/app/components/pab-results/pab-results.component.ts
index 4c3418eab..510867ca6 100644
--- a/src/app/components/pab-results/pab-results.component.ts
+++ b/src/app/components/pab-results/pab-results.component.ts
@@ -109,12 +109,12 @@ export class PabResultsComponent implements DoCheck {
 
     private mergeGlobalLog(result: Result, log: cLog) {
         if (result) {
-            if (result.hasGlobalLog) {
+            if (result.hasGlobalLog()) {
                 log.addLog(result.globalLog);
             }
             // if no parameter is varying, 1st element log is considered "global"
             if (this.pabResults.variatedParameters.length === 0) {
-                if (result.hasResultElements && result.resultElement.hasLog) {
+                if (result.hasResultElements() && result.resultElement.hasLog()) {
                     log.addLog(result.log);
                 }
             }
@@ -130,9 +130,9 @@ export class PabResultsComponent implements DoCheck {
             warning: 0,
             error: 0
         };
-        if (this._pabResults.result && this._pabResults.result.hasLog) {
+        if (this._pabResults.result && this._pabResults.result.hasLog()) {
             for (const re of this._pabResults.result.resultElements) {
-                if (re.hasLog) {
+                if (re.hasLog()) {
                     for (const m of re.log.messages) {
                         const s = m.getSeverity();
                         switch (s) {
@@ -151,9 +151,9 @@ export class PabResultsComponent implements DoCheck {
             }
         }
         for (const cr of this._pabResults.cloisonsResults) {
-            if (cr && cr.hasLog) {
+            if (cr && cr.hasLog()) {
                 for (const re of cr.resultElements) {
-                    if (re.hasLog) {
+                    if (re.hasLog()) {
                         for (const m of re.log.messages) {
                             const s = m.getSeverity();
                             switch (s) {
@@ -172,9 +172,9 @@ export class PabResultsComponent implements DoCheck {
                 }
             }
         }
-        if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.hasLog) {
+        if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.hasLog()) {
             for (const re of this._pabResults.cloisonAvalResults.resultElements) {
-                if (re.hasLog) {
+                if (re.hasLog()) {
                     for (const m of re.log.messages) {
                         const s = m.getSeverity();
                         switch (s) {
@@ -235,19 +235,19 @@ export class PabResultsComponent implements DoCheck {
                 // log de la PAB pour l'itération en cours
                 if (
                     this._pabResults.result
-                    && this._pabResults.result.hasResultElements
+                    && this._pabResults.result.hasResultElements()
                     && this._pabResults.result.resultElements[vi]
-                    && this._pabResults.result.resultElements[vi].hasLog
+                    && this._pabResults.result.resultElements[vi].hasLog()
                 ) {
                     l.addLog(this._pabResults.result.resultElements[vi].log);
                 }
                 // logs des enfants pour l'itération en cours
                 for (const cr of this._pabResults.cloisonsResults) {
-                    if (cr && cr.hasResultElements && cr.resultElements[vi].hasLog) {
+                    if (cr && cr.hasResultElements() && cr.resultElements[vi].hasLog()) {
                         l.addLog(cr.resultElements[vi].log);
                     }
                 }
-                if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.resultElements[vi].hasLog) {
+                if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.resultElements[vi].hasLog()) {
                     l.addLog(this._pabResults.cloisonAvalResults.resultElements[vi].log);
                 }
             } else {
@@ -255,11 +255,11 @@ export class PabResultsComponent implements DoCheck {
                 this.mergeGlobalLog(this._pabResults.result, l); // faut bien mettre le log global quelque part
                 // logs des enfants
                 for (const cr of this._pabResults.cloisonsResults) {
-                    if (cr && cr.hasResultElements && cr.resultElement.hasLog) {
+                    if (cr && cr.hasResultElements() && cr.resultElement.hasLog()) {
                         l.addLog(cr.resultElement.log);
                     }
                 }
-                if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.resultElement.hasLog) {
+                if (this._pabResults.cloisonAvalResults && this._pabResults.cloisonAvalResults.resultElement.hasLog()) {
                     l.addLog(this._pabResults.cloisonAvalResults.resultElement.log);
                 }
             }
diff --git a/src/app/results/pab-results.ts b/src/app/results/pab-results.ts
index 7cf40aad0..a81d37158 100644
--- a/src/app/results/pab-results.ts
+++ b/src/app/results/pab-results.ts
@@ -77,14 +77,14 @@ export class PabResults extends CalculatedParamResults {
     public get hasLog(): boolean {
         if (this.cloisonsResults) {
             for (const cr of this.cloisonsResults) {
-                if (cr && cr.hasLog) {
+                if (cr && cr.hasLog()) {
                     return true;
                 }
             }
         }
         return (
-            (this.result && this.result.hasLog)
-            || (this.cloisonAvalResults && this.cloisonAvalResults.hasLog)
+            (this.result && this.result.hasLog())
+            || (this.cloisonAvalResults && this.cloisonAvalResults.hasLog())
         );
     }
 
@@ -97,26 +97,26 @@ export class PabResults extends CalculatedParamResults {
     public hasError(): boolean {
         let err = false;
         // log principal
-        err = (err || this.result.hasErrorMessages);
+        err = (err || this.result.hasErrorMessages());
         // logs des cloisons
         for (const c of this.cloisonsResults) {
-            err = (err || c.hasErrorMessages);
+            err = (err || c.hasErrorMessages());
         }
         // log de la cloison aval
-        err = (err || this.cloisonAvalResults.hasErrorMessages);
+        err = (err || this.cloisonAvalResults.hasErrorMessages());
 
         return err;
     }
 
     /** retourne true si le calcul à l'itération i a échoué */
     public iterationHasError(i: number): boolean {
-        let err = this.result.resultElements[i].hasErrorMessages;
+        let err = this.result.resultElements[i].hasErrorMessages();
         // logs des cloisons
         for (const c of this.cloisonsResults) {
-            err = (err || c.resultElements[i].hasErrorMessages);
+            err = (err || c.resultElements[i].hasErrorMessages());
         }
         // log de la cloison aval
-        err = (err || this.cloisonAvalResults.resultElements[i].hasErrorMessages);
+        err = (err || this.cloisonAvalResults.resultElements[i].hasErrorMessages());
 
         return err;
     }
diff --git a/src/app/results/param-calc-results.ts b/src/app/results/param-calc-results.ts
index bdcabde2d..4867c0e0a 100644
--- a/src/app/results/param-calc-results.ts
+++ b/src/app/results/param-calc-results.ts
@@ -48,7 +48,7 @@ export abstract class CalculatedParamResults extends CalculatorResults {
         if (this.result === undefined) {
             return false;
         }
-        return this.result.hasLog;
+        return this.result.hasLog();
     }
 
     public get log(): cLog {
-- 
GitLab


From 1f43d960d61b4b7bba8f2cb4dc45bde9ad3ecc62 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 1 Aug 2019 14:46:16 +0200
Subject: [PATCH 05/11] Adaptation to jalhyd#128

---
 e2e/calculator.po.ts                                      | 8 +++++++-
 .../fixedvar-results/fixed-results.component.ts           | 6 +++---
 .../components/generic-input/generic-input.component.html | 2 +-
 .../section-results/section-results.component.ts          | 2 +-
 src/app/results/var-results.ts                            | 4 ++--
 5 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 1cb6f0456..8ca7eac65 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -191,7 +191,13 @@ export class CalculatorPage {
     const inputs = this.getParamInputs();
     await inputs.each(async (i) => {
       if (await i.isDisplayed()) {
-        await i.sendKeys("" + Math.floor(Math.random() * 9) + 1);
+        const hasDot = (await i.getAttribute("value")).includes(".");
+        const hasExponent = (await i.getAttribute("value")).includes("e");
+        let keys = "" + Math.floor(Math.random() * 9) + 1;
+        if (! hasDot && ! hasExponent) {
+          keys = "." + keys;
+        }
+        await i.sendKeys(keys);
       }
     });
   }
diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index 1a9a0f822..0126d9bb0 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -96,7 +96,7 @@ export class FixedResultsComponent {
             && res.extraResults
         ) {
             // 2.1. main result (sometimes empty, for ex. in "Section paramétrée")
-            if (res.name && res.resultElement.vCalc !== undefined) {
+            if (res.symbol && res.resultElement.vCalc !== undefined) {
                 let rLabel = this._fixedResults.calculatedParameterHeader;
                 // add structure position before label
                 if (res.sourceNub instanceof Structure) {
@@ -105,13 +105,13 @@ export class FixedResultsComponent {
                 }
                 data.push({
                     label: rLabel,
-                    value: this.intlService.formatResult(res.name, res.resultElement.vCalc),
+                    value: this.intlService.formatResult(res.symbol, res.resultElement.vCalc),
                     isCalcResult: true // for CSS
                 });
             }
 
             // 2.2. extra results
-            const extraResults = res.resultElement.extraResults;
+            const extraResults = res.resultElement.realExtraResults;
             for (const k in extraResults) {
                 if (extraResults.hasOwnProperty(k)) {
                     const er: number = extraResults[k];
diff --git a/src/app/components/generic-input/generic-input.component.html b/src/app/components/generic-input/generic-input.component.html
index 0e261b797..9fe6a4690 100644
--- a/src/app/components/generic-input/generic-input.component.html
+++ b/src/app/components/generic-input/generic-input.component.html
@@ -10,5 +10,5 @@
         </mat-icon>
     </div>
 
-    <mat-error>{{ errorMessage }}</mat-error>
+    <mat-error [innerHTML]="errorMessage"></mat-error>
 </mat-form-field>
diff --git a/src/app/components/section-results/section-results.component.ts b/src/app/components/section-results/section-results.component.ts
index 3b841f7cf..9ec2b037a 100644
--- a/src/app/components/section-results/section-results.component.ts
+++ b/src/app/components/section-results/section-results.component.ts
@@ -105,7 +105,7 @@ export class SectionResultsComponent extends ResultsComponent implements DoCheck
             this._resultElement = new ResultElement();
 
             // traduction des symboles des variables calculées
-            for (const k in this._results.result.extraResults) {
+            for (const k in this._results.result.realExtraResults) {
                 const lbl = k.toUpperCase();
                 const er = this._results.result.getExtraResult(k);
                 this._resultElement.addExtraResult(lbl, er);
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index 0b43f067b..dee726647 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -157,7 +157,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         }
         // 3. Result element ?
         for (const r of this.result.resultElements) { // re:ResultElement
-            for (const k in r.extraResults) {
+            for (const k in r.realExtraResults) {
                 if (k === symbol) {
                     series.push(r.extraResults[k]);
                 }
@@ -287,7 +287,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         // clés des résultats supplémentaires
         if (this.extraResultKeys.length === 0) {
             for (const re of this.result.resultElements) { // re:ResultElement
-                for (const erk in re.extraResults) {
+                for (const erk in re.realExtraResults) {
                     if (!this.extraResultKeys.includes(erk)) {
                         this.extraResultKeys.push(erk);
                     }
-- 
GitLab


From 9c269c59b2675317752664e514c1ea7d49be26c1 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 1 Aug 2019 17:57:04 +0200
Subject: [PATCH 06/11] Adaptation of fixedResults and verResults to new
 children results organisation

---
 protractor.conf.js                            |   2 +-
 .../regime-uniforme.config.json               |   2 +-
 .../fixed-results.component.ts                |  35 +++--
 .../fixedvar-results/var-results.component.ts |  48 +++---
 src/app/results/param-calc-results.ts         |   2 +-
 src/app/results/remous-results.ts             |   2 +-
 src/app/results/var-results.ts                | 145 ++++++++++--------
 .../internationalisation.service.ts           |   3 +
 src/locale/messages.en.json                   |   8 +-
 src/locale/messages.fr.json                   |   8 +-
 10 files changed, 133 insertions(+), 122 deletions(-)

diff --git a/protractor.conf.js b/protractor.conf.js
index 6c546c716..4c1db58bb 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -16,7 +16,7 @@ exports.config = {
   capabilities: {
     browserName: 'chrome',
     chromeOptions: {
-      args: [ "--headless", "--window-size=1024x768" ],
+      // args: [ "--headless", "--window-size=1024x768" ],
       prefs: {
         download: {
             prompt_for_download: false, 
diff --git a/src/app/calculators/regime-uniforme/regime-uniforme.config.json b/src/app/calculators/regime-uniforme/regime-uniforme.config.json
index 3633e1aa7..2e0257370 100644
--- a/src/app/calculators/regime-uniforme/regime-uniforme.config.json
+++ b/src/app/calculators/regime-uniforme/regime-uniforme.config.json
@@ -37,6 +37,6 @@
         "defaultNodeType": "SectionRectangle",
         "idCal": "Q",
         "sectionSourceId": "fs_section",
-        "help": "regime_uniforme"
+        "help": "hsl/regime_uniforme"
     }
 ]
\ No newline at end of file
diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index 0126d9bb0..2f1240942 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -95,34 +95,37 @@ export class FixedResultsComponent {
             && res.resultElement
             && res.extraResults
         ) {
-            // 2.1. main result (sometimes empty, for ex. in "Section paramétrée")
-            if (res.symbol && res.resultElement.vCalc !== undefined) {
-                let rLabel = this._fixedResults.calculatedParameterHeader;
-                // add structure position before label
-                if (res.sourceNub instanceof Structure) {
-                    const pos = res.sourceNub.findPositionInParent();
-                    rLabel = this.intlService.localizeText("INFO_OUVRAGE") + " n°" + (pos + 1) + ": " + rLabel;
+            const sn = this._fixedResults.result.sourceNub;
+
+            // 2.1 all results
+            for (const k of res.resultElement.keys) {
+                const er: number = res.resultElement.getValue(k);
+                // console.log(">> extraresult", k, er);
+                // calculator type for translation
+                let ct = sn.calcType;
+                if (sn.parent) {
+                    ct = sn.parent.calcType;
                 }
                 data.push({
-                    label: rLabel,
-                    value: this.intlService.formatResult(res.symbol, res.resultElement.vCalc),
+                    label: this.formService.expandVariableNameAndUnit(ct, k),
+                    value: this.intlService.formatResult(k, er),
                     isCalcResult: true // for CSS
                 });
             }
 
-            // 2.2. extra results
-            const extraResults = res.resultElement.realExtraResults;
-            for (const k in extraResults) {
-                if (extraResults.hasOwnProperty(k)) {
-                    const er: number = extraResults[k];
+            // 2.2. children results
+            for (const c of sn.getChildren()) {
+                for (const k of c.result.resultElement.keys) {
+                    const er: number = c.result.resultElement.getValue(k);
                     // calculator type for translation
-                    const sn = this._fixedResults.result.sourceNub;
                     let ct = sn.calcType;
                     if (sn.parent) {
                         ct = sn.parent.calcType;
                     }
                     data.push({
-                        label: this.formService.expandVariableNameAndUnit(ct, k),
+                        label: this.intlService.localizeText("INFO_OUVRAGE_N")
+                                + (c.findPositionInParent() + 1) + " : "
+                                + this.formService.expandVariableNameAndUnit(ct, k),
                         value: this.intlService.formatResult(k, er),
                         isCalcResult: true // for CSS
                     });
diff --git a/src/app/components/fixedvar-results/var-results.component.ts b/src/app/components/fixedvar-results/var-results.component.ts
index 620f4c90f..6b03eec40 100644
--- a/src/app/components/fixedvar-results/var-results.component.ts
+++ b/src/app/components/fixedvar-results/var-results.component.ts
@@ -56,6 +56,7 @@ export class VarResultsComponent extends ResultsComponent {
         const nDigits = this.appSetupService.displayDigits;
 
         if (this._varResults) {
+            const sn = this._varResults.result.sourceNub;
             // A. gather messages
             for (const re of this._varResults.resultElements) {
                 this._messages = this._messages.concat(re.log.messages); // es6 concat;
@@ -68,10 +69,7 @@ export class VarResultsComponent extends ResultsComponent {
             for (let i = 0; i < this._varResults.variatedParameters.length; i++) {
                 this._headers.push(this._varResults.variableParamHeaders[i]);
             }
-            if (this._varResults.calculatedParameterHeader) {
-                this._headers.push(this._varResults.calculatedParameterHeader);
-            }
-            this._headers = this._headers.concat(this._varResults.extraResultHeaders);
+            this._headers = this._headers.concat(this._varResults.resultHeaders);
 
             // C. pre-extract variable parameters values
             const varValues = [];
@@ -103,17 +101,17 @@ export class VarResultsComponent extends ResultsComponent {
 
                     // log messages for this computation step
                     if (this._messages.length > 0 && re.log.messages.length > 0) {
-                            // find highest log level to display
-                            let highest = 100;
-                            for (const lm of re.log.messages) {
-                                highest = Math.min(highest, lm.getSeverity());
-                            }
-                            list.push({
-                                messages: re.log.messages,
-                                isInfo: (highest === MessageSeverity.INFO),
-                                isWarning: (highest === MessageSeverity.WARNING),
-                                isError: (highest === MessageSeverity.ERROR)
-                            });
+                        // find highest log level to display
+                        let highest = 100;
+                        for (const lm of re.log.messages) {
+                            highest = Math.min(highest, lm.getSeverity());
+                        }
+                        list.push({
+                            messages: re.log.messages,
+                            isInfo: (highest === MessageSeverity.INFO),
+                            isWarning: (highest === MessageSeverity.WARNING),
+                            isError: (highest === MessageSeverity.ERROR)
+                        });
                     } else {
                         list.push({ messages: [] }); // empty log element to preserve row length
                     }
@@ -123,21 +121,19 @@ export class VarResultsComponent extends ResultsComponent {
                         list.push(vv[i]);
                     }
 
-                    // 2. result
-                    if (re.vCalc) { // sometimes does no exist (ex: Section Parametree)
-                        list.push(re.vCalc.toFixed(nDigits));
+                    // 2 all results
+                    for (const k of this._varResults.resultKeys) {
+                        list.push(this.intlService.formatResult(k, re.getValue(k)));
                     }
 
-                    // 3. extra results
-                    for (const erk of this._varResults.extraResultKeys) {
-                        const er = re.getExtraResult(erk);
-                        if (er !== undefined) {
-                            list.push(this.intlService.formatResult(erk, er));
-                        } else {
-                            list.push(er); // keep list ordered
+                    // 3 children results
+                    for (const c of sn.getChildren()) {
+                        for (const k of c.result.resultElements[i].keys) {
+                            const er: number = c.result.resultElements[i].getValue(k);
+                            list.push(this.intlService.formatResult(k, er));
                         }
-
                     }
+
                     this._results.push(list);
                 }
             }
diff --git a/src/app/results/param-calc-results.ts b/src/app/results/param-calc-results.ts
index 4867c0e0a..8cdf9e85e 100644
--- a/src/app/results/param-calc-results.ts
+++ b/src/app/results/param-calc-results.ts
@@ -41,7 +41,7 @@ export abstract class CalculatedParamResults extends CalculatorResults {
         if (this.result === undefined) {
             return false;
         }
-        return this.result.ok;
+        return ! this.result.hasOnlyErrors;
     }
 
     public get hasLog(): boolean {
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index 5610468f5..e0f5b3f3a 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -151,7 +151,7 @@ export class RemousResults extends CalculatorResults {
         if (this._hasExtra) {
             keys.push(this.extraParamSymbol);
         }
-        this._varResults.extraResultKeys = keys;
+        this._varResults.resultKeys = keys;
         this._varResults.update();
     }
 
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index dee726647..bf059017f 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -18,14 +18,14 @@ export class VarResults extends CalculatedParamResults implements PlottableData
     private _variableParamHeaders: string[];
 
     /**
-     * clés des résultats complémentaires
+     * clés des résultats
      */
-    public extraResultKeys: string[];
+    public resultKeys: string[];
 
     /**
-     * entête des colonnes des résultats supplémentaires
+     * entête des colonnes des résultats
      */
-    private _extraResultHeaders: string[];
+    private _resultHeaders: string[];
 
     /**
      * type de graphe
@@ -60,8 +60,8 @@ export class VarResults extends CalculatedParamResults implements PlottableData
     public reset() {
         super.reset();
         this._variableParamHeaders = [];
-        this._extraResultHeaders = [];
-        this.extraResultKeys = [];
+        this._resultHeaders = [];
+        this.resultKeys = [];
         this._yValues = [];
         this.longest = 0;
     }
@@ -89,8 +89,8 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         return this.result.resultElements;
     }
 
-    public get extraResultHeaders() {
-        return this._extraResultHeaders;
+    public get resultHeaders() {
+        return this._resultHeaders;
     }
 
     public get graphType(): GraphType {
@@ -113,9 +113,8 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 return this.variableParamHeaders[i];
             }
         }
-        // 3. Result element
+        // 3. Result element / child result
         return this.expandLabelFromSymbol(symbol);
-
     }
 
     /**
@@ -123,30 +122,32 @@ export class VarResults extends CalculatedParamResults implements PlottableData
      * its unit, but without the symbol itself
      */
     public expandLabelFromSymbol(symbol: string): string {
+        let ret = "";
         // calculator type for translation
         const sn = this.result.sourceNub;
         let ct = sn.calcType;
         if (sn.parent) {
             ct = sn.parent.calcType;
         }
-        return ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, symbol);
+        // detect children results
+        const match = /^([0-9]+)_(.+)$/.exec(symbol);
+        if (match !== null) {
+            const pos = +match[1];
+            ct = sn.getChildren()[pos].calcType;
+            symbol = match[2];
+            ret += ServiceFactory.instance.i18nService.localizeText("INFO_OUVRAGE_N") + (pos + 1) + " : ";
+        }
+        ret += ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, symbol);
+        return ret;
     }
 
     /**
      * Returns the series of values for the required variated parameter / result element
-     * @param symbol parameter / result symbol (ex: "Q")
+     * @param symbol parameter / result symbol (ex: "Q", "0_Q"...)
      */
     public getValuesSeries(symbol: string) {
         const series = [];
-        // 1. calculated param ?
-        if (this._calculatedParam && this._calculatedParam.symbol === symbol) {
-            if (this.result) {
-                for (const r of this.result.resultElements) {
-                    series.push(r.vCalc);
-                }
-            }
-        }
-        // 2. variated param ?
+        // 1. variated param ?
         for (let i = 0; i < this.variatedParameters.length; i++) {
             if (this._variatedParams[i].symbol === symbol) {
                 const iter = this.variatedParameters[i].getExtendedValuesIterator(this.size);
@@ -155,14 +156,26 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 }
             }
         }
-        // 3. Result element ?
+        // 2. Result element ?
         for (const r of this.result.resultElements) { // re:ResultElement
-            for (const k in r.realExtraResults) {
+            for (const k in r.values) {
                 if (k === symbol) {
-                    series.push(r.extraResults[k]);
+                    series.push(r.getValue(k));
                 }
             }
         }
+        // 3. Child result element ?
+        // detect children results
+        const match = /^([0-9]+)_(.+)$/.exec(symbol);
+        if (match !== null) {
+            const sn = this.result.sourceNub;
+            const pos = +match[1];
+            symbol = match[2];
+            const child = sn.getChildren()[pos];
+            for (const r of child.result.resultElements) {
+                series.push(r.getValue(symbol));
+            }
+        }
 
         return series;
     }
@@ -173,14 +186,23 @@ export class VarResults extends CalculatedParamResults implements PlottableData
      */
     public getAvailableXAxis(): string[] {
         const res: string[] = [];
-        if (this.calculatedParameter) {
-            res.push(this.calculatedParameter.symbol);
-        }
         for (const v of this._variatedParams) {
             res.push(v.symbol);
         }
-        for (const erk of this.extraResultKeys) {
-            res.push(erk);
+        for (const erk of this.resultKeys) {
+            if (erk.indexOf("ENUM_") === -1) { // ENUM variables are not plottable
+                res.push(erk);
+            }
+        }
+        // children results
+        const sn = this.result.sourceNub;
+        for (const c of sn.getChildren()) {
+            // using latest ResultElement; results count / types are supposed to be the same on every iteration
+            for (const k of c.result.resultElement.keys) {
+                if (k.indexOf("ENUM_") === -1) { // ENUM variables are not plottable
+                    res.push(c.findPositionInParent() + "_" + k);
+                }
+            }
         }
         return res;
     }
@@ -210,40 +232,21 @@ export class VarResults extends CalculatedParamResults implements PlottableData
      */
     private extractFamilies(): { [key: string]: string[] } {
         const families: { [key: string]: string[] } = {};
-        if (this.calculatedParameter) {
-            const f = ParamFamily[this.calculatedParameter.paramDefinition.family];
-            console.log(`1 - calcParam: ${this.calculatedParameter.symbol} > ${f}`);
-            if (f !== undefined) {
-                if (! (f in families)) {
-                    console.log("-- init to []");
-                    families[f] = [];
-                }
-                console.log("--- push", this.calculatedParameter.symbol);
-                families[f].push(this.calculatedParameter.symbol);
-            }
-        }
         for (const v of this._variatedParams) {
             const f = ParamFamily[v.paramDefinition.family];
-            console.log(`2 - variatedParam: ${v.symbol} > ${f}`);
             if (f !== undefined) {
                 if (! (f in families)) {
-                    console.log("-- init to []");
                     families[f] = [];
                 }
-                console.log("--- push", v.symbol);
                 families[f].push(v.symbol);
             }
         }
-        for (const erk in this.extraResultKeys) {
-
-            const f = ParamFamily[this.result.sourceNub.extraResultsFamilies[erk]];
-            console.log(`3 - extraResult: ${erk} > ${f}`);
+        for (const erk of this.resultKeys) {
+            const f = ParamFamily[this.result.sourceNub.getFamily(erk)];
             if (f !== undefined) {
                 if (! (f in families)) {
-                    console.log("-- init to []");
                     families[f] = [];
                 }
-                console.log("--- push", erk);
                 families[f].push(erk);
             }
         }
@@ -279,17 +282,13 @@ export class VarResults extends CalculatedParamResults implements PlottableData
             i++;
         }
 
-        // valeurs du paramètre à calculer
-        for (const r of this.result.resultElements) {
-            this._yValues.push(r.vCalc);
-        }
-
-        // clés des résultats supplémentaires
-        if (this.extraResultKeys.length === 0) {
+        // result keys (extra or not) - some lines might miss some results, in case of an error;
+        // use those keys to ensure all columns are filled
+        if (this.resultKeys.length === 0) {
             for (const re of this.result.resultElements) { // re:ResultElement
-                for (const erk in re.realExtraResults) {
-                    if (!this.extraResultKeys.includes(erk)) {
-                        this.extraResultKeys.push(erk);
+                for (const erk in re.values) {
+                    if (!this.resultKeys.includes(erk)) {
+                        this.resultKeys.push(erk);
                     }
                 }
             }
@@ -297,10 +296,8 @@ export class VarResults extends CalculatedParamResults implements PlottableData
 
         // set axis selectors values the first time
         let defaultY = this.chartY;
-        if (this.calculatedParameter) {
-            defaultY = this.calculatedParameter.symbol;
-        } else if (this.extraResultKeys.length > 0) {
-            defaultY = this.extraResultKeys[0];
+        if (this.resultKeys.length > 0) {
+            defaultY = this.resultKeys[0];
         }
         this.chartX = this.chartX || this.variatedParameters[this.longest].symbol;
         this.chartY = defaultY;
@@ -311,13 +308,25 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         if (sn.parent) {
             ct = sn.parent.calcType;
         }
-        // entêtes des résultats supplémentaires
-        this._extraResultHeaders = [];
-        for (const k of this.extraResultKeys) {
-            this._extraResultHeaders.push(
+        // entêtes des résultats
+        this._resultHeaders = [];
+        for (const k of this.resultKeys) {
+            this._resultHeaders.push(
                 ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, k)
             );
         }
+        // entêtes des résultats des enfants
+        for (const c of sn.getChildren()) {
+            // using latest ResultElement; results count / types are supposed to be the same on every iteration
+            for (const k of c.result.resultElement.keys) {
+                this._resultHeaders.push(
+                    ServiceFactory.instance.i18nService.localizeText("INFO_OUVRAGE_N")
+                        + (c.findPositionInParent() + 1) + " : "
+                        + ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(c.calcType, k)
+                );
+            }
+        }
+
         this.resetDefaultAxisIfNeeded();
     }
 
diff --git a/src/app/services/internationalisation/internationalisation.service.ts b/src/app/services/internationalisation/internationalisation.service.ts
index f95bcc9ba..ef1629c4f 100644
--- a/src/app/services/internationalisation/internationalisation.service.ts
+++ b/src/app/services/internationalisation/internationalisation.service.ts
@@ -190,6 +190,9 @@ export class I18nService extends Observable implements Observer {
      * Les extraResult avec le terme "ENUM_" sont traduit avec le message INFO_EXTRARES_ENUM_[Nom de la variable après ENUM_]
      */
     public formatResult(label: string, value: number): string {
+        if (value === undefined) {
+            return "";
+        }
         const match = label.indexOf("ENUM_");
         if (match > -1) {
                 return this.localizeText(`INFO_EXTRARES_${label.substring(match).toUpperCase()}_${value}`);
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 033387261..85f684af9 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -170,7 +170,6 @@
     "INFO_LIB_DISTANCE_AMONT": "Distance from upstream (m)",
     "INFO_LIB_EC": "EC: Kinetic energy",
     "INFO_LIB_ENUM_MACRORUGOFLOWTYPE": "Flow type",
-    "INFO_LIB_ENUM_STRUCTUREJETTYPE": "Jet type",
     "INFO_LIB_FLU": "Subcritical water line",
     "INFO_LIB_FR": "Froude number",
     "INFO_LIB_FS_OUVRAGE": "Device",
@@ -187,9 +186,9 @@
     "INFO_LIB_Y": "Water line",
     "INFO_LIB_MINZDV": "Minimal crest elevation",
     "INFO_LIB_MAXZDV": "Maximal crest elevation",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREFLOWMODE": "Mode",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREFLOWREGIME": "Regime",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREJETTYPE": "Jet type",
+    "INFO_LIB_ENUM_STRUCTUREFLOWMODE": "Mode",
+    "INFO_LIB_ENUM_STRUCTUREFLOWREGIME": "Regime",
+    "INFO_LIB_ENUM_STRUCTUREJETTYPE": "Jet type",
     "INFO_LIB_OUVRAGE_Q": "Discharge",
     "INFO_LIB_OUVRAGE_ZDV": "Sill elevation",
     "INFO_LIB_P": "Wetted perimeter",
@@ -280,6 +279,7 @@
     "INFO_OPTION_VALIDATE": "Validate",
     "INFO_OPTION_YES": "Yes",
     "INFO_OUVRAGE": "Structure",
+    "INFO_OUVRAGE_N": "Device #",
     "INFO_PAB_BASSIN": "Basin",
     "INFO_PAB_BASSINS": "Basins",
     "INFO_PAB_OUVRAGES": "Devices",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 932338269..2d69da54f 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -169,7 +169,6 @@
     "INFO_LIB_DISTANCE_AMONT": "Distance depuis l'amont (m)",
     "INFO_LIB_EC": "EC: Énergie cinétique",
     "INFO_LIB_ENUM_MACRORUGOFLOWTYPE": "Type d'écoulement",
-    "INFO_LIB_ENUM_STRUCTUREJETTYPE": "Type de jet",
     "INFO_LIB_FLU": "Ligne d'eau fluviale",
     "INFO_LIB_FR": "Froude",
     "INFO_LIB_FS_OUVRAGE": "Ouvrage",
@@ -186,9 +185,9 @@
     "INFO_LIB_Y": "Ligne d'eau",
     "INFO_LIB_MINZDV": "Cote minimale de la crête",
     "INFO_LIB_MAXZDV": "Cote maximale de la crête",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREFLOWMODE": "Type d'écoulement",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREFLOWREGIME": "Régime",
-    "INFO_LIB_OUVRAGE_Q_ENUM_STRUCTUREJETTYPE": "Type de jet",
+    "INFO_LIB_ENUM_STRUCTUREFLOWMODE": "Type d'écoulement",
+    "INFO_LIB_ENUM_STRUCTUREFLOWREGIME": "Régime",
+    "INFO_LIB_ENUM_STRUCTUREJETTYPE": "Type de jet",
     "INFO_LIB_OUVRAGE_Q": "Débit",
     "INFO_LIB_OUVRAGE_ZDV": "Cote du seuil",
     "INFO_LIB_P": "Périmètre mouillé",
@@ -279,6 +278,7 @@
     "INFO_OPTION_VALIDATE": "Valider",
     "INFO_OPTION_YES": "Oui",
     "INFO_OUVRAGE": "Ouvrage",
+    "INFO_OUVRAGE_N": "Ouvrage n°",
     "INFO_PAB_BASSIN": "Bassin",
     "INFO_PAB_BASSINS": "Bassins",
     "INFO_PAB_OUVRAGES": "Ouvrages",
-- 
GitLab


From 2c6f338ef6335a7ddf2259f4cf3f930a94cc95f2 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 5 Aug 2019 15:03:18 +0200
Subject: [PATCH 07/11] Removed most references to old "extraResults"

---
 .../fixed-results.component.ts                |  5 +--
 .../fixedvar-results/var-results.component.ts |  4 +-
 .../pab-profile-graph.component.ts            | 10 ++---
 .../pab-results-table.component.ts            | 12 +++---
 .../remous-results.component.ts               | 10 ++---
 .../section-results.component.ts              | 17 ++++----
 src/app/results/plottable-data.ts             |  2 +-
 src/app/results/plottable-pab-results.ts      | 10 ++---
 src/app/results/remous-results.ts             |  6 +--
 src/app/results/var-results.ts                |  2 +-
 .../services/formulaire/formulaire.service.ts |  2 +-
 .../internationalisation.service.ts           |  6 +--
 src/locale/messages.en.json                   | 40 +++++++++----------
 src/locale/messages.fr.json                   | 40 +++++++++----------
 14 files changed, 84 insertions(+), 82 deletions(-)

diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index 2f1240942..354b068a9 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -69,7 +69,7 @@ export class FixedResultsComponent {
     }
 
     /**
-     * Returns a combination of and results and extraResults for mat-table
+     * Returns a set of parameters and results for mat-table
      */
     public get dataSet() {
         const data = [];
@@ -93,14 +93,13 @@ export class FixedResultsComponent {
             res
             && res.resultElements.length > 0
             && res.resultElement
-            && res.extraResults
+            && res.resultElement.count() > 0
         ) {
             const sn = this._fixedResults.result.sourceNub;
 
             // 2.1 all results
             for (const k of res.resultElement.keys) {
                 const er: number = res.resultElement.getValue(k);
-                // console.log(">> extraresult", k, er);
                 // calculator type for translation
                 let ct = sn.calcType;
                 if (sn.parent) {
diff --git a/src/app/components/fixedvar-results/var-results.component.ts b/src/app/components/fixedvar-results/var-results.component.ts
index 6b03eec40..18a813a80 100644
--- a/src/app/components/fixedvar-results/var-results.component.ts
+++ b/src/app/components/fixedvar-results/var-results.component.ts
@@ -29,7 +29,7 @@ export class VarResultsComponent extends ResultsComponent {
     /** résultats mis en forme */
     protected _results: any[];
 
-    /** entêtes des colonnes (param à varier, à calculer + extraResults) */
+    /** entêtes des colonnes (param à varier, résultats) */
     protected _headers: string[];
 
     /** messages de log issus des résultats variés */
@@ -161,7 +161,7 @@ export class VarResultsComponent extends ResultsComponent {
     }
 
     /**
-     * Returns a combination of results and extraResults for mat-table
+     * Returns a combination of parameters and results for mat-table
      */
     public get dataSet() {
         return this._results;
diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
index f6cb671da..00dc20354 100644
--- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
+++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
@@ -208,10 +208,10 @@ export class PabProfileGraphComponent extends ResultsComponent {
         const nDigits = this.appSetupService.displayDigits;
         // X is always wall abscissa
         for (const cr of this._results.cloisonsResults) {
-            const x = cr.resultElement.getExtraResult("x"); // any resultElement will do
+            const x = cr.resultElement.getValue("x"); // any resultElement will do
             data.push(x.toFixed(nDigits));
         }
-        const xdw = this._results.cloisonAvalResults.resultElement.getExtraResult("x");
+        const xdw = this._results.cloisonAvalResults.resultElement.getValue("x");
         data.push(xdw.toFixed(nDigits));
         return data;
     }
@@ -228,19 +228,19 @@ export class PabProfileGraphComponent extends ResultsComponent {
         // extend upstrem
         dataF.push({
             x: (Number(xs[0]) - pabLength5Pct).toFixed(nDigits),
-            y: this._results.cloisonsResults[0].resultElement.getExtraResult("ZRAM").toFixed(nDigits)
+            y: this._results.cloisonsResults[0].resultElement.getValue("ZRAM").toFixed(nDigits)
         });
         // regular walls
         for (let i = 0; i < this._results.cloisonsResults.length; i++) {
             const cr = this._results.cloisonsResults[i];
-            const ZRAM = cr.resultElement.getExtraResult("ZRAM"); // any ResultElement will do
+            const ZRAM = cr.resultElement.getValue("ZRAM"); // any ResultElement will do
             dataF.push({
                 x: xs[i],
                 y: ZRAM.toFixed(nDigits)
             });
         }
         // downwall
-        const ZRAMdw = this._results.cloisonAvalResults.resultElement.getExtraResult("ZRAM");
+        const ZRAMdw = this._results.cloisonAvalResults.resultElement.getValue("ZRAM");
         dataF.push({
             x: xs[ xs.length - 1 ],
             y: ZRAMdw.toFixed(nDigits)
diff --git a/src/app/components/pab-results/pab-results-table.component.ts b/src/app/components/pab-results/pab-results-table.component.ts
index ad39f84bb..6b0550eb7 100644
--- a/src/app/components/pab-results/pab-results-table.component.ts
+++ b/src/app/components/pab-results/pab-results-table.component.ts
@@ -41,8 +41,8 @@ export class PabResultsTableComponent extends ResultsComponent {
         // jet type for each device
         const devices = re.sourceNub.getChildren();
         const jetTypes: string[] = devices.map((device) => {
-            const jt = device.result.resultElements[vi].getExtraResult("ENUM_StructureJetType");
-            let jetType = this.intlService.localizeText("INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_" + jt);
+            const jt = device.result.resultElements[vi].getValue("ENUM_StructureJetType");
+            let jetType = this.intlService.localizeText("INFO_ENUM_STRUCTUREJETTYPE_" + jt);
             if (devices.length > 1) {
                 // evil HTML injection in table cell (simpler)
                 jetType = this.intlService.localizeText("INFO_LIB_FS_OUVRAGE") + " n°"
@@ -86,7 +86,7 @@ export class PabResultsTableComponent extends ResultsComponent {
                 if (
                     pr.cloisonsResults[i].resultElements[vi].vCalc
                 ) {
-                    const r2n = pr.cloisonsResults[i].resultElements[vi].extraResults;
+                    const r2n = pr.cloisonsResults[i].resultElements[vi].values;
                     let Z1: number;
                     if (i < pr.cloisonsResults.length - 1) {
                         Z1 = pr.cloisonsResults[i + 1].resultElements[vi].vCalc;
@@ -111,7 +111,7 @@ export class PabResultsTableComponent extends ResultsComponent {
 
             // downstream line
             if (pr.cloisonAvalResults.resultElements[vi].vCalc) {
-                const rln = pr.cloisonAvalResults.resultElements[vi].extraResults;
+                const rln = pr.cloisonAvalResults.resultElements[vi].values;
                 this._dataSet.push([
                     this.intlService.localizeText("INFO_LIB_AVAL"),
                     pr.Z2[vi].toFixed(nDigits),
@@ -124,7 +124,7 @@ export class PabResultsTableComponent extends ResultsComponent {
                 // extra lift gate ?
                 const cloisonAval = (pr.cloisonAvalResults.sourceNub as CloisonAval);
                 if (cloisonAval && cloisonAval.hasVanneLevante()) {
-                    const vanneZDV = cloisonAval.result.resultElements[vi].getExtraResult("ZDV");
+                    const vanneZDV = cloisonAval.result.resultElements[vi].getValue("ZDV");
                     if (vanneZDV) {
                         this._dataSet.push([
                             this.intlService.localizeText("INFO_LIB_COTE_VANNE_LEVANTE"),
@@ -142,7 +142,7 @@ export class PabResultsTableComponent extends ResultsComponent {
     }
 
     /**
-     * Returns a combination of and results and extraResults for mat-table
+     * Returns a combination of parameters and results for mat-table
      */
     public get dataSet() {
         return this._dataSet;
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
index 1d7274ca7..da77b6c0d 100644
--- a/src/app/components/remous-results/remous-results.component.ts
+++ b/src/app/components/remous-results/remous-results.component.ts
@@ -403,7 +403,7 @@ export class RemousResultsComponent extends ResultsComponent implements DoCheck
                     throw new Error("RemousResultsComponent.connectRessaut() : erreur interne (itérateur sur x)");
                 }
                 const x = itX.next().value;
-                if (re.getExtraResult("flu") !== undefined) {
+                if (re.getValue("flu") !== undefined) {
                     minXflu = x;
                     break;
                 }
@@ -426,7 +426,7 @@ export class RemousResultsComponent extends ResultsComponent implements DoCheck
                     throw new Error("RemousResultsComponent.connectRessaut() : erreur interne (itérateur sur x)");
                 }
                 const x = itX.next();
-                if (r.getExtraResult("tor") !== undefined) {
+                if (r.getValue("tor") !== undefined) {
                     maxXtor = x;
                     break;
                 }
@@ -527,17 +527,17 @@ export class RemousResultsComponent extends ResultsComponent implements DoCheck
             }
 
             const x = itX.next().value;
-            const yExtra = re.getExtraResult(this._remousResults.extraParamSymbol);
+            const yExtra = re.getValue(this._remousResults.extraParamSymbol);
             if (yExtra !== undefined) {
                 lineExtra.mapPoint(x, yExtra);
             }
 
-            const yFlu = re.getExtraResult("flu");
+            const yFlu = re.getValue("flu");
             if (yFlu !== undefined) {
                 lineFlu.mapPoint(x, yFlu);
             }
 
-            const yTor = re.getExtraResult("tor");
+            const yTor = re.getValue("tor");
             if (yTor !== undefined) {
                 lineTor.mapPoint(x, yTor);
             }
diff --git a/src/app/components/section-results/section-results.component.ts b/src/app/components/section-results/section-results.component.ts
index 9ec2b037a..dc00f2a1c 100644
--- a/src/app/components/section-results/section-results.component.ts
+++ b/src/app/components/section-results/section-results.component.ts
@@ -105,13 +105,16 @@ export class SectionResultsComponent extends ResultsComponent implements DoCheck
             this._resultElement = new ResultElement();
 
             // traduction des symboles des variables calculées
-            for (const k in this._results.result.realExtraResults) {
-                const lbl = k.toUpperCase();
-                const er = this._results.result.getExtraResult(k);
-                this._resultElement.addExtraResult(lbl, er);
-
-                if (this.isSectionLevel(k)) {
-                    this._sectionCanvas.addLevel(er, k + " = " + er.toFixed(nDigits), SectionResultsComponent.labelColors[k]);
+            const re = this._results.result.resultElement;
+            for (const k in re.values) {
+                if (k !== re.vCalcSymbol) {
+                    const lbl = k.toUpperCase();
+                    const er = re.getValue(k);
+                    this._resultElement.addExtraResult(lbl, er);
+
+                    if (this.isSectionLevel(k)) {
+                        this._sectionCanvas.addLevel(er, k + " = " + er.toFixed(nDigits), SectionResultsComponent.labelColors[k]);
+                    }
                 }
             }
 
diff --git a/src/app/results/plottable-data.ts b/src/app/results/plottable-data.ts
index 687c40273..4b5d3f678 100644
--- a/src/app/results/plottable-data.ts
+++ b/src/app/results/plottable-data.ts
@@ -17,7 +17,7 @@ export interface PlottableData {
     getChartAxisLabel(symbol: string): string;
 
     /**
-     * Returns the translated name of the given symbol (usually an extraResult)
+     * Returns the translated name of the given symbol (usually a result or child result)
      * if available, with its unit, but without the symbol itself
      */
     expandLabelFromSymbol(symbol: string): string;
diff --git a/src/app/results/plottable-pab-results.ts b/src/app/results/plottable-pab-results.ts
index c75e3f5b3..03875d2d1 100644
--- a/src/app/results/plottable-pab-results.ts
+++ b/src/app/results/plottable-pab-results.ts
@@ -93,10 +93,10 @@ export class PlottablePabResults implements PlottableData {
             case "Q":
                 data.push("");
                 for (let i = 0; i < l; i++) {
-                    const er = pr.cloisonsResults[i].resultElements[vi].getExtraResult(symbol);
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
                     data.push((er !== undefined) ? er.toFixed(nDigits) : "");
                 }
-                const zrAval = pr.cloisonAvalResults.resultElements[vi].getExtraResult(symbol);
+                const zrAval = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
                 data.push((zrAval !== undefined) ? zrAval.toFixed(nDigits) : "");
                 break;
 
@@ -114,7 +114,7 @@ export class PlottablePabResults implements PlottableData {
             case "QA":
                 data.push("");
                 for (let i = 0; i < l; i++) {
-                    const er = pr.cloisonsResults[i].resultElements[vi].getExtraResult(symbol);
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
                     data.push((er !== undefined) ? er.toFixed(nDigits) : "");
                 }
                 data.push("");
@@ -123,10 +123,10 @@ export class PlottablePabResults implements PlottableData {
             case "x": // wall abscissa
                 data.push("");
                 for (let i = 0; i < l; i++) {
-                    const er = pr.cloisonsResults[i].resultElements[vi].getExtraResult(symbol);
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
                     data.push((er !== undefined) ? er.toFixed(nDigits) : "");
                 }
-                const erXdw = pr.cloisonAvalResults.resultElements[vi].getExtraResult(symbol);
+                const erXdw = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
                 data.push((erXdw !== undefined) ? erXdw.toFixed(nDigits) : "");
                 break;
         }
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index e0f5b3f3a..5f3bcbc56 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -123,13 +123,13 @@ export class RemousResults extends CalculatorResults {
         this._hasExtra = false;
 
         for (const re of this._result.resultElements) {
-            if (!this._hasFlu && re.getExtraResult("flu")) {
+            if (!this._hasFlu && re.getValue("flu")) {
                 this._hasFlu = true;
             }
-            if (!this._hasTor && re.getExtraResult("tor")) {
+            if (!this._hasTor && re.getValue("tor")) {
                 this._hasTor = true;
             }
-            if (!this._hasExtra && re.getExtraResult(this.extraParamSymbol)) {
+            if (!this._hasExtra && re.getValue(this.extraParamSymbol)) {
                 this._hasExtra = true;
             }
         }
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index bf059017f..cd6effda2 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -118,7 +118,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
     }
 
     /**
-     * Returns the translated name of the given symbol (usually an extraResult) with
+     * Returns the translated name of the given symbol (usually a result or child result) with
      * its unit, but without the symbol itself
      */
     public expandLabelFromSymbol(symbol: string): string {
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index a89142101..c88c9681a 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -191,7 +191,7 @@ export class FormulaireService extends Observable {
             const re = /([A-Z,a-z]+)\[(\d+)\]\.(.+)/;
             const match = re.exec(symbol);
             if (match) {
-                // Les libellés correspondants sont INFO OUVRAGE et INFO_EXTRARES_LIB_OUVRAGE_XXX
+                // Les libellés correspondants sont INFO OUVRAGE et INFO_LIB_OUVRAGE_XXX
                 s = this.intlService.localizeText(`INFO_${match[1].toUpperCase()}`)
                 + " n°" + (+match[2] + 1) + ": "
                 + this.expandVariableName(calcType, `${match[1].toUpperCase()}_${match[3].toUpperCase()}`);
diff --git a/src/app/services/internationalisation/internationalisation.service.ts b/src/app/services/internationalisation/internationalisation.service.ts
index ef1629c4f..7590f251d 100644
--- a/src/app/services/internationalisation/internationalisation.service.ts
+++ b/src/app/services/internationalisation/internationalisation.service.ts
@@ -186,8 +186,8 @@ export class I18nService extends Observable implements Observer {
     }
 
     /**
-     * Met en forme un extraResult en fonction du libellé qui l'accompagne
-     * Les extraResult avec le terme "ENUM_" sont traduit avec le message INFO_EXTRARES_ENUM_[Nom de la variable après ENUM_]
+     * Met en forme un result en fonction du libellé qui l'accompagne
+     * Les result avec le terme "ENUM_" sont traduit avec le message INFO_ENUM_[Nom de la variable après ENUM_]
      */
     public formatResult(label: string, value: number): string {
         if (value === undefined) {
@@ -195,7 +195,7 @@ export class I18nService extends Observable implements Observer {
         }
         const match = label.indexOf("ENUM_");
         if (match > -1) {
-                return this.localizeText(`INFO_EXTRARES_${label.substring(match).toUpperCase()}_${value}`);
+            return this.localizeText(`INFO_${label.substring(match).toUpperCase()}_${value}`);
         }
         const nDigits = this.applicationSetupService.displayDigits;
         return value.toFixed(nDigits);
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 85f684af9..e670ce51e 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -90,26 +90,26 @@
     "INFO_DIALOG_SAVE_SESSION_TITLE": "Save calculator modules",
     "INFO_EMPTY_SESSION_DIALOGUE_TEXT": "Warning ! All open calculators will be lost. Continue ?",
     "INFO_EMPTY_SESSION_DIALOGUE_TITRE": "New session",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_0": "Emergent",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-emergent",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_2": "Submerged",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_0": "Weir",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_1": "Orifice",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_2": "Zero flow",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_0": "Free flow",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_1": "Partially submerged",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_2": "Submerged",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_3": "Zero flow",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_0": "Weir",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_1": "Orifice",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_2": "Zero flow",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_0": "Free flow",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_1": "Partially submerged",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_2": "Submerged",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_3": "Zero flow",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_0": "Not applicable",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_1": "Diving",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_2": "Surface",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_0": "Emergent",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-emergent",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_2": "Submerged",
+    "INFO_ENUM_OUVRAGE_Q_MODE_0": "Weir",
+    "INFO_ENUM_OUVRAGE_Q_MODE_1": "Orifice",
+    "INFO_ENUM_OUVRAGE_Q_MODE_2": "Zero flow",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_0": "Free flow",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_1": "Partially submerged",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_2": "Submerged",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_3": "Zero flow",
+    "INFO_ENUM_STRUCTUREFLOWMODE_0": "Weir",
+    "INFO_ENUM_STRUCTUREFLOWMODE_1": "Orifice",
+    "INFO_ENUM_STRUCTUREFLOWMODE_2": "Zero flow",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_0": "Free flow",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_1": "Partially submerged",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_2": "Submerged",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_3": "Zero flow",
+    "INFO_ENUM_STRUCTUREJETTYPE_0": "Not applicable",
+    "INFO_ENUM_STRUCTUREJETTYPE_1": "Diving",
+    "INFO_ENUM_STRUCTUREJETTYPE_2": "Surface",
     "INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM": "Restore default zoom",
     "INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE": "Save picture",
     "INFO_GRAPH_BUTTON_TITLE_ENTER_FS": "Display fullscreen",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 2d69da54f..4eb47086a 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -90,26 +90,26 @@
     "INFO_DIALOG_SAVE_SESSION_TITLE": "Enregistrer les modules de calcul",
     "INFO_EMPTY_SESSION_DIALOGUE_TEXT": "Attention&nbsp;! Tous les modules de calcul ouverts seront perdus.",
     "INFO_EMPTY_SESSION_DIALOGUE_TITRE": "Démarrer une nouvelle session",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_0": "Émergent",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-émergent",
-    "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_2": "Immergé",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_0": "Surface libre",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_1": "En charge",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_MODE_2": "Débit nul",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_0": "Dénoyé",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_1": "Partiellement noyé",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_2": "Noyé",
-    "INFO_EXTRARES_ENUM_OUVRAGE_Q_REGIME_3": "Débit nul",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_0": "Surface libre",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_1": "En charge",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWMODE_2": "Débit nul",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_0": "Dénoyé",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_1": "Partiellement noyé",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_2": "Noyé",
-    "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_3": "Débit nul",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_0": "Sans objet",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_1": "Plongeant",
-    "INFO_EXTRARES_ENUM_STRUCTUREJETTYPE_2": "De surface",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_0": "Émergent",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-émergent",
+    "INFO_ENUM_MACRORUGOFLOWTYPE_2": "Immergé",
+    "INFO_ENUM_OUVRAGE_Q_MODE_0": "Surface libre",
+    "INFO_ENUM_OUVRAGE_Q_MODE_1": "En charge",
+    "INFO_ENUM_OUVRAGE_Q_MODE_2": "Débit nul",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_0": "Dénoyé",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_1": "Partiellement noyé",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_2": "Noyé",
+    "INFO_ENUM_OUVRAGE_Q_REGIME_3": "Débit nul",
+    "INFO_ENUM_STRUCTUREFLOWMODE_0": "Surface libre",
+    "INFO_ENUM_STRUCTUREFLOWMODE_1": "En charge",
+    "INFO_ENUM_STRUCTUREFLOWMODE_2": "Débit nul",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_0": "Dénoyé",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_1": "Partiellement noyé",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_2": "Noyé",
+    "INFO_ENUM_STRUCTUREFLOWREGIME_3": "Débit nul",
+    "INFO_ENUM_STRUCTUREJETTYPE_0": "Sans objet",
+    "INFO_ENUM_STRUCTUREJETTYPE_1": "Plongeant",
+    "INFO_ENUM_STRUCTUREJETTYPE_2": "De surface",
     "INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM": "Réinitialiser le zoom",
     "INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE": "Enregistrer l'image",
     "INFO_GRAPH_BUTTON_TITLE_ENTER_FS": "Afficher en plein écran",
-- 
GitLab


From 7ca9d4d3594d3e85d2f3acdb78eba0cd5b1e638f Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 5 Aug 2019 15:28:40 +0200
Subject: [PATCH 08/11] Update translation

---
 src/locale/messages.en.json | 2 +-
 src/locale/messages.fr.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index e670ce51e..152d21b6c 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -1,6 +1,6 @@
 {
     "ERROR_CLOISON_AVAL_UN_OUVRAGE_REGULE": "Only one regulated device is allowed on the downstream wall",
-    "ERROR_DEVER_ZR_SUP_Z1": "Elevation of the river bed can't be higher than water elevation: Impossible to calculate the kinetic energy",
+    "WARNING_DEVER_ZR_SUP_Z1": "Elevation of the river bed can't be higher than water elevation: Impossible to calculate the kinetic energy",
     "ERROR_DICHO_CONVERGE": "Dichotomy could not converge",
     "ERROR_DICHO_FUNCTION_VARIATION": "unable to determinate function direction of variation",
     "ERROR_DICHO_INIT_DOMAIN": "Dichotomy: target %targetSymbol%=%targetValue% does not exist for variable %variableSymbol% valued in interval %variableInterval%",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 4eb47086a..60e15cb86 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -1,6 +1,6 @@
 {
     "ERROR_CLOISON_AVAL_UN_OUVRAGE_REGULE": "Un seul ouvrage régulé est autorisé sur la cloison aval",
-    "ERROR_DEVER_ZR_SUP_Z1": "La cote du lit du cours d'eau ne peut pas être supérieure à la cote de l'eau&nbsp;: Impossible de calculer l'énergie cinétique",
+    "WARNING_DEVER_ZR_SUP_Z1": "La cote du lit du cours d'eau ne peut pas être supérieure à la cote de l'eau&nbsp;: Impossible de calculer l'énergie cinétique",
     "ERROR_DICHO_CONVERGE": "La dichotomie n'a pas pu converger",
     "ERROR_DICHO_FUNCTION_VARIATION": "Dichotomie&nbsp;: impossible de determiner le sens de  variation de la fonction",
     "ERROR_DICHO_INIT_DOMAIN": "Dichotomie&nbsp;: la valeur cible %targetSymbol%=%targetValue% n'existe pas pour la variable %variableSymbol% prise dans l'intervalle %variableInterval%",
-- 
GitLab


From 4cd2809d035f16e09ec50a302de9c5350f21c8ce Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 6 Aug 2019 11:01:37 +0200
Subject: [PATCH 09/11] Fix #246, #260

reorganized plottable data generation
---
 .../fixed-results.component.ts                |  28 +--
 .../fixedvar-results/results.component.ts     |  22 +++
 .../fixedvar-results/var-results.component.ts |   8 +-
 .../pab-profile-graph.component.ts            |  32 +---
 .../results-graph/results-graph.component.ts  | 162 ++++++++++++------
 src/app/results/plottable-data.ts             |   2 +-
 src/app/results/plottable-pab-results.ts      |  43 +++--
 src/app/results/remous-results.ts             |   7 +-
 src/app/results/var-results.ts                |  85 ++++++---
 src/app/results/y-series.ts                   |  11 ++
 10 files changed, 259 insertions(+), 141 deletions(-)
 create mode 100644 src/app/results/y-series.ts

diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index 354b068a9..6a38cb84e 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -114,20 +114,22 @@ export class FixedResultsComponent {
 
             // 2.2. children results
             for (const c of sn.getChildren()) {
-                for (const k of c.result.resultElement.keys) {
-                    const er: number = c.result.resultElement.getValue(k);
-                    // calculator type for translation
-                    let ct = sn.calcType;
-                    if (sn.parent) {
-                        ct = sn.parent.calcType;
+                if (c.result) {
+                    for (const k of c.result.resultElement.keys) {
+                        const er: number = c.result.resultElement.getValue(k);
+                        // calculator type for translation
+                        let ct = sn.calcType;
+                        if (sn.parent) {
+                            ct = sn.parent.calcType;
+                        }
+                        data.push({
+                            label: this.intlService.localizeText("INFO_OUVRAGE_N")
+                                    + (c.findPositionInParent() + 1) + " : "
+                                    + this.formService.expandVariableNameAndUnit(ct, k),
+                            value: this.intlService.formatResult(k, er),
+                            isCalcResult: true // for CSS
+                        });
                     }
-                    data.push({
-                        label: this.intlService.localizeText("INFO_OUVRAGE_N")
-                                + (c.findPositionInParent() + 1) + " : "
-                                + this.formService.expandVariableNameAndUnit(ct, k),
-                        value: this.intlService.formatResult(k, er),
-                        isCalcResult: true // for CSS
-                    });
                 }
             }
         }
diff --git a/src/app/components/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts
index 57c95d10a..2675d065e 100644
--- a/src/app/components/fixedvar-results/results.component.ts
+++ b/src/app/components/fixedvar-results/results.component.ts
@@ -30,4 +30,26 @@ export class ResultsComponent {
             sf.exit();
         }
     }
+
+    /**
+     * 14 distinct colors @see https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors
+     */
+    public static get distinctColors(): string[] {
+        return [
+            "#4363d8", // blue
+            "#f58231", // orange
+            "#3cb44b", // green
+            "#e6194B", // red
+            "#911eb4", // purple
+            "#ffe119", // yellow
+            "#f032e6", // magenta
+            "#9A6324", // brown
+            "#000075", // navy
+            "#808000", // olive
+            "#42d4f4", // cyan
+            "#a9a9a9", // grey
+            "#bfef45", // lime
+            "#469990", // teal
+        ];
+    }
 }
diff --git a/src/app/components/fixedvar-results/var-results.component.ts b/src/app/components/fixedvar-results/var-results.component.ts
index 18a813a80..5eb499f01 100644
--- a/src/app/components/fixedvar-results/var-results.component.ts
+++ b/src/app/components/fixedvar-results/var-results.component.ts
@@ -128,9 +128,11 @@ export class VarResultsComponent extends ResultsComponent {
 
                     // 3 children results
                     for (const c of sn.getChildren()) {
-                        for (const k of c.result.resultElements[i].keys) {
-                            const er: number = c.result.resultElements[i].getValue(k);
-                            list.push(this.intlService.formatResult(k, er));
+                        if (c.result) {
+                            for (const k of c.result.resultElements[i].keys) {
+                                const er: number = c.result.resultElements[i].getValue(k);
+                                list.push(this.intlService.formatResult(k, er));
+                            }
                         }
                     }
 
diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
index 00dc20354..f31a29cff 100644
--- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
+++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
@@ -6,6 +6,7 @@ import { ApplicationSetupService } from "../../services/app-setup/app-setup.serv
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
 import { ResultsComponent } from "../fixedvar-results/results.component";
 import { PabResults } from "../../results/pab-results";
+import { IYSeries } from "../../results/y-series";
 
 @Component({
     selector: "pab-profile-graph",
@@ -36,6 +37,7 @@ export class PabProfileGraphComponent extends ResultsComponent {
     public graph_options = {
         responsive: true,
         maintainAspectRatio: true,
+        aspectRatio: 1.5,
         animation: {
             duration: 0
         },
@@ -216,8 +218,8 @@ export class PabProfileGraphComponent extends ResultsComponent {
         return data;
     }
 
-    private getYSeries(): { data: { x: string, y: string }[], label: string, color: string }[] {
-        const ret: { data: { x: string, y: string }[], label: string, color: string }[] = [];
+    private getYSeries(): IYSeries[] {
+        const ret: IYSeries[] = [];
         const xs = this.getXSeries(); // abscissae
         const pabLength = Number(xs[xs.length - 1]) - Number(xs[0]);
         const pabLength5Pct = (pabLength * 5) / 100;
@@ -259,7 +261,7 @@ export class PabProfileGraphComponent extends ResultsComponent {
 
         // 2. séries
         const nbSeries = this._results.cloisonsResults[0].resultElements.length;
-        const palette = this.distinctColors;
+        const palette = ResultsComponent.distinctColors;
 
         seriesLoop:
         for (let n = 0; n < nbSeries; n++) {
@@ -320,7 +322,7 @@ export class PabProfileGraphComponent extends ResultsComponent {
                 label: (
                     this._results.variatedParameters.length > 0 ?
                     this.getLegendForSeries(n) :
-                    this.intlService.localizeText("INFO_LIB_LIGNE_D_EAU")
+                    this.intlService.localizeText("INFO_LIB_Y") // ligne d'eau
                 ),
                 color: palette[ n % palette.length ]
             });
@@ -344,26 +346,4 @@ export class PabProfileGraphComponent extends ResultsComponent {
             return `${vp.symbol} = ${value}`;
         }).join(", ");
     }
-
-    /**
-     * 14 distinct colors @see https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors
-     */
-    private get distinctColors(): string[] {
-        return [
-            "#4363d8", // blue
-            "#f58231", // orange
-            "#3cb44b", // green
-            "#e6194B", // red
-            "#911eb4", // purple
-            "#ffe119", // yellow
-            "#f032e6", // magenta
-            "#9A6324", // brown
-            "#000075", // navy
-            "#808000", // olive
-            "#42d4f4", // cyan
-            "#a9a9a9", // grey
-            "#bfef45", // lime
-            "#469990", // teal
-        ];
-    }
 }
diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
index 07f5703a8..16224f9ff 100644
--- a/src/app/components/results-graph/results-graph.component.ts
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -2,7 +2,7 @@ import { Component, ViewChild, AfterContentInit, ChangeDetectorRef } from "@angu
 
 import { ChartComponent } from "angular2-chartjs";
 
-import { Observer } from "jalhyd";
+import { Observer, ParamFamily } from "jalhyd";
 
 import { GraphTypeSelectComponent } from "./graph-type.component";
 import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
@@ -10,6 +10,8 @@ import { I18nService } from "../../services/internationalisation/internationalis
 import { PlottableData } from "../../results/plottable-data";
 import { GraphType } from "../../results/graph-type";
 import { ResultsComponent } from "../fixedvar-results/results.component";
+import { IYSeries } from "../../results/y-series";
+import { VarResults } from "../../results/var-results";
 
 @Component({
     selector: "results-graph",
@@ -37,8 +39,8 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
      * config du graphe
      */
     public graph_type: string;
-    public graph_data = {};
-    public graph_options = {
+    public graph_data: any = {};
+    public graph_options: any = {
         responsive: true,
         maintainAspectRatio: true,
         animation: {
@@ -191,10 +193,16 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
      * (cannot rebuild a clean label here)
      */
     private axisLabelWithoutSymbol(symbol: string) {
+        // detect children results
+        const match = /^([0-9]+)_(.+)$/.exec(symbol);
+        // get label with symbol
         let l = this._results.getChartAxisLabel(symbol);
-        const i = l.indexOf(": ");
-        if (i !== -1) {
-            l = l.substring(i + 2);
+        // remove symbol
+        if (match === null) { // child prefix also uses ":"
+            const i = l.indexOf(": ");
+            if (i !== -1) {
+                l = l.substring(i + 2);
+            }
         }
         return l;
     }
@@ -216,10 +224,11 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
         const dat = [];
         const xSeries = this._results.getValuesSeries(this.chartX);
         const ySeries = this._results.getValuesSeries(this.chartY);
+
         // both series are supposed to be the same length
         for (let i = 0; i < xSeries.length; i++) {
-            labs.push(xSeries[i]);
-            dat.push(ySeries[i]);
+            labs.push((xSeries[i] !== undefined) ? xSeries[i] : "");
+            dat.push((ySeries[i] !== undefined) ? ySeries[i] : "");
         }
 
         const nDigits = this.appSetup.displayDigits;
@@ -246,6 +255,7 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
                 }
             }]
         };
+
         const that = this;
         this.graph_options["tooltips"] = {
             displayColors: false,
@@ -257,7 +267,7 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
                     const lines: string[] = [];
                     const nbLines = that._results.getVariatingParametersSymbols().length;
                     for (const v of that._results.getVariatingParametersSymbols()) {
-                        const series = that._results.getValuesSeries(v);
+                        const series = that._results.getValuesSeries[0](v);
                         const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
                         if (v === this.chartX) {
                             if (nbLines > 1) {
@@ -286,18 +296,26 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
      * génère les données d'un graphe de type "scatter"
      */
     private generateScatterGraph() {
-        const dat = [];
-        const xSeries = this._results.getValuesSeries(this.chartX);
-        const ySeries = this._results.getValuesSeries(this.chartY);
-        // both series are supposed to be the same length
-        for (let i = 0; i < xSeries.length; i++) {
-            dat.push({
-                x: xSeries[i],
-                y: ySeries[i]
+        this.graph_data = {
+            datasets: []
+        };
+        const nDigits = this.appSetup.displayDigits;
+        const ySeries = this.getYSeries(this.chartY);
+
+        // are we dealing with multiple Y series ?
+        const isMultiple = (ySeries.length > 1);
+
+        // all series are supposed to be the same length
+        for (const ys of ySeries) {
+            this.graph_data.datasets.push({
+                label: ys.label,
+                data: ys.data,
+                borderColor: ys.color,
+                backgroundColor: "rgba(0,0,0,0)",  // fill color under the line : transparent
+                showLine: "true"
             });
         }
 
-        const nDigits = this.appSetup.displayDigits;
         this.graph_options["scales"] = {
             xAxes: [{
                 type: "linear",
@@ -322,42 +340,90 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
                 }
             }]
         };
-        const that = this;
-        this.graph_options["tooltips"] = {
-            displayColors: false,
-            callbacks: {
-                title: (tooltipItems, data) => {
-                    return this.chartY + " = " + Number(tooltipItems[0].yLabel).toFixed(nDigits);
-                },
-                label: (tooltipItem, data) => {
-                    const lines: string[] = [];
-                    const nbLines = that._results.getVariatingParametersSymbols().length;
-                    for (const v of that._results.getVariatingParametersSymbols()) {
-                        const series = that._results.getValuesSeries(v);
-                        const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
-                        if (v === this.chartX) {
-                            if (nbLines > 1) {
-                                lines.unshift("");
+
+        if (isMultiple) {
+            // add legend for multiple series
+            this.graph_options.legend = {
+                display: true,
+                position: "bottom",
+                reverse: false
+            };
+            // remove tooltips @TODO make them work for multiple series
+            delete this.graph_options.tooltips;
+        } else {
+            // enhanced tooltips for single series
+            const that = this;
+            this.graph_options.tooltips = {
+                displayColors: false,
+                callbacks: {
+                    title: (tooltipItems, data) => {
+                        return this.chartY + " = " + Number(tooltipItems[0].yLabel).toFixed(nDigits);
+                    },
+                    label: (tooltipItem, data) => {
+                        const lines: string[] = [];
+                        const nbLines = that._results.getVariatingParametersSymbols().length;
+                        for (const v of that._results.getVariatingParametersSymbols()) {
+                            const series = that._results.getValuesSeries(v);
+                            const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
+                            if (v === this.chartX) {
+                                if (nbLines > 1) {
+                                    lines.unshift("");
+                                }
+                                lines.unshift(line);
+                            } else {
+                                lines.push(line);
                             }
-                            lines.unshift(line);
-                        } else {
-                            lines.push(line);
                         }
+                        return lines;
                     }
-                    return lines;
                 }
-            }
-        };
+            };
+            // remove legend
+            this.graph_options.legend = {
+                display: false
+            };
+        }
+    }
 
-        this.graph_data = {
-            datasets: [{
-                label: "",
+    /**
+     * Returns a list of plottable data series for the given symbol; unless symbol
+     * is a ParamFamily, the returned list will have only one value
+     */
+    private getYSeries(symbol: string): IYSeries[] {
+        const ret: IYSeries[] = [];
+        const palette = ResultsComponent.distinctColors;
+        const xSeries = this._results.getValuesSeries(this.chartX);
+        const nDigits = this.appSetup.displayDigits;
+        let symbols: string[];
+
+        // whole family of variables => multiple series (should only happen with VarResults)
+        if (ParamFamily[symbol] !== undefined && this._results instanceof VarResults) {
+            symbols = this._results.extractFamilies()[symbol];
+        } else {
+            symbols = [ symbol ];
+        }
+        // loop over found symbol(s)
+        let i = 0;
+        for (const s of symbols) {
+            const dat = [];
+            const ySeries = this._results.getValuesSeries(s);
+            // build fixed precision x/y coordinate pairs
+            for (let j = 0; j < xSeries.length; j++) {
+                dat.push({
+                    x: (xSeries[j] !== undefined) ? xSeries[j].toFixed(nDigits) : "",
+                    y: (ySeries[j] !== undefined) ? ySeries[j].toFixed(nDigits) : ""
+                });
+            }
+            // add series
+            ret.push({
                 data: dat,
-                borderColor: "#808080", // couleur de la ligne
-                backgroundColor: "rgba(0,0,0,0)",  // couleur de remplissage sous la courbe : transparent
-                showLine: "true"
-            }]
-        };
+                label: this.axisLabelWithoutSymbol(s),
+                color: palette[ i % palette.length ]
+            });
+            i++;
+        }
+
+        return ret;
     }
 
     public exportAsImage(element: HTMLDivElement) {
diff --git a/src/app/results/plottable-data.ts b/src/app/results/plottable-data.ts
index 4b5d3f678..a9a65fa99 100644
--- a/src/app/results/plottable-data.ts
+++ b/src/app/results/plottable-data.ts
@@ -38,7 +38,7 @@ export interface PlottableData {
      * Returns the series of values for the required variated parameter / result element
      * @param symbol parameter / result symbol (ex: "Q")
      */
-    getValuesSeries(symbol: string): any[];
+    getValuesSeries(symbol: string): number[];
 
     /**
      * Returns the list of variating parameters
diff --git a/src/app/results/plottable-pab-results.ts b/src/app/results/plottable-pab-results.ts
index 03875d2d1..f697ecac0 100644
--- a/src/app/results/plottable-pab-results.ts
+++ b/src/app/results/plottable-pab-results.ts
@@ -46,8 +46,14 @@ export class PlottablePabResults implements PlottableData {
      * as X or Y chart axis
      */
     public getAvailableChartAxis(): string[] {
-        // add wall abscissa on the fly
-        return [ "x" ].concat(this.pabResults.columns);
+        const axis = [];
+        axis.push("x"); // wall abscissa
+        for (const c of this.pabResults.columns) {
+            if (c.indexOf("ENUM_") === -1) { // ENUM variables are not plottable
+                axis.push(c);
+            }
+        }
+        return axis;
     }
 
     public getAvailableXAxis(): string[] {
@@ -67,10 +73,9 @@ export class PlottablePabResults implements PlottableData {
      * Returns the series of values for the required symbol
      * @param symbol parameter / result symbol (ex: "Q")
      */
-    public getValuesSeries(symbol: string): any[] {
-        const data: string[] = [];
+    public getValuesSeries(symbol: string): number[] {
+        const data: number[] = [];
         const pr = this.pabResults;
-        const nDigits = ServiceFactory.instance.applicationSetupService.displayDigits;
         const l = this.pabResults.cloisonsResults.length;
         // when a parameter is variating, index of the variating parameter
         // values to build the data from
@@ -82,52 +87,52 @@ export class PlottablePabResults implements PlottableData {
 
         switch (symbol) {
             case "CLOISON":
-                data.push("");
+                data.push(undefined);
                 for (let i = 0; i <= l; i++) { // <= for one extra step (downwall)
-                    data.push("" + (i + 1));
+                    data.push(i + 1);
                 }
                 break;
 
             case "DH":
             case "ZRAM":
             case "Q":
-                data.push("");
+                data.push(undefined);
                 for (let i = 0; i < l; i++) {
                     const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    data.push(er);
                 }
                 const zrAval = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
-                data.push((zrAval !== undefined) ? zrAval.toFixed(nDigits) : "");
+                data.push(zrAval);
                 break;
 
             case "Z":
                 for (let i = 0; i < l; i++) {
-                    data.push(pr.cloisonsResults[i].resultElements[vi].vCalc.toFixed(nDigits));
+                    data.push(pr.cloisonsResults[i].resultElements[vi].vCalc);
                 }
-                data.push(pr.cloisonAvalResults.resultElements[vi].vCalc.toFixed(nDigits));
-                data.push(pr.Z2[vi].toFixed(nDigits));
+                data.push(pr.cloisonAvalResults.resultElements[vi].vCalc);
+                data.push(pr.Z2[vi]);
                 break;
 
             case "PV":
             case "YMOY":
             case "ZRMB":
             case "QA":
-                data.push("");
+                data.push(undefined);
                 for (let i = 0; i < l; i++) {
                     const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    data.push(er);
                 }
-                data.push("");
+                data.push(undefined);
                 break;
 
             case "x": // wall abscissa
-                data.push("");
+                data.push(undefined);
                 for (let i = 0; i < l; i++) {
                     const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    data.push(er);
                 }
                 const erXdw = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
-                data.push((erXdw !== undefined) ? erXdw.toFixed(nDigits) : "");
+                data.push(erXdw);
                 break;
         }
 
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index 5f3bcbc56..6853bd899 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -138,10 +138,9 @@ export class RemousResults extends CalculatorResults {
 
         this._varResults = new VarResults();
         this._varResults.variatedParameters = [ new NgParameter(this._xValues, undefined) ];
-        this._varResults.calculatedParameter
-            = new NgParameter(new ParamDefinition(null, "Ligne d'eau", ParamDomainValue.POS_NULL), undefined);
         this._varResults.result = this._result;
         const keys = [];
+        keys.push("Y"); // ligne d'eau
         if (this._hasFlu) {
             keys.push("flu");
         }
@@ -160,7 +159,9 @@ export class RemousResults extends CalculatorResults {
     }
 
     public set extraParamSymbol(l: string) {
-        this._extraParamSymbol = l;
+        if (l !== "") {
+            this._extraParamSymbol = l;
+        }
     }
 
     public get hautBerge() {
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index cd6effda2..40765f6a7 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -145,11 +145,13 @@ export class VarResults extends CalculatedParamResults implements PlottableData
      * Returns the series of values for the required variated parameter / result element
      * @param symbol parameter / result symbol (ex: "Q", "0_Q"...)
      */
-    public getValuesSeries(symbol: string) {
-        const series = [];
+    public getValuesSeries(symbol: string): number[] {
+        let found = false;
+        const series: number[] = [];
         // 1. variated param ?
         for (let i = 0; i < this.variatedParameters.length; i++) {
             if (this._variatedParams[i].symbol === symbol) {
+                found = true;
                 const iter = this.variatedParameters[i].getExtendedValuesIterator(this.size);
                 for (const v of iter) {
                     series.push(v);
@@ -157,23 +159,29 @@ export class VarResults extends CalculatedParamResults implements PlottableData
             }
         }
         // 2. Result element ?
-        for (const r of this.result.resultElements) { // re:ResultElement
-            for (const k in r.values) {
-                if (k === symbol) {
-                    series.push(r.getValue(k));
+        if (! found) {
+            for (const r of this.result.resultElements) { // re:ResultElement
+                for (const k in r.values) {
+                    if (k === symbol) {
+                        found = true;
+                        series.push(r.getValue(k));
+                    }
                 }
             }
         }
         // 3. Child result element ?
-        // detect children results
-        const match = /^([0-9]+)_(.+)$/.exec(symbol);
-        if (match !== null) {
-            const sn = this.result.sourceNub;
-            const pos = +match[1];
-            symbol = match[2];
-            const child = sn.getChildren()[pos];
-            for (const r of child.result.resultElements) {
-                series.push(r.getValue(symbol));
+        if (! found) {
+            // detect children results
+            const match = /^([0-9]+)_(.+)$/.exec(symbol);
+            if (match !== null) {
+                found = true;
+                const sn = this.result.sourceNub;
+                const pos = +match[1];
+                symbol = match[2];
+                const child = sn.getChildren()[pos];
+                for (const r of child.result.resultElements) {
+                    series.push(r.getValue(symbol));
+                }
             }
         }
 
@@ -197,10 +205,12 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         // children results
         const sn = this.result.sourceNub;
         for (const c of sn.getChildren()) {
-            // using latest ResultElement; results count / types are supposed to be the same on every iteration
-            for (const k of c.result.resultElement.keys) {
-                if (k.indexOf("ENUM_") === -1) { // ENUM variables are not plottable
-                    res.push(c.findPositionInParent() + "_" + k);
+            if (c.result) {
+                // using latest ResultElement; results count / types are supposed to be the same on every iteration
+                for (const k of c.result.resultElement.keys) {
+                    if (k.indexOf("ENUM_") === -1) { // ENUM variables are not plottable
+                        res.push(c.findPositionInParent() + "_" + k);
+                    }
                 }
             }
         }
@@ -216,7 +226,6 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         if (this._graphType === GraphType.Scatter) {
             // add families having more than 1 variable as plottable ordinates
             const families = this.extractFamilies();
-            console.log("FOUND FAMILIES", families);
             for (const f in families) {
                 if (families[f].length > 1) {
                     res.push(f);
@@ -230,8 +239,9 @@ export class VarResults extends CalculatedParamResults implements PlottableData
      * Browses all parameters and results to produce a map of families => list of
      * symbols in this family
      */
-    private extractFamilies(): { [key: string]: string[] } {
+    public extractFamilies(): { [key: string]: string[] } {
         const families: { [key: string]: string[] } = {};
+        // variating parameters
         for (const v of this._variatedParams) {
             const f = ParamFamily[v.paramDefinition.family];
             if (f !== undefined) {
@@ -241,6 +251,7 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 families[f].push(v.symbol);
             }
         }
+        // results
         for (const erk of this.resultKeys) {
             const f = ParamFamily[this.result.sourceNub.getFamily(erk)];
             if (f !== undefined) {
@@ -250,6 +261,22 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 families[f].push(erk);
             }
         }
+        // children results
+        const sn = this.result.sourceNub;
+        for (const c of sn.getChildren()) {
+            if (c.result) {
+                for (const k of c.result.resultElement.keys) {
+                    const f = ParamFamily[this.result.sourceNub.getFamily(k)];
+                    if (f !== undefined) {
+                        if (! (f in families)) {
+                            families[f] = [];
+                        }
+                        const pos = c.findPositionInParent();
+                        families[f].push(pos + "_" + k);
+                    }
+                }
+            }
+        }
         return families;
     }
 
@@ -317,13 +344,15 @@ export class VarResults extends CalculatedParamResults implements PlottableData
         }
         // entêtes des résultats des enfants
         for (const c of sn.getChildren()) {
-            // using latest ResultElement; results count / types are supposed to be the same on every iteration
-            for (const k of c.result.resultElement.keys) {
-                this._resultHeaders.push(
-                    ServiceFactory.instance.i18nService.localizeText("INFO_OUVRAGE_N")
-                        + (c.findPositionInParent() + 1) + " : "
-                        + ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(c.calcType, k)
-                );
+            if (c.result) {
+                // using latest ResultElement; results count / types are supposed to be the same on every iteration
+                for (const k of c.result.resultElement.keys) {
+                    this._resultHeaders.push(
+                        ServiceFactory.instance.i18nService.localizeText("INFO_OUVRAGE_N")
+                            + (c.findPositionInParent() + 1) + " : "
+                            + ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(c.calcType, k)
+                    );
+                }
             }
         }
 
diff --git a/src/app/results/y-series.ts b/src/app/results/y-series.ts
new file mode 100644
index 000000000..365e6fbfb
--- /dev/null
+++ b/src/app/results/y-series.ts
@@ -0,0 +1,11 @@
+/**
+ * A minimalistic description of a plottable data series, for charts
+ */
+export interface IYSeries {
+    /** points to plot */
+    data: { x: string, y: string }[];
+    /** text for the legend */
+    label: string;
+    /** line color */
+    color: string;
+}
-- 
GitLab


From 7747a32a1ddd04af350b492c1e64b1946098537f Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 6 Aug 2019 11:01:48 +0200
Subject: [PATCH 10/11] PAB table : translation

---
 src/app/components/pab-table/pab-table.component.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 6145a4b12..beef1d668 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -835,9 +835,9 @@ export class PabTableComponent implements AfterViewInit, OnInit {
     public get relatedEntityTitle() {
         let title = "";
         if (this.onlyDevicesAreSelected()) {
-            title = "Ouvrages";
+            title = this.i18nService.localizeText("INFO_PAB_OUVRAGES");
         } else if (this.onlyWallsAreSelected()) {
-            title = "Cloisons";
+            title = this.i18nService.localizeText("INFO_PAB_BASSINS");
         }
         if (title !== "") {
             title += " :";
-- 
GitLab


From 9fb33f1647e779994d5c67ec391b919948714329 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 6 Aug 2019 11:12:31 +0200
Subject: [PATCH 11/11] Set protractor back to headless mode

---
 protractor.conf.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/protractor.conf.js b/protractor.conf.js
index 4c1db58bb..6c546c716 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -16,7 +16,7 @@ exports.config = {
   capabilities: {
     browserName: 'chrome',
     chromeOptions: {
-      // args: [ "--headless", "--window-size=1024x768" ],
+      args: [ "--headless", "--window-size=1024x768" ],
       prefs: {
         download: {
             prompt_for_download: false, 
-- 
GitLab