diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 1cb6f0456b19b65e0ed3ff42f4fe75ab5fdd81a8..8ca7eac65d5090fdd31c84072c9fc4b74b14e788 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/jalhyd_branch b/jalhyd_branch
index 4cc13e7cb71a58ec7660acfdd54c2b275f2529e5..c9cd8896aab158c293672a2feece50b940fadf67 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
+128-reorganisation-du-stockage-des-resultats-dans-le-nub
diff --git a/src/app/calculators/regime-uniforme/regime-uniforme.config.json b/src/app/calculators/regime-uniforme/regime-uniforme.config.json
index 3633e1aa733fa01c4ca01ae195b554533fc8d66e..2e025737005e3ded4ad85416b4dbe3b8d2871f16 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 4a95346548c43d1a535070758790f75d2f693c37..6a38cb84eb649a562e81824f6f98a479291ab40a 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 = [];
@@ -91,41 +91,45 @@ export class FixedResultsComponent {
         const res = this._fixedResults.result;
         if (
             res
-            && res.nbResultElements > 0
+            && res.resultElements.length > 0
             && res.resultElement
-            && res.extraResults
+            && res.resultElement.count() > 0
         ) {
-            // 2.1. main result (sometimes empty, for ex. in "Section paramétrée")
-            if (res.name && 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);
+                // calculator type for translation
+                let ct = sn.calcType;
+                if (sn.parent) {
+                    ct = sn.parent.calcType;
                 }
                 data.push({
-                    label: rLabel,
-                    value: this.intlService.formatResult(res.name, 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.extraResults;
-            for (const k in extraResults) {
-                if (extraResults.hasOwnProperty(k)) {
-                    const er: number = extraResults[k];
-                    // calculator type for translation
-                    const sn = this._fixedResults.result.sourceNub;
-                    let ct = sn.calcType;
-                    if (sn.parent) {
-                        ct = sn.parent.calcType;
+            // 2.2. children results
+            for (const c of sn.getChildren()) {
+                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.formService.expandVariableNameAndUnit(ct, k),
-                        value: this.intlService.formatResult(k, er),
-                        isCalcResult: true // for CSS
-                    });
                 }
             }
         }
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index d5d9c85cc78079954997e8cebc90fec2abe65563..87a483a11aa5a8a2773beb7dbb95767567872fb8 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/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts
index 57c95d10a068ced07cc943ed40fe7f931f01513a..2675d065e16b3cb8c9279656349e9bf66ed3f2d0 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 620f4c90fa58d544a9803f9c215e94c2522e2992..5eb499f01060bb0de3af6e671585eb2ee06ef59c 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 */
@@ -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,21 @@ 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()) {
+                        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));
+                            }
                         }
-
                     }
+
                     this._results.push(list);
                 }
             }
@@ -165,7 +163,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/generic-input/generic-input.component.html b/src/app/components/generic-input/generic-input.component.html
index 0e261b797e5db2e48cda20bdb30cc8ad3a5d2035..9fe6a46901eb67d30ddf4b0d8ef109bc0f0e7af9 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/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts
index f6cb671dabcaf5949da196878abb7699d72cd5f8..f31a29cff4f06d8128b9d575db12e02a80ae63e5 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
         },
@@ -208,16 +210,16 @@ 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;
     }
 
-    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;
@@ -228,19 +230,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)
@@ -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/pab-results/pab-results-table.component.ts b/src/app/components/pab-results/pab-results-table.component.ts
index ad39f84bb3cc768779006ad28fdbc73dd6b3b0bb..6b0550eb718b7aea0ba9783224ddcd479e173887 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/pab-results/pab-results.component.ts b/src/app/components/pab-results/pab-results.component.ts
index 4c3418eabceb9d80f811a8a5d1bdc4525037a396..510867ca6f1655075e52eab16f92b8f0580fd26f 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/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 6145a4b127f2b4b8e5c55de4388f41d0402175ad..beef1d66822a1ee1df474dab65c2b2a7f33a36cc 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 += " :";
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
index 1d7274ca7e9c401eefd24e2fae805a3eaf3d18a4..da77b6c0d789e676d5e2b72c5c3e70713bc4a2d5 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/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html
index 50024d806d5cfa794c3279ef6cc0fe975acea5a1..d27357a5e101741950d26cdde8409611d6e989a1 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 6ea796e94b9161eac14c5bc545e51089afc5ab8d..16224f9ff85cd119c292b3fae05a215ddd71fc2b 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: {
@@ -96,9 +98,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();
+            }
         }
     }
 
@@ -180,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;
     }
@@ -205,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;
@@ -235,6 +255,7 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont
                 }
             }]
         };
+
         const that = this;
         this.graph_options["tooltips"] = {
             displayColors: false,
@@ -246,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) {
@@ -275,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",
@@ -311,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/components/section-results/section-results.component.ts b/src/app/components/section-results/section-results.component.ts
index 3b841f7cf8d31d1ca92d41e1c28b54dc0ef339b1..dc00f2a1c413f6ebc25f5210994e624b50b626a6 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.extraResults) {
-                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/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
index 2900c66b1b2f49a2c5674fc4af906ca92583befa..00d5793b3e0b26a34340904c1e2e504c371b8b3e 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 3e833eed46eeac7a0a991bafde36403d373036b9..a1380b6588b7852a912e471b31d0d375cc4aaa39 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/pab-results.ts b/src/app/results/pab-results.ts
index 7cf40aad077dc4767584c3709ce12370387640d1..a81d371583a9a71b80c1d0242482021689be7f0a 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 bdcabde2d0ce7879a4e4a88f71af88cb3f27d176..8cdf9e85ecd7462e6bc9d9649144c220602ddc1b 100644
--- a/src/app/results/param-calc-results.ts
+++ b/src/app/results/param-calc-results.ts
@@ -41,14 +41,14 @@ export abstract class CalculatedParamResults extends CalculatorResults {
         if (this.result === undefined) {
             return false;
         }
-        return this.result.ok;
+        return ! this.result.hasOnlyErrors;
     }
 
     public get hasLog(): boolean {
         if (this.result === undefined) {
             return false;
         }
-        return this.result.hasLog;
+        return this.result.hasLog();
     }
 
     public get log(): cLog {
diff --git a/src/app/results/plottable-data.ts b/src/app/results/plottable-data.ts
index a5493b94be96bd509ec89ad9c9a61facd54ffa9c..a9a65fa997667f325ec293f1e952c7aea5029dbf 100644
--- a/src/app/results/plottable-data.ts
+++ b/src/app/results/plottable-data.ts
@@ -17,22 +17,28 @@ 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;
 
     /**
      * 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
      * @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 57a4dd318b9c815ad3f36d5c65959ea61c78c7d8..f697ecac0e648037d23239ef4e912bf3f084afcc 100644
--- a/src/app/results/plottable-pab-results.ts
+++ b/src/app/results/plottable-pab-results.ts
@@ -46,8 +46,22 @@ 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[] {
+        return this.getAvailableChartAxis();
+    }
+
+    public getAvailableYAxis(): string[] {
+        return this.getAvailableChartAxis();
     }
 
     // just to implement interface
@@ -59,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
@@ -74,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].getExtraResult(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
+                    data.push(er);
                 }
-                const zrAval = pr.cloisonAvalResults.resultElements[vi].getExtraResult(symbol);
-                data.push((zrAval !== undefined) ? zrAval.toFixed(nDigits) : "");
+                const zrAval = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
+                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].getExtraResult(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
+                    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].getExtraResult(symbol);
-                    data.push((er !== undefined) ? er.toFixed(nDigits) : "");
+                    const er = pr.cloisonsResults[i].resultElements[vi].getValue(symbol);
+                    data.push(er);
                 }
-                const erXdw = pr.cloisonAvalResults.resultElements[vi].getExtraResult(symbol);
-                data.push((erXdw !== undefined) ? erXdw.toFixed(nDigits) : "");
+                const erXdw = pr.cloisonAvalResults.resultElements[vi].getValue(symbol);
+                data.push(erXdw);
                 break;
         }
 
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index 6d6e1f6e104badd016b4c449f01127e889ee05f0..6853bd899049faeca56b8727df0cf170632ffb9f 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;
             }
         }
@@ -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");
         }
@@ -151,8 +150,8 @@ export class RemousResults extends CalculatorResults {
         if (this._hasExtra) {
             keys.push(this.extraParamSymbol);
         }
-        this._varResults.extraResultKeys = keys;
-        this._varResults.update(true);
+        this._varResults.resultKeys = keys;
+        this._varResults.update();
     }
 
     public get extraParamSymbol(): string {
@@ -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 b01195b15a1cd932d5b18b4fdf6d8ae9cd9fd795..40765f6a727405ee859715ac0a17cfbd94618b9a 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";
@@ -18,19 +18,19 @@ 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
      */
-    public graphType: GraphType = GraphType.Scatter;
+    protected _graphType: GraphType = GraphType.Scatter;
 
     /**
      * variated parameter or result displayed as chart's X-axis
@@ -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,17 @@ 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 {
+        return this._graphType;
+    }
+
+    public set graphType(gt: GraphType) {
+        this._graphType = gt;
+        this.resetDefaultAxisIfNeeded();
     }
 
     public getChartAxisLabel(symbol: string): string {
@@ -104,53 +113,74 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                 return this.variableParamHeaders[i];
             }
         }
-        // 3. Result element
+        // 3. Result element / child result
         return this.expandLabelFromSymbol(symbol);
-
     }
 
     /**
-     * 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 {
+        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 ?
+    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);
                 }
             }
         }
-        // 3. Result element ?
-        for (const r of this.result.resultElements) { // re:ResultElement
-            for (const k in r.extraResults) {
-                if (k === symbol) {
-                    series.push(r.extraResults[k]);
+        // 2. Result element ?
+        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 ?
+        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));
                 }
             }
         }
@@ -160,22 +190,96 @@ 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);
-        }
         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()) {
+            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);
+                    }
+                }
+            }
         }
         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();
+            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
+     */
+    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) {
+                if (! (f in families)) {
+                    families[f] = [];
+                }
+                families[f].push(v.symbol);
+            }
+        }
+        // results
+        for (const erk of this.resultKeys) {
+            const f = ParamFamily[this.result.sourceNub.getFamily(erk)];
+            if (f !== undefined) {
+                if (! (f in families)) {
+                    families[f] = [];
+                }
+                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;
+    }
+
     /**
      * Returns the list of variating parameters
      * (used by tooltip functions)
@@ -186,7 +290,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);
@@ -205,17 +309,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.extraResults) {
-                    if (!this.extraResultKeys.includes(erk)) {
-                        this.extraResultKeys.push(erk);
+                for (const erk in re.values) {
+                    if (!this.resultKeys.includes(erk)) {
+                        this.resultKeys.push(erk);
                     }
                 }
             }
@@ -223,10 +323,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;
@@ -237,21 +335,39 @@ 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()) {
+            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)
+                    );
+                }
+            }
+        }
+
+        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/app/results/y-series.ts b/src/app/results/y-series.ts
new file mode 100644
index 0000000000000000000000000000000000000000..365e6fbfb997d47fc418c1937c582576025734d7
--- /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;
+}
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index a89142101f13a029a760c64f07ee9059e0c63e01..c88c9681a90d317e2c765f912688c241a0dedd4b 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 f95bcc9ba2a26d4f29cc52698770142a585453a8..7590f251dc3410941b9a04f7e86204ec92d69636 100644
--- a/src/app/services/internationalisation/internationalisation.service.ts
+++ b/src/app/services/internationalisation/internationalisation.service.ts
@@ -186,13 +186,16 @@ 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) {
+            return "";
+        }
         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 42c454e76a7660fe2fe527740e4eb2f9877817ba..152d21b6c44dd8ecf83397eb11000cdae094872f 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%",
@@ -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",
@@ -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",
@@ -160,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",
@@ -177,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",
@@ -270,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 245c7a8208014c210291c5503482b46ec59705c7..60e15cb86a189fe5a8edd307f26f3d57d6e05111 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%",
@@ -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",
@@ -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",
@@ -159,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",
@@ -176,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é",
@@ -269,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",