From 72fc44f37633b63da4ec3e4247321293adb0e22c Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 25 Mar 2019 15:38:48 +0100
Subject: [PATCH] Better representation of parameter to calculate, when it is a
 child nub parameter (Structure)

---
 spec/structure/functions.ts               | 20 ++++--
 spec/structure/parallel_structure.spec.ts | 17 +++--
 src/nub.ts                                | 25 ++++++--
 src/structure/parallel_structure.ts       | 76 +++++------------------
 src/structure/structure.ts                |  6 +-
 5 files changed, 70 insertions(+), 74 deletions(-)

diff --git a/spec/structure/functions.ts b/spec/structure/functions.ts
index 0ea2b260..298ab9c7 100644
--- a/spec/structure/functions.ts
+++ b/spec/structure/functions.ts
@@ -118,7 +118,10 @@ export function testParallelStructures(oPS: ParallelStructure, iStTypes: number[
                         // Le calcul de l'ouverture sur les seuils doit renvoyer une exception (cas impossible)
                         it(`Calc(${prm.symbol}) should return exception`, () => {
                             expect(
-                                () => { oPS.Calc(i + "." + prm.symbol); }
+                                () => { oPS.Calc({
+                                    uid: oPS.structures[i].uid,
+                                    symbol: prm.symbol
+                                }); }
                             ).toThrow(new Error("Structure:Calc : Calcul de W impossible sur un seuil"));
                         });
                     } else if (
@@ -129,7 +132,10 @@ export function testParallelStructures(oPS: ParallelStructure, iStTypes: number[
                         // Les lois CEM88D et CUNGE80 ne font pas intervenir ZDV dans le calcul d'un orifice noyé
                         it(`Calc(${prm.symbol}) should return an error`, () => {
                             expect(
-                                oPS.Calc(i + "." + prm.symbol).code
+                                oPS.Calc({
+                                    uid: oPS.structures[i].uid,
+                                    symbol: prm.symbol
+                                }).code
                             ).toBe(MessageCode.ERROR_STRUCTURE_ZDV_PAS_CALCULABLE);
                         });
                     } else if (
@@ -138,12 +144,18 @@ export function testParallelStructures(oPS: ParallelStructure, iStTypes: number[
                     ) {
                         // Le calcul de l'angle de l'équation triangulaire n'est pas assez précis
                         it(`Calc(${prm.symbol}) should return ${ref}`, () => {
-                            checkResult(oPS.Calc(i + "." + prm.symbol), ref, 1);
+                            checkResult(oPS.Calc({
+                                uid: oPS.structures[i].uid,
+                                symbol: prm.symbol
+                            }), ref, 1);
                         });
                     } else {
                         // Cas normal : On teste la valeur calculée
                         it(`Calc(${prm.symbol}) should return ${ref}`, () => {
-                            checkResult(oPS.Calc(i + "." + prm.symbol), ref);
+                            checkResult(oPS.Calc({
+                                uid: oPS.structures[i].uid,
+                                symbol: prm.symbol
+                            }), ref);
                         });
                     }
                     prm.v = ref; // Go back to initial value for following tests
diff --git a/spec/structure/parallel_structure.spec.ts b/spec/structure/parallel_structure.spec.ts
index e13a7b16..78c0be76 100644
--- a/spec/structure/parallel_structure.spec.ts
+++ b/spec/structure/parallel_structure.spec.ts
@@ -39,11 +39,20 @@ describe("Class ParallelStructure: ", () => {
         itParallelStructure("Q", 30, 15);
         itParallelStructure("Z1", 30, 15);
         itParallelStructure("Z2", 15, 15);
-        itParallelStructure("0.ZDV", 0, 15);
-        itParallelStructure("1.ZDV", 0, 15);
+        itParallelStructure({
+            uid: pstruct.structures[0].uid,
+            symbol: "ZDV"
+        }, 0, 15);
+        itParallelStructure({
+            uid: pstruct.structures[1].uid,
+            symbol: "ZDV"
+        }, 0, 15);
         it("shoud return an error Q too high", () => {
             pstruct.prms.Q.v = 14;
-            const res: Result = pstruct.Calc("1.ZDV");
+            const res: Result = pstruct.Calc({
+                uid: pstruct.structures[1].uid,
+                symbol: "ZDV"
+            });
             expect(res.code).toBe(MessageCode.ERROR_STRUCTURE_Q_TROP_ELEVE);
         });
     });
@@ -55,7 +64,7 @@ describe("Class ParallelStructure: ", () => {
  * @param rVcalc Valeur de référence à retrouver
  * @param Q Débit de chacune des structures (pour structures identiques uniquement)
  */
-function itParallelStructure(sVarCalc: string, rVcalc: number, Q?: number) {
+function itParallelStructure(sVarCalc: any, rVcalc: number, Q?: number) {
     it(`${sVarCalc} should be ${rVcalc}`, () => {
         checkResult(pstruct.Calc(sVarCalc), rVcalc);
     });
diff --git a/src/nub.ts b/src/nub.ts
index efef15d7..c6f9b612 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition, Session } from ".";
+import { ParamDefinition, Session, Structure } from ".";
 import { ComputeNode } from "./compute-node";
 import { Dichotomie } from "./dichotomie";
 import { INamedIterableValues, IterableValues } from "./param/param-value-iterator";
@@ -91,9 +91,9 @@ export abstract class Nub extends ComputeNode {
     /**
      * effectue une série de calculs sur un paramètre
      * @param rInit solution approximative du paramètre
-     * @param sDonnee éventuel symbole du paramètre à calculer
+     * @param sDonnee éventuel symbole / paire symbole-uid du paramètre à calculer
      */
-    public CalcSerie(rInit?: number, sDonnee?: string): Result {
+    public CalcSerie(rInit?: number, sDonnee?: any): Result {
         let computedParam: ParamDefinition;
         // instance de ParamValues utilisée pour le paramètre varié (qui peut être un paramètre référencé (importé))
         let variatedValues: IterableValues;
@@ -149,7 +149,7 @@ export abstract class Nub extends ComputeNode {
             }
         }
 
-        let computedSymbol: string;
+        let computedSymbol: any;
         if (sDonnee) {
             computedSymbol = sDonnee;
         } else {
@@ -182,7 +182,9 @@ export abstract class Nub extends ComputeNode {
             this._result = res;
         }
 
-        this._result.name = computedSymbol;
+        const realSymbol = (typeof computedSymbol === "string") ? computedSymbol : computedSymbol.symbol;
+        this._result.name = realSymbol;
+
         return this._result;
     }
 
@@ -234,7 +236,18 @@ export abstract class Nub extends ComputeNode {
                 ) {
                     // if it is safe to link p's value to src
                     if (p.isLinkableTo(src)) {
-                        res.push(new LinkedValue(this, p, p.symbol));
+                        // if p is a CALC param of a Structure, other than "Q", expose its parent
+                        // (structures always have Q as CALC param and cannot have another)
+                        if (
+                            (this instanceof Structure)
+                            && (p.valueMode === ParamValueMode.CALCUL)
+                            && p.symbol !== "Q"
+                        ) {
+                            // trick to expose p a a result of the parent Nub
+                            res.push(new LinkedValue(this.parent, p, p.symbol));
+                        } else {
+                            res.push(new LinkedValue(this, p, p.symbol));
+                        }
                     }
                 }
             }
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index 984fce3b..9638dace 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -1,27 +1,15 @@
 import { Nub } from "../nub";
 import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { ParallelStructureParams } from "./parallel_structure_params";
-import { Structure } from "./structure";
-
-import { ParamDefinition } from "../param/param-definition";
 import { IParamDefinitionIterator, ParamsEquation, ParamsEquationArrayIterator } from "../param/params-equation";
-
 import { Props } from "../props";
 import { Session } from "../session";
-import { LinkedValue } from "../value_ref/object_ref";
+import { Result } from "../util/result";
+import { ParallelStructureParams } from "./parallel_structure_params";
+import { Structure } from "./structure";
 import { loiAdmissiblesOuvrages, LoiDebit } from "./structure_props";
 
 export { ParallelStructureParams };
 
-/**
- * Interface pour mémoriser le n° d'ouvrage et le paramètre à calculer
- */
-interface IStructureVarCalc {
-    index: number;
-    prm: string;
-}
-
 /**
  * Calcul de une ou plusieurs structures hydrauliques en parallèles
  * reliées par les cotes amont et aval et dont le débit est égal à la
@@ -125,12 +113,13 @@ export class ParallelStructure extends Nub {
     /**
      * Returns the current index of the given structure if any,
      * or else returns -1
-     * @param structure Structure to look for
+     * @param structure Structure or Structure UID to look for
      */
-    public getIndexForStructure(structure: Structure): number {
+    public getIndexForStructure(structure: Structure | string): number {
         let index: number = -1;
+        const uid = (structure instanceof Structure) ? structure.uid : structure;
         for (let i = 0; i < this._structures.length; i++) {
-            if (this._structures[i].uid === structure.uid) {
+            if (this._structures[i].uid === uid) {
                 index = i;
             }
         }
@@ -239,10 +228,11 @@ export class ParallelStructure extends Nub {
     /**
      * Calcul du débit total, de la cote amont ou aval ou d'un paramètre d'une structure
      * @param sVarCalc Nom du paramètre à calculer :
-     *                 "Q", "Z1", "Z2" ou "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre
+     *                 "Q", "Z1", "Z2"
+     *                 ou { uid: "abcdef", symbol: "X" } avec "abcdef" l'index de l'ouvrage et "X" son paramètre
      * @param rInit Valeur initiale
      */
-    public Calc(sVarCalc: string, rInit?: number): Result {
+    public Calc(sVarCalc: string | any, rInit?: number): Result {
         let res: Result;
         switch (sVarCalc) {
             case "Z1":
@@ -255,12 +245,13 @@ export class ParallelStructure extends Nub {
                 break;
             default:
                 // Pour les caractéristiques des ouvrages
-                const sVC = this.getStructureVarCalc(sVarCalc);
-                res = this.CalcStructPrm(sVC, rInit);
+                // const sVC = this.getStructureVarCalc(sVarCalc);
+                const structureIndex = this.getIndexForStructure(sVarCalc.uid);
+                res = this.CalcStructPrm(structureIndex, sVarCalc.symbol);
                 // Suppression des extraResults : ils sont complétés plus bas pour chaque ouvrage
                 res.resultElement.extraResults = {};
                 if (res.ok) {
-                    this._structures[sVC.index].getParameter(sVC.prm).setValue(res.vCalc);
+                    this._structures[structureIndex].getParameter(sVarCalc.symbol).setValue(res.vCalc);
                 }
         }
         if (res.ok) {
@@ -378,50 +369,17 @@ export class ParallelStructure extends Nub {
         }
     }
 
-    /**
-     * Renvoie le n° de structure et le paramètre à calculer
-     * @param sVarCalc Nom du paramètre à calculer : "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre
-     */
-    protected getStructureVarCalc(sVarCalc: string): IStructureVarCalc {
-        let sIndex: string;
-        let sPrm: string;
-        if (sVarCalc.indexOf(".") === -1) {
-            throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc}, (pas de la forme n.X)`);
-        }
-        [sIndex, sPrm] = sVarCalc.split(".");
-        const i = parseInt(sIndex, 10);
-        if (isNaN(i)) {
-            throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc} (${sIndex} n'est pas un nombre)`);
-        }
-        return { index: i, prm: sPrm };
-    }
-
     /**
      * Calcul du paramètre d'un des ouvrages en parallèle
      * @param sVC Index de l'ouvrage et paramètre à calculer
      * @param rInit Valeur initiale
      */
-    protected CalcStructPrm(sVC: IStructureVarCalc, rInit?: number): Result {
+    protected CalcStructPrm(index: number, symbol: string, rInit?: number): Result {
         // Le débit restant sur la structure en calcul est :
-        this._structures[sVC.index].prms.Q.setValue(this.prms.Q.v - this.CalcQ(sVC.index).vCalc);
+        this._structures[index].prms.Q.setValue(this.prms.Q.v - this.CalcQ(index).vCalc);
 
         // Calcul du paramètre de la structure en calcul
-        return this._structures[sVC.index].Calc(sVC.prm, rInit);
-    }
-
-    /**
-     * Renvoie le n° de structure et le paramètre à calculer
-     * @param sVarCalc Nom du paramètre à calculer : "ouvrage[n].X" avec "n" l'index de l'ouvrage et "X" son paramètre
-     */
-    private getStructureVarCalc2(sVarCalc: string): IStructureVarCalc {
-        const re = /([A-Z,a-z]+)\[(\d+)\]\.(.+)/;
-        const match = re.exec(sVarCalc);
-        if (match === null || match[1] !== "ouvrage") {
-            throw new Error(
-                `getStructureVarCalc2() : erreur d'analyse de ${sVarCalc}, (pas de la forme ouvrage[n].X)`
-            );
-        }
-        return { index: +match[2], prm: match[3] };
+        return this._structures[index].Calc(symbol, rInit);
     }
 
 }
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index e7062aa4..f19bca59 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -1,8 +1,8 @@
 import { Nub } from "../nub";
 import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
+import { ParamValueMode } from "../param/param-value-mode";
 import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
-import { LinkedValue } from "../value_ref/object_ref";
 
 import { ParallelStructure } from "./parallel_structure";
 import { StructureParams } from "./structure_params";
@@ -71,6 +71,10 @@ export abstract class Structure extends Nub {
     constructor(prms: StructureParams, dbg: boolean = false) {
         super(prms, dbg);
         this._isZDVcalculable = true;
+        // Q is always the only calculated variable; setting another parameter
+        // of a Structure to CALC mode makes it the calculated variable of the
+        // *parent* ParallelStructures
+        this.prms.Q.valueMode = ParamValueMode.CALCUL;
     }
 
     get isZDVcalculable(): boolean {
-- 
GitLab