diff --git a/package-lock.json b/package-lock.json
index 40a0a88844caec2751355edbfe23225fea4cb738..68ecfc131657005f9145c7a754a91b8c8669b22b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -110,15 +110,15 @@
       "dev": true
     },
     "@types/jasmine": {
-      "version": "3.5.13",
-      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.13.tgz",
-      "integrity": "sha512-bVSrTEWdCNH2RHN+E0QlEr4pGPMRA6puKOmL/X13ZeZmUS0q12ZR1rkB9PVvJSX0zi/OXrMDNvUai+PC380+rQ==",
+      "version": "3.5.14",
+      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.14.tgz",
+      "integrity": "sha512-Fkgk536sHPqcOtd+Ow+WiUNuk0TSo/BntKkF8wSvcd6M2FvPjeXcUE6Oz/bwDZiUZEaXLslAgw00Q94Pnx6T4w==",
       "dev": true
     },
     "@types/node": {
-      "version": "14.6.0",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.0.tgz",
-      "integrity": "sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==",
+      "version": "14.6.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
+      "integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ==",
       "dev": true
     },
     "ansi-regex": {
@@ -715,6 +715,29 @@
         "is-glob": "^4.0.0",
         "merge2": "^1.2.3",
         "micromatch": "^3.1.10"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^2.1.0"
+              }
+            }
+          }
+        }
       }
     },
     "fill-range": {
@@ -833,27 +856,6 @@
         "path-is-absolute": "^1.0.0"
       }
     },
-    "glob-parent": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
-      "dev": true,
-      "requires": {
-        "is-glob": "^3.1.0",
-        "path-dirname": "^1.0.0"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.0"
-          }
-        }
-      }
-    },
     "glob-to-regexp": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
@@ -935,9 +937,9 @@
       }
     },
     "highlight.js": {
-      "version": "10.1.2",
-      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz",
-      "integrity": "sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==",
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.0.tgz",
+      "integrity": "sha512-OryzPiqqNCfO/wtFo619W+nPYALM6u7iCQkum4bqRmmlcTikOkmlL06i009QelynBPAlNByTQU6cBB2cOBQtCw==",
       "dev": true
     },
     "hosted-git-info": {
@@ -2456,42 +2458,51 @@
       }
     },
     "typedoc": {
-      "version": "0.18.0",
-      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.18.0.tgz",
-      "integrity": "sha512-UgDQwapCGQCCdYhEQzQ+kGutmcedklilgUGf62Vw6RdI29u6FcfAXFQfRTiJEbf16aK3YnkB20ctQK1JusCRbA==",
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.19.1.tgz",
+      "integrity": "sha512-EqZpRJQUnkwHA1yBhaDExEXUZIiWKddkrDXhRcfUzpnu6pizxNmVTw5IZ3mu682Noa4zQCniE0YNjaAwHQodrA==",
       "dev": true,
       "requires": {
         "fs-extra": "^9.0.1",
         "handlebars": "^4.7.6",
         "highlight.js": "^10.0.0",
-        "lodash": "^4.17.15",
-        "lunr": "^2.3.8",
+        "lodash": "^4.17.20",
+        "lunr": "^2.3.9",
         "marked": "^1.1.1",
         "minimatch": "^3.0.0",
         "progress": "^2.0.3",
+        "semver": "^7.3.2",
         "shelljs": "^0.8.4",
-        "typedoc-default-themes": "^0.10.2"
+        "typedoc-default-themes": "^0.11.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.2",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+          "dev": true
+        }
       }
     },
     "typedoc-default-themes": {
-      "version": "0.10.2",
-      "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.2.tgz",
-      "integrity": "sha512-zo09yRj+xwLFE3hyhJeVHWRSPuKEIAsFK5r2u47KL/HBKqpwdUSanoaz5L34IKiSATFrjG5ywmIu98hPVMfxZg==",
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.11.1.tgz",
+      "integrity": "sha512-1yl8pbhjrLywqGJx9TfT+wzP+ntudPYjgJdpCj+s5ed2etBkqZPOCBMKwpaN9o6pdoFQF195PggqWTLVEkaRQQ==",
       "dev": true,
       "requires": {
-        "lunr": "^2.3.8"
+        "lunr": "^2.3.9"
       }
     },
     "typescript": {
-      "version": "3.7.5",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
-      "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
+      "version": "3.9.7",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
+      "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
       "dev": true
     },
     "uglify-js": {
-      "version": "3.10.2",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.2.tgz",
-      "integrity": "sha512-GXCYNwqoo0MbLARghYjxVBxDCnU0tLqN7IPLdHHbibCb1NI5zBkU2EPcy/GaVxc0BtTjqyGXJCINe6JMR2Dpow==",
+      "version": "3.10.4",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz",
+      "integrity": "sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw==",
       "dev": true,
       "optional": true
     },
@@ -2638,9 +2649,9 @@
       "dev": true
     },
     "yargs": {
-      "version": "15.4.1",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
-      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "version": "15.3.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
+      "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
       "dev": true,
       "requires": {
         "cliui": "^6.0.0",
@@ -2653,7 +2664,7 @@
         "string-width": "^4.2.0",
         "which-module": "^2.0.0",
         "y18n": "^4.0.0",
-        "yargs-parser": "^18.1.2"
+        "yargs-parser": "^18.1.1"
       }
     },
     "yargs-parser": {
diff --git a/package.json b/package.json
index d9a7a35c9727e919cad541098d9a4a4c1d509e53..6bb92b560f32211e0a2bcd1825e5a9b2ca11518b 100644
--- a/package.json
+++ b/package.json
@@ -41,8 +41,8 @@
     "base-64": "^0.1.0"
   },
   "devDependencies": {
-    "@types/jasmine": "^3.5.13",
-    "@types/node": "^14.6.0",
+    "@types/jasmine": "^3.5.14",
+    "@types/node": "^14.6.4",
     "buffer": "^5.6.0",
     "find": "^0.3.0",
     "jasmine": "^3.6.1",
@@ -54,8 +54,8 @@
     "rimraf": "^3.0.2",
     "ts-node": "^8.10.2",
     "tslint": "^6.1.3",
-    "typedoc": "^0.18.0",
-    "typescript": "~3.7.5"
+    "typedoc": "^0.19.1",
+    "typescript": "^3.9.7"
   },
   "scripts": {
     "preprocess": "node scripts/preprocessors.js",
diff --git a/spec/fuzzing.spec.ts b/spec/fuzzing.spec.ts
index c7ef1746cc42e93ec008fc03ebcce5ca9e69a589..0b8380149d1687c80cb1c5d5a00dc2d7f0eb3c05 100644
--- a/spec/fuzzing.spec.ts
+++ b/spec/fuzzing.spec.ts
@@ -42,7 +42,10 @@ const nubsNotTested: CalculatorType[] = [
     CalculatorType.Solveur,
     CalculatorType.YAXN,
     CalculatorType.Verificateur,
-    CalculatorType.Espece
+    CalculatorType.Espece,
+    CalculatorType.PbBassin,
+    CalculatorType.PbCloison,
+    CalculatorType.PreBarrage // TODO: Add special treatments for creating fuzzy PreBarrage
 ];
 
 const nubsWithStructures: CalculatorType[] = [
diff --git a/spec/par/par_simulation.spec.ts b/spec/par/par_simulation.spec.ts
index 917b725f9d43043838a2feb905cbc57f843215d0..7cd2eea82232241111c648e62a01d3f1d972524d 100644
--- a/spec/par/par_simulation.spec.ts
+++ b/spec/par/par_simulation.spec.ts
@@ -106,8 +106,7 @@ describe("Class ParSimulation −", () => {
                     // regime: ParFlowRegime.FREE
                     message: MessageCode.WARNING_PAR_NOT_SUBMERGED
                 },
-                {
-                    Z1: 14, // (dans Cv3, "calcul" est "off", sous-entendant que le calcul a raté ? Mais il y a tout de même des valeurs…)
+                {   Z1: 14, // (dans Cv3, "calcul" est "off", sous-entendant que le calcul a raté ? Mais il y a tout de même des valeurs…)
                     /* vCalc: 0.549,
                     h: 0.937,
                     ha: 4.64,
diff --git a/spec/pre_barrage/pre-barrage.spec.ts b/spec/pre_barrage/pre-barrage.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5bc3c51f032b560f9499d16b0791a8fa90abe2cd
--- /dev/null
+++ b/spec/pre_barrage/pre-barrage.spec.ts
@@ -0,0 +1,592 @@
+import { PreBarrage } from "../../src/prebarrage/pre_barrage";
+import { PreBarrageParams } from "../../src/prebarrage/pre_barrage_params";
+import { PbBassin } from "../../src/prebarrage/pb_bassin";
+import { PbBassinParams } from "../../src/prebarrage/pb_bassin_params";
+import { PbCloison } from "../../src/prebarrage/pb_cloison";
+import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params";
+import { StructureWeirVillemonte } from "../../src/structure/structure_weir_villemonte";
+import { StructureWeirCunge80 } from "../../src/structure/structure_weir_cunge80";
+import { MessageCode } from "../../src/index";
+
+function createPbCloisonTest(ZDV: number) {
+    const rectStructPrms = new RectangularStructureParams(
+        0,  // Q
+        ZDV,        // ZDV
+        0,        // Z1 entered here for good assignation of h1
+        0,      // Z2
+        0.25,          // L
+        0.4        // Cd pour un seuil rectangulaire
+        // W = Infinity par défaut pour un seuil
+    );
+    return new StructureWeirVillemonte(rectStructPrms);
+}
+
+function createPreBarrageTest(bMeshed: boolean = false): PreBarrage {
+    // Pré-barrage Z1 = 101 m, Z2 = 100 m
+    let Q: number;
+    if (bMeshed) {
+        Q = 1.350722;
+    } else {
+        Q = 0.601266;
+    }
+    const pb = new PreBarrage(new PreBarrageParams(Q, 101, 100), false);
+    pb.calculatedParam = pb.prms.Z1;
+
+    // 1 bassin intermédiaire à la cote de fond 99 m
+    pb.addChild(new PbBassin(new PbBassinParams(20, 99)));
+
+    // 1 cloison entre l'amont et le bassin avec une fente cote de radier 99.5
+    pb.addChild(new PbCloison(undefined, pb.children[0] as PbBassin));
+    pb.children[pb.children.length-1].addChild(createPbCloisonTest(99.5));
+
+    // 1 cloison entre le bassin et l'aval avec une fente cote de radier 99
+    pb.addChild(new PbCloison(pb.children[0] as PbBassin, undefined));
+    pb.children[pb.children.length-1].addChild(createPbCloisonTest(99));
+
+    if (bMeshed) {
+        // 1 cloison entre l'amont et l'aval avec une fente cote de radier 99.5
+        pb.addChild(new PbCloison(undefined, undefined));
+        pb.children[pb.children.length-1].addChild(createPbCloisonTest(99.5));
+    }
+
+    return pb;
+}
+
+function uidsOfAllPointedNubs(pb: PreBarrage): string[] {
+    let uids: string[] = [];
+    for (const c of pb.children) {
+        if (c instanceof PbCloison) {
+            if (c.bassinAmont !== undefined) {
+                uids.push(c.bassinAmont.uid)
+            }
+            if (c.bassinAval !== undefined) {
+                uids.push(c.bassinAval.uid)
+            }
+        } else if (c instanceof PbBassin) {
+            uids = uids.concat(c.cloisonsAval.map(ca => ca.uid));
+            uids = uids.concat(c.cloisonsAmont.map(ca => ca.uid));
+        }
+    }
+    for (const c of pb.cloisonsAmont) {
+        if (c.bassinAval !== undefined) {
+            uids.push(c.bassinAval.uid)
+        }
+    }
+    for (const c of pb.bassins) {
+        uids = uids.concat(c.cloisonsAval.map(ca => ca.uid));
+        uids = uids.concat(c.cloisonsAmont.map(ca => ca.uid));
+    }
+    // deduplicate
+    uids = uids.filter(
+        (element, index, self) => self.indexOf(element) === index
+    );
+    return uids;
+}
+
+describe("Class PreBarrage:", () => {
+
+    describe("Basic non meshed:", () => {
+        it("Calc(Z1) should return 101", () => {
+            const pb = createPreBarrageTest();
+            const res = pb.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(101, 3);
+        });
+        it("Calc(Q) should return 0.601", () => {
+            const pb = createPreBarrageTest();
+            pb.calculatedParam = pb.prms.Q;
+            pb.prms.Q.singleValue = 0;
+            expect(pb.CalcSerie().vCalc).toBeCloseTo(0.601266, 3);
+        });
+    });
+
+    describe("Basic meshed:", () => {
+        it("Calc(Z1) should return 101", () => {
+            const pb = createPreBarrageTest(true);
+            expect(pb.CalcSerie().vCalc).toBeCloseTo(101, 3);
+        });
+        it("Calc(Q) should return 1.351", () => {
+            const pb = createPreBarrageTest(true);
+            pb.calculatedParam = pb.prms.Q;
+            pb.prms.Q.singleValue = 0;
+            expect(pb.CalcSerie().vCalc).toBeCloseTo(1.350722, 3);
+        });
+    });
+
+    describe("Complex meshed:", () => {
+        let pb: PreBarrage;
+        beforeEach(() => {
+            pb = createPreBarrageTest(true);
+            pb.maxIterations = 100;
+            pb.prms.Q.singleValue = pb.prms.Q.singleValue + 0.601266;
+            pb.addChild(new PbBassin(new PbBassinParams(20, 99)));
+            // 1 cloison entre l'amont et le bassin avec une fente cote de radier 99.5
+            pb.addChild(new PbCloison(undefined, pb.bassins[1] as PbBassin));
+            pb.children[pb.children.length-1].addChild(createPbCloisonTest(99.5));
+            // 1 cloison entre le bassin et l'aval avec une fente cote de radier 99
+            pb.addChild(new PbCloison(pb.bassins[1] as PbBassin, undefined));
+            pb.children[pb.children.length-1].addChild(createPbCloisonTest(99));
+            // 1 cloison entre les 2 bassins avec une fente cote de radier 99
+            pb.addChild(new PbCloison(pb.bassins[0] as PbBassin, pb.bassins[1] as PbBassin));
+            pb.children[pb.children.length-1].addChild(createPbCloisonTest(99));
+        });
+        it("Calc(Z1) should return 101", () => {
+            const r = pb.CalcSerie();
+            expect(r.ok).toBe(true);
+            expect(Math.abs(r.vCalc - 101)).toBeLessThanOrEqual(1E-4);
+        });
+        it("Calc(Q) should return 1.951988", () => {
+            pb.calculatedParam = pb.prms.Q;
+            pb.prms.Q.singleValue = 0;
+            const r = pb.CalcSerie();
+            expect(r.ok).toBe(true);
+            expect(Math.abs(r.vCalc - 1.951988)).toBeLessThanOrEqual(1E-4);
+        });
+    });
+
+    describe("Real case:", () => {
+        let pbc: PreBarrage;
+        beforeEach(()=> {
+            pbc = new PreBarrage(new PreBarrageParams(0.869, 95.25, 94.45), false);
+            // add basins
+            pbc.addChild(new PbBassin(new PbBassinParams(13.80, 95)));
+            pbc.addChild(new PbBassin(new PbBassinParams(15.40, 94.70)));
+            pbc.addChild(new PbBassin(new PbBassinParams(16.20, 94.70)));
+            pbc.addChild(new PbBassin(new PbBassinParams(17.50, 94.40)));
+            pbc.addChild(new PbBassin(new PbBassinParams(32.10, 94.25)));
+            pbc.addChild(new PbBassin(new PbBassinParams(35.00, 94.10)));
+            // add walls
+            // Wall between upstream and basin 1
+            pbc.addChild(new PbCloison(undefined, pbc.children[0] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.30, 0, 0, 0.4, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.25, 0, 0, 4.40, 1.04)
+                )
+            );
+            //  Wall between upstream and basin 2
+            pbc.addChild(new PbCloison(undefined, pbc.children[1] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.00, 0, 0, 1.00, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.25, 0, 0, 5.00, 0.91)
+                )
+            );
+            // Wall between upstream and basin 5
+            pbc.addChild(new PbCloison(undefined, pbc.children[4] as PbBassin));
+             pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.25, 0, 0, 3.50, 0.99)
+                )
+            );
+            // Wall between upstream and basin 6
+            pbc.addChild(new PbCloison(undefined, pbc.children[5] as PbBassin));
+             pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.25, 0, 0, 3.60, 0.99)
+                )
+            );
+            // Wall between basin 1 & 3
+            pbc.addChild(new PbCloison(pbc.children[0] as PbBassin, pbc.children[2] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.00, 0, 0, 0.40, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 96.25, 0, 0, 5.20, 0.99)
+                )
+            );
+            // Wall between basin 2 & 3
+            pbc.addChild(new PbCloison(pbc.children[1] as PbBassin, pbc.children[2] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.85, 0, 0, 4.38, 0.91)
+                )
+            );
+            // Wall between basin 2 & 4
+            pbc.addChild(new PbCloison(pbc.children[1] as PbBassin, pbc.children[3] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.85, 0, 0, 3.00, 0.99)
+                )
+            );
+            // Wall between basin 2 & 5
+            pbc.addChild(new PbCloison(pbc.children[1] as PbBassin, pbc.children[4] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.50, 0, 0, 1.00, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.75, 0, 0, 3.00, 0.99)
+                )
+            );
+            // Wall between basin 3 & 4
+            pbc.addChild(new PbCloison(pbc.children[2] as PbBassin, pbc.children[3] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 94.70, 0, 0, 0.40, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.65, 0, 0, 5.74, 0.99)
+                )
+            );
+            // Wall between basin 4 & 5
+            pbc.addChild(new PbCloison(pbc.children[3] as PbBassin, pbc.children[4] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 94.40, 0, 0, 0.40, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.35, 0, 0, 6.00, 0.99)
+                )
+            );
+            // Wall between basin 5 & 6
+            pbc.addChild(new PbCloison(pbc.children[4] as PbBassin, pbc.children[5] as PbBassin));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 94.25, 0, 0, 0.70, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 95.05, 0, 0, 9.50, 0.99)
+                )
+            );
+            // Wall between basin 6 & downstream
+            pbc.addChild(new PbCloison(pbc.children[5] as PbBassin, undefined));
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 94.10, 0, 0, 0.95, 1.04)
+                )
+            );
+            pbc.children[pbc.children.length-1].addChild(
+                new StructureWeirCunge80(
+                    new RectangularStructureParams(0, 94.75, 0, 0, 10.20, 0.99)
+                )
+            );
+        });
+        it("Calc(Z1) should converge to 96.25", () => {
+            pbc.calculatedParam = pbc.prms.Z1;
+            const r = pbc.CalcSerie()
+            expect(r.ok).toBeTrue();
+            expect(r.vCalc).toBeCloseTo(96.25, 2);
+        });
+        it("Calc(Z1, Q=0) should converge to 95.30", () => {
+            pbc.prms.Q.singleValue = 0;
+            pbc.calculatedParam = pbc.prms.Z1;
+            const r = pbc.CalcSerie()
+            expect(r.ok).toBeTrue();
+            expect(r.vCalc).toBeCloseTo(95.30, 1);
+        });
+        it("Calc(Z1, Q=1E-5) should converge to 95.301", () => {
+            pbc.prms.Q.singleValue = 1E-5;
+            pbc.calculatedParam = pbc.prms.Z1;
+            const r = pbc.CalcSerie()
+            expect(r.ok).toBeTrue();
+            expect(r.vCalc).toBeCloseTo(95.301, 3);
+        });
+        it("Calc(Z1, Q=0.1265) should converge to 95.616859", () => {
+            pbc.prms.Q.singleValue = 0.1265;
+            pbc.calculatedParam = pbc.prms.Z1;
+            const r = pbc.CalcSerie()
+            expect(r.ok).toBeTrue();
+            expect(r.vCalc).toBeCloseTo(95.616859, 3);
+        });
+        it("Calc(Q) should converge to 0.869", () => {
+            pbc.calculatedParam = pbc.prms.Q;
+            pbc.prms.Z1.singleValue = 96.25;
+            pbc.prms.Q.singleValue = 0;
+            const r = pbc.CalcSerie()
+            expect(r.ok).toBeTrue();
+            expect(r.vCalc).toBeCloseTo(0.869, 1);
+        });
+    });
+
+    describe("Basins and Walls results:", () => {
+
+        it("basins results", () => {
+            const pb = createPreBarrageTest();
+            pb.CalcSerie();
+            expect(pb.bassins[0].result).toBeDefined();
+            expect(pb.bassins[0].result.resultElements.length).toBeGreaterThan(0);
+            expect(Object.keys(pb.bassins[0].result.resultElements[0].values).length).toBeGreaterThan(0);
+        });
+    });
+
+    describe("Add, move and remove children:", () => {
+        let pb: PreBarrage;
+
+        it("add then remove basin", () => {
+            pb = createPreBarrageTest(true);
+            expect(pb.children.length).toBe(4); // 3 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+
+            // add 1 basin with 2 walls
+            const nb = new PbBassin(new PbBassinParams(15, 94));
+            pb.addChild(nb);
+            pb.addChild(new PbCloison(pb.children[0] as PbBassin, nb));
+            pb.children[pb.children.length-1].addChild(createPbCloisonTest(99.5));
+            pb.addChild(new PbCloison(nb, undefined));
+            pb.children[pb.children.length-1].addChild(createPbCloisonTest(99));
+
+            expect(pb.children.length).toBe(7); // 5 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            pb.deleteChild(pb.bassins[pb.bassins.length - 1].findPositionInParent()); // newly added basin
+
+            expect(pb.children.length).toBe(6); // 5 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+        });
+
+        it("remove basin", () => {
+            pb = createPreBarrageTest(true);
+            expect(pb.children.length).toBe(4); // 3 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+
+            pb.deleteChild(0); // basin 1
+
+            expect(pb.children.length).toBe(3); // 3 walls, 0 basin
+            expect(pb.bassins.length).toBe(0);
+        });
+
+        it("remove walls", () => {
+            pb = createPreBarrageTest(true);
+            expect(pb.children.length).toBe(4); // 3 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+
+            pb.deleteChild(1); // wall 1
+
+            expect(pb.children.length).toBe(3); // 2 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+
+            pb.deleteChild(1); // wall 2 (now 1)
+
+            expect(pb.children.length).toBe(2); // 1 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+        });
+
+        it("basin removal in GUI example", () => {
+            pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+            const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+            pb.addChild(b1);
+            const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+            pb.addChild(b2);
+            pb.addChild(new PbCloison(undefined, b1));
+            pb.addChild(new PbCloison(b1, b2));
+            pb.addChild(new PbCloison(b2, undefined));
+            pb.addChild(new PbCloison(b1, undefined));
+
+            expect(pb.children.length).toBe(6); // 4 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            pb.deleteChild(0); // remove b1
+
+            expect(pb.children.length).toBe(5); // 4 walls, 1 basin
+            expect(pb.bassins.length).toBe(1);
+
+            expect(pb.cloisonsAmont[0].bassinAval).toBeUndefined();
+
+            expect(uidsOfAllPointedNubs(pb)).not.toContain(b1.uid);
+        });
+
+        it("move basin up (1)", () => {
+            pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+            const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+            pb.addChild(b1);
+            const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+            pb.addChild(b2);
+            pb.addChild(new PbCloison(undefined, b1));
+            pb.addChild(new PbCloison(b1, b2));
+            pb.addChild(new PbCloison(b2, undefined));
+            pb.addChild(new PbCloison(b1, undefined));
+
+            expect(pb.children.length).toBe(6); // 4 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            // move b2 to become 1st basin (basin #0)
+            pb.moveBasin(b2.uid, 0);
+
+            expect(pb.children.length).toBe(6); // 4 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            expect(pb.children[0].uid).toBe(b2.uid);
+            expect(pb.children[1].uid).toBe(b1.uid);
+        });
+
+        it("move basin up (2)", () => {
+            pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+            const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+            pb.addChild(b1);
+            pb.addChild(new PbCloison(undefined, b1));
+            pb.addChild(new PbCloison(b1, undefined));
+            const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+            pb.addChild(b2);
+            pb.addChild(new PbCloison(b1, b2));
+            pb.addChild(new PbCloison(b2, undefined));
+            const b3 = new PbBassin(new PbBassinParams(0.17, 35));
+            pb.addChild(b3);
+            pb.addChild(new PbCloison(b1, b3));
+            pb.addChild(new PbCloison(b3, undefined));
+
+            expect(pb.children.length).toBe(9); // 6 walls, 3 basins
+            expect(pb.bassins.length).toBe(3);
+
+            expect(pb.bassins[0].uid).toBe(b1.uid);
+            expect(pb.bassins[1].uid).toBe(b2.uid);
+            expect(pb.bassins[2].uid).toBe(b3.uid);
+
+            // console.log("AVANT", pb.children.map(c => c.uid));
+            // move b3 to become 2nd basin (basin #1)
+            pb.moveBasin(b3.uid, 1);
+
+            expect(pb.children.length).toBe(9); // 6 walls, 3 basins
+            expect(pb.bassins.length).toBe(3);
+
+            expect(pb.children[0].uid).toBe(b1.uid);
+            expect(pb.children[3].uid).toBe(b3.uid);
+            expect(pb.children[4].uid).toBe(b2.uid);
+
+            expect(pb.bassins[0].uid).toBe(b1.uid);
+            expect(pb.bassins[1].uid).toBe(b3.uid);
+            expect(pb.bassins[2].uid).toBe(b2.uid);
+        });
+
+        it("move basin down (1)", () => {
+            pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+            const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+            pb.addChild(b1);
+            const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+            pb.addChild(b2);
+            pb.addChild(new PbCloison(undefined, b1));
+            pb.addChild(new PbCloison(b1, b2));
+            pb.addChild(new PbCloison(b2, undefined));
+            pb.addChild(new PbCloison(b1, undefined));
+
+            expect(pb.children.length).toBe(6); // 4 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            // move b1 to become 2nd basin (basin #1)
+            pb.moveBasin(b1.uid, 1);
+
+            expect(pb.children.length).toBe(6); // 4 walls, 2 basins
+            expect(pb.bassins.length).toBe(2);
+
+            expect(pb.children[0].uid).toBe(b2.uid);
+            expect(pb.children[1].uid).toBe(b1.uid);
+        });
+
+        it("move basin down (2)", () => {
+            pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+            const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+            pb.addChild(b1);
+            pb.addChild(new PbCloison(undefined, b1));
+            pb.addChild(new PbCloison(b1, undefined));
+            const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+            pb.addChild(b2);
+            pb.addChild(new PbCloison(b1, b2));
+            pb.addChild(new PbCloison(b2, undefined));
+            const b3 = new PbBassin(new PbBassinParams(0.17, 35));
+            pb.addChild(b3);
+            pb.addChild(new PbCloison(b1, b3));
+            pb.addChild(new PbCloison(b3, undefined));
+
+            expect(pb.children.length).toBe(9); // 6 walls, 3 basins
+            expect(pb.bassins.length).toBe(3);
+
+            expect(pb.bassins[0].uid).toBe(b1.uid);
+            expect(pb.bassins[1].uid).toBe(b2.uid);
+            expect(pb.bassins[2].uid).toBe(b3.uid);
+
+            // console.log("AVANT", pb.children.map(c => c.uid));
+            // move b1 to become 3rd basin (basin #2)
+            pb.moveBasin(b1.uid, 2);
+
+            expect(pb.children.length).toBe(9); // 6 walls, 3 basins
+            expect(pb.bassins.length).toBe(3);
+
+            expect(pb.children[2].uid).toBe(b2.uid);
+            expect(pb.children[5].uid).toBe(b3.uid);
+            expect(pb.children[6].uid).toBe(b1.uid);
+
+            expect(pb.bassins[0].uid).toBe(b2.uid);
+            expect(pb.bassins[1].uid).toBe(b3.uid);
+            expect(pb.bassins[2].uid).toBe(b1.uid);
+        });
+
+    });
+
+    describe("error cases −", () => {
+
+        it("downstream water elevation > upstream water elevation", () => {
+            const pb = createPreBarrageTest();
+            pb.prms.Z2.singleValue = pb.prms.Z1.singleValue + 1;
+            const res = pb.CalcSerie();
+            expect(res.ok).toBe(false);
+            expect(res.resultElement.log.messages.length).toBe(1);
+            expect(res.resultElement.log.messages[0].code).toBe(MessageCode.ERROR_PREBARRAGE_Z2_SUP_Z1);
+        });
+
+        it("basin apron elevation > upstream water elevation", () => {
+            const pb = createPreBarrageTest();
+            pb.prms.Z1.singleValue = pb.bassins[0].prms.ZF.singleValue - 1;
+            pb.prms.Z2.singleValue = pb.prms.Z1.singleValue - 1;
+            const res = pb.CalcSerie();
+            expect(res.ok).toBe(true);
+            expect(res.resultElement.log.messages.length).toBe(1);
+            expect(res.resultElement.log.messages[0].code).toBe(MessageCode.WARNING_PREBARRAGE_BASSIN_ZF_SUP_Z1);
+            expect(res.resultElement.log.messages[0].extraVar.n).toBe("1");
+        });
+
+        it("device ZDV < ZF of upstream basin", () => {
+            const pb = createPreBarrageTest();
+            pb.bassins[0].cloisonsAval[0].structures[0].prms.ZDV.singleValue = pb.bassins[0].prms.ZF.singleValue - 1;
+            const res = pb.CalcSerie();
+            expect(res.ok).toBe(false);
+            expect(res.resultElement.log.messages.length).toBe(1);
+            expect(res.resultElement.log.messages[0].code).toBe(MessageCode.ERROR_PREBARRAGE_STRUCTURE_ZDV_INF_ZF);
+            expect(res.resultElement.log.messages[0].extraVar.cub).toBe("B1", "wall upstream basin");
+            expect(res.resultElement.log.messages[0].extraVar.cdb).toBe("MSG_INFO_LIB_AVAL", "wall downstream basin");
+            expect(res.resultElement.log.messages[0].extraVar.ns).toBe("1", "structure number in wall");
+        });
+
+        it("PreBarrage must have at least one path from upstream to downstream", () => {
+            const pb = createPreBarrageTest();
+            pb.bassins[0].cloisonsAval[0].bassinAval = pb.bassins[0]; // nonsense wall having the same basin at upstream and downstream
+            expect(() => {
+                pb.CalcSerie();
+            }).toThrowError("PreBarrage.checkGeometry(): must have at least one path from upstream to downstream");
+        })
+
+        it("PreBarrage must have at least one upstream wall", () => {
+            const pb = createPreBarrageTest();
+            pb.cloisonsAmont = [];
+            expect(() => {
+                pb.CalcSerie();
+            }).toThrowError("PreBarrage.checkGeometry(): must have at least one upstream wall (has 0)");
+        })
+
+        it("each basin must have at least one upstream wall and one downstream wall", () => {
+            const pb = createPreBarrageTest();
+            pb.bassins[0].cloisonsAmont = [];
+            expect(() => {
+                pb.CalcSerie();
+            }).toThrowError("PreBarrage.checkGeometry(): basin 0 (starting at 0) must have at least one upstream wall (has 0) and one downstream wall (has 1)");
+        })
+
+    })
+});
diff --git a/spec/session/serialisation.spec.ts b/spec/session/serialisation.spec.ts
index 1aca6700b93b03319da76daf3d2ef1faac802ad8..7bfab78c4d03d16b4ddcf0dbf05032695efec651 100644
--- a/spec/session/serialisation.spec.ts
+++ b/spec/session/serialisation.spec.ts
@@ -33,6 +33,14 @@ import { RectangularStructure } from "../../src/structure/rectangular_structure"
 import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params";
 import { LoiDebit } from "../../src/structure/structure_props";
 import { StructureWeirSubmergedLarinier, } from "../../src/structure/structure_weir_submerged_larinier";
+import { PreBarrage } from "../../src/prebarrage/pre_barrage";
+import { PbCloison } from "../../src/prebarrage/pb_cloison";
+import { PreBarrageParams } from "../../src/prebarrage/pre_barrage_params";
+import { PbBassin } from "../../src/prebarrage/pb_bassin";
+import { PbBassinParams } from "../../src/prebarrage/pb_bassin_params";
+import { TriangularStructureParams } from "../../src/structure/structure_triangular_weir_params";
+import { StructureOrificeFreeParams } from "../../src/structure/structure_orifice_free_params";
+
 import { TriangularTruncStructureParams } from "../../src/structure/structure_triangular_trunc_weir_params";
 import { StructureJetType } from "../../src/structure/structure";
 import { CloisonsAvalParams } from "../../src/pab/cloison_aval_params";
@@ -48,6 +56,7 @@ import { sessionSolveurLast } from "./session.solveur.last";
 import { sessionSpaghetti } from "./session.spaghetti";
 import { sessionVerificateurLast } from "./session.verificateur.last";
 import { sessionVerificateurFirst } from "./session.verificateur.first";
+import { Structure } from "../../src/structure/structure";
 
 let dever: Dever;
 let cloisons: Cloisons;
@@ -442,6 +451,166 @@ describe("sessions containing Solveur - ", () => {
         expect(sp4.symbol).toBe("Z1");
         expect(sp4.parentNub.uid).toBe("NjRvcG");
     });
+
+});
+
+describe("PreBarrage - ", () => {
+
+    it("serialise", () => {
+        const pb = new PreBarrage(new PreBarrageParams(1, 100, 90));
+        pb.addChild(new PbCloison(undefined, undefined)); // amont-aval
+        const b1 = new PbBassin(new PbBassinParams(0.1, 42));
+        pb.addChild(b1);
+        pb.addChild(new PbCloison(undefined, b1)); // amont-B1
+        const b2 = new PbBassin(new PbBassinParams(0.15, 38));
+
+        const c2 = new PbCloison(undefined, b2); // amont-B2
+        const s1: Structure = CreateStructure(LoiDebit.WeirCunge80);
+        s1.prms.ZDV.singleValue = 95.30;
+        s1.getParameter("L").singleValue = 0.4;
+        s1.getParameter("CdGR").singleValue = 1.04;
+        c2.addChild(s1);
+        pb.addChild(c2);
+
+        pb.addChild(b2);
+        pb.addChild(new PbCloison(b1, b2)); // B1-B2
+        pb.addChild(new PbCloison(b2, undefined)); // B2-aval
+
+        Session.getInstance().clear();
+        Session.getInstance().registerNub(pb);
+        const json = Session.getInstance().serialise();
+        expect(json).toContain(`"props":{"calcType":"PbCloison","upstreamBasin":"","downstreamBasin":""}`);
+
+        // check that no parameter is in CALC mode in children
+        const calcCount = (json.match(/"mode":"CALCUL"/g) || []).length;
+        expect(calcCount).toBe(1);
+    });
+
+    it("unserialise", () => {
+        Session.getInstance().clear();
+        const json = `{ "header": { "source": "jalhyd", "format_version": "1.3", "created": "2020-06-29T07:58:18.237Z" }, "settings": { "precision": 1e-7, "maxIterations": 100, "displayPrecision": 3 }, "documentation": "", "session": [ { "uid": "bG5oYW", "props": { "calcType": "PreBarrage" }, "meta": { "title": "Prébarrages" }, "children": [ { "uid": "a3c1eH", "props": { "calcType": "PbCloison", "upstreamBasin": "", "downstreamBasin": "" }, "children": [ { "uid": "bHdvOW", "props": { "calcType": "Structure", "structureType": "SeuilRectangulaire", "loiDebit": "WeirSubmergedLarinier" }, "children": [], "parameters": [ { "symbol": "ZDV", "mode": "SINGLE", "value": 101.11 }, { "symbol": "L", "mode": "SINGLE", "value": 0.211 }, { "symbol": "CdWSL", "mode": "SINGLE", "value": 0.7511 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE" }, { "symbol": "Z1", "mode": "SINGLE", "value": 0 }, { "symbol": "Z2", "mode": "SINGLE", "value": 0 } ] }, { "uid": "M3AxbT", "props": { "calcType": "PbBassin" }, "children": [], "parameters": [ { "symbol": "S", "mode": "SINGLE", "value": 0.111 }, { "symbol": "ZF", "mode": "SINGLE", "value": 42.11 } ] }, { "uid": "bjRzNG", "props": { "calcType": "PbCloison", "upstreamBasin": "", "downstreamBasin": "M3AxbT" }, "children": [ { "uid": "MGYycm", "props": { "calcType": "Structure", "structureType": "SeuilTriangulaire", "loiDebit": "TriangularWeirBroad" }, "children": [], "parameters": [ { "symbol": "ZDV", "mode": "SINGLE", "value": 101.22 }, { "symbol": "alpha2", "mode": "SINGLE", "value": 45.22 }, { "symbol": "CdT", "mode": "SINGLE", "value": 1.3622 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE" }, { "symbol": "Z1", "mode": "SINGLE", "value": 0 }, { "symbol": "Z2", "mode": "SINGLE", "value": 0 } ] }, { "uid": "OTg1en", "props": { "calcType": "PbCloison", "upstreamBasin": "", "downstreamBasin": "d2kxcD" }, "children": [ { "uid": "Ym1qZH", "props": { "calcType": "Structure", "structureType": "Orifice", "loiDebit": "OrificeFree" }, "children": [], "parameters": [ { "symbol": "S", "mode": "SINGLE", "value": 0.133 }, { "symbol": "CdO", "mode": "SINGLE", "value": 0.733 }, { "symbol": "Zco", "mode": "SINGLE", "value": 101.33 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE" }, { "symbol": "Z1", "mode": "SINGLE", "value": 0 }, { "symbol": "Z2", "mode": "SINGLE", "value": 0 } ] }, { "uid": "d2kxcD", "props": { "calcType": "PbBassin" }, "children": [], "parameters": [ { "symbol": "S", "mode": "SINGLE", "value": 0.1522 }, { "symbol": "ZF", "mode": "SINGLE", "value": 38.22 } ] }, { "uid": "Z3J2cD", "props": { "calcType": "PbCloison", "upstreamBasin": "M3AxbT", "downstreamBasin": "d2kxcD" }, "children": [ { "uid": "aHpubT", "props": { "calcType": "Structure", "structureType": "VanneRectangulaire", "loiDebit": "RectangularOrificeSubmerged" }, "children": [], "parameters": [ { "symbol": "ZDV", "mode": "SINGLE", "value": 101.44 }, { "symbol": "W", "mode": "SINGLE", "value": 0.544 }, { "symbol": "L", "mode": "SINGLE", "value": 0.244 }, { "symbol": "CdGR", "mode": "SINGLE", "value": 0.644 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE" }, { "symbol": "Z1", "mode": "SINGLE", "value": 0 }, { "symbol": "Z2", "mode": "SINGLE", "value": 0 } ] }, { "uid": "anQ0Zn", "props": { "calcType": "PbCloison", "upstreamBasin": "d2kxcD", "downstreamBasin": "" }, "children": [ { "uid": "ZzJtan", "props": { "calcType": "Structure", "structureType": "VanneRectangulaire", "loiDebit": "GateCunge80" }, "children": [], "parameters": [ { "symbol": "ZDV", "mode": "SINGLE", "value": 101.55 }, { "symbol": "W", "mode": "SINGLE", "value": 0.555 }, { "symbol": "L", "mode": "SINGLE", "value": 0.255 }, { "symbol": "CdCunge", "mode": "SINGLE", "value": 1.55 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE" }, { "symbol": "Z1", "mode": "SINGLE", "value": 0 }, { "symbol": "Z2", "mode": "SINGLE", "value": 0 } ] } ], "parameters": [ { "symbol": "Q", "mode": "SINGLE", "value": 1.0101 }, { "symbol": "Z1", "mode": "CALCUL" }, { "symbol": "Z2", "mode": "SINGLE", "value": 90.0101 } ] } ] }`;
+        const res = Session.getInstance().unserialise(json);
+        expect(res.hasErrors).toBe(false);
+
+        const pb = Session.getInstance().findNubByUid("bG5oYW") as PreBarrage;
+        expect(pb).toBeDefined();
+        expect(pb.children.length).toBe(7); // 2 basins, 5 walls
+        expect(pb.bassins.length).toBe(2);
+
+        // paramètres de la rivière
+        expect(pb.prms.Q.singleValue).toBe(1.0101);
+        expect(pb.prms.Z2.singleValue).toBe(90.0101);
+        expect(pb.prms.Z1.valueMode).toBe(ParamValueMode.CALCUL);
+        expect(pb.calculatedParam.symbol).toBe("Z1");
+
+        const b1: PbBassin = pb.findChild("M3AxbT") as PbBassin;
+        expect(b1.prms.S.singleValue).toBe(0.111);
+        expect(b1.prms.ZF.singleValue).toBe(42.11);
+        const b2: PbBassin = pb.findChild("d2kxcD") as PbBassin;
+        expect(b2.prms.S.singleValue).toBe(0.1522);
+        expect(b2.prms.ZF.singleValue).toBe(38.22);
+
+        const c1: PbCloison = pb.findChild("a3c1eH") as PbCloison; // amont-aval
+        expect(c1.bassinAmont).toBeUndefined();
+        expect(c1.bassinAval).toBeUndefined();
+        expect(c1.structures.length).toBe(1);
+        expect(c1.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.WeirSubmergedLarinier);
+        const s1 = c1.structures[0].prms as RectangularStructureParams;
+        expect(s1.ZDV.singleValue).toBe(101.11);
+        expect(s1.L.singleValue).toBe(0.211);
+        expect(s1.CdWSL.singleValue).toBe(0.7511);
+
+        const c2: PbCloison = pb.findChild("bjRzNG") as PbCloison; // amont-B1
+        expect(c2.bassinAmont).toBeUndefined();
+        expect(c2.bassinAval.uid).toBe("M3AxbT");
+        expect(c2.structures.length).toBe(1);
+        expect(c2.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.TriangularWeirBroad);
+        const s2 = c2.structures[0].prms as TriangularStructureParams;
+        expect(s2.ZDV.singleValue).toBe(101.22);
+        expect(s2.CdT.singleValue).toBe(1.3622);
+        expect(s2.alpha2.singleValue).toBe(45.22);
+
+        const c3: PbCloison = pb.findChild("OTg1en") as PbCloison; // amont-B2
+        expect(c3.bassinAmont).toBeUndefined();
+        expect(c3.bassinAval.uid).toBe("d2kxcD");
+        expect(c3.structures.length).toBe(1);
+        expect(c3.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.OrificeFree);
+        const s3 = c3.structures[0].prms as StructureOrificeFreeParams;
+        expect(s3.S.singleValue).toBe(0.133);
+        expect(s3.CdO.singleValue).toBe(0.733);
+        expect(s3.Zco.singleValue).toBe(101.33);
+
+        const c4: PbCloison = pb.findChild("Z3J2cD") as PbCloison; // B1-B2
+        expect(c4.bassinAmont.uid).toBe("M3AxbT");
+        expect(c4.bassinAval.uid).toBe("d2kxcD");
+        expect(c4.structures.length).toBe(1);
+        expect(c4.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.RectangularOrificeSubmerged);
+        const s4 = c4.structures[0].prms as RectangularStructureParams;
+        expect(s4.ZDV.singleValue).toBe(101.44);
+        expect(s4.L.singleValue).toBe(0.244);
+        expect(s4.W.singleValue).toBe(0.544);
+        expect(s4.CdGR.singleValue).toBe(0.644);
+
+        const c5: PbCloison = pb.findChild("anQ0Zn") as PbCloison; // B2-aval
+        expect(c5.bassinAmont.uid).toBe("d2kxcD");
+        expect(c5.bassinAval).toBeUndefined();
+        expect(c5.structures.length).toBe(1);
+        expect(c5.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.GateCunge80);
+        const s5 = c5.structures[0].prms as RectangularStructureParams;
+        expect(s5.ZDV.singleValue).toBe(101.55);
+        expect(s5.L.singleValue).toBe(0.255);
+        expect(s5.W.singleValue).toBe(0.555);
+        expect(s5.CdCunge.singleValue).toBe(1.55);
+
+        // calculate
+        const resPb = pb.CalcSerie();
+        expect(resPb).toBeDefined();
+    });
+
+    it("unserialise multiple times", () => {
+        Session.getInstance().clear();
+        const json = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-07-03T11:58:35.049Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"YmZ6eW","props":{"calcType":"PreBarrage"},"meta":{"title":"Prébarrages"},"children":[{"uid":"ZW8yaX","props":{"calcType":"PbBassin"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":13.8},{"symbol":"ZF","mode":"SINGLE","value":95}]},{"uid":"bXkwZW","props":{"calcType":"PbCloison","upstreamBasin":"","downstreamBasin":"ZW8yaX"},"children":[{"uid":"cmw3eH","props":{"calcType":"Structure","loiDebit":"WeirCunge80","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":95.3},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdCunge","mode":"SINGLE","value":1}]}],"parameters":[]},{"uid":"OHV2cH","props":{"calcType":"PbCloison","upstreamBasin":"ZW8yaX","downstreamBasin":""},"children":[{"uid":"OGM3bm","props":{"calcType":"Structure","loiDebit":"WeirCunge80","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":95.3},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdCunge","mode":"SINGLE","value":1}]}],"parameters":[]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":1},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":100}]}]}`;
+        // unserialise
+        const res = Session.getInstance().unserialise(json);
+        expect(res.hasErrors).toBe(false);
+        expect(Session.getInstance().getAllNubs().length).toBe(1);
+
+        const pb = Session.getInstance().findNubByUid("YmZ6eW") as PreBarrage;
+        expect(pb).toBeDefined();
+        expect(pb.children.length).toBe(3); // 1 basins, 2 walls
+        expect(pb.bassins.length).toBe(1);
+
+        const c1: PbCloison = pb.findChild("bXkwZW") as PbCloison; // amont-B1
+        expect(c1.bassinAmont).toBeUndefined();
+        expect(c1.bassinAval.uid).toBe("ZW8yaX");
+
+        const c2: PbCloison = pb.findChild("OHV2cH") as PbCloison; // B1-aval
+        expect(c2.bassinAmont.uid).toBe("ZW8yaX");
+        expect(c2.bassinAval).toBeUndefined();
+
+        // unserialise the same Nub a second time
+        const res2 = Session.getInstance().unserialise(json);
+        expect(res2.hasErrors).toBe(false);
+        expect(Session.getInstance().getAllNubs().length).toBe(2);
+
+        const pb2 = Session.getInstance().getAllNubs()[1] as PreBarrage;
+        expect(pb2).toBeDefined();
+        expect(pb2.uid).not.toBe("YmZ6eW");
+        expect(pb2.children.length).toBe(3); // 1 basins, 2 walls
+        expect(pb2.bassins.length).toBe(1);
+        // check that UIDs changed
+        expect(pb2.uid).not.toBe(pb.uid);
+        expect(pb2.bassins[0].uid).not.toBe(pb.bassins[0].uid);
+
+        const c12: PbCloison = pb2.getChildren()[1] as PbCloison; // amont-B1
+        expect(c12.bassinAmont).toBeUndefined();
+        expect(c12.bassinAval.uid).toBe(pb2.bassins[0].uid);
+
+        const c22: PbCloison = pb2.getChildren()[2] as PbCloison; // B1-aval
+        expect(c22.bassinAmont.uid).toBe(pb2.bassins[0].uid);
+        expect(c22.bassinAval).toBeUndefined();
+    });
+
 });
 
 describe("sessions containing Verificateur - ", () => {
diff --git a/spec/verificateur/verificateur.spec.ts b/spec/verificateur/verificateur.spec.ts
index 385366ad4e509faa57bc94e171f159ebc2a43b1a..b790b5ee98152eeb0277b2eda1a05e11c11371e0 100644
--- a/spec/verificateur/verificateur.spec.ts
+++ b/spec/verificateur/verificateur.spec.ts
@@ -25,10 +25,12 @@ function createPab(): Pab {
     const pab = Session.getInstance().createSessionNub(
         new Props({ calcType: CalculatorType.Pab })
     ) as Pab;
-    pab.children.push(Session.getInstance().createNub(
+    const cl = Session.getInstance().createNub(
         new Props({ calcType: CalculatorType.Cloisons })
-    ) as Cloisons);
-    pab.children[0].structures[0] = CreateStructure(LoiDebit.WeirSubmergedLarinier);
+    ) as Cloisons;
+    cl.parent = pab;
+    pab.children.push(cl);
+    pab.children[0].structures[0] = CreateStructure(LoiDebit.WeirSubmergedLarinier, cl);
     const dw = Session.getInstance().createNub(
         new Props({ calcType: CalculatorType.CloisonAval })
     ) as CloisonAval;
@@ -235,6 +237,7 @@ describe("vérificateur de franchissement −", () => {
             pab.children[4].structures[0] = new StructureWeirVillemonte( // Échancrure (Villemonte 1957)
                 pab.children[4].structures[0].prms as RectangularStructureParams
             );
+            pab.children[4].structures[0].parent = pab.children[4];
             pab.children[4].structures[0].getParameter("L").singleValue = 0.35;
             pab.prms.Z2.singleValue = 30.4; // évite une chute trop importante à la cloison 5
             // vérificateur
diff --git a/src/compute-node.ts b/src/compute-node.ts
index 512ab5d660ab865c7fff00fbbdafeec031ef1cfe..7dc9278b4befd7a58f16e39c610ba92456c29559 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -38,6 +38,9 @@ export enum CalculatorType {
     ConcentrationBlocs,
     Par,                // Passe à ralentisseurs, calage
     ParSimulation,      // Passe à ralentisseurs, simulation
+    PreBarrage,         // Pré-barrage
+    PbCloison,          // Cloison de pré-barrage
+    PbBassin,           // Bassin de pré-barrage
     Espece,             // Critères de vérification pour une espèce de poissons
     Verificateur        // Vérificateur de contraintes sur une passe pour une ou plusieurs espèces
 }
diff --git a/src/dichotomie.ts b/src/dichotomie.ts
index 66aaad989513409fa520c2b9add9ed04ceaf0f99..d90fcf869e3742b3631f1205b13c1b235df96ff0 100644
--- a/src/dichotomie.ts
+++ b/src/dichotomie.ts
@@ -150,13 +150,17 @@ export class Dichotomie extends Debug {
      * @param dom domaine de définition de la variable
      */
     private isIncreasingFunction(x: number, dom: Interval): boolean {
-        const epsilon = 1e-8;
-        const bounds = new Interval(x - epsilon, x + epsilon);
-        bounds.setInterval(bounds.intersect(dom)); // au cas où l'on sorte du domaine de la variable de la fonction
-
-        const y1 = this.CalculX(bounds.min);
-        const y2 = this.CalculX(bounds.max);
-        return y2 > y1;
+        let epsilon = 1e-8;
+        for(let i=0; i < 20; i++) {
+            const bounds = new Interval(x - epsilon, x + epsilon);
+            bounds.setInterval(bounds.intersect(dom)); // au cas où l'on sorte du domaine de la variable de la fonction
+
+            const y1 = this.CalculX(bounds.min);
+            const y2 = this.CalculX(bounds.max);
+            if(Math.abs(y2 - y1) > 1E-6) return y2 > y1;
+            epsilon *= 10;
+        }
+        return true;
     }
 
     /**
diff --git a/src/index.ts b/src/index.ts
index b0532a82333dd472c991beacc390a1bfdc3af533..41e1307a7fd71c58bb39889a0fd2326322dae388 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -93,3 +93,8 @@ export * from "./verification/verificateur_params";
 export * from "./verification/fish_species";
 export * from "./verification/diving-jet-support";
 export * from "./fish_pass";
+export * from "./prebarrage/pre_barrage";
+export * from "./prebarrage/pre_barrage_params";
+export * from "./prebarrage/pb_cloison";
+export * from "./prebarrage/pb_bassin";
+export * from "./prebarrage/pb_bassin_params";
diff --git a/src/macrorugo/macrorugo_params.ts b/src/macrorugo/macrorugo_params.ts
index b67f1814f9b081a805f43568e52719ffe53b2f51..348f8e5806a83abf187db45dd1ced426e8010c85 100644
--- a/src/macrorugo/macrorugo_params.ts
+++ b/src/macrorugo/macrorugo_params.ts
@@ -77,7 +77,7 @@ export class MacrorugoParams extends ParamsEquation {
         this._Ks = new ParamDefinition(this, "Ks", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "m", rRF);
         this.addParamDefinition(this._Ks);
 
-        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "-", rCB);
+        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "", rCB);
         this.addParamDefinition(this._C);
 
         this._PBD = new ParamDefinition(this, "PBD", new ParamDomain(ParamDomainValue.INTERVAL, 0, 2), "m", rPBD);
diff --git a/src/nub.ts b/src/nub.ts
index b9b1b913d9600c6f4c6aa3ff44ba2d29c669fdcd..3b841b290c00a6c6c6ff82b784b368e28ba354de 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -461,6 +461,28 @@ export abstract class Nub extends ComputeNode implements IObservable {
         };
     }
 
+    /**
+     * Returns a list of parameters that are fixed, either because their valueMode
+     * is SINGLE, or because their valueMode is LINK and the reference is
+     * defined and fixed. Does not take calculated parameters into account.
+     */
+    public findFixedParams(): ParamDefinition[] {
+        const fixed: ParamDefinition[] = [];
+        for (const p of this.parameterIterator) {
+            if (
+                p.valueMode === ParamValueMode.SINGLE
+                || (
+                    p.valueMode === ParamValueMode.LINK
+                    && p.isReferenceDefined()
+                    && ! p.referencedValue.hasMultipleValues()
+                )
+            ) {
+                fixed.push(p);
+            }
+        }
+        return fixed;
+    }
+
     /**
      * Returns a list of parameters that are variating, either because their valueMode
      * is LISTE or MINMAX, or because their valueMode is LINK and the reference is
@@ -493,7 +515,6 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * Effectue une série de calculs sur un paramètre; déclenche le calcul en chaîne
      * des modules en amont si nécessaire
      * @param rInit solution approximative du paramètre
-     * @param sDonnee éventuel symbole / paire symbole-uid du paramètre à calculer
      */
     public CalcSerie(rInit?: number): Result {
         // prepare calculation
@@ -1033,8 +1054,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 // is this a Solveur
                 if (this instanceof Solveur) {
                     return (
-                        (this.searchedParameter !== undefined && this.searchedParameter.nubUid === uid)
-                        || (this.nubToCalculate !== undefined && this.nubToCalculate.uid === uid)
+                        (this.searchedParameter?.nubUid === uid)
+                        || (this.nubToCalculate?.uid === uid)
                     );
                 } else if (this instanceof Verificateur) {
                     return (
@@ -1159,16 +1180,17 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * @returns the calculated parameter found, if any - used by child Nub to notify
      *          its parent of the calculated parameter to set
      */
-    public loadObjectRepresentation(obj: any): { p: ParamDefinition, hasErrors: boolean } {
+    public loadObjectRepresentation(obj: any): { p: ParamDefinition, hasErrors: boolean, changedUids: { [key: string]: string } } {
         // return value
-        const ret: { p: ParamDefinition, hasErrors: boolean } = {
+        const ret: { p: ParamDefinition, hasErrors: boolean, changedUids: { [key: string]: string } } = {
             p: undefined,
-            hasErrors: false
+            hasErrors: false,
+            changedUids: {}
         };
         // set parameter modes and values
         if (obj.parameters && Array.isArray(obj.parameters)) {
             // 1st pass: find calculated param
-            // (if calculated param is not the default one, and default one is processes
+            // (if calculated param is not the default one, and default one is processed
             // before new one, prevents changing the former's mode from setting the 1st
             // param of the Nub to calculated, resetting the mode that had been loaded)
             for (const p of obj.parameters) {
@@ -1198,6 +1220,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 // try to keep the original ID
                 if (! Session.getInstance().uidAlreadyUsed(s.uid)) {
                     subNub.setUid(s.uid);
+                } else {
+                    ret.changedUids[s.uid] = subNub.uid;
                 }
                 const childRet = subNub.loadObjectRepresentation(s);
                 // add Structure to parent
@@ -1296,7 +1320,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 for (const p of this._children[index].parameterIterator) {
                     // if p is also present and visible in new Nub
                     const cp = child.getParameter(p.symbol);
-                    if (cp !== undefined && cp.visible && p.visible) {
+                    if (cp?.visible && p.visible) {
                         parametersState[p.symbol] = p.objectRepresentation([]);
                     }
                 }
@@ -1392,9 +1416,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         return undefined;
     }
 
-    /**
-     * Moves a child to first position
-     */
+    /** Moves a child up (1 step) */
     public moveChildUp(child: Nub) {
         let i = 0;
         for (const s of this._children) {
@@ -1408,9 +1430,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         }
     }
 
-    /**
-     * Moves a child to last position
-     */
+    /** Moves a child down (1 step) */
     public moveChildDown(child: Nub) {
         let i = 0;
         for (const s of this._children) {
diff --git a/src/open-channel/remous.ts b/src/open-channel/remous.ts
index 9b9b23af27f4484e227db38a975f09bd55865960..0beb4ede2105dd25a833664192a55da7f4ef201c 100644
--- a/src/open-channel/remous.ts
+++ b/src/open-channel/remous.ts
@@ -179,13 +179,13 @@ export class CourbeRemous extends SectionNub {
         }
 
         let crbFlu;
-        if (rCourbeFlu !== undefined && rCourbeFlu.trY !== undefined) {
+        if (rCourbeFlu?.trY !== undefined) {
             crbFlu = rCourbeFlu.trY;
         } else {
             crbFlu = {};
         }
         let crbTor;
-        if (rCourbeTor !== undefined && rCourbeTor.trY !== undefined) {
+        if (rCourbeTor?.trY !== undefined) {
             crbTor = rCourbeTor.trY;
         } else {
             crbTor = {};
diff --git a/src/pab/pab.ts b/src/pab/pab.ts
index 0df2fa42aaef0f9e12665893b5050e18661a10ed..597d82631b0cac5d4f05d10bd8bd2fb1ff4549bf 100644
--- a/src/pab/pab.ts
+++ b/src/pab/pab.ts
@@ -245,9 +245,9 @@ export class Pab extends FishPass {
      * @returns the calculated parameter found, if any - used by child Nub to notify
      *          its parent of the calculated parameter to set
      */
-    public loadObjectRepresentation(obj: any): { p: ParamDefinition, hasErrors: boolean } {
+    public loadObjectRepresentation(obj: any): { p: ParamDefinition, hasErrors: boolean, changedUids: { [key: string]: string } } {
         // return value
-        const ret: { p: ParamDefinition, hasErrors: boolean } = super.loadObjectRepresentation(obj);
+        const ret: { p: ParamDefinition, hasErrors: boolean, changedUids: { [key: string]: string } } = super.loadObjectRepresentation(obj);
         // load downwall if any
         if (obj.downWall) {
             // decode properties
diff --git a/src/par/par_type_chevron.ts b/src/par/par_type_chevron.ts
index 49da5bd5909cb4147ed819bceadb27adeb5ccae4..8ffc30cd26d36ca2f459755df3e54612b548334c 100644
--- a/src/par/par_type_chevron.ts
+++ b/src/par/par_type_chevron.ts
@@ -3,7 +3,6 @@ import { ParTypeSC } from "./par_type_sc";
 import { ParParams } from "./par_params";
 import { ParType } from "./par";
 import { Message, MessageCode } from "../util/message";
-import { ParamDefinition } from "../param/param-definition";
 
 export class ParTypeChevron extends ParTypeSC {
 
diff --git a/src/par/par_type_superactive.ts b/src/par/par_type_superactive.ts
index f4315e3c55729ee0c88a644845c471c3190fcdd2..1f9b17a1da6f4e65461de93c8592da31de397395 100644
--- a/src/par/par_type_superactive.ts
+++ b/src/par/par_type_superactive.ts
@@ -2,8 +2,6 @@ import { Result } from "../util/result";
 import { ParTypeSC } from "./par_type_sc";
 import { ParType } from "./par";
 import { ParParams } from "./par_params";
-import { Message, MessageCode } from "../util/message";
-import { ParamDefinition } from "../param/param-definition";
 
 export class ParTypeSuperactive extends ParTypeSC {
 
diff --git a/src/param/params-equation.ts b/src/param/params-equation.ts
index c40a8d540e47bc28818b6fe2b73729535d5e4a15..5e2549fdf4561bf92ddb1e75901ef6fff81da188 100644
--- a/src/param/params-equation.ts
+++ b/src/param/params-equation.ts
@@ -15,9 +15,6 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> {
 
     protected _paramMap: { [key: string]: ParamDefinition } = {};
 
-    /** Précision de calcul */
-    private _Pr: ParamDefinition;
-
     public constructor(parent?: ComputeNode) {
         this.parent = parent;
     }
diff --git a/src/prebarrage/pb_bassin.ts b/src/prebarrage/pb_bassin.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4242e202af6d527eb6c675199260704e9bbd7660
--- /dev/null
+++ b/src/prebarrage/pb_bassin.ts
@@ -0,0 +1,121 @@
+import { Nub } from "../nub";
+import { Result } from "../util/result";
+import { PbBassinParams } from "./pb_bassin_params";
+import { ParamCalculability } from "../param/param-definition";
+import { PbCloison } from "./pb_cloison";
+import { CalculatorType } from "../compute-node";
+import { PreBarrage } from "./pre_barrage";
+import { Message, MessageCode } from "../util/message";
+
+export interface IPbBassinZstat{
+    moy: number,
+    min: number,
+    max: number
+}
+export class PbBassin extends Nub {
+
+    /** Liste des cloisons amont */
+    public cloisonsAmont: PbCloison[];
+
+    /** Liste des cloisons aval */
+    public cloisonsAval: PbCloison[];
+
+    public parent: PreBarrage;
+
+    /** Débit transitant dans le bassin en m³/s */
+    public Q: number;
+
+    /** Cote de l'eau dans le bassin en m */
+    public Z: number;
+
+    constructor(prms: PbBassinParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this._calcType = CalculatorType.PbBassin;
+        this.cloisonsAmont = [];
+        this.cloisonsAval = [];
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PbBassinParams {
+        return this._prms as PbBassinParams;
+    }
+
+    public Calc(sVarCalc?: string | any, rInit?: number): Result {
+        // if Calc() is called outside of CalcSerie(), _result might not be initialized
+        if (! this.result) {
+            this.initNewResultElement();
+        }
+        const r = this.result;
+
+        // Ajout du calcul de la puissance dissipée
+        const prms = this.getParamValuesAfterCalc(sVarCalc, r);
+        let sumQ = 0; // sum of Q in upstream walls
+        for (const w of this.cloisonsAmont) {
+            sumQ += w.prms.Q.v;
+        }
+        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.resultElement.values.PV = ro * g * sumQ * (this.Z - prms.ZF) / (prms.S);
+
+        r.resultElement.values.Z = this.CalcZ().moy;
+        r.resultElement.values.Q = this.CalcQ();
+        r.resultElement.values.YMOY = r.resultElement.values.Z - this.prms.ZF.V;
+
+        return r;
+    }
+
+    public Equation(sVarCalc: string): Result {
+        switch(sVarCalc) {
+            case "Q":
+            case "Z":
+                const r = new Result();
+                r.values.Q = this.CalcQ();
+                r.values.Z = this.CalcZ().moy;
+                return r;
+            default:
+                throw new Error("PbBassin.Equation() : invalid variable name " + sVarCalc);
+        }
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.S.calculability = ParamCalculability.FIXED;
+        this.prms.ZF.calculability = ParamCalculability.FIXED;
+    }
+
+    public CalcQ(): number {
+        this.Q = 0;
+        for(const c of this.cloisonsAmont) {
+            this.Q += Math.max(0, c.prms.Q.v);
+        }
+        return this.Q;
+    }
+
+    public CalcZ(): IPbBassinZstat {
+        const zStat = this.parent.CalcZ1Cloisons(this.cloisonsAval);
+        this.Z = zStat.moy;
+        return zStat;
+    }
+
+    public getMinZDV(): number {
+        return this.parent.getMinZDV(this.cloisonsAval);
+    }
+
+    /** Returns order of current basin in parent PreBarrage, starting at 1 */
+    public get order(): number {
+        return this.parent.findBasinPosition(this.uid) + 1;
+    }
+
+    /**
+     * Returns a translatable message for basin description, containing order number
+     */
+    public get description(): Message {
+        return new Message(MessageCode.INFO_PB_BASSIN_DESCRIPTION, {
+            order: String(this.order)
+        });
+    }
+}
\ No newline at end of file
diff --git a/src/prebarrage/pb_bassin_params.ts b/src/prebarrage/pb_bassin_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e4e94526d6a17505a4cd16372461343d3670e8f1
--- /dev/null
+++ b/src/prebarrage/pb_bassin_params.ts
@@ -0,0 +1,20 @@
+import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+
+export class PbBassinParams extends ParamsEquation {
+
+    /** Surface du bassin en m2 */
+    public S: ParamDefinition;
+
+    /** Cote de fond du bassin en m */
+    public ZF: ParamDefinition;
+
+    constructor(rS: number, rZF: number) {
+        super();
+        this.S = new ParamDefinition(this, "S", ParamDomainValue.POS, "m²", rS);
+        this.addParamDefinition(this.S);
+        this.ZF = new ParamDefinition(this, "ZF", ParamDomainValue.ANY, "m", rZF, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.ZF);
+    }
+}
diff --git a/src/prebarrage/pb_cloison.ts b/src/prebarrage/pb_cloison.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1be292683fe6295eb07c5a6b7a943169591fd851
--- /dev/null
+++ b/src/prebarrage/pb_cloison.ts
@@ -0,0 +1,148 @@
+import { ParallelStructure } from "../structure/parallel_structure";
+import { PbBassin } from "./pb_bassin";
+import { PreBarrage } from "./pre_barrage";
+import { ParallelStructureParams } from "../structure/parallel_structure_params";
+import { CalculatorType } from "../compute-node";
+import { Result } from "../util/result";
+import { LoiDebit, loiAdmissiblesOuvrages } from "../structure/structure_props";
+import { Message, MessageCode } from "../util/message";
+
+export class PbCloison extends ParallelStructure {
+
+    /** pointer to parent Nub */
+    public parent: PreBarrage;
+
+    constructor(bassinAmont: PbBassin, bassinAval: PbBassin, dbg: boolean = false) {
+        super(new ParallelStructureParams(0,0,0), dbg);
+        // prevent multiple CALC params in session file
+        this.prms.Q.visible = false;
+        this.prms.Z1.visible = false;
+        this.prms.Z2.visible = false;
+        this.properties.setPropValue("upstreamBasin", bassinAmont === undefined ? "" : bassinAmont.uid);
+        this.properties.setPropValue("downstreamBasin", bassinAval === undefined ? "" : bassinAval.uid);
+        this._calcType = CalculatorType.PbCloison;
+    }
+
+    /** Bassin à l'amont de la cloison ou undefined pour condition limite amont */
+    public get bassinAmont(): PbBassin {
+        let basin: PbBassin;
+        const basinUID: string = this._props.getPropValue("upstreamBasin");
+        if (basinUID !== undefined && basinUID !== "") {
+            basin = this.parent.findChild(basinUID) as PbBassin;
+            if (basin === undefined) {
+                // silent fail
+            }
+        }
+        return basin;
+    }
+
+    /** sets the upstream basin by setting property "upstreamBasin" to the UID of the given PbBassin */
+    public set bassinAmont(b: PbBassin) {
+        let uid = ""; // empty value
+        if (b !== undefined) {
+            uid = b.uid;
+        }
+        this.properties.setPropValue("upstreamBasin", uid);
+        this.parent.updatePointers();
+    }
+
+    /** Bassin à l'aval de la cloison ou undefined pour condition limite aval */
+    public get bassinAval(): PbBassin {
+        let basin: PbBassin;
+        const basinUID: string = this._props.getPropValue("downstreamBasin");
+        if (basinUID !== undefined && basinUID !== "") {
+            basin = this.parent.findChild(basinUID) as PbBassin;
+            if (basin === undefined) {
+                // silent fail
+            }
+        }
+        return basin;
+    }
+
+    /** sets the downstream basin by setting property "downstreamBasin" to the UID of the given PbBassin */
+    public set bassinAval(b: PbBassin) {
+        let uid = ""; // empty value
+        if (b !== undefined) {
+            uid = b.uid;
+        }
+        this.properties.setPropValue("downstreamBasin", uid);
+        this.parent.updatePointers();
+    }
+
+    public get Z1(): number {
+        if(this.bassinAmont !== undefined) {
+            return this.bassinAmont.Z;
+        } else {
+            return this.parent.prms.Z1.v;
+        }
+    }
+
+    public get Z2(): number {
+        if(this.bassinAval !== undefined) {
+            return this.bassinAval.Z;
+        } else {
+            return this.parent.prms.Z2.v;
+        }
+    }
+
+    public Calc(sVarCalc?: string, rInit?: number): Result {
+        this.updateZ1Z2();
+        const r = super.Calc(sVarCalc, rInit);
+        switch(sVarCalc) {
+            case "Z1":
+                // Upstream water elevation should be at least equal minZDV
+                r.vCalc = Math.max(this.getMinZDV(), r.vCalc);
+                break;
+
+            case "Q":
+                r.vCalc = Math.max(0, r.vCalc);
+        }
+        return r;
+    }
+
+    public finalCalc() {
+        this.calculatedParam = this.prms.Q;
+        this.Calc("Q");
+        // add Z1 & Z2 extra results for GUI convenience
+        this.result.resultElement.values.Z1 = this.prms.Z1.v;
+        this.result.resultElement.values.Z2 = this.prms.Z2.v;
+    }
+
+    public updateZ1Z2() {
+        this.prms.Z1.v = this.Z1;
+        this.prms.Z2.v = this.Z2;
+    }
+
+    /**
+     * Give the minimum ZDV on all structures. Undefined if only orifice without ZDV.
+     */
+    public getMinZDV(): number {
+        let minZDV: number;
+        for(const s of this.structures) {
+            if(s.prms.ZDV.visible) {
+                if(minZDV === undefined) {
+                    minZDV = s.prms.ZDV.v;
+                } else {
+                    minZDV = Math.min(minZDV, s.prms.ZDV.v);
+                }
+            }
+        }
+        return minZDV;
+    }
+
+    public getLoisAdmissibles(): { [key: string]: LoiDebit[]; } {
+        return loiAdmissiblesOuvrages; // @TODO loiAdmissiblesCloisons plutôt, mais penser à y intégrer Cunge80
+    }
+
+    /**
+     * Returns a translatable message for wall description, containing order numbers of
+     * upstream and downstream basin, or "upstream" / "downstream" mention if wall is
+     * directly connected to the river
+     */
+    public get description(): Message {
+        return new Message(MessageCode.INFO_PB_CLOISON_DESCRIPTION, {
+            ub: this.bassinAmont === undefined ? "MSG_INFO_LIB_AMONT" : "B" + String(this.bassinAmont.order),
+            db: this.bassinAval === undefined ? "MSG_INFO_LIB_AVAL" : "B" + String(this.bassinAval.order),
+        });
+    }
+}
diff --git a/src/prebarrage/pre_barrage.ts b/src/prebarrage/pre_barrage.ts
new file mode 100644
index 0000000000000000000000000000000000000000..317b474f9bab8af5e815b780896ffd62c88555c1
--- /dev/null
+++ b/src/prebarrage/pre_barrage.ts
@@ -0,0 +1,561 @@
+import { Nub } from "../nub";
+import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { Result } from "../util/result";
+import { PreBarrageParams } from "./pre_barrage_params";
+import { CalculatorType } from "../compute-node";
+import { PbBassin, IPbBassinZstat } from "./pb_bassin";
+import { PbCloison } from "./pb_cloison";
+import { SessionSettings } from "../session_settings";
+import { MessageCode, Message, MessageSeverity } from "../util/message";
+import { ResultElement } from "../util/resultelement";
+
+export class PreBarrage extends Nub {
+
+    /** Liste des cloisons amont */
+    public cloisonsAmont: PbCloison[];
+
+    public maxIterations: number;
+
+    /** Pointeurs vers les bassins dans this.children */
+    private _bassins: PbBassin[];
+
+    /** Coefficient de relaxation pour la répartition des débits */
+    private _relax: number;
+
+    /** Precision du calcul  (Min. 1E-4) */
+    private _precision: number;
+
+    constructor(prms: PreBarrageParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this._calcType = CalculatorType.PreBarrage;
+        this.cloisonsAmont = [];
+        this._bassins = [];
+        this.maxIterations = SessionSettings.maxIterations;
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PreBarrageParams {
+        return this._prms as PreBarrageParams;
+    }
+
+    /**
+     * enfants castés au bon type
+     */
+    get children(): (PbCloison | PbBassin)[] {
+        return this._children as (PbCloison | PbBassin)[];
+    }
+
+    get bassins(): PbBassin[] {
+        return this._bassins;
+    }
+
+    /**
+     * Removes a child, along with all features (basins or walls) that are
+     * related only to it, and pointers to it
+     */
+    public deleteChild(index: number) {
+        const item = this._children[index];
+        if (item instanceof PbBassin) {
+            // reconnect walls to river upstream / downstream
+            for (const w of item.cloisonsAmont) {
+                w.bassinAval = undefined;
+            }
+            for (const w of item.cloisonsAval) {
+                w.bassinAmont = undefined;
+            }
+        } else if (item instanceof PbCloison) {
+            if (item.bassinAmont !== undefined) {
+                item.bassinAmont.cloisonsAval = item.bassinAmont.cloisonsAval.filter((v) => v !== item);
+            }
+            if (item.bassinAval !== undefined) {
+                item.bassinAval.cloisonsAmont = item.bassinAval.cloisonsAmont.filter((v) => v !== item);
+            }
+        }
+        // remove item
+        super.deleteChild(index);
+        this.updatePointers();
+    }
+
+    /**
+     * Returns true if at least one path is connecting river upstream to river downstream,
+     * using at least one basin (direct connection without basin doesn't count)
+     */
+    public hasUpDownConnection(startWall?: PbCloison, nbBasins: number = 0, visited: PbCloison[] = []): boolean {
+        let ok = false;
+        // starting at river upstream ?
+        if (startWall === undefined) {
+            if (this.cloisonsAmont.length === 0) {
+                return false;
+            }
+            // browse graph downwards
+            for (const ca of this.cloisonsAmont) {
+                ok = ok || this.hasUpDownConnection(ca, 0, visited);
+            }
+        } else {
+            // starting from a wall
+            if (startWall.bassinAval === undefined) {
+                return (nbBasins > 0);
+            } else {
+                // browse graph downwards
+                for (const ca of startWall.bassinAval.cloisonsAval) {
+                    // prevent loops @TODO detect loops instead, and throw an error ?
+                    if (! visited.includes(ca)) {
+                        visited.push(ca);
+                        ok = ok || this.hasUpDownConnection(ca, nbBasins + 1, visited);
+                    }
+                }
+            }
+        }
+        return ok;
+    }
+
+    /**
+     * Returns true if at least one basin is lacking upstream or downstream connection (or both)
+     */
+    public hasBasinNotConnected(): boolean {
+        for (const b of this._bassins) {
+            if (b.cloisonsAmont.length === 0 || b.cloisonsAval.length === 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the child (basin or wall) having the given UID, along with its position
+     * among the _children array (*not* the _bassins array !)
+     */
+    protected findChildAndPosition(uid: string): { child: PbBassin | PbCloison, position: number } {
+        const res: { child: PbBassin | PbCloison, position: number } = { child: undefined, position: undefined };
+        let pos = 0;
+        for (const c of this.children) {
+            if (c.uid === uid) {
+                res.child = c;
+                res.position = pos;
+            }
+            pos++;
+        }
+        return res;
+    }
+
+    /**
+     * Returns the child (basin or wall) having the given UID
+     */
+    public findChild(uid: string): PbBassin | PbCloison {
+        const { child } = this.findChildAndPosition(uid);
+        return child;
+    }
+
+    /**
+     * Returns the position of the child (basin or wall) having the given UID,
+     * among the _children array (*not* the _bassins array !)
+     */
+    public findChildPosition(uid: string): number {
+        const { position } = this.findChildAndPosition(uid);
+        return position;
+    }
+
+    /**
+     * Returns the position of the basin having the given UID,
+     * among the _bassins array (*not* the _children array !)
+     */
+    public findBasinPosition(uid: string): number {
+        let i = 0;
+        for (const b of this._bassins) {
+            if (b.uid === uid) {
+                break;
+            }
+            i++;
+        }
+        return i;
+    }
+
+    /**
+     * Moves the basin having the given UID, so that it becomes
+     * basin #newBasinNumber, by reordering _children array and
+     * rebuilding _bassins array afterwards
+     */
+    public moveBasin(uid: string, newBasinNumber: number) {
+        if (newBasinNumber >= this._bassins.length) {
+            throw new Error(`PreBarrage.moveBasin: cannot make it #${newBasinNumber}, there are only ${this._bassins.length} basins`);
+        }
+        const tmp: Nub[] = [];
+        // find position of basin currently occupying #newBasinNumber, in _children array
+        const newPosition = this.findChildPosition(this._bassins[newBasinNumber].uid);
+        // find basin to move and its current position
+        const { child, position } = this.findChildAndPosition(uid);
+        if (position > newPosition) {
+            // move up:
+            // insert slice [0 - newPosition[
+            for (let i = 0; i < newPosition; i++) {
+                tmp.push(this._children[i]);
+            }
+            // insert basin
+            tmp.push(child);
+            // insert slice [newPosition - position[
+            for (let i = newPosition; i < position; i++) {
+                tmp.push(this._children[i]);
+            }
+            // insert slice ]position, end]
+            for (let i = position + 1; i < this._children.length; i++) {
+                tmp.push(this._children[i]);
+            }
+            this._children = tmp;
+        } else if (position < newPosition) {
+            // move down:
+            // @TODO should we also move down all walls connected to the moving basin, so that
+            // they are still declared after it and not before ?
+
+            // insert slice [0 - position[
+            for (let i = 0; i < position; i++) {
+                tmp.push(this._children[i]);
+            }
+            // insert slice ]position, newPosition[
+            for (let i = position + 1; i < newPosition + 1; i++) {
+                tmp.push(this._children[i]);
+            }
+            // insert basin
+            tmp.push(child);
+            // insert slice [newPosition - end]
+            for (let i = newPosition + 1; i < this._children.length; i++) {
+                tmp.push(this._children[i]);
+            }
+            this._children = tmp;
+        } // else already at the right position, do nothing
+        this.updatePointers();
+    }
+
+    /**
+     * Effectue une série de calculs sur un paramètre; déclenche le calcul en chaîne
+     * des modules en amont si nécessaire
+     * @param rInit solution approximative du paramètre
+     */
+    public CalcSerie(rInit?: number): Result {
+        this._precision = Math.max(5E-4, SessionSettings.precision);
+        return super.CalcSerie(rInit);
+    }
+
+    public Calc(sVarCalc: string, rInit?: number): Result {
+        // check elevations before calculating
+        const cgResult = this.checkGeometry();
+        if (cgResult.resultElement.hasErrorMessages()) {
+            this._result = cgResult;
+            return this.result;
+        }
+
+        const res = super.Calc(sVarCalc, rInit);
+        // calculate basins so that they have a proper .result
+        for (const b of this._bassins) {
+            b.Calc();
+        }
+        // calculate Q on all walls so that their result shows Q and not Z1
+        for (const c of this._children) {
+            if (c instanceof PbCloison) {
+                c.finalCalc();
+            }
+        }
+
+        // copy warnings issued by checkGeometry, if any
+        for (const m of cgResult.resultElement.log.messages) {
+            if (m.getSeverity() !== MessageSeverity.ERROR) {
+                this._result.resultElement.log.add(m);
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * Calcul de Z1 pour une valeur fixe des paramètres
+     * @param sVarCalc ignoré: Z1 uniquement
+     */
+    public Equation(sVarCalc: string): Result {
+        // Initialisation des cotes sur les bassins et la CL amont
+        if (this.isMeshed()) {
+            for(const b of this.bassins) {
+                const zB = b.getMinZDV();
+                if(zB !== undefined) {
+                    b.Z = Math.max(zB, b.prms.ZF.v) + 1;
+                } else {
+                    b.Z = b.prms.ZF.v + 1;
+                }
+            }
+            const Z1 = this.getMinZDV(this.cloisonsAmont);
+            if(Z1 !== undefined) {
+                this.prms.Z1.v = Math.max(Z1, this.bassins[0].Z) + 1;
+            } else {
+                this.prms.Z1.v = this.bassins[0].Z + 1;
+            }
+        } else {
+            // On a le même débit dans tous les bassins et Cloisons
+            for (const child of this.children) {
+                if (child instanceof PbBassin) {
+                    child.Q = this.prms.Q.v;
+                } else {
+                    child.prms.Q.v = this.prms.Q.v;
+                }
+            }
+        }
+        let iter: number = this.maxIterations;
+        let bConverged;
+        // const tZ1: IPbBassinZstat[] = [];
+        // const tQ: number[][] = [];
+        while (iter-- > 0) {
+            this._relax = Math.pow(iter / this.maxIterations, 3) * 0.25 + 0.05;
+            this.debug(`***** Iteration n°${iter} relax=${this._relax} *****`);
+            bConverged = true;
+            if (this.isMeshed()) {
+                // Balayage amont-aval: distribution des débits
+                this.debug("*** Calcul des Q amont --> aval ***")
+                // Répartition cloisons amont du PB
+                // tQ.push(this.CalcQ(this.cloisonsAmont, this.prms.Q.v));
+                this.CalcQ(this.cloisonsAmont, this.prms.Q.v);
+                // Répartition pour chaque bassin sens amont-aval
+                // TODO s'assurer du sens amont-aval des bassins dans this.children
+                for (const b of this.bassins) {
+                    this.debug("Bassin n°" + this.getIndexForChild(b))
+                    this.CalcQ(b.cloisonsAval, b.CalcQ());
+                }
+            }
+            // Balayage aval-amont: Calcul des cotes amont des cloisons
+            this.debug("*** Calcul des Z aval --> amont ***")
+            for (let i = this.bassins.length - 1; i >= 0; i--) {
+                this.debug("Bassin "+ i);
+                const zStat = this.bassins[i].CalcZ();
+                bConverged = bConverged && (zStat.max - zStat.min) < this._precision;
+            }
+            this.debug("Cloison amont");
+            const z1stat = this.CalcZ1Cloisons(this.cloisonsAmont);
+            this.prms.Z1.v = z1stat.moy;
+            // tZ1.push(z1stat);
+            bConverged = bConverged && (z1stat.max - z1stat.min) < this._precision
+            if(bConverged) {
+                break;
+            }
+        }
+        // console.debug(tQ);
+        // console.debug(tZ1);
+        const r = new Result(this.prms.Z1.v);
+        if(!bConverged) {
+            r.resultElement.addMessage(new Message(MessageCode.ERROR_PREBARRAGE_NON_CONVERGENCE, {
+                lastApproximation: this.prms.Z1.v
+            }));
+        }
+        return r;
+    }
+
+    /**
+     * Checks pass geometry before calculation; adds relevant log messages
+     */
+    protected checkGeometry(): Result {
+        // A. error throwing cases: cannot calculate
+        // each basin must have at least one upstream wall and one downstream wall
+        for (const b of this._bassins) {
+            if (b.cloisonsAmont.length === 0 || b.cloisonsAval.length === 0) {
+                throw new Error(
+                    `PreBarrage.checkGeometry(): basin ${b.findPositionInParent()} (starting at 0) must have at least one upstream wall (has ${b.cloisonsAmont.length}) and one downstream wall (has ${b.cloisonsAval.length})`
+                );
+            }
+        }
+        // PreBarrage must have an upstream wall and a downstream wall
+        if (this.cloisonsAmont.length === 0 /* || this.cloisonsAval.length === 0 */) {
+            throw new Error(
+                `PreBarrage.checkGeometry(): must have at least one upstream wall (has ${this.cloisonsAmont.length})` /* + ` and one downstream wall (has ${b.cloisonsAval.length})` */
+            );
+        }
+        // PreBarrage must have at least one path from upstream to downstream
+        if (! this.hasUpDownConnection()) {
+            throw new Error("PreBarrage.checkGeometry(): must have at least one path from upstream to downstream");
+        }
+
+        // B. messages generating cases: calculation goes on
+        const res = new Result(new ResultElement(), this);
+        // downstream water elevation > upstream water elevation ?
+        if (this.prms.Z2.v > this.prms.Z1.v) {
+            res.resultElement.log.add(new Message(MessageCode.ERROR_PREBARRAGE_Z2_SUP_Z1));
+        }
+        // for each basin: is apron elevation > upstream water elevation ?
+        for (const b of this._bassins) {
+            if (b.prms.ZF.v > this.prms.Z1.v) {
+                const m = new Message(MessageCode.WARNING_PREBARRAGE_BASSIN_ZF_SUP_Z1);
+                m.extraVar.n = String(b.findPositionInParent() + 1);
+                res.resultElement.log.add(m);
+            }
+        }
+        // for each device of each wall: is ZDV < ZF of upstream basin ?
+        for (const b of this.bassins) {
+            for (const c of b.cloisonsAval) {
+                for (const s of c.structures) {
+                    if (s.prms.ZDV.v < b.prms.ZF.v) {
+                        const m = new Message(MessageCode.ERROR_PREBARRAGE_STRUCTURE_ZDV_INF_ZF);
+                        m.extraVar.ns = String(s.findPositionInParent() + 1);
+                        const desc = c.description;
+                        m.extraVar.cub = desc.extraVar.ub;
+                        m.extraVar.cdb = desc.extraVar.db;
+                        res.resultElement.log.add(m);
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    protected setParametersCalculability() {
+        this.prms.Z1.calculability = ParamCalculability.EQUATION;
+        this.prms.Z2.calculability = ParamCalculability.FREE;
+        this.prms.Q.calculability = ParamCalculability.DICHO;
+    }
+
+    protected adjustChildParameters(child: (PbCloison | PbBassin)) {
+        this.updatePointers();
+    }
+
+    /** Clears basins list then builds it again fom children list */
+    public updatePointers() {
+        this._bassins = [];
+        this.cloisonsAmont = [];
+        for (const c of this.children) {
+            if (c.calcType === CalculatorType.PbBassin) {
+                this._bassins.push(c as PbBassin);
+            } else if (c instanceof PbCloison) {
+                if (c.bassinAmont === undefined) {
+                    this.cloisonsAmont.push(c);
+                }
+                if (c.bassinAmont !== undefined) {
+                    if (! c.bassinAmont.cloisonsAval.includes(c)) {
+                        c.bassinAmont.cloisonsAval.push(c);
+                    }
+                }
+                if (c.bassinAval !== undefined) {
+                    if (! c.bassinAval.cloisonsAmont.includes(c)) {
+                        c.bassinAval.cloisonsAmont.push(c);
+                    }
+                }
+            }
+        }
+    }
+
+    private isMeshed(): boolean {
+        if (this.cloisonsAmont.length > 1) {
+            return true;
+        }
+        for (const bassin of this.bassins) {
+            if (bassin.cloisonsAval.length > 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private CalcQ(cloisons: PbCloison[], QT: number) {
+        // Calculation of repartition regarding actual water elevations
+        let QT2: number = 0;
+        for (const c of cloisons) {
+            c.prms.Q.initValue = c.prms.Q.v;
+            c.Calc("Q");
+            // Relax! On ne prend pas toute la modification proposée !
+            if(c.prms.Q.v > 0) {
+                c.prms.Q.v = (1 - this._relax) * c.prms.Q.initValue + this._relax * c.prms.Q.v;
+                QT2 += c.prms.Q.v;
+            }
+            if(this.DBG) {this.debug(`CalcQ: Q=${c.prms.Q.v} Z1=${c.prms.Z1.v} Z2=${c.prms.Z2.v}`);}
+        }
+        if(this.DBG) {this.debug(`CalcQ: QT=${QT} QT2=${QT2}`);}
+        // Adjustement of each Q in order to get the good sum
+        const adjustCoef = QT / QT2;
+        // const tQ: number[] = [];
+        for (const c of cloisons) {
+            if(c.prms.Q.v >= 0) {
+                if(QT2 !== 0) {
+                    c.prms.Q.v = c.prms.Q.v * adjustCoef;
+                } else {
+                    c.prms.Q.v = QT / cloisons.length;
+                }
+            }
+            // tQ.push(c.prms.Q.v)
+            this.debug("CalcQ: Qc=" + c.prms.Q.v);
+        }
+        // return tQ;
+    }
+
+    public CalcZ1Cloisons(cloisons: PbCloison[]): IPbBassinZstat {
+        const zStat: IPbBassinZstat = {moy : 0, min: Infinity, max: -Infinity};
+        let n: number = 0;
+        for (const c of cloisons) {
+            let Z1: number;
+            if(c.prms.Q.v >= 1E-6) {
+                Z1 = c.Calc("Z1").vCalc;
+                zStat.moy += Z1;
+                n++;
+                this.debug(`CalcZ1Cloisons: n°${n} Z1=${Z1} Q=${c.prms.Q.v} Z2=${c.prms.Z2.v}`);
+            } else {
+                // Nul flow in submerged flow: Z1 = Z2
+                c.updateZ1Z2();
+                if(c.prms.Z2.v > c.getMinZDV()) {
+                    Z1 = c.prms.Z2.v;
+                    zStat.moy += Z1;
+                    n++;
+                } else {
+                    c.prms.Q.v = 0;
+                }
+            }
+            if(Z1 !== undefined) {
+                zStat.min = Math.min(zStat.min, Z1);
+                zStat.max = Math.max(zStat.max, Z1);
+            }
+        }
+        if(n > 0) {
+            zStat.moy = zStat.moy / n;
+        } else {
+            // Nul flow on all cloisons which are all in free flow => Z1 = ZminZDV
+            zStat.moy = this.getMinZDV(cloisons)
+            zStat.min = zStat.moy;
+            zStat.max = zStat.moy;
+        }
+        this.debug(`CalcZ1Cloisons: Z= ${zStat.moy} [${(zStat.max-zStat.min)}]`);
+        return zStat;
+    }
+
+    public getMinZDV(cloisons: PbCloison[]): number {
+        let minZDV: number;
+        for(const c of cloisons) {
+            const minZDVCloison = c.getMinZDV();
+            if(minZDVCloison !== undefined) {
+                if(minZDV === undefined) {
+                    minZDV = minZDVCloison
+                } else {
+                    minZDV = Math.min(minZDV, minZDVCloison);
+                }
+            }
+        }
+        return minZDV;
+    }
+
+    /**
+     * Fills the current Nub with parameter values, provided an object representation
+     * @param obj object representation of a Nub content (parameters)
+     * @returns the calculated parameter found, if any - used by child Nub to notify
+     *          its parent of the calculated parameter to set
+     */
+    public loadObjectRepresentation(obj: any): { p: ParamDefinition, hasErrors: boolean, changedUids: { [key: string]: string } } {
+        // return value
+        const ret = super.loadObjectRepresentation(obj);
+        // propagate changed UIDs to walls properties
+        for (const c of this._children) {
+            if (c instanceof PbCloison) {
+                for (const k of Object.keys(ret.changedUids)) {
+                    // find basins having the changed UID
+                    if (c.properties.props.upstreamBasin === k) {
+                        c.bassinAmont = this.findChild(ret.changedUids[k]) as PbBassin;
+                    }
+                    if (c.properties.props.downstreamBasin === k) {
+                        c.bassinAval = this.findChild(ret.changedUids[k]) as PbBassin;
+                    }
+                }
+            }
+        }
+        return ret;
+    }
+}
diff --git a/src/prebarrage/pre_barrage_params.ts b/src/prebarrage/pre_barrage_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5caa0784ccbf487739e5c8b9945131d5a68eaaa9
--- /dev/null
+++ b/src/prebarrage/pre_barrage_params.ts
@@ -0,0 +1,25 @@
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../param/params-equation";
+
+export class PreBarrageParams 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;
+
+    constructor(rQ: number, rZ1: number, rZ2: number) {
+        super();
+        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, "m³/s", rQ, ParamFamily.FLOWS);
+        this.addParamDefinition(this.Q);
+        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, "m", rZ1, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.Z1);
+        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, "m", rZ2, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.Z2);
+    }
+}
diff --git a/src/session.ts b/src/session.ts
index 6ca04b6029a8ecea1f85435a39590acfb0746729..dc54dd53b3644558c5035e745bbafe0ab426dc08 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -81,6 +81,11 @@ import { Espece } from "./verification/espece";
 import { EspeceParams } from "./verification/espece_params";
 import { Verificateur } from "./verification/verificateur";
 import { DivingJetSupport } from "./verification/diving-jet-support";
+import { PreBarrage } from "./prebarrage/pre_barrage";
+import { PreBarrageParams } from "./prebarrage/pre_barrage_params";
+import { PbCloison } from "./prebarrage/pb_cloison";
+import { PbBassin } from "./prebarrage/pb_bassin";
+import { PbBassinParams } from "./prebarrage/pb_bassin_params";
 
 export class Session {
 
@@ -422,7 +427,7 @@ export class Session {
 
             case CalculatorType.Structure:
                 const loiDebit: LoiDebit = params.getPropValue("loiDebit");
-                nub = CreateStructure(loiDebit, (parentNub as ParallelStructure));
+                nub = CreateStructure(loiDebit, (parentNub as ParallelStructure), dbg);
                 break;
 
             case CalculatorType.ParallelStructure:
@@ -535,7 +540,7 @@ export class Session {
                         0.4,    // D
                         0.4,    // k
                         1.2     // Cd0
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -548,7 +553,7 @@ export class Session {
                         29.2,   // ZW
                         28.5,   // ZF
                         3       // D
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -571,7 +576,7 @@ export class Session {
                         0.5,        // Ob
                         0.1,        // OEntH
                         4           // cIncl
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -582,7 +587,7 @@ export class Session {
                         99.5,       // Z2
                         10,         // L
                         0.15        // I
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -656,7 +661,7 @@ export class Session {
                         5,     // Nombre de motifs
                         4.9,   // Largeur de la passe
                         0.35   // Diamètre des plots
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -673,7 +678,7 @@ export class Session {
                         0.1,    // a
                         1,      // N
                         1       // M
-                    )
+                    ), dbg
                 );
                 break;
 
@@ -694,7 +699,17 @@ export class Session {
                         0.1,        // a
                         1,          // N
                         1           // M
-                    )
+                    ), dbg
+                );
+                break;
+
+            case CalculatorType.PreBarrage:
+                nub = new PreBarrage(
+                    new PreBarrageParams(
+                        1,      // Q
+                        101,    // Z1
+                        100     // Z2
+                    ), dbg
                 );
                 break;
 
@@ -724,6 +739,17 @@ export class Session {
                 nub = new Verificateur();
                 break;
 
+            case CalculatorType.PbBassin:
+                nub = new PbBassin(new PbBassinParams(
+                    10,  // S
+                    100  // ZF
+                ), dbg);
+                break;
+
+            case CalculatorType.PbCloison:
+                nub = new PbCloison(undefined, undefined);
+                break;
+
             default:
                 throw new Error(
                     `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge`
@@ -749,19 +775,15 @@ export class Session {
      * Returns true if given uid is already used by a Nub in this session,
      * or a Structure nub inside one of them
      */
-    public uidAlreadyUsed(uid: string): boolean {
+    public uidAlreadyUsed(uid: string, nubs: Nub[] = this._nubs): boolean {
         let alreadyUsed = false;
-        outerLoop:
-        for (const n of this._nubs) {
+        for (const n of nubs) {
             if (n.uid === uid) {
                 alreadyUsed = true;
-                break outerLoop;
+                break;
             }
-            for (const s of n.getChildren()) {
-                if (s.uid === uid) {
-                    alreadyUsed = true;
-                    break outerLoop;
-                }
+            if (! alreadyUsed) {
+                alreadyUsed = this.uidAlreadyUsed(uid, n.getChildren());
             }
         }
         return alreadyUsed;
diff --git a/src/structure/dever.ts b/src/structure/dever.ts
index 764b90a25d96843ef6654a69a8bf6c074235353f..44efef9c86957cc1ae48d18aca6480b52718b040 100644
--- a/src/structure/dever.ts
+++ b/src/structure/dever.ts
@@ -82,7 +82,7 @@ export class Dever extends ParallelStructure {
             let r: Result;
             let i: number = SessionSettings.maxIterations;
             do {
-                if (r !== undefined && r.ok) { this.prms.Q.v = r.vCalc; }
+                if (r?.ok) { this.prms.Q.v = r.vCalc; }
                 r = super.CalcQ(iExcept);
                 i--;
             } while (i && Math.abs(r.vCalc - this.prms.Q.v) > SessionSettings.precision);
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index 25d720163a3f7625236296837af856e3698cc1a3..446bc1e0fa0a1d3f89a4ba4671792dc18ff13865 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -7,6 +7,7 @@ import { Result } from "../util/result";
 import { ParallelStructureParams } from "./parallel_structure_params";
 import { Structure } from "./structure";
 import { loiAdmissiblesOuvrages, LoiDebit } from "./structure_props";
+import { MessageCode, Message } from "../util/message";
 
 /**
  * Calcul de une ou plusieurs structures hydrauliques en parallèles
@@ -62,6 +63,21 @@ export class ParallelStructure extends Nub {
         return lois[Object.keys(lois)[0]][0];
     }
 
+    /**
+     * Effectue une série de calculs sur un paramètre; déclenche le calcul en chaîne
+     * des modules en amont si nécessaire
+     * Surcharge pour les tests préalables liés à la structure du nub
+     * @param rInit solution approximative du paramètre
+     */
+    public CalcSerie(rInit?: number): Result {
+        if (this.structures.length === 0) {
+            this._result = new Result(undefined, this);
+            this._result.globalLog.insert(new Message(MessageCode.ERROR_STRUCTURE_AU_MOINS_UNE));
+            return this._result;
+        }
+        return super.CalcSerie(rInit);
+    }
+
     /**
      * Calcul du débit des structures en parallèle (sans détail pour chaque structure)
      * @param sVarCalc Variable à calculer (Q uniquement)
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index 1797f8a421bd09e531498eddd726b2ad5196f068..d222bef99dde983a007e2b2b5a78ca90f00b5947 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -5,7 +5,8 @@ import { Props } from "../props";
 import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
 import { StructureParams } from "./structure_params";
-import { LoiDebit } from "./structure_props";
+import { LoiDebit, StructureProperties } from "./structure_props";
+import { ParallelStructure } from "./parallel_structure";
 
 /**
  * Flow mode: weir or orifice flow
@@ -75,11 +76,14 @@ export abstract class Structure extends ChildNub {
 
     /** Returns Props object (observable set of key-values) associated to this Nub */
     public get properties(): Props {
-        // completes props with calcType and loiDebit if not already set
+        // completes props with calcType, structureType and loiDebit if not already set
         this._props.setPropValue("calcType", this.calcType);
         if (this._props.getPropValue("loiDebit") === undefined) {
             this._props.setPropValue("loiDebit", this._loiDebit);
         }
+        if (this._props.getPropValue("structureType") === undefined) {
+            this._props.setPropValue("structureType", StructureProperties.findCompatibleStructure(this._props.getPropValue("loiDebit"), this.parent as ParallelStructure));
+        }
         return this._props;
     }
 
@@ -338,4 +342,7 @@ export abstract class Structure extends ChildNub {
         };
     }
 
+    public getFirstAnalyticalParameter() {
+        return this.prms.Q;
+    }
 }
diff --git a/src/structure/structure_props.ts b/src/structure/structure_props.ts
index 59794f0c0046c11f7175269e62c474bbdd5c42dc..3197ef4b5c891dd3e9f0b6a8b48017d639f07c4c 100644
--- a/src/structure/structure_props.ts
+++ b/src/structure/structure_props.ts
@@ -134,7 +134,7 @@ export class StructureProperties {
 
     /**
      * @return la 1ère valeur de StructureType compatible avec la loi de débit, dans le contexte
-     * du module de calcul parentNub
+     * du module de calcul parentNub @TODO la 1ère ? normalement il n'y en a qu'une !
      */
     public static findCompatibleStructure(loi: LoiDebit, parentNub: ParallelStructure): StructureType {
         const loisAdmissibles = parentNub.getLoisAdmissibles();
diff --git a/src/util/message.ts b/src/util/message.ts
index 04dc71da0665a7e26ad87d474630f4cd12b57a9c..cef0877ac5c509e48cf9b5760d3988a76b55cdb0 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -343,6 +343,12 @@ export enum MessageCode {
      */
     WARNING_REMOUS_ARRET_CRITIQUE,
 
+    /** Baqssin d'un PréBarrage : description (numéro d'ordre %order%) */
+    INFO_PB_BASSIN_DESCRIPTION,
+
+    /** Cloison d'un PréBarrage : description (bassin amont %ub%, bassin aval %db%) */
+    INFO_PB_CLOISON_DESCRIPTION,
+
     /**
      * courbe de remous : Condition limite aval >= Hauteur critique : calcul de la partie fluviale à partir de l'aval
      */
@@ -485,6 +491,11 @@ export enum MessageCode {
      */
     ERROR_STRUCTURE_Z_EGAUX_Q_NON_NUL,
 
+    /**
+     * Il faut au moins un ouvrage dans une structure
+     */
+    ERROR_STRUCTURE_AU_MOINS_UNE,
+
     /** On essaye d'appliquer une puissance non entière à un nombre négatif */
     ERROR_NON_INTEGER_POWER_ON_NEGATIVE_NUMBER,
 
@@ -643,7 +654,21 @@ export enum MessageCode {
     INFO_PARENT_PREFIX,
 
     /** downwall : */
-    INFO_PARENT_PREFIX_DOWNWALL
+    INFO_PARENT_PREFIX_DOWNWALL,
+
+    /**
+     * Pré-barrage : non convergence du calcul
+     */
+    ERROR_PREBARRAGE_NON_CONVERGENCE,
+
+    /** Pré-barrage : cote de l'eau aval supérieure à la cote de l'eau amont */
+    ERROR_PREBARRAGE_Z2_SUP_Z1,
+
+    /** Pré-barrage : cote de fond du bassin %n% supérieure à la cote de l'eau amont */
+    WARNING_PREBARRAGE_BASSIN_ZF_SUP_Z1,
+
+    /** Pré-barrage : cote de radier de l'ouvrage %ns% inférieure à la cote de fond du bassin amont de la cloison %nc% */
+    ERROR_PREBARRAGE_STRUCTURE_ZDV_INF_ZF
 }
 
 /**