diff --git a/spec/pab/pab.spec.ts b/spec/pab/pab.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ff7a5a54589a2d441132e4519141507d162188b
--- /dev/null
+++ b/spec/pab/pab.spec.ts
@@ -0,0 +1,95 @@
+/**
+ * IMPORTANT !
+ * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
+ * Pour exécuter ce code dans le débugger.
+ * Faire de même avec le fichier test_func.ts
+ */
+// import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";
+
+import { Pab, PabParams } from "../../src/pab/pab";
+import { PabCloisons } from "../../src/pab/pab_cloisons";
+import { Cloisons, CloisonsParams } from "../../src/structure/cloisons";
+import { ParallelStructure, ParallelStructureParams } from "../../src/structure/parallel_structure";
+import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params";
+import { StructureKivi, StructureKiviParams } from "../../src/structure/structure_kivi";
+import { StructureWeirSubmergedLarinier } from "../../src/structure/structure_weir_submerged_larinier";
+
+const dbg: boolean = false;
+
+/**
+ * Exemple formation Cassiopée 2018-09
+ */
+
+// Modèle de cloison
+const modelCloisons = new Cloisons(
+    new CloisonsParams(
+        0.773,      // Débit total (m3/s)
+        78.27,    // Cote de l'eau amont (m)
+        3.1,     // Longueur des bassins (m)
+        2.5,      // Largeur des bassins (m)
+        1.5,      // Profondeur moyenne (m)
+        0.23     // Hauteur de chute (m)
+    )
+);
+
+const rectStructPrms = new RectangularStructureParams(
+    0.773,  // Q
+    76.67,        // ZDV
+    0,        // Z1
+    0,      // Z2
+    0.35,          // L
+    0.65        // Cd pour un seuil rectangulaire
+    // W = Infinity par défaut pour un seuil
+);
+
+// Ajout d'ouvrage dans la cloison
+modelCloisons.addChild(new StructureWeirSubmergedLarinier(rectStructPrms));
+
+// Création de la cloison aval
+const downWall = new ParallelStructure(new ParallelStructureParams(0, 0, 0));
+const kiviPrms = new StructureKiviParams(
+    0.773,  // Q
+    73.95,        // ZDV
+    0,        // Z1
+    0,      // Z2
+    0.6,          // L
+    0.4,        // Cd pour un seuil rectangulaire
+    0,
+    73.435
+);
+downWall.addChild(new StructureKivi(kiviPrms));
+
+// Création de la passe
+const pab: Pab = new Pab(
+    new PabParams(
+        modelCloisons.prms.Q.v,
+        100,
+        74.86
+    ),
+    downWall,
+    dbg
+);
+
+// Ajout des cloisons
+
+const pabCloison = new PabCloisons(modelCloisons, 0, dbg);
+
+for (let i = 0; i < 14; i++) {
+    pab.addChild(pabCloison);
+}
+
+// Tests
+
+describe("Class Pab: ", () => {
+    describe("Exemple Formation 2018-09 p.14", () => {
+        it("CalcSerie(Z1) should return 78.27", () => {
+            pab.calculatedParam = pab.prms.Z1;
+            expect(pab.CalcSerie().vCalc).toBeCloseTo(78.27, 2);
+        });
+        it("Calc(Q) should return 0.773", () => {
+            pab.prms.Z1.v = modelCloisons.prms.Z1.v;
+            pab.prms.Q.v = 0;
+            expect(pab.Calc("Q").vCalc).toBeCloseTo(0.773, 2);
+        });
+    });
+});
diff --git a/spec/pab/pab_chute.spec.ts b/spec/pab/pab_chute.spec.ts
index 4fe6f25d757b7b98ccac00f8bbc0a440a2b021e4..2f2f5b5943be7218fe42cfc69fbff14952da8aec 100644
--- a/spec/pab/pab_chute.spec.ts
+++ b/spec/pab/pab_chute.spec.ts
@@ -25,4 +25,16 @@ describe("Class PabChute: ", () => {
     pabChuteTest("Z2", 0.5);
     pabChuteTest("DH", 1.5);
 
+    it ("Z1 < Z2 should lead to log error entry", () => {
+        const prms = new PabChuteParams(
+            100,      // Cote amont Z1
+            100.5,    // Cote aval Z2
+            1.5,      // Chute DH
+        );
+
+        const nub = new PabChute(prms);
+
+        expect(nub.Calc("DH", 0).log.messages.length).toBeGreaterThan(0);
+    });
+
 });
diff --git a/spec/pab/pab_nombre.spec.ts b/spec/pab/pab_nombre.spec.ts
index fb5d9619e763d67cad5ce5d2e9099f74e4dba854..9136553725fb39bdb301f17c33c949d9d40a942b 100644
--- a/spec/pab/pab_nombre.spec.ts
+++ b/spec/pab/pab_nombre.spec.ts
@@ -28,13 +28,40 @@ describe("Class PabNombre: ", () => {
     it ("DHR should be 0.3", () => {
         const prms = new PabNombreParams(
             7.5,      // Chute totale DHT
-            9,    // Nombre de bassins N
+            666,    // Nombre de bassins N
             0.8,    // Chute entre bassins DH
         );
 
         const nub = new PabNombre(prms);
 
         nub.Calc("N", 0);
+        expect(nub.result.vCalc).toBe(9);
         expect(nub.result.getExtraResult("DHR")).toBeCloseTo(0.3);
     });
+
+    it ("DHR should be 0", () => {
+        const prms = new PabNombreParams(
+            3,      // Chute totale DHT
+            666,    // Nombre de bassins N
+            0.2,    // Chute entre bassins DH
+        );
+
+        const nub = new PabNombre(prms);
+
+        nub.Calc("N", 0);
+        expect(nub.result.vCalc).toBe(15);
+        expect(nub.result.getExtraResult("DHR")).toBe(0);
+    });
+
+    it ("non-integer number of basins should lead to log error entry", () => {
+        const prms = new PabNombreParams(
+            3,      // Chute totale DHT
+            4.5,    // Nombre de bassins N
+            0.2,    // Chute entre bassins DH
+        );
+
+        const nub = new PabNombre(prms);
+
+        expect(nub.Calc("DH", 0).log.messages.length).toBeGreaterThan(0);
+    });
 });
diff --git a/spec/param/param_modes.spec.ts b/spec/param/param_modes.spec.ts
index ab9a2c1a1943f5be6aceb708043a5f1dc0280198..9ed7a9cc66b6ced69e6ae2adedb9c80f0e8c1273 100644
--- a/spec/param/param_modes.spec.ts
+++ b/spec/param/param_modes.spec.ts
@@ -1,5 +1,8 @@
-import { cSnTrapez, LinkedValue, Nub, ParallelStructure, ParallelStructureParams,
-         ParamsSectionTrapez, ParamValueMode, SectionParametree, Session } from "../../src/index";
+import {
+    cSnTrapez, LinkedValue, Nub, ParallelStructure, ParallelStructureParams,
+    ParamCalculability, ParamsSectionTrapez, ParamValueMode, SectionParametree,
+    Session
+} from "../../src/index";
 import { RegimeUniforme } from "../../src/regime_uniforme";
 import { cSnCirc, ParamsSectionCirc } from "../../src/section/section_circulaire";
 import { Cloisons } from "../../src/structure/cloisons";
@@ -162,23 +165,22 @@ function testModesPermutations(nubToTest: Nub) {
 
     // set every parameter to CALC mode
     for (const p of nubToTest.parameterIterator) {
-        if (p.symbol === "Pr" || ! p.visible) {
-            continue;
+        if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(p.calculability) && p.visible) {
+            p.setCalculated();
+            checkConsistency(nubToTest);
         }
-        p.setCalculated();
-        checkConsistency(nubToTest);
     }
 
     // set every parameter to MINMAX / LISTE mode
     let i = 0;
     for (const p of nubToTest.parameterIterator) {
-        if (p.symbol === "Pr" || ! p.visible) {
+        if (p.symbol === "Pr" || !p.visible) {
             continue;
         }
         if (i % 2 === 0) {
             p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
         } else {
-            p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+            p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
         }
         checkConsistency(nubToTest);
         i++;
@@ -186,18 +188,17 @@ function testModesPermutations(nubToTest: Nub) {
 
     // set every parameter to CALC then to SINGLE mode
     for (const p of nubToTest.parameterIterator) {
-        if (p.symbol === "Pr" || ! p.visible) {
-            continue;
+        if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(p.calculability) && p.visible) {
+            p.setCalculated();
+            checkConsistency(nubToTest);
+            p.valueMode = ParamValueMode.SINGLE;
+            checkConsistency(nubToTest);
         }
-        p.setCalculated();
-        checkConsistency(nubToTest);
-        p.valueMode = ParamValueMode.SINGLE;
-        checkConsistency(nubToTest);
     }
 
     // set every parameter to LINK mode then to SINGLE mode
     for (const p of nubToTest.parameterIterator) {
-        if (p.symbol === "Pr" || ! p.visible) {
+        if (p.symbol === "Pr" || !p.visible) {
             continue;
         }
         const lv: LinkedValue[] = Session.getInstance().getLinkableValues(p);
@@ -248,7 +249,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm1.Q.setValues(0.6, 2.4, 0.09);
 
         // link other Nubs Q to nub1.Q
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub1.section, "Q");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -257,7 +258,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
@@ -275,7 +276,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm6.Q.defineReference(nub1.section, "Q");
 
         // link other Nubs Q to nub6.Q
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub6.section, "Q");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -284,7 +285,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
@@ -300,7 +301,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm1.Q.setCalculated();
 
         // link other Nubs Q to nub1.Q
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub1, "Q");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -309,7 +310,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
@@ -328,7 +329,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm6.Q.defineReference(nub1, "Q");
 
         // link other Nubs Q to nub6.Q
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub6.section, "Q");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -337,7 +338,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
@@ -353,7 +354,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm5.Q.setCalculated();
 
         // link other Nubs Q to nub5.CvQT
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub5, "CvQT");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -362,7 +363,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
@@ -381,7 +382,7 @@ describe("cohérence des modes de paramètres : ", () => {
         prm6.Q.defineReference(nub5, "CvQT");
 
         // link other Nubs Q to nub6.Q
-        for (const n of [ nub2, nub3, nub4 ]) {
+        for (const n of [nub2, nub3, nub4]) {
             n.prms.Q.defineReference(nub6.section, "Q");
             // set every parameter to MINMAX / LISTE mode
             let i = 0;
@@ -390,7 +391,7 @@ describe("cohérence des modes de paramètres : ", () => {
                     if (i % 2 === 0) {
                         p.setValues(1, 5, 0.5); // sets valueMode to MINMAX
                     } else {
-                        p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE
+                        p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE
                     }
                 }
                 checkConsistency(n);
diff --git a/spec/real.spec.ts b/spec/real.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ab26118764a183e0f160c09247e8677c292a472f
--- /dev/null
+++ b/spec/real.spec.ts
@@ -0,0 +1,39 @@
+import { floatDivAndMod, isEqual } from "../src/base";
+
+/**
+ * Tests d'égalité, de divisions entières et de modulo, à la tolérance près
+ */
+
+const divAndModCases = [
+    { D: 3, d: 0.2, q: 15, r: 0 },
+    { D: 3, d: 0.1, q: 30, r: 0 },
+    { D: 3, d: 0.3, q: 10, r: 0 },
+    { D: 3, d: 3, q: 1, r: 0 },
+    { D: 3, d: 3.00000000001, q: 1, r: 0 }
+];
+
+for (const c of divAndModCases) {
+    describe("real numbers division and modulo - ", () => {
+        it(`(${c.D} / ${c.d}) should be ${c.q}, (${c.D} % ${c.d}) should be ${c.r}`, () => {
+            const divAndMod = floatDivAndMod(c.D, c.d);
+            expect(divAndMod.q).toBe(c.q);
+            expect(divAndMod.r).toBe(c.r);
+        });
+    });
+}
+
+const eqCases = [
+    { a: 0, b: 0, eq: true },
+    { a: 0, b: 0.0000000000001, eq: true },
+    { a: 0.0000000000001, b: 0, eq: true },
+    { a: 0.0000000000001, b: 0.0000000000001, eq: true },
+    { a: 0, b: 0.1, eq: false }
+];
+
+for (const c of eqCases) {
+    describe("real numbers equality - ", () => {
+        it(c.a + " should " + (c.eq ? "" : "not ") + " be equal to " + c.b, () => {
+            expect(isEqual(c.a, c.b)).toBe(c.eq);
+        });
+    });
+}
diff --git a/spec/session/serialisation.spec.ts b/spec/session/serialisation.spec.ts
index 591d6401273cb891be9c27f94ed319dcfd917a55..6a6e93e90b724cf62df6f097c9bf54b12fb2a75a 100644
--- a/spec/session/serialisation.spec.ts
+++ b/spec/session/serialisation.spec.ts
@@ -144,7 +144,7 @@ describe("serialising / deserialising session - ", () => {
         );
         const section = new cSnCirc(paramSection);
         const sp = new SectionParametree(section);
-        sp.section.prms.Ks.v = 42;
+        sp.section.prms.Ks.singleValue = 42;
 
         const serialised = sp.serialise();
         expect(serialised).toContain('{"symbol":"Ks","mode":"SINGLE","value":42}');
diff --git a/spec/structure/cloisons.spec.ts b/spec/structure/cloisons.spec.ts
index 9e52d240ce214aa388913fde50ff506922e47f1c..65b3991d7a65d359d7f1af6e8f7ad6042fc1e4f0 100644
--- a/spec/structure/cloisons.spec.ts
+++ b/spec/structure/cloisons.spec.ts
@@ -6,6 +6,7 @@
  */
 // import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";
 
+import { ParamDefinition } from "../../src/index";
 import { Cloisons } from "../../src/structure/cloisons";
 import { CloisonsParams } from "../../src/structure/cloisons_params";
 import { CreateStructure } from "../../src/structure/factory_structure";
@@ -41,6 +42,7 @@ const fente: StructureWeirSubmergedLarinier = new StructureWeirSubmergedLarinier
 cloisons.addChild(fente);
 
 describe("Class Cloisons: ", () => {
+
     describe("Calc(Q) Fente noyée (Larinier 1992)", () => {
         it("vCalc should return 0.407", () => {
             expect(cloisons.Calc("Q").vCalc).toBeCloseTo(0.407, 3);
@@ -68,7 +70,7 @@ describe("Class Cloisons: ", () => {
         LoiDebit.WeirSubmergedLarinier,
         LoiDebit.KIVI
     ];
-    for (let i = 0; i < 3; i++ ) {
+    for (let i = 0; i < 3; i++) {
         c2.addChild(CreateStructure(iLoiDebits[i], c2, false));
     }
     const prmsKivi: StructureKiviParams = c2.structures[2].prms as StructureKiviParams;
@@ -82,4 +84,96 @@ describe("Class Cloisons: ", () => {
             expect(prmsKivi.ZRAM.v).toBeCloseTo(101, 3);
         });
     });
+
+    describe("Calcul avec Calc - ", () => {
+        const descs = [
+            "Q",
+            "Z1",
+            "DH"
+        ];
+        for (const desc of descs) {
+            describe("calcul de " + JSON.stringify(desc), () => {
+                it("", () => {
+                    expect(cloisons.Calc(desc).vCalc).toBeDefined();
+                });
+            });
+        }
+    });
+
+    describe("Calcul avec CalcSerie - ", () => {
+        const descs = [
+            "Q",
+            "Z1",
+            "DH",
+            { uid: fente.uid, symbol: "ZDV" },
+            { uid: fente.uid, symbol: "L" },
+            { uid: fente.uid, symbol: "Cd" }
+        ];
+        for (const desc of descs) {
+            describe("calcul de " + JSON.stringify(desc), () => {
+                it("", () => {
+                    expect(cloisons.CalcSerie(0, desc).vCalc).toBeDefined();
+                });
+            });
+        }
+    });
+
+    describe("Calcul avec CalcSerie et calculatedParam - ", () => {
+        const descs = [
+            "Q",
+            "Z1",
+            "DH",
+            { uid: fente.uid, symbol: "ZDV" },
+            { uid: fente.uid, symbol: "L" },
+            { uid: fente.uid, symbol: "Cd" }
+        ];
+        for (const desc of descs) {
+            describe("calcul de " + JSON.stringify(desc), () => {
+                it("", () => {
+                    let p: ParamDefinition;
+                    if (typeof desc === "string") {
+                        p = cloisons.getParameter(desc);
+                    } else {
+                        p = fente.getParameter(desc.symbol);
+                    }
+                    cloisons.calculatedParam = p;
+                    expect(cloisons.CalcSerie().vCalc).toBeDefined();
+                });
+            });
+        }
+    });
+
+    describe("Exemple Formation Cassiopée 2018-09", () => {
+        it("Calc(Z1) Exemple Formation Cassiopée 2018-09", () => {
+            // Modèle de cloison
+            const modelCloisons = new Cloisons(
+                new CloisonsParams(
+                    0.773,      // Débit total (m3/s)
+                    102,    // Cote de l'eau amont (m)
+                    3.1,     // Longueur des bassins (m)
+                    2.5,      // Largeur des bassins (m)
+                    1.5,      // Profondeur moyenne (m)
+                    0.23     // Hauteur de chute (m)
+                )
+            );
+
+            const rectStructPrms = new RectangularStructureParams(
+                0.773,  // Q
+                76.67,        // ZDV
+                0,        // Z1
+                0,      // Z2
+                0.35,          // L
+                0.65        // Cd pour un seuil rectangulaire
+                // W = Infinity par défaut pour un seuil
+            );
+
+            // Ajout d'ouvrage dans la cloison
+            modelCloisons.addChild(new StructureWeirSubmergedLarinier(rectStructPrms));
+            modelCloisons.calculatedParam = modelCloisons.prms.Z1;
+            const res = modelCloisons.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(78.27, 2);
+            expect(res.extraResults.PV).toBeCloseTo(150.03, 2);
+        });
+    });
+
 });
diff --git a/spec/structure/functions.ts b/spec/structure/functions.ts
index 65863fbd5f7be392c62905cf5dd0a7b8607eb854..cb7dfc4dac08ba17787efb750177e8d98a01170a 100644
--- a/spec/structure/functions.ts
+++ b/spec/structure/functions.ts
@@ -95,6 +95,17 @@ export function testStructure(
 export function testParallelStructures(oPS: ParallelStructure, iLoiDebits: number[]) {
     oPS.prms.Q.v = oPS.Calc("Q").vCalc;
 
+    // Mémorisation des valeurs initiales pour les références
+    for (const prm of oPS.prms) {
+        prm.currentValue = prm.v;
+    }
+    for (const st of oPS.structures) {
+        for (const prm of st.prms) {
+            prm.currentValue = prm.v;
+        }
+    }
+
+    // Tests sur tous les ouvrages
     for (let i = 0; i < oPS.structures.length; i++) {
         const st: Structure = oPS.structures[i];
         describe(`this.structures[${i}]: Structure${LoiDebit[iLoiDebits[i]]}: `, () => {
@@ -113,7 +124,8 @@ export function testParallelStructures(oPS: ParallelStructure, iLoiDebits: numbe
                     prm.calculability === ParamCalculability.DICHO &&
                     prm.symbol !== "Z1" && prm.symbol !== "Z2"
                 ) {
-                    const ref: number = prm.v;
+                    const ref: number = prm.currentValue;
+                    prm.v += 100; // Pour éviter de donner la bonne solution en valeur initiale
                     if (prm.symbol === "W" && prm.v === Infinity) {
                         // Le calcul de l'ouverture sur les seuils doit renvoyer une exception (cas impossible)
                         it(`Calc(${prm.symbol}) should return exception`, () => {
diff --git a/spec/structure/parallel_structure.spec.ts b/spec/structure/parallel_structure.spec.ts
index a473e54cfed2ff39ac5cba2a01c7b619ffe90a7e..8a01b1d2014e232fa97f1147a6ae49803962326f 100644
--- a/spec/structure/parallel_structure.spec.ts
+++ b/spec/structure/parallel_structure.spec.ts
@@ -18,35 +18,36 @@ import { checkResult } from "../test_func";
 import { testParallelStructures } from "./functions";
 import { structTest } from "./structure_test";
 
-const pstruct: ParallelStructure = new ParallelStructure(
-    new ParallelStructureParams(30, 30, 15), // Q = 30, Z1 = 30, Z2 = 15
-    false // debug
-);
-
-/*
- * Tests avec deux structures test identiques
- */
+function createEnv() {
+    const pstruct = new ParallelStructure(
+        new ParallelStructureParams(30, 30, 15), // Q = 30, Z1 = 30, Z2 = 15
+        false // debug
+    );
+    /*
+     * Tests avec deux structures test identiques
+     */
+    pstruct.addChild(structTest);
+    pstruct.addChild(structTest);
+    return pstruct;
+}
 
-pstruct.addChild(structTest);
-pstruct.addChild(structTest);
+let pstruct: ParallelStructure;
 
 describe("Class ParallelStructure: ", () => {
     describe("Calc()", () => {
+        beforeEach(() => {
+            pstruct = createEnv();
+        });
         it("should return 1 result", () => {
-            const res: Result = pstruct.Calc("Q");
-            expect(pstruct.Calc("Q").nbResultElements).toEqual(1);
+            const p1 = createEnv();
+            const res: Result = p1.Calc("Q");
+            expect(p1.Calc("Q").nbResultElements).toEqual(1);
         });
-        itParallelStructure("Q", 30, 15);
-        itParallelStructure("Z1", 30, 15);
-        itParallelStructure("Z2", 15, 15);
-        itParallelStructure({
-            uid: pstruct.structures[0].uid,
-            symbol: "ZDV"
-        }, 0, 15);
-        itParallelStructure({
-            uid: pstruct.structures[1].uid,
-            symbol: "ZDV"
-        }, 0, 15);
+        itParallelStructure(null, "Q", 30, 15);
+        itParallelStructure(null, "Z1", 30, 15);
+        itParallelStructure(null, "Z2", 15, 15);
+        itParallelStructure(0, "ZDV", 0, 15);
+        itParallelStructure(1, "ZDV", 0, 15);
         it("shoud return an error Q too high", () => {
             pstruct.prms.Q.v = 14;
             const res: Result = pstruct.Calc({
@@ -57,6 +58,16 @@ describe("Class ParallelStructure: ", () => {
         });
     });
 });
+function getVarCalc(pstructLoc: ParallelStructure, structIndex: number, sVarCalc: string) : any { 
+    if (structIndex !== null) {
+        return {
+            uid: pstructLoc.structures[structIndex].uid,
+            symbol: sVarCalc
+        };
+    } else {
+        return sVarCalc;
+    }
+}
 
 /**
  * Test sur ParallelStructure
@@ -64,25 +75,30 @@ 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: any, rVcalc: number, Q?: number) {
+function itParallelStructure(structIndex: number, sVarCalc: string, rVcalc: number, Q?: number) {  
     it(`${sVarCalc} should be ${rVcalc}`, () => {
-        checkResult(pstruct.Calc(sVarCalc), rVcalc);
+        const VC1: any = getVarCalc(pstruct, structIndex, sVarCalc);
+        checkResult(pstruct.Calc(VC1), rVcalc);
     });
     if (Q !== undefined) {
-        for (let i = 0; i < pstruct.structures.length; i++) {
-            it(`ExtraResult[ouvrage[${i}].Q] should be ${Q}`, () => {
+        const pstructLocal = createEnv();
+        for (let i = 0; i < pstructLocal.structures.length; i++) {
+            it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q] should be ${Q}`, () => {
+                const VC2: any = getVarCalc(pstruct, structIndex, sVarCalc);
                 expect(
-                    pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q`]
+                    pstruct.Calc(VC2).resultElement.extraResults[`ouvrage[${i}].Q`]
                 ).toBeCloseTo(Q, Math.max(0, precDigits - 1));
             });
-            it(`ExtraResult[ouvrage[${i}].Q_Mode] should be 0`, () => {
+            it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q_Mode] should be 0`, () => {
+                const VC3 = getVarCalc(pstruct, structIndex, sVarCalc);
                 expect(
-                    pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowMode`]
+                    pstruct.Calc(VC3).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowMode`]
                 ).toEqual(0);
             });
-            it(`ExtraResult[ouvrage[${i}].Q_Regime] should be 0`, () => {
+            it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q_Regime] should be 0`, () => {
+                const VC4 = getVarCalc(pstruct, structIndex, sVarCalc);
                 expect(
-                    pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowRegime`]
+                    pstruct.Calc(VC4).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowRegime`]
                 ).toEqual(0);
             });
         }
diff --git a/spec/structure/structure_test.ts b/spec/structure/structure_test.ts
index d574a9fa1a561fbd6f4b4f96e8318ab198b7bf57..225bc0fd6d5849c811a2253bd985896981a5af71 100644
--- a/spec/structure/structure_test.ts
+++ b/spec/structure/structure_test.ts
@@ -31,9 +31,8 @@ class StructureTest extends Structure {
         return this.getFlowRegime();
     }
 
-    public Equation(sVarCalc: string): Result {
+    public CalcQ(): Result {
         this.prms.update_h1h2();
-        Structure.CheckEquation(sVarCalc);
         const data = this.getResultData();
 
         return new Result(this.prms.Z1.v - this.prms.Z2.v - this.prms.ZDV.v, this, data);
diff --git a/spec/value_ref/value_ref.spec.ts b/spec/value_ref/value_ref.spec.ts
index c07d15df38100e24403282aca46a88343773331c..c101298864c894401e8b4b5257bdcbbba19af3a5 100644
--- a/spec/value_ref/value_ref.spec.ts
+++ b/spec/value_ref/value_ref.spec.ts
@@ -6,7 +6,7 @@
  */
 // import { describe, expect, it } from "../mock_jasmine";
 
-import { Result, Session } from "../../src/index";
+import { Result, Session, ParamValueMode } from "../../src/index";
 import { NubTest, NubTestParams } from "../nubtest";
 import { precDigits } from "../test_config";
 
@@ -42,15 +42,16 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.A.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
+            // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "A");
 
-            expect(prm1.A.v).toEqual(1);
-            expect(prm1.B.v).toEqual(2);
-            expect(prm1.C.v).toEqual(3);
-            expect(prm2.A.v).toEqual(1);
-            expect(prm2.B.v).toEqual(2);
-            expect(prm2.C.v).toEqual(3);
+            expect(prm1.A.singleValue).toEqual(1);
+            expect(prm1.B.singleValue).toEqual(2);
+            expect(prm1.C.singleValue).toEqual(3);
+            expect(prm2.A.singleValue).toEqual(1);
+            expect(prm2.B.singleValue).toEqual(2);
+            expect(prm2.C.singleValue).toEqual(3);
         });
 
         it("test 2", () => {
@@ -60,15 +61,16 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.B.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2)
+            // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2)
+            prm2.B.singleValue = 0;
             prm2.B.defineReference(nub1, "B");
 
-            expect(prm1.A.v).toEqual(1);
-            expect(prm1.B.v).toEqual(2);
-            expect(prm1.C.v).toEqual(3);
-            expect(prm2.A.v).toEqual(1);
-            expect(prm2.B.v).toEqual(2);
-            expect(prm2.C.v).toEqual(3);
+            expect(prm1.A.singleValue).toEqual(1);
+            expect(prm1.B.singleValue).toEqual(2);
+            expect(prm1.C.singleValue).toEqual(3);
+            expect(prm2.A.singleValue).toEqual(1);
+            expect(prm2.B.singleValue).toEqual(2);
+            expect(prm2.C.singleValue).toEqual(3);
         });
 
         it("test 3", () => {
@@ -78,18 +80,19 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.C.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            prm2.C.singleValue = 0;
             prm2.C.defineReference(nub1, "C");
 
             // as C is a calculated param
             nub2.triggerChainCalculation();
 
-            expect(prm1.A.v).toEqual(1);
-            expect(prm1.B.v).toEqual(2);
-            expect(prm1.C.v).toEqual(3);
-            expect(prm2.A.v).toEqual(1);
-            expect(prm2.B.v).toEqual(2);
-            expect(prm2.C.v).toEqual(3);
+            expect(prm1.A.singleValue).toEqual(1);
+            expect(prm1.B.singleValue).toEqual(2);
+            expect(prm1.C.singleValue).toEqual(3);
+            expect(prm2.A.singleValue).toEqual(1);
+            expect(prm2.B.singleValue).toEqual(2);
+            expect(prm2.C.singleValue).toEqual(3);
         });
 
         it("test 4", () => {
@@ -99,7 +102,8 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.A.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
+            // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "A");
 
             expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits);
@@ -118,18 +122,18 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm1.B.v = 3;  // valeur maître
-            prm2.B.v = 0;  // valeur esclave (doit être masquée par la valeur maître)
+            prm1.B.singleValue = 3;  // valeur maître
+            prm2.B.singleValue = 0;  // valeur esclave (doit être masquée par la valeur maître)
             prm2.B.defineReference(nub1, "B");
 
-            expect(nub1.Calc("A").vCalc).toBeCloseTo(0, precDigits);
-            expect(nub1.Calc("B").vCalc).toBeCloseTo(3, precDigits);
-            expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits);
+            expect(nub1.CalcSerie(undefined, "A").vCalc).toBeCloseTo(0, precDigits);
+            expect(nub1.CalcSerie(undefined, "B").vCalc).toBeCloseTo(2, precDigits);
+            expect(nub1.CalcSerie(undefined, "C").vCalc).toBeCloseTo(4, precDigits);
+
+            expect(nub2.CalcSerie(undefined, "A").vCalc).toBeCloseTo(0, precDigits);
+            expect(nub2.CalcSerie(undefined, "B").vCalc).toBeCloseTo(2, precDigits);
+            expect(nub2.CalcSerie(undefined, "C").vCalc).toBeCloseTo(4, precDigits);
 
-            expect(nub2.Calc("A").vCalc).toBeCloseTo(0, precDigits);
-            // tslint:disable-next-line:max-line-length
-            // expect(nub2.Calc("B").vCalc).toBeCloseTo(3, precDigits); // échoue car l'écriture du paramètre esclave (pendant la dichotomie) n'affecte pas la valeur maître; la relecture du paramètre esclave ne reflète pas la valeur écrite
-            expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits);
         });
 
         it("test 6", () => {
@@ -139,7 +143,8 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.C.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            prm2.C.singleValue = 0;
             prm2.C.defineReference(nub1, "C");
 
             expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits);
@@ -160,15 +165,16 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm1.B.v = 5;
+            prm1.B.singleValue = 5;
             nub1.calculatedParam = prm1.C;
-            prm2.A.v = 0;  // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3)
+            // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3)
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "C");
 
             // as C is a calculated param
             nub2.triggerChainCalculation();
 
-            expect(prm2.A.v).toBeCloseTo(6, precDigits);
+            expect(prm2.A.singleValue).toBeCloseTo(6, precDigits);
         });
 
         it("test 2", () => {
@@ -178,16 +184,14 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm1.C.v = 0;  // valeur bidon, doit être 3 après calcul
+            prm1.C.singleValue = 0;  // valeur bidon, doit être 3 après calcul
             nub1.calculatedParam = prm1.C;
-            prm2.C.v = 0;  // valeur bidon, doit être 5 après calcul
-            prm2.A.v = 0;  // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            prm2.C.singleValue = 0;  // valeur bidon, doit être 5 après calcul
+            // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "C");
 
-            // as C is a calculated param
-            nub2.triggerChainCalculation();
-
-            expect(nub2.Calc("C").vCalc).toBeCloseTo(5, precDigits);
+            expect(nub2.CalcSerie(undefined, "C").vCalc).toBeCloseTo(5, precDigits);
         });
 
         it("test 3", () => {
@@ -204,7 +208,7 @@ describe("référence d'un paramètre à un autre : ", () => {
             prm1.A.setValues(min, max, step);
 
             // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [1,2,3,4,5])
-            prm2.A.v = 0;
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "A");
 
             let n = 0;
@@ -228,9 +232,9 @@ describe("référence d'un paramètre à un autre : ", () => {
             prm1.A.setValues(input);
 
             // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [2,3,4,5,6])
-            prm2.A.v = 0;
+            prm2.A.singleValue = 0;
             prm2.A.defineReference(nub1, "A");
-            prm2.Pr.v = 0.001;
+            prm2.Pr.singleValue = 0.001;
 
             const r: Result = nub2.CalcSerie(0.1, "C");
 
diff --git a/spec/value_ref/value_ref_indirect.spec.ts b/spec/value_ref/value_ref_indirect.spec.ts
index 9e59d8766dd39005dfd4c3552296be7ae27eb6b2..aca3ba20d54efab48f4e95bc6fe2a572a1bf8212 100644
--- a/spec/value_ref/value_ref_indirect.spec.ts
+++ b/spec/value_ref/value_ref_indirect.spec.ts
@@ -29,14 +29,14 @@ let prm4: DeverParams;
 function createEnv() {
     // Nub 1 : Régime Uniforme
     const paramSect = new ParamsSectionCirc(2, 0.6613, 40, 1.2, 0.001, 1);
-    paramSect.Pr.v = 0.01;
+    paramSect.Pr.singleValue = 0.01;
     const sect = new cSnCirc(paramSect);
     nub1 = new RegimeUniforme(sect);
     prm1 = nub1.section.prms as ParamsSectionCirc;
 
     // Nub 2 : Section Paramétrée
     const prmsS = new ParamsSectionTrapez(1, 0.5, 1, 0.01, 1, 0.01, 2);
-    prmsS.Pr.v = 0.01;
+    prmsS.Pr.singleValue = 0.01;
     nub2 = new SectionParametree(new cSnTrapez(prmsS));
     prm2 = nub2.section.prms as ParamsSectionTrapez; // = prmsS
 
@@ -46,7 +46,7 @@ function createEnv() {
 
     // Nub 4 : Déversoirs Dénoyés
     prm4 = new DeverParams(0.5, 102, 10, 99);
-    prm4.Pr.v = 0.01;
+    prm4.Pr.singleValue = 0.01;
     nub4 = new Dever(prm4);
     nub4.addChild(
         CreateStructure(
@@ -72,7 +72,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm3.Y.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
+        prm3.Y.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
         prm3.Y.defineReference(nub2.section, "Y");
         prm2.Y.defineReference(nub1.section, "Y");
 
@@ -88,7 +88,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm3.Y.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
+        prm3.Y.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
         prm3.Y.defineReference(nub2.section, "Y");
         prm2.Y.defineReference(nub1.section, "Y");
         prm1.Y.setValues(2, 5, 1);
@@ -105,12 +105,11 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm3.Y.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
+        prm3.Y.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
         prm3.Y.defineReference(nub2.section, "Y");
         prm2.Y.defineReference(nub1.section, "Y");
 
-        prm1.LargeurBerge.v = 3.5; // Section Circ !
-        prm1.Ks.v = 42;
+        prm1.Ks.singleValue = 42;
         nub1.calculatedParam = prm1.Y;
 
         nub3.CalcSerie();
@@ -125,12 +124,12 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm3.Y.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
+        prm3.Y.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y)
         prm3.Y.defineReference(nub2.section, "Y");
         prm2.Y.defineReference(nub1.section, "Y");
 
         prm1.D.setValues(2.5, 7, 0.5);
-        prm1.Ks.v = 42;
+        prm1.Ks.singleValue = 42;
         nub1.calculatedParam = prm1.Y;
 
         nub3.CalcSerie();
@@ -154,7 +153,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm1.Q.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q)
+        prm1.Q.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q)
         prm1.Q.defineReference(nub2.section, "Q");
         nub1.calculatedParam = prm1.Ks;
         prm2.Q.defineReference(nub4, "CvQT");
@@ -173,7 +172,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => {
 
         createEnv();
 
-        prm1.Q.v = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q)
+        prm1.Q.singleValue = 0.1;  // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q)
         prm1.Q.defineReference(nub2.section, "Q");
         nub1.calculatedParam = prm1.Ks;
         prm2.Q.defineReference(nub4, "CvQT");
diff --git a/spec/value_ref/value_ref_section.spec.ts b/spec/value_ref/value_ref_section.spec.ts
index 50c1d19e6419ec62779b975ed7799bed2bc2b25c..4dec46b616240f2baf4b5511b19816800cba6f2a 100644
--- a/spec/value_ref/value_ref_section.spec.ts
+++ b/spec/value_ref/value_ref_section.spec.ts
@@ -51,12 +51,12 @@ describe("référence d'un paramètre à un autre : ", () => {
 
             createEnv();
 
-            prm2.Q.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.CvQT)
+            prm2.Q.singleValue = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.CvQT)
             prm2.Q.defineReference(nub1, "CvQT");
 
-            nub2.CalcSerie();
+            nub2.CalcSerie(); // triggers chain calculation
 
-            expect(prm2.Q.v).toBeCloseTo(10.106);
+            expect(prm2.Q.singleValue).toBeCloseTo(10.106);
         });
     });
 });
diff --git a/src/base.ts b/src/base.ts
index be98cf9a14d653128998caeb00d1e356552eba97..9b0c9494aa93512cf67456824b205ea8f23498ec 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -63,3 +63,42 @@ export function isNumeric(s: string): boolean {
     }
     return false;
 }
+
+/**
+ * Retourne true si a et b sont égaux à e près (en gros)
+ */
+export function isEqual(a: number, b: number, e: number = 1E-7): boolean {
+    if (a === 0 && b === 0) {
+        return true;
+    }
+    if (b === 0) { // ne pas diviser par 0
+        [ a, b ] = [ b, a ];
+    }
+    if (a === 0) { // éviter d'avoir un quotient toujours nul
+        return (Math.abs(b) < e);
+    }
+    // cas général
+    return (Math.abs((a / b) - 1) < e);
+}
+
+/**
+ * Division entière de a par b, plus modulo, avec une tolérance e
+ * pour gérer le cas des nombres réels
+ */
+export function floatDivAndMod(a: number, b: number, e: number = 1E-7): { q: number, r: number } {
+    let q = Math.floor(a / b);
+    let r = a % b;
+    // si le modulo est bon à un pouïème, pas de reste
+    if (isEqual(r, b)) {
+        r = 0;
+        // si la division entière n'est pas tombée juste, +1 au quotient
+        if (q !== (a / b)) {
+            q++;
+        }
+    }
+    // si le modulo est nul à un pouïème, il est nul
+    if (isEqual(r, 0)) {
+        r = 0;
+    }
+    return { q, r };
+}
diff --git a/src/compute-node.ts b/src/compute-node.ts
index 93b34ea7160a4055098335d253f5680507276a32..a49820c6d44b12fa1cb70212cb8ea2f5888d0d65 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -17,11 +17,13 @@ export enum CalculatorType {
     Structure,          // ouvrages hydrauliques simples
     ParallelStructure,  // ouvrages hydrauliques en parallèle
     Dever,              // Outil Cassiopée Dever
-    Cloisons,            // Outil Cassiopée PAB Cloisons
-    MacroRugo,       // Passe à enrochement simple (Cassan et al., 2016)
+    Cloisons,           // Outil Cassiopée PAB Cloisons
+    MacroRugo,          // Passe à enrochement simple (Cassan et al., 2016)
     PabChute,
     PabNombre,
-    Section
+    Section,
+    Pab,                // Passe à bassins;
+    PabCloisons         // modèle de cloisons + débit d'attrait, pour Passe à bassins
 }
 
 /**
diff --git a/src/dichotomie.ts b/src/dichotomie.ts
index b17acfe1bfd897b7f52ea572e4c3ff058034a1df..edaab56e446f42ec15223afb94ccbb5b15f6484e 100644
--- a/src/dichotomie.ts
+++ b/src/dichotomie.ts
@@ -159,7 +159,7 @@ export class Dichotomie extends Debug {
     }
 
     private set vX(vCalc: number) {
-        this._paramX.setValue(vCalc);
+        this._paramX.v = vCalc;
     }
 
     /**
@@ -215,7 +215,7 @@ export class Dichotomie extends Debug {
      * Il faudra s'assurer que cette première variable correspond à la méthode de calcul la plus rapide
      */
     private Calcul(): Result {
-        const r: Result = this.nub.Calc(this.analyticalSymbol);
+        const r: Result = this.nub.Equation(this.analyticalSymbol);
         this.debug(
             "dicho : Calcul(vX=" + this.sVarCalc + "=" + this.vX + ") -> " +
             this.analyticalSymbol + "=" + r.vCalc);
diff --git a/src/index.ts b/src/index.ts
index a8b1bd974fd57751fccf86d6025d60213bf867b7..2ca952317449ddd2a7e9415090d71f7b4bdfe067 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -24,6 +24,7 @@ export * from "./util/interval";
 export * from "./util/observer";
 export * from "./util/iterator";
 export * from "./util/enum";
+export * from "./structure/cloisons";
 export * from "./structure/parallel_structure";
 export * from "./structure/parallel_structure_params";
 export * from "./structure/structure";
@@ -34,3 +35,5 @@ export * from "./linked-value";
 export * from "./jalhyd_object";
 export * from "./date_revision";
 export * from "./section/section_nub";
+export * from "./pab/pab";
+export * from "./pab/pab_cloisons";
diff --git a/src/linked-value.ts b/src/linked-value.ts
index 9de169224e6fc016b6e4a57478df2163e78100d0..e1d6a0a3499a807513c4849925529fb0b089fd7b 100644
--- a/src/linked-value.ts
+++ b/src/linked-value.ts
@@ -3,7 +3,6 @@ import { ParamDefinition } from "./param/param-definition";
 import { INamedIterableValues } from "./param/param-value-iterator";
 import { ParamValueMode } from "./param/param-value-mode";
 import { ParamValues } from "./param/param-values";
-import { Message, MessageCode } from "./util/message";
 
 export class LinkedValue {
     /** linked value metadata (ex: calculator title for GUI) */
@@ -134,10 +133,6 @@ export class LinkedValue {
                         if (targetParam.hasMultipleValues) {
                             const multipleRes = this.nub.result.getCalculatedValues();
                             this._paramValues.setValues(multipleRes);
-                            if (this._paramValues.currentValue === undefined) {
-                                // or else isDefined() will return false
-                                this._paramValues.currentValue = multipleRes[0];
-                            }
                         } else {
                             const singleRes = this.nub.result.vCalc;
                             this._paramValues.setValues(singleRes);
@@ -146,9 +141,6 @@ export class LinkedValue {
                     // return local cache
                     ret = this._paramValues;
                 } else {
-                    // else simple parameter proxy (see below)
-                    // @TODO why ? risk of getting obsolete values !
-                    // ret = targetParam.paramValues;
                     throw new Error("LinkedValue.getParamValues() - result not available");
                 }
 
@@ -169,10 +161,6 @@ export class LinkedValue {
                     if (this.nub.resultHasMultipleValues()) {
                         const multipleExtraRes = this.nub.result.getExtraResults(this.symbol);
                         this._paramValues.setValues(multipleExtraRes);
-                        if (this._paramValues.currentValue === undefined) {
-                            // or else isDefined() will return false
-                            this._paramValues.currentValue = multipleExtraRes[0];
-                        }
                     } else {
                         const singleExtraRes = this.nub.result.getExtraResult(this.symbol);
                         this._paramValues.setValues(singleExtraRes);
@@ -192,33 +180,12 @@ export class LinkedValue {
     }
 
     /**
-     * Returns the current value of this.paramValues; triggers a chain computation
-     * if required to obtain ParamValues; throws an error if this.paramValues is
-     * ultimately not defined
+     * Returns the single value of this.paramValues; triggers a chain computation
+     * if required to obtain ParamValues
      */
     public getValue(triggerChainComputation: boolean = false) {
         const pv = this.getParamValues(triggerChainComputation);
-        if (! pv.isDefined) {
-            const e = new Message(MessageCode.ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED);
-            e.extraVar.symbol = this.symbol;
-            throw e;
-        }
-        return pv.currentValue;
-    }
-
-    /**
-     * Returns the current multiple values list of this.paramValues; triggers a
-     * chain computation if required to obtain ParamValues; throws an error if
-     * this.paramValues is ultimately not defined
-     */
-    public getValues(triggerChainComputation: boolean = false): number[] {
-        const pv = this.getParamValues(triggerChainComputation);
-        if (! pv.isDefined) {
-            const e = new Message(MessageCode.ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED);
-            e.extraVar.symbol = this.symbol;
-            throw e;
-        }
-        return pv.valueList;
+        return pv.singleValue;
     }
 
     /**
@@ -236,6 +203,17 @@ export class LinkedValue {
         return false;
     }
 
+    /**
+     * Returns true if target value is available
+     */
+    public isDefined() {
+        if (this.isExtraResult()) {
+            return (this.nub.result !== undefined);
+        } else {
+            return (this.element as ParamDefinition).isDefined;
+        }
+    }
+
     /**
      * When invalidating a Nub's result, parameters pointing to this result should
      * invalidate their proxy paramValues too
diff --git a/src/nub.ts b/src/nub.ts
index d6132a92cbb2e0651bdac96817b6c4f84805359d..b53b73f6a6cfdb1216435f883419d178ad1b279c 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,7 +1,7 @@
 import { CalculatorType, ComputeNode } from "./compute-node"; // nghyd build fails when commenting CalculatorType @WTF
 import { Dichotomie } from "./dichotomie";
-import { acSection, IParamDefinitionIterator, ParamDefinition, ParamsEquation, ParamsEquationArrayIterator,
-         Session, Structure } from "./index";
+import { acSection, IParamDefinitionIterator, Pab, ParamDefinition, ParamsEquation,
+         ParamsEquationArrayIterator, Session, Structure } from "./index";
 import { LinkedValue } from "./linked-value";
 import { ParamCalculability } from "./param/param-definition";
 import { ParamValueMode } from "./param/param-value-mode";
@@ -256,7 +256,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
             return this._result;
         }
         const sAnalyticalPrm: string = this.getFirstAnalyticalParameter().symbol;
-        computedVar.setValue(resSolve.vCalc);
+        computedVar.v = resSolve.vCalc;
         const res: Result = this.Equation(sAnalyticalPrm);
         res.vCalc = resSolve.vCalc;
         this._result = res;
@@ -298,8 +298,10 @@ export abstract class Nub extends ComputeNode implements IObservable {
         this.progress = 0;
         this.triggerChainCalculation();
 
+        this.copySingleValuesToSandboxValues();
+
+        // check which values are variating, if any
         for (const p of this.parameterIterator) {
-            // checks which values are variating, if any
             switch (p.valueMode) {
                 case ParamValueMode.SINGLE:
                 case ParamValueMode.CALCUL:
@@ -360,7 +362,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
 
             variatedValues.initValuesIterator(false);
             while (variatedValues.hasNext) {
-                variatedValues.next();
+                const currentIteratorValue = variatedValues.next();
+                variatedParam.v = currentIteratorValue.value; // copy to local sandbox value
 
                 this.Calc(computedSymbol, rInit);  // résultat dans this._result
                 if (this._result.ok) {
@@ -411,6 +414,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
         child.parent = this;
         // propagate precision
         child.prms.Pr.setValue(this.prms.Pr.v); // does not write to .v to bypass calculability control
+        // postprocessing
+        this.adjustChildParameters(child);
     }
 
     public getChildren(): Nub[] {
@@ -469,7 +474,10 @@ export abstract class Nub extends ComputeNode implements IObservable {
                             // 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));
+                            // do not suggest parameters that are already linked to another one
+                            if (p.valueMode !== ParamValueMode.LINK) {
+                                res.push(new LinkedValue(this, p, p.symbol));
+                            }
                         }
                     }
                 }
@@ -492,9 +500,11 @@ export abstract class Nub extends ComputeNode implements IObservable {
             }
         }
 
-        // 3. children Nubs
-        for (const cn of this.getChildren()) {
-            res = res.concat(cn.getLinkableValues(src));
+        // 3. children Nubs, except for PAB
+        if (! (this instanceof Pab)) {
+            for (const cn of this.getChildren()) {
+                res = res.concat(cn.getLinkableValues(src));
+            }
         }
 
         return res;
@@ -790,7 +800,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 }
             }
             // define calculated param at Nub level
-            // @TODO except if we are a Section or Structure ?
+            // @TODO except if we are a Section / Structure / PabCloisons ?
             if (calculatedParam) {
                 this.calculatedParam = calculatedParam;
             }
@@ -882,6 +892,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
         }
         // add reference to parent collection (this)
         child.parent = this;
+        // postprocessing
+        this.adjustChildParameters(child);
     }
 
     /**
@@ -937,6 +949,18 @@ export abstract class Nub extends ComputeNode implements IObservable {
         return false;
     }
 
+    /**
+     * @return child having the given UID
+     */
+    public getChild(uid: string): Nub {
+        for (const s of this._children) {
+            if (s.uid === uid) {
+                return s;
+            }
+        }
+        return undefined;
+    }
+
     /**
      * Moves a child to first position
      */
@@ -1015,6 +1039,48 @@ export abstract class Nub extends ComputeNode implements IObservable {
         this._observable.notifyObservers(data, sender);
     }
 
+    /**
+     * Returns values of parameters and the result of the calculation for the calculated parameter
+     * @param sVarCalc Symbol of the calculated param
+     * @param result Result object of the calculation
+     */
+    protected getParamValuesAfterCalc(sVarCalc: string, result: Result): { [key: string]: number } {
+        const cPrms: { [key: string]: number } = {};
+        for (const p of this.parameterIterator) {
+            if (p.symbol === sVarCalc) {
+                cPrms[p.symbol] = result.vCalc;
+            } else {
+                cPrms[p.symbol] = p.v;
+            }
+        }
+        return cPrms;
+    }
+
+    /**
+     * For all SINGLE, LINK and CALC parameters, copies singleValue to
+     * sandbox value (.v) before calculation
+     */
+    protected copySingleValuesToSandboxValues() {
+        for (const p of this.parameterIterator) {
+            switch (p.valueMode) {
+                case ParamValueMode.SINGLE:
+                case ParamValueMode.CALCUL:
+                    p.v = p.singleValue;
+                    break;
+                case ParamValueMode.LINK:
+                    if (p.referencedValue) {
+                        p.v = p.referencedValue.getValue();
+                    } else {
+                        throw Error("Nub.CalcSerie() : linked value not defined");
+                    }
+                    break;
+                default:
+                    // variable mode, let iterator do the job
+                    p.v = undefined;
+            }
+        }
+    }
+
     /**
      * To call Nub.calc(…) from indirect child
      */
@@ -1053,6 +1119,12 @@ export abstract class Nub extends ComputeNode implements IObservable {
         }, this);
     }
 
+    /**
+     * Optional postprocessing after adding / replacing a child
+     */
+    // tslint:disable-next-line:no-empty
+    protected adjustChildParameters(child: Nub) {}
+
     /**
      * Résoud l'équation par une méthode numérique
      * @param sVarCalc nom de la variable à calculer
diff --git a/src/pab/pab.ts b/src/pab/pab.ts
new file mode 100644
index 0000000000000000000000000000000000000000..39c9b0467405363c2b889a90fc7bcdc4c578478a
--- /dev/null
+++ b/src/pab/pab.ts
@@ -0,0 +1,166 @@
+import { CalculatorType } from "../compute-node";
+import { Nub } from "../nub";
+import { ParamCalculability } from "../param/param-definition";
+import { Session } from "../session";
+import { ParallelStructure } from "../structure/parallel_structure";
+import { Result } from "../util/result";
+import { PabCloisons } from "./pab_cloisons";
+import { PabParams } from "./pab_params";
+
+export { PabParams };
+
+export class Pab extends Nub {
+
+    /**
+     * Last wall at downstream
+     */
+    public downWall: ParallelStructure;
+
+    constructor(prms: PabParams, downWall: ParallelStructure, dbg: boolean = false) {
+        super(prms, dbg);
+        this.downWall = downWall;
+        this._calcType = CalculatorType.Pab;
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PabParams {
+        return this._prms as PabParams;
+    }
+
+    /**
+     * enfants castés au bon type
+     */
+    get children(): PabCloisons[] {
+        return this._children as PabCloisons[];
+    }
+
+    public Calc(sVarCalc?: string, rInit?: number): Result  {
+        // Update array of PabCloisons with last Models current values
+        for (const cl of this.children) {
+            cl.prms.setCurrentValuesFromModel();
+        }
+        return super.Calc(sVarCalc, rInit);
+    }
+
+    /**
+     * Calcul analytique
+     * @warning Should be called by this.Calc only for parameter initialisations
+     * @param sVarCalc Variable à calculer (Z1 uniquement)
+     */
+    public Equation(sVarCalc: string): Result {
+        const r: Result = new Result(0, this);
+
+        // Up to down course : discharge distribution and bottom elevation
+        let Q: number = this.prms.Q.v; // Upstream discharge
+        // upstream basin apron elevation
+        let rZRam: number = this.children[0].prms.Z1.currentValue - this.children[0].Yam;
+
+        for (const cl of this.children) {
+            Q += cl.prms.QA.v;  // Discharge in the current basin
+            rZRam -= cl.prms.DH.currentValue;
+        }
+
+        // Down to up course : water surface calculation
+        let Z: number = this.prms.Z2.v;
+        Z = this.calcCloisonZ1(this.downWall, Q, Z);
+        this.downWall.result.extraResults.ZRAM = rZRam;
+
+        for (let i = this.children.length - 1; i >= 0; i--) {
+
+            // Initialisations for current cloison
+            const cl: PabCloisons = this.children[i];
+            rZRam += cl.prms.DH.currentValue;
+            cl.updateZDV(rZRam);
+
+            // Calculation of upstream water elevation
+            Z = this.calcCloisonZ1(cl, Q, Z);
+            if (this.debug) {
+                console.log("Bassin n°" + i);
+                let s: string = "";
+                for (const p of cl.prms) {
+                    // tslint:disable-next-line:no-console
+                    s += p.symbol + " = " + p.v + "; " ;
+                }
+                console.log(s);
+
+                for (const c of cl.getChildren()) {
+                    console.log("Ouvrage");
+                    s = "";
+                    for (const p of c.prms) {
+                        // tslint:disable-next-line:no-console
+                        s += p.symbol + " = " + p.v;
+                    }
+                    console.log(s);
+                }
+            }
+            Q -= cl.prms.QA.v;
+        }
+
+        r.vCalc = Z;
+        return r;
+    }
+
+    /**
+     * Finds the ParallelStructure targetted by modelUid and defines it as the current downWall
+     */
+    public setDownWall(modelUid: string) {
+        this.properties.setPropValue("modeleCloisonAval", modelUid);
+        const dw = (Session.getInstance().findNubByUid(modelUid) as ParallelStructure);
+        if (dw) {
+            this.downWall = dw;
+        } /* else {
+            console.error("Pab.setDownWall : cannot find target ParallelStructure");
+        } */
+    }
+
+    /**
+     * Once session is loaded, run a second pass on all PabCloisons to
+     * reinit their target if needed
+     */
+    public fixPAB(obj: any) {
+        if (obj.children && Array.isArray(obj.children)) {
+            // Cloisons models
+            for (const c of obj.children) {
+                if (c.props.calcType === CalculatorType.PabCloisons) { // who knows ?
+                    const childUid = c.uid;
+                    const targetCloisonsUid = c.props.modeleCloisons;
+                    // find child PabCloisons to relink
+                    const pabCloisons = (this.getChild(childUid) as PabCloisons);
+                    if (pabCloisons) {
+                        pabCloisons.setModel(targetCloisonsUid);
+                    } // else cannot find target
+                }
+            }
+            // Downstream wall
+            if (obj.props.modeleCloisonAval) {
+                this.setDownWall(obj.props.modeleCloisonAval);
+            }
+        }
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.Z1.calculability = ParamCalculability.EQUATION;
+        this.prms.Z2.calculability = ParamCalculability.DICHO;
+        this.prms.Q.calculability = ParamCalculability.DICHO;
+    }
+
+    private calcCloisonZ1(cl: ParallelStructure, Q: number, Z: number): number {
+        // Initialisations for current cloison
+        cl.prms.Q.v = Q;
+        cl.prms.Z2.v = Z;
+
+        // Calculation of upstream water elevation
+        cl.Calc("Z1");
+
+        // TODO: Add extraresults: discharge, apron elevation upstream the wall, apron elevation at half basin
+        cl.result.extraResults.YMOY = cl.prms.Z2.v - cl.result.extraResults.ZRB;
+
+        // Update elevation and discharge for next basin
+        return cl.prms.Z1.v;
+    }
+}
diff --git a/src/pab/pab_chute.ts b/src/pab/pab_chute.ts
index e7b41568894db60e8c52a34cdc26069c4a373145..0e1eb454b4cc1f494410069a48e62283bb556108 100644
--- a/src/pab/pab_chute.ts
+++ b/src/pab/pab_chute.ts
@@ -3,6 +3,7 @@ import { Nub } from "../nub";
 import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
+import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
 
 export class PabChuteParams extends ParamsEquation {
@@ -60,6 +61,13 @@ export class PabChute extends Nub {
     public Equation(sVarCalc: string): Result {
         let v: number;
 
+        if (! [ "Z1", "Z2" ].includes(sVarCalc) && this.prms.Z1.v <= this.prms.Z2.v) {
+            const m = new Message(MessageCode.ERROR_ELEVATION_ZI_LOWER_THAN_Z2);
+            m.extraVar.Z1 = this.prms.Z1.v;
+            m.extraVar.Z2 = this.prms.Z2.v;
+            return new Result(m);
+        }
+
         switch (sVarCalc) {
             case "Z1":
                 v = this.prms.Z2.v + this.prms.DH.v;
diff --git a/src/pab/pab_cloisons.ts b/src/pab/pab_cloisons.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aeb74a2dec83aa4a2ae5bf06185548bfc3281f68
--- /dev/null
+++ b/src/pab/pab_cloisons.ts
@@ -0,0 +1,151 @@
+import { ParamCalculability, ParamDefinition, ParamFamily} from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { Result } from "../util/result";
+
+import { CalculatorType, Session } from "../index";
+import { Cloisons, CloisonsParams } from "../structure/cloisons";
+import { Pab } from "./pab";
+
+class PabCloisonsParams extends CloisonsParams {
+
+    /** Débit d'attrait d'un bassin (m3/s) */
+    public _QA: ParamDefinition;
+
+    /** Model of cloison on which this pabCloison is based */
+    private _modelCloisonsParams: CloisonsParams;
+
+    /**
+     * Paramètres communs à toutes les équations de structure
+     * @param rQ Débit total (m3/s)
+     * @param rZ1 Cote de l'eau amont (m)
+     * @param rLB Longueur des bassins (m)
+     * @param rBB Largeur des bassins (m)
+     * @param rPB Profondeur moyenne (m)
+     * @param rDH Hauteur de chute (m)
+     */
+    constructor(modelCloisonsParams?: CloisonsParams, rQA: number = 0) {
+        super(1, 1, 1, 1, 1, 1); // overwritten by init() below
+        this.modelCloisonsParams = modelCloisonsParams;
+
+        // Débit d'attrait
+        this._QA = new ParamDefinition(this, "QA", ParamDomainValue.POS_NULL, rQA, ParamFamily.FLOWS);
+        this.addParamDefinition(this._QA);
+    }
+
+    public get QA() {
+        return this._QA;
+    }
+
+    /**
+     * Record pointer to the cloison model for future updating of local parameters
+     */
+    set modelCloisonsParams(modelCloisonsParams: CloisonsParams) {
+        this._modelCloisonsParams = modelCloisonsParams;
+    }
+
+    /**
+     * Update Current values and sandobx values of parameter from cloison model
+     */
+    public setCurrentValuesFromModel() {
+        if (this._modelCloisonsParams !== undefined) {
+            for (const p of this._modelCloisonsParams) {
+                this._paramMap[p.symbol].currentValue = p.currentValue;
+                this._paramMap[p.symbol].v = p.currentValue;
+            }
+        }
+    }
+
+}
+
+// tslint:disable-next-line:max-classes-per-file
+export class PabCloisons extends Cloisons {
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PabCloisonsParams {
+        return this._prms as PabCloisonsParams;
+    }
+
+    /**
+     * Calculation of upstream water depth
+     */
+    get Yam(): number {
+        // TODO: ajouter l'option radier horizontal
+        return this.prms.PB.currentValue + this.prms.DH.currentValue / 2;
+    }
+
+    public parent: Pab;
+
+    constructor(modelCloisons: Cloisons, rQA: number = 0, dbg: boolean = false) {
+        super(new PabCloisonsParams(), dbg); // model is set below
+        this.initModelCloisons(modelCloisons);
+        this._calcType = CalculatorType.PabCloisons;
+    }
+
+    public Calc(sVarCalc: string, rInit?: number): Result {
+        const r: Result = super.Calc(sVarCalc, rInit);
+        const p = this.getParamValuesAfterCalc(sVarCalc, r);
+        r.extraResults.ZRAM = p.Z1 - p.PB;
+        return r;
+    }
+
+    /**
+     * Update crest elevations from upstream apron elevation
+     */
+    public updateZDV(rZR: number) {
+        for (const st of this.structures) {
+            if (st.prms.ZDV.calculability !== ParamCalculability.NONE) {
+                st.prms.ZDV.v = st.prms.ZDV.currentValue + rZR - (this.prms.Z1.currentValue - this.Yam);
+            }
+        }
+    }
+
+    /**
+     * Sets modelCloisons as the current model (set pointers to parameters and structure array)
+     */
+    public initModelCloisons(modelCloisons: Cloisons) {
+        this.prms.modelCloisonsParams = modelCloisons ? modelCloisons.prms : undefined;
+        this._children = modelCloisons ? modelCloisons.structures : [];
+    }
+
+    /**
+     * Finds the Cloisons targetted by modelUid and defines it as the current model
+     */
+    public setModel(modelUid: string) {
+        this.properties.setPropValue("modeleCloisons", modelUid);
+        const cloisons = (Session.getInstance().findNubByUid(modelUid) as Cloisons);
+        if (cloisons) {
+            this.initModelCloisons(cloisons);
+        } /* else {
+            console.error("PabCloisons.setModel : cannot find target Cloisons");
+        } */
+    }
+
+    /**
+     * Returns an object representation of the Nub's current state
+     */
+    public objectRepresentation() {
+        const ret: any = {
+            uid: this.uid,
+            props: this.properties.props,
+            parameters: []
+        };
+
+        // ! do not iterate over local parameters (would copy the parameters of the Cloisons used as model),
+        // just serialise QA
+        ret.parameters.push(this.prms.QA.objectRepresentation());
+
+        // ! do not iterate over children Nubs (would copy the children of the Cloisons used as model)
+
+        return ret;
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        super.setParametersCalculability();
+        this.prms._QA.calculability = ParamCalculability.FREE;
+    }
+}
diff --git a/src/pab/pab_nombre.ts b/src/pab/pab_nombre.ts
index a853df31ee87c3c4fcad2fc950f2f4adc8d85b23..a9c34bc512bea954d6cfb09297d3c350cc06030d 100644
--- a/src/pab/pab_nombre.ts
+++ b/src/pab/pab_nombre.ts
@@ -1,8 +1,10 @@
+import { floatDivAndMod } from "../base";
 import { CalculatorType } from "../compute-node";
 import { Nub } from "../nub";
 import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
+import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
 
 export class PabNombreParams extends ParamsEquation {
@@ -11,7 +13,7 @@ export class PabNombreParams extends ParamsEquation {
     /** Chute totale DHT */
     private _DHT: ParamDefinition;
 
-    /** Nombre de bassins N */
+    /** Nombre de chutes N */
     private _N: ParamDefinition;
 
     /** Chute entre bassins DH */
@@ -58,6 +60,12 @@ export class PabNombre extends Nub {
     }
 
     public Equation(sVarCalc: string): Result {
+        if (sVarCalc !== "N" && ! Number.isInteger(this.prms.N.v)) {
+            const m = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTEGER);
+            m.extraVar.N = this.prms.N.v;
+            return new Result(m);
+        }
+
         let v: number;
         let DHR = 0;
 
@@ -67,8 +75,9 @@ export class PabNombre extends Nub {
                 break;
 
             case "N":
-                v = Math.floor(this.prms.DHT.v / this.prms.DH.v);
-                DHR = this.prms.DHT.v % this.prms.DH.v;
+                const divAndMod = floatDivAndMod(this.prms.DHT.v, this.prms.DH.v);
+                v = divAndMod.q;
+                DHR = divAndMod.r;
                 break;
 
             case "DH":
@@ -99,5 +108,4 @@ export class PabNombre extends Nub {
             DHR: ParamFamily.HEIGHTS
         };
     }
-
 }
diff --git a/src/pab/pab_params.ts b/src/pab/pab_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..94d71df2782d9f3f12905b393f04a3170e9cced0
--- /dev/null
+++ b/src/pab/pab_params.ts
@@ -0,0 +1,33 @@
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../param/params-equation";
+
+/**
+ * Parameters of a fish ladder
+ */
+export class PabParams extends ParamsEquation {
+
+    /** Débit entrant à l'amont de la passe (m3/s) */
+    public Q: ParamDefinition;
+
+    /** Cote de l'eau amont (m) */
+    public Z1: ParamDefinition;
+
+    /** Cote de l'eau aval (m) */
+    public Z2: ParamDefinition;
+
+    /**
+     * Paramètres communs à toutes les équations de structure
+     * @param rZ1 Cote de l'eau amont (m)
+     * @param rZ2 Cote de l'eau aval (m)
+     */
+    constructor(rQ: number, rZ1: number, rZ2: number) {
+        super();
+        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ, ParamFamily.FLOWS);
+        this.addParamDefinition(this.Q);
+        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.Z1);
+        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.Z2);
+    }
+}
diff --git a/src/pab/pab_puissance.ts b/src/pab/pab_puissance.ts
index 44368c506f899b5fe70f8ca5148ec88d1eaabdfd..460add1fd8cb6897f27756116e70e902bec54c5c 100644
--- a/src/pab/pab_puissance.ts
+++ b/src/pab/pab_puissance.ts
@@ -23,7 +23,7 @@ export class PabPuissanceParams extends ParamsEquation {
     constructor(rDH: number, rQ: number, rV: number, rPV?: number) {
         super();
         this._DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH, ParamFamily.HEIGHTS);
-        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS);
+        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ, ParamFamily.FLOWS);
         this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV, ParamFamily.VOLUMES);
         this._PV = new ParamDefinition(this, "PV", ParamDomainValue.POS, rPV);
 
diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts
index 13b100c3b7c605837b1a4c51322a232d588f32c7..fc9b44f5ea2c5b780f66f7046d0e5a3c5f90e3a6 100644
--- a/src/param/param-definition.ts
+++ b/src/param/param-definition.ts
@@ -50,6 +50,9 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
     /** le paramètre doit-il être exposé (par ex: affiché par l'interface graphique) ? */
     public visible: boolean = true;
 
+    /** sandbox value used during calculation */
+    public v: number;
+
     /** mode de génération des valeurs : min/max, liste, ... */
     private _valueMode: ParamValueMode;
 
@@ -84,7 +87,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
         this._symbol = symb;
         this._observable = new Observable();
         this._paramValues = new ParamValues();
+
+        // set single value and copy it to currentValue
         this._paramValues.singleValue = val;
+        this.v = val;
+
         this._calc = ParamCalculability.FREE;
         this._family = family;
         this.visible = visible;
@@ -370,74 +377,84 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
     }
 
     /**
-     * Proxy to getValue(); never triggers chain computation
+     * Returns true if current value (not singleValue !) is defined
      */
-    get v(): number {
-        return this.getValue();
+    public get hasCurrentValue(): boolean {
+        return (this.v !== undefined);
     }
 
     /**
-     * set value, with calculability control
-     * @TODO move calculability control to setValue() ?
+     * Returns true if held value (not currentValue !) is defined,
+     * depending on the value mode
      */
-    set v(val: number) {
-        if (this.calculability === ParamCalculability.NONE) {
-            const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED);
-            e.extraVar.symbol = this.symbol;
-            throw e;
-        }
-        this.setValue(val);
-    }
-
     public get isDefined(): boolean {
-        try {
-            return this.paramValues.isDefined;
-        } catch (e) {
-            // unavailable targetted result (pending calculation)
-            return false;
+        let defined = false;
+        switch (this.valueMode) {
+            case ParamValueMode.SINGLE:
+                defined = (this.singleValue !== undefined);
+                break;
+            case ParamValueMode.MINMAX:
+                defined = (
+                    this.paramValues.min !== undefined
+                    && this.paramValues.max !== undefined
+                    && this.paramValues.step !== undefined
+                );
+                break;
+            case ParamValueMode.LISTE:
+                defined = (this.valueList.length > 0 && this.valueList[0] !== undefined);
+                break;
+            case ParamValueMode.CALCUL:
+                if (this.parentNub && this.parentNub.result && this.parentNub.result.nbResultElements > 0) {
+                    const res = this.parentNub.result;
+                    defined = (res.vCalc !== undefined);
+                }
+                break;
+            case ParamValueMode.LINK:
+                defined = this.referencedValue.isDefined();
         }
+        return defined;
     }
 
     // -- values getters / setters; in LINK mode, reads / writes from / to the target values
 
     public get singleValue(): number {
-        this.checkValueMode(ParamValueMode.SINGLE);
+        this.checkValueMode([ParamValueMode.SINGLE, ParamValueMode.CALCUL, ParamValueMode.LINK]);
         return this.paramValues.singleValue;
     }
 
     public set singleValue(v: number) {
-        this.checkValueMode(ParamValueMode.SINGLE);
+        this.checkValueMode([ParamValueMode.SINGLE, ParamValueMode.CALCUL, ParamValueMode.LINK]);
         this.paramValues.singleValue = v;
         this.notifyValueModified(this);
     }
 
     public get min() {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]);
         return this.paramValues.min;
     }
 
     public set min(v: number) {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX]);
         this.paramValues.min = v;
     }
 
     public get max() {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]);
         return this.paramValues.max;
     }
 
     public set max(v: number) {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX]);
         this.paramValues.max = v;
     }
 
     public get step() {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]);
         return this.paramValues.step;
     }
 
     public set step(v: number) {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX]);
         this.paramValues.step = v;
     }
 
@@ -445,17 +462,17 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
      * Generates a reference step value, given the current (local) values for min / max
      */
     public get stepRefValue(): Interval {
-        this.checkValueMode(ParamValueMode.MINMAX);
+        this.checkValueMode([ParamValueMode.MINMAX]);
         return new Interval(1e-9, this._paramValues.max - this._paramValues.min);
     }
 
     public get valueList() {
-        this.checkValueMode(ParamValueMode.LISTE);
+        this.checkValueMode([ParamValueMode.LISTE, ParamValueMode.LINK]);
         return this.paramValues.valueList;
     }
 
     public set valueList(l: number[]) {
-        this.checkValueMode(ParamValueMode.LISTE);
+        this.checkValueMode([ParamValueMode.LISTE]);
         this.paramValues.valueList = l;
     }
 
@@ -463,23 +480,22 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
         return this.paramValues.valuesIterator.count();
     }
 
-    /**
-     * Get current value (not singleValue !)
-     * Might throw an error if parameter is in LINK mode, and target
-     * value is a result that is not yet computed
-     */
-    public getValue(): number {
-        if (! this.paramValues.isDefined) {
-            const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED);
-            e.extraVar.symbol = this.symbol;
-            throw e;
-        }
+    // for INumberiterator interface
+    public get currentValue(): number {
+        // magically follows links
         return this.paramValues.currentValue;
     }
 
-    // for INumberiterator interface
-    public get currentValue(): number {
-        return this.getValue();
+    public set currentValue(v: number) {
+        // magically follows links
+        this.paramValues.currentValue = v;
+    }
+
+    /**
+     * Get single value
+     */
+    public getValue(): number {
+        return this.paramValues.singleValue;
     }
 
     /**
@@ -507,7 +523,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
      */
     public setValue(val: number, sender?: any) {
         this.checkValueAgainstDomain(val);
-        this.paramValues.currentValue = val;
+        this.paramValues.singleValue = val;
         // this.notifyValueModified(sender); // @TODO why ? currentValue is only used temporarily for calculation
     }
 
@@ -590,11 +606,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
     }
 
     /**
-     * Return true if current value is valid regarding the domain constraints
+     * Return true if single value is valid regarding the domain constraints
      */
     get isValueValid(): boolean {
         try {
-            const v = this.getValue();
+            const v = this.paramValues.singleValue;
             this.checkValueAgainstDomain(v);
             return true;
         } catch (e) {
@@ -760,7 +776,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
         // adjust parameter representation depending on value mode
         switch (this._valueMode) {
             case ParamValueMode.SINGLE:
-                paramRep.value = this.getValue();
+                paramRep.value = this.singleValue;
                 break;
 
             case ParamValueMode.MINMAX:
@@ -1100,9 +1116,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
      * In LINK mode, the tested valueMode is the mode of the ultimately targetted
      * set of values (may never be LINK)
      */
-    private checkValueMode(expected: ParamValueMode) {
-        if (this.paramValues.valueMode !== expected) {
-            throw new Error(`ParamValues : mode de valeurs ${ParamValueMode[expected]} incorrect`);
+    private checkValueMode(expected: ParamValueMode[]) {
+        if (! expected.includes(this.valueMode)) {
+            throw new Error(
+                `ParamDefinition : mode de valeurs ${ParamValueMode[this.valueMode]} incorrect`
+            );
         }
     }
 
diff --git a/src/param/param-values.ts b/src/param/param-values.ts
index badb8433f819f721766be6945e081e18fbbf2842..9d850c7d16bcf7c042d6e4f298ac74bf15b6b37b 100644
--- a/src/param/param-values.ts
+++ b/src/param/param-values.ts
@@ -54,18 +54,15 @@ export class ParamValues implements IterableValues {
             if (max === undefined) {
                 this.valueMode = ParamValueMode.SINGLE;
                 this.singleValue = o;
-                this.currentValue = o;
             } else {
                 this.valueMode = ParamValueMode.MINMAX;
                 this.min = o;
                 this.max = max;
                 this.step = step;
-                this.currentValue = undefined;
             }
         } else if (Array.isArray(o)) {
             this.valueMode = ParamValueMode.LISTE;
             this.valueList = o;
-            this.currentValue = undefined;
         } else {
             throw new Error(`ParamValues.setValues() :  appel invalide`);
         }
@@ -107,10 +104,6 @@ export class ParamValues implements IterableValues {
         }
     }
 
-    public get isDefined() {
-        return this.currentValue !== undefined;
-    }
-
     // -- iterator-related methods
 
     /**
diff --git a/src/param/params-equation.ts b/src/param/params-equation.ts
index 5e13164f33b44d5d0603d38f8134a2c7eb96f232..91a81b7115b5f5c9665d7e937171331a44675fe9 100644
--- a/src/param/params-equation.ts
+++ b/src/param/params-equation.ts
@@ -104,7 +104,9 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> {
     public constructor(parent?: ComputeNode) {
         this.parent = parent;
         this._calculabilityDefined = false;
-        this._Pr = new ParamDefinition(this, "Pr", ParamDomainValue.POS, ParamsEquation.DEFAULT_COMPUTE_PREC);
+        this._Pr = new ParamDefinition(
+            this, "Pr", ParamDomainValue.POS, ParamsEquation.DEFAULT_COMPUTE_PREC, undefined, false
+        );
         this.addParamDefinition(this._Pr);
     }
 
@@ -168,15 +170,16 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> {
         return new ParamDefinitionIterator(this);
     }
 
-    protected addParamDefinition(p: ParamDefinition) {
-        if (!this.hasParameter(p.symbol)) {
+    protected addParamDefinition(p: ParamDefinition, force: boolean = false) {
+        if (force || !this.hasParameter(p.symbol)) {
             this._paramMap[p.symbol] = p;
         }
     }
 
     protected addParamDefinitions(ps: ParamsEquation) {
         for (const p of ps) {
-            this.addParamDefinition(p);
+            // Force update of the map index
+            this.addParamDefinition(p, true);
         }
     }
 }
diff --git a/src/regime_uniforme.ts b/src/regime_uniforme.ts
index 4a349f3b3bc65450607f4c274a65a5485f6606ef..bf0685c50bf4fd037095904e68cd806e2991fdac 100644
--- a/src/regime_uniforme.ts
+++ b/src/regime_uniforme.ts
@@ -50,7 +50,7 @@ export class RegimeUniforme extends SectionNub {
     // tslint:disable-next-line:no-empty
     protected setParametersCalculability() {}
 
-    protected setSectionParametersCalculability(): void {
+    protected adjustChildParameters(): void {
         this.section.prms.Q.calculability = ParamCalculability.EQUATION;
         this.section.prms.Y.calculability = ParamCalculability.EQUATION;
     }
diff --git a/src/remous.ts b/src/remous.ts
index 234c1d8a7a8359cc070d0848c8e0e263ef1915cf..867f3cbf18dab2f062e923a10e63f12ad2c4a817 100644
--- a/src/remous.ts
+++ b/src/remous.ts
@@ -519,7 +519,7 @@ export class CourbeRemous extends SectionNub {
         this.prms.Yaval.calculability = ParamCalculability.FREE;
     }
 
-    protected setSectionParametersCalculability(): void {
+    protected adjustChildParameters(): void {
         this.section.prms.Y.calculability = ParamCalculability.DICHO;
     }
 
diff --git a/src/section/section_circulaire.ts b/src/section/section_circulaire.ts
index 4ff68af501fbcdcc70f02a0985eb0d4d341e4d1e..af68e902e0e87710bff49ebcfb450b4a9790135b 100644
--- a/src/section/section_circulaire.ts
+++ b/src/section/section_circulaire.ts
@@ -92,7 +92,7 @@ export class cSnCirc extends acSection {
                 }
 
                 this.debug("circ.Calc_B() : PAS débordement");
-                if (this.prms.D.isDefined && this.prms.Y.isDefined) {
+                if (this.prms.D.hasCurrentValue && this.prms.Y.hasCurrentValue) {
                         const rAlpha: Result = this.calcFromY("Alpha");
                         if (!rAlpha.ok) {
                                 return rAlpha;
@@ -104,8 +104,8 @@ export class cSnCirc extends acSection {
                 }
 
                 const e: Message = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED);
-                e.extraVar.diameterValue = this.prms.D.isDefined ? String(this.prms.D.v) : "undefined";
-                e.extraVar.yValue = this.prms.Y.isDefined ? String(this.prms.Y.v) : "undefined";
+                e.extraVar.diameterValue = this.prms.D.hasCurrentValue ? String(this.prms.D.v) : "undefined";
+                e.extraVar.yValue = this.prms.Y.hasCurrentValue ? String(this.prms.Y.v) : "undefined";
                 throw e;
         }
 
diff --git a/src/section/section_nub.ts b/src/section/section_nub.ts
index 37cf0dff307d7dec1b6146e5ae072641abb8423e..c53b7cda13a8dd46ba051405868d6fb25932b461 100644
--- a/src/section/section_nub.ts
+++ b/src/section/section_nub.ts
@@ -96,10 +96,6 @@ export abstract class SectionNub extends Nub {
                 this._children[0] = undefined;
             }
             this.replaceChild(0, s);
-            this.setSectionParametersCalculability();
         }
     }
-
-    /** Called everytime a section is set / replaced */
-    protected abstract setSectionParametersCalculability(): void;
 }
diff --git a/src/section/section_parametree.ts b/src/section/section_parametree.ts
index 874418aac3269a0ab419e75721bcf13c4a201c84..b3d03d8d4c561d9eaa828adfb44717ea539d9a24 100644
--- a/src/section/section_parametree.ts
+++ b/src/section/section_parametree.ts
@@ -202,7 +202,7 @@ export class SectionParametree extends SectionNub {
     protected setParametersCalculability(): void {}
 
     // tslint:disable-next-line:no-empty
-    protected setSectionParametersCalculability(): void {}
+    protected adjustChildParameters(): void {}
 
     protected setExtraResultsFamilies() {
         this._extraResultsFamilies = {
diff --git a/src/session.ts b/src/session.ts
index c70f3d5b03dfb63c94ecaf2abc95ef98e973f0f9..8e9b40421bbd4332f890c2c3b6eecacfa1efa52d 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -1,4 +1,5 @@
 import { CalculatorType, ComputeNodeType } from "./compute-node";
+import { LinkedValue } from "./linked-value";
 import { Nub } from "./nub";
 import { Props } from "./props";
 
@@ -22,14 +23,14 @@ import { cSnTrapez, ParamsSectionTrapez } from "./section/section_trapez";
 import { acSection } from "./section/section_type";
 
 // Classes relatives aux structures
-import { LinkedValue } from "./linked-value";
+import { Pab, PabParams } from "./pab/pab";
+import { PabCloisons } from "./pab/pab_cloisons";
 import { ParamDefinition } from "./param/param-definition";
 import { Cloisons } from "./structure/cloisons";
 import { CloisonsParams } from "./structure/cloisons_params";
 import { Dever, DeverParams } from "./structure/dever";
 import { CreateStructure } from "./structure/factory_structure";
 import { ParallelStructure, ParallelStructureParams } from "./structure/parallel_structure";
-import { Structure } from "./structure/structure";
 import { LoiDebit } from "./structure/structure_props";
 
 export class Session {
@@ -149,6 +150,9 @@ export class Session {
         // second pass for links
         this.fixLinks(serialised, uids);
 
+        // second pass for PABs
+        this.fixPAB(serialised, uids);
+
         return newNubs;
     }
 
@@ -332,7 +336,7 @@ export class Session {
                         0.5,    // D
                         0.8,    // k
                         1.5     // Cd0
-                    )
+                    ), dbg
                 );
                 break;
             }
@@ -344,7 +348,7 @@ export class Session {
                         2,      // Z1
                         0.5,    // Z2
                         1.5     // DH
-                    )
+                    ), dbg
                 );
                 break;
             }
@@ -356,7 +360,7 @@ export class Session {
                         6,     // DHT
                         10,    // N
                         0.6    // DH
-                    )
+                    ), dbg
                 );
                 break;
             }
@@ -367,6 +371,33 @@ export class Session {
                 break;
             }
 
+            case CalculatorType.Pab:
+                const modeleCloisonAval: string = params.getPropValue("modeleCloisonAval");
+                let downWall;
+                if (modeleCloisonAval) {
+                    downWall = (Session.getInstance().findNubByUid(modeleCloisonAval) as ParallelStructure);
+                    // si le module ParallelStructure ciblé n'existe pas, Session.fixPAB() est censé s'en occuper
+                }
+                nub = new Pab(
+                    new PabParams(
+                        1.5,    // Q
+                        102,    // Z1
+                        99      // Z2
+                    ), downWall, dbg
+                );
+                break;
+
+            case CalculatorType.PabCloisons:
+                const modeleCloisons: string = params.getPropValue("modeleCloisons");
+                if (modeleCloisons) {
+                    const cloisons = (Session.getInstance().findNubByUid(modeleCloisons) as Cloisons);
+                    // si le module Cloisons ciblé n'existe pas, Session.fixPAB() est censé s'en occuper
+                    nub = new PabCloisons(cloisons);
+                } else {
+                    nub = new PabCloisons(undefined); // don't forget to init with a Cloisons model afterwards !
+                }
+                break;
+
             default:
             {
                 throw new Error(
@@ -435,6 +466,33 @@ export class Session {
         return res;
     }
 
+    /**
+     * Returns all Nubs of type Cloisons, to be used as models in PAB
+     */
+    public getCloisonsNubs() {
+        const cloisonsNubs: Nub[] = [];
+        for (const n of this._nubs) {
+            if (n instanceof Cloisons) {
+                cloisonsNubs.push(n);
+            }
+        }
+        return cloisonsNubs;
+    }
+
+    /**
+     * Returns all Nubs of type ParallelStructure (no sub-types),
+     * to be used as downWall models in PAB
+     */
+    public getParallelStructureNubs() {
+        const psNubs: Nub[] = [];
+        for (const n of this._nubs) {
+            if (n.constructor === ParallelStructure) { // exact class checking
+                psNubs.push(n);
+            }
+        }
+        return psNubs;
+    }
+
     /**
      * Crée un Nub de type Section
      * @param nt ComputeNodeType
@@ -537,4 +595,24 @@ export class Session {
             });
         }
     }
+
+    /**
+     * Asks all loaded PAB Nubs to reinit any PabCloisons from their model
+     */
+    private fixPAB(serialised: string, uids?: string[]) {
+        const data = JSON.parse(serialised);
+        if (data.session && Array.isArray(data.session)) {
+            // find each PAB in the session
+            data.session.forEach((e: any) => {
+                if (
+                    (! uids || uids.length === 0 || uids.includes(e.uid))
+                    && (e.props.calcType === CalculatorType.Pab)
+                 ) {
+                    const nub = (this.findNubByUid(e.uid) as Pab);
+                    // find linked parameters
+                    nub.fixPAB(e);
+                }
+            });
+        }
+    }
 }
diff --git a/src/structure/cloisons.ts b/src/structure/cloisons.ts
index bfc110a8e1a665d36a349fe34a86df858d7b816b..54e9c2c5da10447d33c960e97f29711cc316abc5 100644
--- a/src/structure/cloisons.ts
+++ b/src/structure/cloisons.ts
@@ -1,4 +1,5 @@
 import { CalculatorType } from "../compute-node";
+import { Nub } from "../index";
 import { PabPuissance, PabPuissanceParams } from "../pab/pab_puissance";
 import { ParamCalculability } from "../param/param-definition";
 import { Result } from "../util/result";
@@ -7,6 +8,7 @@ import { ParallelStructure } from "./parallel_structure";
 import { StructureKiviParams } from "./structure_kivi";
 import { loiAdmissiblesCloisons, LoiDebit } from "./structure_props";
 
+export { CloisonsParams };
 export class Cloisons extends ParallelStructure {
     constructor(prms: CloisonsParams, dbg: boolean = false) {
         super(prms, dbg);
@@ -24,6 +26,16 @@ export class Cloisons extends ParallelStructure {
         return loiAdmissiblesCloisons;
     }
 
+    public Equation(sVarCalc: string): Result {
+        // Mise à jour de ZRAM pour Kivi à partir de Z1 - PB
+        this.updateKiviZRAM();
+
+        // Transformation DH => Z2
+        this.prms.Z2.v = this.prms.Z1.v - this.prms.DH.v;
+
+        return super.Equation(sVarCalc);
+    }
+
     /**
      * 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 :
@@ -31,33 +43,12 @@ export class Cloisons extends ParallelStructure {
      * @param rInit Valeur initiale
      */
     public Calc(sVarCalc: string, rInit?: number): Result {
-        // Mise à jour de ZRAM pour Kivi à partir de Z1 - PB
-        this.updateKiviZRAM();
-
-        // Transformation DH => Z2
-        this.prms.Z2.v = this.prms.Z1.v - this.prms.DH.v;
         let sVC: string = sVarCalc;
         if (sVarCalc === "DH") {
             sVC = "Z2";
         }
 
-        // let r: Result = super.Calc(sVC, rInit);
-        let r: Result;
-        switch (sVC) {
-            case "Z1":
-            case "Z2":
-            case "Q":
-            case "LB":
-            case "PB":
-            case "BB":
-                r = this.nubCalc(sVC, rInit);
-                if (r.ok) {
-                    this.getParameter(sVC).setValue(r.vCalc);
-                }
-                break;
-            default:
-                r = super.Calc(sVC, rInit);
-        }
+        const r: Result = super.Calc(sVC, rInit);
 
         if (r.ok) {
             // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires
@@ -75,19 +66,24 @@ export class Cloisons extends ParallelStructure {
         }
 
         // Ajout du calcul de la puissance dissipée
-        const prms = this.getcalculatedparams(sVarCalc, r);
-        const puissanceNub: PabPuissance = new PabPuissance(
-            new PabPuissanceParams(
-                prms.DH,
-                prms.Q,
-                prms.LB * prms.BB * prms.PB
-            )
-        );
-        r.extraResults.PV = puissanceNub.Calc("PV", 0).vCalc;
+        const prms = this.getParamValuesAfterCalc(sVarCalc, r);
+        const ro: number = 1000;     // masse volumique de l'eau en kg/m3
+        const g: number = 9.81;     // accélération de la gravité terrestre en m/s2.
+        r.extraResults.PV = ro * g * this.prms.Q.v * (prms.Z1 - prms.Z2) / (prms.LB * prms.BB * prms.PB);
+
+        // Ajout de la cote de radier de bassin
+        r.extraResults.ZRB = prms.Z1 - prms.DH - prms.PB;
 
         return r;
     }
 
+    public adjustChildParameters(child: Nub) {
+        if (child.prms instanceof StructureKiviParams) {
+            // hide ZRAM for KIVI, in Cloisons context only
+            child.prms.ZRAM.visible = false;
+        }
+    }
+
     /**
      * paramétrage de la calculabilité des paramètres
      */
@@ -99,18 +95,6 @@ export class Cloisons extends ParallelStructure {
         this.prms.DH.calculability = ParamCalculability.DICHO;
     }
 
-    protected getcalculatedparams(sVarCalc: string, result: Result): { [key: string]: number } {
-        const cPrms: { [key: string]: number } = {};
-        for (const p of this.parameterIterator) {
-            if (p.symbol === sVarCalc) {
-                cPrms[p.symbol] = result.vCalc;
-            } else {
-                cPrms[p.symbol] = p.v;
-            }
-        }
-        return cPrms;
-    }
-
     private updateKiviZRAM() {
         for (const structure of this.structures) {
             if (structure.prms instanceof StructureKiviParams) {
diff --git a/src/structure/dever.ts b/src/structure/dever.ts
index fedcf19599084101a75386072526d3feee0eaba2..24cfeb68011b83d1747189374143b08f6ae3a2a7 100644
--- a/src/structure/dever.ts
+++ b/src/structure/dever.ts
@@ -50,42 +50,6 @@ export class Dever extends ParallelStructure {
         return r;
     }
 
-    /**
-     * Calcul du débit total, de la cote amont ou aval, de la largeur du lit amont, de la cote
-     * du lit amont, ou d'un paramètre d'une structure
-     * @param sVarCalc Nom du paramètre à calculer :
-     *                 "Q", "Z1", "Z2", "BR", "ZR" ou "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre
-     * @param rInit Valeur initiale
-     */
-    public Calc(sVarCalc: string, rInit?: number): Result {
-        let res: Result;
-        switch (sVarCalc) {
-            case "Z1":
-            case "Z2":
-            case "Q":
-            case "BR":
-            case "ZR":
-                res = this.nubCalc(sVarCalc, rInit);
-                if (res.ok) {
-                    this.getParameter(sVarCalc).setValue(res.vCalc);
-                }
-                break;
-            default:
-                res = super.Calc(sVarCalc, rInit);
-        }
-        if (res.ok) {
-            // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires
-            const resQtot: Result = this.CalcQ();
-            for (const extraResKey in resQtot.extraResults) {
-                if (resQtot.extraResults.hasOwnProperty(extraResKey)) {
-                    res.resultElement.addExtraResult(extraResKey, resQtot.extraResults[extraResKey]);
-                }
-            }
-        }
-        this._result = res;
-        return res;
-    }
-
     /**
      * paramétrage de la calculabilité des paramètres
      */
diff --git a/src/structure/factory_structure.ts b/src/structure/factory_structure.ts
index e4a9f2b17cdb6dc22b661ee935e3f53d12f9bbe3..48d711d014617ed8b064bf1484dc420248308c64 100644
--- a/src/structure/factory_structure.ts
+++ b/src/structure/factory_structure.ts
@@ -39,7 +39,7 @@ export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructur
         case LoiDebit.Cunge80:
         case LoiDebit.RectangularOrificeFree:
         case LoiDebit.RectangularOrificeSubmerged:
-            rectStructPrms.W.v = 0.5;
+            rectStructPrms.W.singleValue = 0.5;
             rectStructPrms.Cd.v = oCd.VanneR; // Cd pour une vanne rectangulaire
     }
 
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index 7b589783e9e8a691e86169891de7852f0fc1e564..2f4f8e32a49a17ff2db8ed51f02d1c95173c2730 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -105,7 +105,7 @@ export class ParallelStructure extends Nub {
             case "Q":
                 res = super.Calc(sVarCalc, rInit);
                 if (res.ok) {
-                    this.getParameter(sVarCalc).setValue(res.vCalc);
+                    this.getParameter(sVarCalc).v = res.vCalc;
                 }
                 break;
             default:
@@ -118,7 +118,7 @@ export class ParallelStructure extends Nub {
                 // Suppression des extraResults : ils sont complétés plus bas pour chaque ouvrage
                 res.resultElement.extraResults = {};
                 if (res.ok) {
-                    this._children[structureIndex].getParameter(sVarCalc.symbol).setValue(res.vCalc);
+                    this._children[structureIndex].getParameter(sVarCalc.symbol).v = res.vCalc;
                 }
         }
         if (res.ok) {
@@ -179,7 +179,7 @@ export class ParallelStructure extends Nub {
      */
     protected CalcStructPrm(index: number, symbol: string, rInit?: number): Result {
         // Le débit restant sur la structure en calcul est :
-        this.structures[index].prms.Q.setValue(this.prms.Q.v - this.CalcQ(index).vCalc);
+        this.structures[index].prms.Q.v = this.prms.Q.v - this.CalcQ(index).vCalc;
 
         // Calcul du paramètre de la structure en calcul
         return this.structures[index].Calc(symbol, rInit);
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index 0d44f85b78c5971fd2856f550cc523eff6a063f1..2547d78fb204f3873e8b380469213b5d218e4ebf 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -180,14 +180,11 @@ export abstract class Structure extends Nub {
             );
         }
 
-        // Mise à jour de h1 et h2
-        this.prms.update_h1h2();
-
         // Gestion du débit nul
         const flagsNull = { ENUM_StructureFlowMode: StructureFlowMode.NULL,
                             ENUM_StructureFlowRegime: StructureFlowRegime.NULL };
         if (sVarCalc === "Q") {
-            if (this.prms.h1.v <= 0 || this.prms.Z1.v === this.prms.Z2.v || this.prms.W.v <= 0) {
+            if (this.prms.Z1.v <= this.prms.ZDV.v || this.prms.Z1.v === this.prms.Z2.v || this.prms.W.v <= 0) {
                 return new Result(0, this, flagsNull);
             }
         } else if (this.prms.Q.v === 0) {
@@ -229,20 +226,43 @@ export abstract class Structure extends Nub {
         }
 
         // Gestion de l'inversion de débit : on inverse l'amont et l'aval pour le calcul
-        if ((sVarCalc === "Q" && (this.prms.h1.v < this.prms.h2.v)) || (sVarCalc !== "Q" && this.prms.Q.v < 0)) {
-            [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion
+        if (sVarCalc !== "Q" && this.prms.Q.v < 0) {
+            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
             const res: Result = super.Calc(sVarCalc, rInit);
+            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
+            return res;
+        }
+
+        // Calcul normal hors débit nul
+        return super.Calc(sVarCalc, rInit);
+    }
+
+    /**
+     * Equation preprocessing
+     * @return true if inverted discharge
+     */
+    public Equation(sVarCalc: string): Result {
+        Structure.CheckEquation(sVarCalc);
+        this.prms.update_h1h2();
+        let res: Result;
+        if (this.prms.h1.v < this.prms.h2.v) {
+            [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion
+            res = this.CalcQ();
             if (sVarCalc === "Q") {
                 res.vCalc = -res.vCalc;
             }
             [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion
-            return res;
+        } else {
+            res = this.CalcQ();
         }
-
-        // Calcul normal hors débit nul et inversion de débit
-        return super.Calc(sVarCalc, rInit);
+        return res;
     }
 
+    /**
+     * Function to implement for the stage discharge equation of hydraulic structure
+     */
+    protected abstract CalcQ(): Result;
+
     protected getResultData() {
         return {
             ENUM_StructureFlowMode: this.getFlowMode(),
diff --git a/src/structure/structure_cem88d.ts b/src/structure/structure_cem88d.ts
index 8c08a710694713d4cc809de003996e08f22f269d..9b973e98dbac8f5021870bf97c4d82ff434a5086 100644
--- a/src/structure/structure_cem88d.ts
+++ b/src/structure/structure_cem88d.ts
@@ -6,8 +6,6 @@ import { LoiDebit } from "./structure_props";
 
 export { RectangularStructureParams };
 
-
-
 /**
  * Equation CEM88D : déversoir / orifice (pelle importante) Cemagref 1988
  */
@@ -25,8 +23,7 @@ export class StructureWeirCem88d extends RectangularStructure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) CEM88D
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         let v: number;
diff --git a/src/structure/structure_cem88v.ts b/src/structure/structure_cem88v.ts
index f02f9f33d1ad74584231ff71ba53c300ea7dc7d0..e416201c256638bd992ac69dfd5b4c2d2acadcd7 100644
--- a/src/structure/structure_cem88v.ts
+++ b/src/structure/structure_cem88v.ts
@@ -20,8 +20,7 @@ export class StructureWeirCem88v extends RectangularStructure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) CEM88V
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         let v: number;
diff --git a/src/structure/structure_cunge80.ts b/src/structure/structure_cunge80.ts
index a6196e6217539d5320ae1b44749f17c2901abf48..2df43729d906b503cb579f1b9044231ecbbc1d82 100644
--- a/src/structure/structure_cunge80.ts
+++ b/src/structure/structure_cunge80.ts
@@ -25,8 +25,7 @@ export class StructureCunge80 extends RectangularStructure {
      * Calcul du débit avec l'équation Cunge80
      * @param sVarCalc Variable à calculer (doit être égale à Q ici)
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
         let v: number;
 
diff --git a/src/structure/structure_kivi.ts b/src/structure/structure_kivi.ts
index 7bbbaccbf369fd9a52b0ae52be69763a9595414f..55acfd95debee908badc0ee4cffaf2d45f03ac98 100644
--- a/src/structure/structure_kivi.ts
+++ b/src/structure/structure_kivi.ts
@@ -22,8 +22,7 @@ export class StructureKivi extends Structure {
         return this._prms as StructureKiviParams;
     }
 
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const res: Result = new Result(0, this, this.getResultData());
 
         // p : pelle
diff --git a/src/structure/structure_orifice_submerged.ts b/src/structure/structure_orifice_submerged.ts
index ebbd4a20acaba8e0168f067c073159bbb0aa2db0..c353843274005201c90b71c9709f8adb6d712544 100644
--- a/src/structure/structure_orifice_submerged.ts
+++ b/src/structure/structure_orifice_submerged.ts
@@ -28,8 +28,7 @@ export class StructureOrificeSubmerged extends Structure {
      * Calcul du débit avec l'équation classique d'un orifice noyé
      * @param sVarCalc Variable à calculer (doit être égale à Q ici)
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         const v = this.prms.Cd.v * this.prms.S.v * Structure.R2G * Math.sqrt(this.prms.Z1.v - this.prms.Z2.v);
diff --git a/src/structure/structure_rectangular_orifice_free.ts b/src/structure/structure_rectangular_orifice_free.ts
index 22212ec0133b1bd02cf1e26b9174830e4dc21040..0b9b96e205e0fd9882f021e70bc57f09165d0cd8 100644
--- a/src/structure/structure_rectangular_orifice_free.ts
+++ b/src/structure/structure_rectangular_orifice_free.ts
@@ -21,8 +21,7 @@ export class StructureRectangularOrificeFree extends RectangularStructure {
      * Calcul du débit avec l'équation classique d'un orifice dénoyé
      * @param sVarCalc Variable à calculer (doit être égale à Q ici)
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v
diff --git a/src/structure/structure_rectangular_orifice_submerged.ts b/src/structure/structure_rectangular_orifice_submerged.ts
index 6c278cc6d14291cca136b721d08f2863f916c1c5..48e038bec84b771f139ac9f56bb8eea65c242942 100644
--- a/src/structure/structure_rectangular_orifice_submerged.ts
+++ b/src/structure/structure_rectangular_orifice_submerged.ts
@@ -24,8 +24,7 @@ export class StructureRectangularOrificeSubmerged extends RectangularStructure {
      * Calcul du débit avec l'équation classique d'un orifice noyé
      * @param sVarCalc Variable à calculer (doit être égale à Q ici)
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v
diff --git a/src/structure/structure_triangular_trunc_weir.ts b/src/structure/structure_triangular_trunc_weir.ts
index 4a709256902b2df80ba87018251b3fdf8b0ece24..dee0d35ff128dfeefd54b7f62339f8a9829ba1e8 100644
--- a/src/structure/structure_triangular_trunc_weir.ts
+++ b/src/structure/structure_triangular_trunc_weir.ts
@@ -28,8 +28,7 @@ export class StructureTriangularTruncWeirFree extends Structure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         let Q: number = this.prms.Cd.v * this.prms.BT.v / (this.prms.ZT.v - this.prms.ZDV.v);
diff --git a/src/structure/structure_triangular_weir.ts b/src/structure/structure_triangular_weir.ts
index ee505df9c103fe166a3f0cb955642393db99468b..e6def5d489e1ab88531e3187e89ef1ab6c628bfd 100644
--- a/src/structure/structure_triangular_weir.ts
+++ b/src/structure/structure_triangular_weir.ts
@@ -28,8 +28,7 @@ export class StructureTriangularWeir extends Structure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         let Q = this.prms.Cd.v * this.getTanFromDegrees(this.prms.alpha2.v)
diff --git a/src/structure/structure_weir_free.ts b/src/structure/structure_weir_free.ts
index 957791c6fe43bafc59d5d9616d6f53b67362d5b2..fcda6652dbe705186ab346058e190cb1be63893a 100644
--- a/src/structure/structure_weir_free.ts
+++ b/src/structure/structure_weir_free.ts
@@ -20,8 +20,7 @@ export class StructureWeirFree extends RectangularStructure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         const v = this.prms.Cd.v * this.prms.L.v * Structure.R2G * Math.pow(this.prms.h1.v, 1.5);
diff --git a/src/structure/structure_weir_submerged_larinier.ts b/src/structure/structure_weir_submerged_larinier.ts
index f7d7af00872ce3886c8e72ad4a2f8c1376007459..d34a1d337ada1894b9062c05e0b16997534c15ff 100644
--- a/src/structure/structure_weir_submerged_larinier.ts
+++ b/src/structure/structure_weir_submerged_larinier.ts
@@ -22,8 +22,7 @@ export class StructureWeirSubmergedLarinier extends RectangularStructure {
      * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
      * @param sVarCalc Variable à calculer (doit être "Q")
      */
-    public Equation(sVarCalc: string): Result {
-        Structure.CheckEquation(sVarCalc);
+    public CalcQ(): Result {
         const data = this.getResultData();
 
         const v = this.prms.Cd.v * this.prms.L.v * Structure.R2G
diff --git a/src/util/message.ts b/src/util/message.ts
index cd5b6e391250a41ce7262a6cfe7b65f44dfc7648..8cdaa78ec234e7667ba8ce00801e1c5cf0541c54 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -43,6 +43,11 @@ export enum MessageCode {
      */
     ERROR_DICHO_FUNCTION_VARIATION,
 
+    /**
+     * la cote amont Z1 est plus basse que la cote aval Z2
+     */
+    ERROR_ELEVATION_ZI_LOWER_THAN_Z2,
+
     /**
      * les bornes de l'intervalle d'un ParamDomain sont incorrectes
      */
@@ -73,6 +78,11 @@ export enum MessageCode {
      */
     ERROR_PARAMDEF_VALUE_FIXED,
 
+    /**
+     * la valeur d'un ParamDefinition doit être entière
+     */
+    ERROR_PARAMDEF_VALUE_INTEGER,
+
     /**
      * la valeur d'un ParamDefinition doit être > 0
      */