diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d48ad122a7f16fd3ee155b21bb02fedf1785fad..1668f39737f828af5c645af6b139fd77e321f9d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,33 @@
+nghyd_4.17.0 - 2023-05-30
+===================
+
+new features
+------------
+
+* Structure : ajout d'une erreur sur l'ennoiement (#302)
+* Courbe de remous : rendre facultatif l'une des deux conditions limites en cote (#343)
+* Conduites en charge : ajout de la loi de Strickler (#215)
+* Courbe de remous : calculer une courbe de remous de passe à macro-rugosités (#325)
+* Courbe de remous : renommer la ligne d'eau en ZW et fournir le tirant d'eau d'après celle ci (#333)
+
+bug fixes
+---------
+
+* Solveur multimodule : le module existe toujours après suppression (#342)
+* Structure : résultat du calcul de la cote amont dépendant de la cote initiale pour un débit nul (#219)
+* Un paramètre cible d'un lien ne doit pas se lier à un autre paramètre (#341)
+* Passe à macro-rugosités : des champs ne sont pas liables avec le module "Concentration de blocs" (#345)
+* Courbe de remous : NaN produit lors d'un fuzzy test (#339)
+* les résultats ne sont pas réinitialisés quand on modifie des paramètres globaux (#331)
+
+changes
+-------
+
+* Restructuration de Lechapt et Calmon pour de nouvelles lois de pertes de charge (#334)
+* Optimisation de l'affichage des unités (#338)
+* Passe à macro-rugosités : la largeur conseillée doit avoir un cm de tolérance (#344)
+* Fusionner les "select" avec "source" et les "select_custom" (#328)
+
 nghyd_4.16.2 - 2023-01-10
 ===================
 
diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index dc88947ee05a50ac270702f0ef0936427e9bf656..1445aaa321f27fa6222c85339e7a656a979afff6 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -19,7 +19,7 @@ JaLHyd offers **calculation modules** also called **Nub**s, that are each respon
 
 #### calculator type
 
-Each Nub must have a **calculator type**, that is an item of the `CalculatorType` enum. It is stored in `this._calcType` and must be defined in the Nub's constructor.
+Each Nub must have a **calculator type**, that is an item of the `CalculatorType` enum. It is stored in the `calcType` property and must be defined in the properties passed to the Nub `setProperties` method.
 
 #### calculated parameter
 
@@ -51,7 +51,7 @@ To be calculated, a Nub might require the results of one or more other Nubs. See
 
 Parameters are objects that represent the input/outputs of a Nub's equation. All the parameters of a given Nub must be grouped in an object derived from `ParamsEquation`, (ex: `CloisonsParams` for Nub `Cloisons`). Only one parameter at a time may be the **calculated parameter** of its Nub; its value is computed based on the fixed values of other parameters.
 
-A parameter is characterized by a **symbol** (ex: "Q"), a **definition domain** (from the `ParamDomainValue` enum, or a free interval), a **unit** (for display purposes only, ex: "m³/s"), an **initial value**, a **family** (see "Links" below), and a **visibility** (for display purposes only).
+A parameter is characterized by a **symbol** (ex: "Q"), a **definition domain** (from the `ParamDomainValue` enum, or a free interval), a **unit** (for display purposes only, ex: "m³/s"), an **initial value**, a **family** (see "Links" below), its **calculability**, a **mode** and a **visibility** (for display purposes only).
 
 #### calculability
 
@@ -103,7 +103,7 @@ Parameters are grouped into **families**, indicating that they may be linked to
 
 A **property** is an attribute of a Nub that is not numerical and/or accepts only values from a limited set. It is thus distinct from a **parameter**. Usually they are bound to enums, through `Session.enumFromProperty`. Example: "trigoOperation" in `Trigo` that only accepts items from `TrigoOperation` enum.
 
-Properties are stored in `this.properties`. Not all Nubs have properties. Those who do should set a default value for each property in their constructor, through a call to `this.properties.setPropValue()`.
+Properties are stored in `this._props_` and accessed by client code through `getPropValue`/`setPropValue` methods. Not all Nubs have properties. Those who do should set a default value for each property in their constructor, through a call to `this.setPropValue()`.
 
 Properties are **observable** objects: subscribing to a Nub's properties through `addObserver()` method guarantees to be informed of a property value change through the `update()` method of the `Observer` interface.
 
@@ -119,9 +119,9 @@ Otherwise, when no parameter is varying there is exactly one result element, and
 
 #### result elements
 
-A `ResultElement` is an object that contains a main calculated value `.vCalc`, optional additional calculated values stored as key-value pairs in `.values` (often referred to as "extra results"), and a calculation log concerning this calculation step only.
+A `ResultElement` is an object that contains a main calculated value `vCalc`, optional additional calculated values stored as key-value pairs in `values` (often referred to as "extra results"), and a calculation log concerning this calculation step only.
 
-A result element is `.ok` if it has a value and no error-level message.
+The result element state (returned by `ok` getter) is true if it has a value and no error-level message.
 
 #### families
 
@@ -129,13 +129,13 @@ Results families allow results to be linked to parameters of the same **family**
 
 ### Log
 
-A **log** is a collection of `Messages` objects used to inform about events during the calculation process.
+A **log** is a collection of `Message` objects used to inform about events during the calculation process.
 
-Every result element has a log, and the `Result` object has an additional `.globalLog`.
+Every result element has a log, and the `Result` object has an additional `globalLog`.
 
 #### messages
 
-A **message** is an object containing a `MessageCode` that describes the issue, along with optional key-value pairs stored in `.extraVars`. The message severity `INFO`, `WARNING` or `ERROR` is inferred from the message code string prefix.
+A **message** is an object containing a `MessageCode` that describes the issue, along with optional key-value pairs stored in `extraVars`. The message severity `INFO`, `WARNING` or `ERROR` is inferred from the message code string prefix.
 
 ### Links
 
@@ -215,7 +215,7 @@ Note the **mandatory** call to `this.addParamDefinition()` and getter method for
 
 #### Nub class
 
-In `addition.ts`, create and export a new class named `Addition`:
+In `addition.ts`, create and export a new class named `Addition` that extends Nub class:
 ```typescript
 import { CalculatorType } from "../compute-node";
 import { Nub } from "../nub";
@@ -361,6 +361,8 @@ export * from "./addition";
 export * from "./addition_params";
 ```
 
+Also add exports in `internal_modules.ts` for the new classes, as index.ts should not be used in JalHyd to avoid the "TypeError: Class extends value undefined is not a constructor or null" error (internal module pattern).
+
 ## Further considerations for adding more complex modules
 
 ### properties
@@ -371,7 +373,7 @@ If the module uses **properties**, one should add a default value in the Nub's c
 constructor(prms: TrigoParams, dbg: boolean = false) {
   …
   this._props.addObserver(this);
-  this.properties.setPropValue("trigoOperation", TrigoOperation.COS);
+  this.setPropValue("trigoOperation", TrigoOperation.COS);
 }
 ```
 
@@ -387,12 +389,12 @@ public update(sender: any, data: any) {
 }
 ```
 
-Update property-enum associations list in `src/app/formulaire/elements/select-field.ts` (example for operation property in Trigo module)
+Update property-enum associations list in `src/props.ts` (example for operation property in Trigo module)
 
 ```typescript
 public static enumFromProperty = {
   …
-  "trigoOperation": TrigoOperation
+  trigoOperation: TrigoOperation
 };
 ```
 
@@ -415,12 +417,12 @@ function setRandomTrigoOperation(sn: Trigo) {
 
 ### Nubs with children
 
-If a module has children, the `childrenType` attribute should be set in the Nub's constructor. This attribute is used for translation in GUIs, notably ngHyd. Example from `MacroRugoCompound`:
+If a module has children, the `intlType` attribute should be set in the Nub's constructor. This attribute is used for translation in GUIs, notably ngHyd. Example from `MacroRugoCompound`:
 
 ```typescript
 constructor(prms: MacrorugoCompoundParams, dbg: boolean = false) {
   …
-  this._childrenType = "MacroRugo";
+  this._intlType = "MacroRugo";
 ```
 
 When implementing parent's `Equation()` method, children should be calculated using `Calc()` and not `Equation()` or `Solve()`, so that their logs and results are properly attached to them.
diff --git a/boilerplate/ts/src/boilerplate.ts b/boilerplate/ts/src/boilerplate.ts
index 4c8587c6e14765e139c229a9c02d5b82934252b0..5421d43e8cad7b288b749d5847993efa810fda65 100644
--- a/boilerplate/ts/src/boilerplate.ts
+++ b/boilerplate/ts/src/boilerplate.ts
@@ -7,20 +7,15 @@ import {
     formattedValue,
     LoiDebit,
     Props,
-    Session
+    Session,
+    Cloisons,
+    PabChute,
+    PabNombre,
+    PabPuissance,
+    PabDimension,
+    RectangularStructure
 } from "jalhyd";
 
-/**
- * Not all classes are exported through index.d.ts, prefer importing
- * classes using full path
- */
-import { Cloisons } from "jalhyd/build/pab/cloisons";
-import { PabChute } from "jalhyd/build/pab/pab_chute";
-import { PabDimension } from "jalhyd/build/pab/pab_dimension";
-import { PabNombre } from "jalhyd/build/pab/pab_nombre";
-import { PabPuissance } from "jalhyd/build/pab/pab_puissance";
-import { RectangularStructure } from "jalhyd/build/structure/rectangular_structure";
-
 // ---- example of modules setup and calculation : fish ladder ----
 
 const pabChute = Session.getInstance().createSessionNub(
diff --git a/package-lock.json b/package-lock.json
index 81da99e6e87b129e1a01de03ad740f4ac6ecb94a..3726cb5715387e4d42ea6cae09b51acc3512d829 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
       "license": "LGPL-3.0-or-later",
       "dependencies": {
         "@types/base-64": "^1.0.0",
+        "@types/lodash": "^4.14.191",
         "base-64": "^1.0.0"
       },
       "devDependencies": {
@@ -284,6 +285,11 @@
       "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
       "dev": true
     },
+    "node_modules/@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+    },
     "node_modules/@types/node": {
       "version": "18.0.3",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
@@ -2777,6 +2783,11 @@
       "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
       "dev": true
     },
+    "@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+    },
     "@types/node": {
       "version": "18.0.3",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
diff --git a/package.json b/package.json
index 01d22ed74231dc3a8f8113a703c00815a64fb564..0b8cfecc6d68330f4db0e94ed0f798ee2a22bf0a 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
   "module": "build/index.js",
   "dependencies": {
     "@types/base-64": "^1.0.0",
+    "@types/lodash": "^4.14.191",
     "base-64": "^1.0.0"
   },
   "devDependencies": {
diff --git a/spec/fuzzing.spec.ts b/spec/fuzzing.spec.ts
index a10ea3a49282740f73eedd5c76000adcd2fb204a..6642d0c07ca2363d1510da182fc08f2a14cecbcd 100644
--- a/spec/fuzzing.spec.ts
+++ b/spec/fuzzing.spec.ts
@@ -1,5 +1,5 @@
 import { CalculatorType } from "../src/compute-node";
-import { Grille, ParamDomainValue, Session, SPP, YAXN, YAXNParams, Par, ParSimulation, ParSimulationParams } from "../src/index";
+import { Grille, ParamDomainValue, Session, SPP, YAXN, YAXNParams, Par, ParSimulation, PressureLoss, PL_LechaptCalmonParams, PL_LechaptCalmon, PL_StricklerParams, PL_Strickler } from "../src/index";
 import { MacrorugoCompound } from "../src/macrorugo/macrorugo_compound";
 import { Trigo, TrigoOperation } from "../src/math/trigo";
 import { Nub } from "../src/nub";
@@ -7,6 +7,7 @@ import { SectionNub } from "../src/open-channel/section/section_nub";
 import { CloisonAval } from "../src/pab/cloison_aval";
 import { Pab } from "../src/pab/pab";
 import { ParamDefinition } from "../src/param/param-definition";
+import { PressureLossLaw, PressureLossType } from "../src/pipe_flow/pressureloss_law";
 import { Props } from "../src/props";
 import { CreateStructure } from "../src/structure/factory_structure";
 import { ParallelStructure } from "../src/structure/parallel_structure";
@@ -45,7 +46,9 @@ const nubsNotTested: CalculatorType[] = [
     CalculatorType.Espece,
     CalculatorType.PbBassin,
     CalculatorType.PbCloison,
-    CalculatorType.PreBarrage // TODO: Add special treatments for creating fuzzy PreBarrage
+    CalculatorType.PreBarrage, // TODO: Add special treatments for creating fuzzy PreBarrage
+    CalculatorType.LechaptCalmon,
+    CalculatorType.PressureLossLaw
 ];
 
 const nubsWithStructures: CalculatorType[] = [
@@ -60,6 +63,10 @@ const nubsWithSection: CalculatorType[] = [
     CalculatorType.CourbeRemous
 ];
 
+const nubsWithPressureLossLaw: CalculatorType[] = [
+    CalculatorType.PressureLoss
+]
+
 const calTypes =
     Object.keys(CalculatorType)
         .filter((key: any) =>
@@ -126,6 +133,33 @@ function setRandomSection(sn: SectionNub) {
     sn.setSection(newSect);
 }
 
+function setRandomPressureLossLaw(pl: PressureLoss) {
+    const pressureLossLaws = [PressureLossType.LechaptCalmon, PressureLossType.Strickler];
+    const i = Math.floor(Math.random() * pressureLossLaws.length);
+    let pll: PressureLossLaw;
+    switch (pressureLossLaws[i]) {
+        case PressureLossType.LechaptCalmon:
+            const lcp = new PL_LechaptCalmonParams(1.863, 2, 5.33); // peu importe les valeurs, elles sont randomisées
+            randomizeParameter(lcp.L);
+            randomizeParameter(lcp.M);
+            randomizeParameter(lcp.N);
+            const lc = new PL_LechaptCalmon(lcp);
+            pll = lc;
+            break;
+
+        case PressureLossType.Strickler:
+            const sp = new PL_StricklerParams(1);
+            randomizeParameter(sp.Ks);
+            const s = new PL_Strickler(sp);
+            pll = s;
+            break;
+
+        default:
+            throw new Error("invalid pressure loss law");
+    }
+    pl.setLaw(pll);
+}
+
 function setRandomTrigoOperation(sn: Trigo) {
     const op = Math.floor(Math.random() * 6);
     sn.operation = op;
@@ -168,7 +202,7 @@ function setPab(pab: Pab, nClMax = 30, nStMax = 3) {
 }
 
 function setMacrorugoCompound(n: MacrorugoCompound) {
-    n.properties.setPropValue("inclinedApron", Math.floor(Math.random() * 2));
+    n.setPropValue("inclinedApron", Math.floor(Math.random() * 2));
 }
 
 function setGrille(g: Grille) {
@@ -180,7 +214,7 @@ function setGrille(g: Grille) {
 
 function CreateTestNub(iCalType: number): Nub {
     const n = Session.getInstance().createNub(
-        new Props({ calcType: iCalType })
+        new Props({ calcType: iCalType, pressureLossType: PressureLossType.LechaptCalmon })
     );
     if (nubsWithStructures.includes(iCalType)) {
         addRandomStructures(n as ParallelStructure, fuzzyCfg.ParallelStructure.structureMax);
@@ -188,8 +222,11 @@ function CreateTestNub(iCalType: number): Nub {
     if (nubsWithSection.includes(iCalType)) {
         setRandomSection(n as SectionNub);
     }
+    if (nubsWithPressureLossLaw.includes(iCalType)) {
+        setRandomPressureLossLaw(n as PressureLoss);
+    }
     if (iCalType === CalculatorType.CourbeRemous) {
-        n.properties.setPropValue(
+        n.setPropValue(
             "methodeResolution",
             Math.floor(Math.random() * 3) // Euler, RK4, Trapèzes
         );
diff --git a/spec/macrorugo/macrorugo.spec.ts b/spec/macrorugo/macrorugo.spec.ts
index 74cb6b1c82e1d9d77ce30c687eddb0451d11af32..5d79f246075e53ebcf56635144282218d16adfd3 100644
--- a/spec/macrorugo/macrorugo.spec.ts
+++ b/spec/macrorugo/macrorugo.spec.ts
@@ -1,4 +1,4 @@
-import { ParamCalculability, ParamValueMode, Session } from "../../src/index";
+import { MessageCode, ParamCalculability, ParamValueMode, Session } from "../../src/index";
 import { MacroRugo, MacroRugoFlowType } from "../../src/macrorugo/macrorugo";
 import { MacrorugoParams } from "../../src/macrorugo/macrorugo_params";
 import { checkResult } from "../test_func";
@@ -242,4 +242,50 @@ describe("Class MacroRugo: ", () => {
             }
         });
     });
+
+    describe("ramp width tolerance should be 1cm", () => {
+        it("", () => {
+            const prms = new MacrorugoParams(
+                12.5,   // ZF1
+                6,      // L
+                2.2,      // B
+                0.05,   // If
+                0.1,    // Q
+                0.6,    // h
+                0.01,   // Ks
+                0.13,   // C
+                0.4,    // D
+                0.6,    // k
+                1     // Cd0
+            );
+            const mr = new MacroRugo(prms);
+            mr.calculatedParam = mr.prms.Q;
+
+            // ramp not wide enough : warning on tolerance (min width=1.109 m)
+
+            prms.B.singleValue = 1.099;
+            let res = mr.CalcSerie();
+            expect(res.log.messages.length).toEqual(1);
+            expect(res.log.messages[0].code).toEqual(MessageCode.WARNING_RAMP_WIDTH_LOWER_THAN_PATTERN_WIDTH);
+
+            // ramp just wide enough for one block pattern : no warning (min width=1.109 m)
+
+            prms.B.singleValue = 1.1;
+            res = mr.CalcSerie();
+            expect(res.log.messages.length).toEqual(0);
+
+            // ramp wide enough : warning on tolerance (B=2.2, closest rounded value=2.219, B-rounded > 0.01)
+
+            prms.B.singleValue = 2.2;
+            res = mr.CalcSerie();
+            expect(res.log.messages.length).toEqual(1);
+            expect(res.log.messages[0].code).toEqual(MessageCode.WARNING_RAMP_WIDTH_NOT_MULTIPLE_OF_HALF_PATTERN_WIDTH);
+
+            // ramp wide enough : no warning (B=2.21, closest rounded value=2.219, B-rounded < 0.01)
+
+            prms.B.singleValue = 2.21;
+            res = mr.CalcSerie();
+            expect(res.log.messages.length).toEqual(0);
+        });
+    });
 });
diff --git a/spec/macrorugo/macrorugo_compound.spec.ts b/spec/macrorugo/macrorugo_compound.spec.ts
index b71376acb302d436b25cd76f991c9b58bdf1ff3e..bc81d33cb2f1ac6490ff32059c8b53939629c890 100644
--- a/spec/macrorugo/macrorugo_compound.spec.ts
+++ b/spec/macrorugo/macrorugo_compound.spec.ts
@@ -1,5 +1,6 @@
 import { CalculatorType } from "../../src/compute-node";
 import { Session } from "../../src/index";
+import { MacrorugoCompoundParams, MessageCode } from "../../src/internal_modules";
 import { MacroRugo } from "../../src/macrorugo/macrorugo";
 import { MacrorugoCompound } from "../../src/macrorugo/macrorugo_compound";
 import { MacrorugoParams } from "../../src/macrorugo/macrorugo_params";
@@ -47,7 +48,7 @@ describe("MacroRugoCompound: ", () => {
             const mr = getMacroRugoRef();
             mr.prms.L.singleValue = mrc.children[0].prms.L.v;
             mr.CalcSerie();
-            compareTwoResults(mrc.children[0].result, mr.result, 3, [ "ZF2" ]);
+            compareTwoResults(mrc.children[0].result, mr.result, 3, ["ZF2"]);
         });
         it("variating Z1, children Y should not always be 0.6", () => {
             const mrc = Session.getInstance().createNub(
@@ -58,7 +59,7 @@ describe("MacroRugoCompound: ", () => {
             mrc.prms.Z1.setValues(10, 15, 5);
             mrc.CalcSerie();
             const childYs = mrc.children[0].prms.Y.getInferredValuesList();
-            expect(childYs).toEqual([ 0, 2.5 ]);
+            expect(childYs).toEqual([0, 2.5]);
         });
     });
     describe("Default inclined but flat apron", () => {
@@ -73,7 +74,7 @@ describe("MacroRugoCompound: ", () => {
                 const mrc = Session.getInstance().createNub(
                     new Props({ calcType: CalculatorType.MacroRugoCompound })
                 ) as MacrorugoCompound;
-                mrc.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+                mrc.setPropValue("inclinedApron", MRCInclination.INCLINED);
                 mrc.prms.BR.singleValue = BR;
                 const mr = getMacroRugoRef();
                 const res = mrc.CalcSerie();
@@ -97,7 +98,7 @@ describe("MacroRugoCompound: ", () => {
             const mrc = Session.getInstance().createNub(
                 new Props({ calcType: CalculatorType.MacroRugoCompound })
             ) as MacrorugoCompound;
-            mrc.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+            mrc.setPropValue("inclinedApron", MRCInclination.INCLINED);
             // width = 4m
             mrc.prms.BR.singleValue = 5;
             // delta Z = 2m
@@ -134,8 +135,72 @@ describe("MacroRugoCompound: ", () => {
             });
             it(`Apron #${i} should return same result as Macrorugo`, () => {
                 const mr = getMacroRugoRef(i);
-                compareTwoResults(mrc2.children[i].result, mr.result, 3, [ "ZF2" ]);
+                compareTwoResults(mrc2.children[i].result, mr.result, 3, ["ZF2"]);
             });
         }
     });
+
+    describe("Ramp width tolerance", () => {
+        it("tolerance should be 1cm", () => {
+            const MRCprms = new MacrorugoCompoundParams(
+                13.1,   // Z1
+                12.5,   // ZRL
+                12.5,   // ZRR
+                60,      // B
+                3,      // DH
+                0.05,   // If
+                0.01,   // RF (Ks)
+                0.13,   // C (concentration de bloc)
+                0.4,    // D (diamètre de bloc)
+                0.4,    // H (hauteur de bloc)
+                1     // Cd0
+            );
+            const mrc = new MacrorugoCompound(MRCprms);
+
+            const MRprms = new MacrorugoParams( // B 1  
+                12.5,   // ZF1
+                6,      // L
+                1,      // B
+                0.05,   // If
+                1.57,    // Q
+                0.6,    // Y
+                0.01,   // Ks
+                0.13,   // C
+                0.4,    // D      
+                0.4,    // H
+                1     // Cd0
+            );
+            mrc.addChild(new MacroRugo(MRprms));
+
+            // ramp not wide enough : warning on tolerance (min width=1.109 m)
+
+            MRprms.B.singleValue = 1.099;
+            mrc.CalcSerie();
+            let res = mrc.children[0].result; // warnings are in the child nub
+            expect(res.log.messages.length).toEqual(1);
+            expect(res.log.messages[0].code).toEqual(MessageCode.WARNING_RAMP_WIDTH_LOWER_THAN_PATTERN_WIDTH);
+
+            // ramp just wide enough for one block pattern : no warning (min width=1.109 m)
+
+            MRprms.B.singleValue = 1.1;
+            mrc.CalcSerie();
+            res = mrc.children[0].result;
+            expect(res.log.messages.length).toEqual(0);
+
+            // ramp wide enough : warning on tolerance (B=2.2, closest rounded value=2.219, B-rounded > 0.01)
+
+            MRprms.B.singleValue = 2.2;
+            mrc.CalcSerie();
+            res = mrc.children[0].result;
+            expect(res.log.messages.length).toEqual(1);
+            expect(res.log.messages[0].code).toEqual(MessageCode.WARNING_RAMP_WIDTH_NOT_MULTIPLE_OF_HALF_PATTERN_WIDTH);
+
+            // ramp wide enough : no warning (B=2.21, closest rounded value=2.219, B-rounded < 0.01)
+
+            MRprms.B.singleValue = 2.21;
+            mrc.CalcSerie();
+            res = mrc.children[0].result;
+            expect(res.log.messages.length).toEqual(0);
+        });
+    });
 });
diff --git a/spec/macrorugo/macrorugo_compound_jalhyd174.spec.ts b/spec/macrorugo/macrorugo_compound_jalhyd174.spec.ts
index ffdc327280fc09bc9f45bfb5b127ae7bc3cdce16..f7178f010cb0db619f578fca8eb18af13920cba8 100644
--- a/spec/macrorugo/macrorugo_compound_jalhyd174.spec.ts
+++ b/spec/macrorugo/macrorugo_compound_jalhyd174.spec.ts
@@ -62,7 +62,7 @@ describe("MacroRugoCompound: ", () => {
             nub = Session.getInstance().createNub(
                 new Props({ calcType: CalculatorType.MacroRugoCompound })
             ) as MacrorugoCompound;
-            nub.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+            nub.setPropValue("inclinedApron", MRCInclination.INCLINED);
             nub.prms.C.singleValue = 0.09; // easy sqrt
             nub.prms.PBD.singleValue = 0.6; // ax = 2
             nub.prms.BR.singleValue = 3;
@@ -82,7 +82,7 @@ describe("MacroRugoCompound: ", () => {
             nub = Session.getInstance().createNub(
                 new Props({ calcType: CalculatorType.MacroRugoCompound })
             ) as MacrorugoCompound;
-            nub.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+            nub.setPropValue("inclinedApron", MRCInclination.INCLINED);
             nub.prms.C.singleValue = 0.09;
             nub.prms.PBD.singleValue = 0.6;
             nub.prms.BR.singleValue = 1.95;
@@ -104,7 +104,7 @@ describe("MacroRugoCompound: ", () => {
             nub = Session.getInstance().createNub(
                 new Props({ calcType: CalculatorType.MacroRugoCompound })
             ) as MacrorugoCompound;
-            nub.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+            nub.setPropValue("inclinedApron", MRCInclination.INCLINED);
             nub.prms.C.singleValue = 0.09;
             nub.prms.PBD.singleValue = 0.6;
             nub.prms.BR.singleValue = 5.8;
diff --git a/spec/macrorugo/macrorugo_compound_jalhyd284.spec.ts b/spec/macrorugo/macrorugo_compound_jalhyd284.spec.ts
index 1c6fe7ef7b09779df031972bb911abda0c58da9e..9c170171a7be7a2f1c466038d80af321ac4a98a2 100644
--- a/spec/macrorugo/macrorugo_compound_jalhyd284.spec.ts
+++ b/spec/macrorugo/macrorugo_compound_jalhyd284.spec.ts
@@ -11,7 +11,7 @@ describe("MacroRugoCompound: ", () => {
         nub = Session.getInstance().createNub(
             new Props({ calcType: CalculatorType.MacroRugoCompound })
         ) as MacrorugoCompound;
-        nub.properties.setPropValue("inclinedApron", MRCInclination.INCLINED);
+        nub.setPropValue("inclinedApron", MRCInclination.INCLINED);
     });
 
     describe("jalhyd #284 warnings about block concentration − ", () => {
diff --git a/spec/pab/cloisons.spec.ts b/spec/pab/cloisons.spec.ts
index 549b1d0a58630595536e1a6b8e110c79dfc56927..2ac797734329621b501beca26c333fb40f91b766 100755
--- a/spec/pab/cloisons.spec.ts
+++ b/spec/pab/cloisons.spec.ts
@@ -27,7 +27,7 @@ function getCloisonsTest(): Cloisons {
     const cloisons: Cloisons = getEmptyCloisonsTest();
     cloisons.addChild(CreateStructure(LoiDebit.WeirSubmergedLarinier));
     cloisons.calculatedParam = cloisons.prms.Q;
-    cloisons.structures[0].prms.h1.singleValue = 1;
+    cloisons.structures[0].prms.h1.singleValue = 2;
     return cloisons;
 }
 
@@ -37,11 +37,11 @@ describe("Class Cloisons: ", () => {
         beforeEach(() => {
             c = getCloisonsTest();
         });
-        it("vCalc should return 0.47", () => {
-            expect(c.CalcSerie().vCalc).toBeCloseTo(0.47, 3);
+        it("vCalc should return 0.94", () => {
+            expect(c.CalcSerie().vCalc).toBeCloseTo(0.94, 3);
         });
-        it("extraResults.PV should return 230.444", () => {
-            expect(c.CalcSerie().values.PV).toBeCloseTo(230.444, 1);
+        it("extraResults.PV should return 460.887", () => {
+            expect(c.CalcSerie().values.PV).toBeCloseTo(460.887, 1);
         });
         it("ZRMB should be 100.5", () => {
             c.CalcSerie();
diff --git a/spec/pab/pab.spec.ts b/spec/pab/pab.spec.ts
index e91dd0365d0e807cfc7e640015e493d54be3d406..70167e7b276f44a24f62b5e4713ce255e2943a32 100644
--- a/spec/pab/pab.spec.ts
+++ b/spec/pab/pab.spec.ts
@@ -272,7 +272,7 @@ describe("Class Pab: ", () => {
     describe("errors inherited from Cloisons −", () => {
 
         it("negative sill warning should be present", () => {
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-05-06T14:44:44.505Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":98},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"cGs5OX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2.349},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":97.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGM1ZG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-05-06T14:44:44.505Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":98},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"cGs5OX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2.349},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101.1}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":97.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGM1ZG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`;
             Session.getInstance().clear();
             Session.getInstance().unserialise(sess);
             const pab2 = Session.getInstance().findNubByUid("M29hc3") as Pab;
diff --git a/spec/pipe_flow/lechaptcalmon.spec.ts b/spec/pipe_flow/lechaptcalmon.spec.ts
index 125dac098aaadabab2a99f7eda196c10d8e8f4c5..7625d080670cc32636422e63de9f3ab8f83e3d19 100644
--- a/spec/pipe_flow/lechaptcalmon.spec.ts
+++ b/spec/pipe_flow/lechaptcalmon.spec.ts
@@ -1,28 +1,56 @@
+import { PressureLoss, PressureLossParams } from "../../src/internal_modules";
+import { LCMaterial } from "../../src/lc-material";
 import { ParamCalculability } from "../../src/param/param-definition";
-import { LechaptCalmon } from "../../src/pipe_flow/lechaptcalmon";
-import { LechaptCalmonParams } from "../../src/pipe_flow/lechaptcalmon_params";
+import { PL_LechaptCalmon } from "../../src/pipe_flow/pl_lechaptcalmon";
+import { PL_LechaptCalmonParams } from "../../src/pipe_flow/pl_lechaptcalmon_params";
 import { SessionSettings } from "../../src/session_settings";
 import { MessageCode } from "../../src/util/message";
 
-function getLechapt(): LechaptCalmon {
-    const l = new LechaptCalmon(
-        new LechaptCalmonParams(
-            0.3, // débit
-            0.5, // diamètre
-            0.1, /// perte de charge
-            20, // longueur du toyo
+function getLechapt(): PressureLoss {
+    const plParams = new PressureLossParams(
+        0.3, // débit
+        0.5, // diamètre
+        0.1, /// perte de charge
+        20, // longueur du toyo
+        1 // Kloc
+    );
+    const lc = new PL_LechaptCalmon(
+        new PL_LechaptCalmonParams(
+            1.863, // paramètre L du matériau
+            2, // paramètre M du matériau
+            5.33 // paramètre N du matériau
+        )
+    );
+    const pl: PressureLoss = new PressureLoss(plParams, lc);
+
+    pl.calculatedParam = pl.prms.J;
+    pl.prms.J.singleValue = pl.CalcSerie().vCalc;
+    return pl;
+}
+
+function getLechaptWith(Q: number, D: number, Lg: number, Kloc: number, mat: LCMaterial): PressureLoss {
+    const plParams = new PressureLossParams(
+        Q, // débit
+        D, // diamètre
+        0, /// perte de charge
+        Lg, // longueur du toyo
+        Kloc, // coef de perte de charge singulière
+    );
+    const lc = new PL_LechaptCalmon(
+        new PL_LechaptCalmonParams(
             1.863, // paramètre L du matériau
             2, // paramètre M du matériau
-            5.33, // paramètre N du matériau
-            1 // Ks
+            5.33 // paramètre N du matériau
         )
     );
-    l.calculatedParam = l.prms.J;
-    l.prms.J.singleValue = l.CalcSerie().vCalc;
-    return l;
+    lc.material = mat;
+    const pl: PressureLoss = new PressureLoss(plParams, lc);
+    pl.calculatedParam = pl.prms.J;
+    pl.prms.J.singleValue = pl.CalcSerie().vCalc;
+    return pl;
 }
 
-let lechapt: LechaptCalmon = getLechapt();
+let lechapt: PressureLoss = getLechapt();
 
 describe("Class LechaptCalmon : ", () => {
     beforeAll(() => {
@@ -35,16 +63,17 @@ describe("Class LechaptCalmon : ", () => {
         if ([ParamCalculability.EQUATION, ParamCalculability.DICHO].includes(p.calculability) && p.visible) {
             it(`Calc(${p.symbol}) should return ${p.currentValue}`, () => {
                 lechapt.calculatedParam = lechapt.getParameter(p.symbol);
-                const ref: number = p.currentValue;
+                lechapt.CalcSerie();
+                const ref: number = lechapt.result.vCalc;
                 const V: number = lechapt.result.values.V;
-                const Jl: number = lechapt.result.values.Jl;
-                const Kl: number = lechapt.result.values.Kl;
+                const Jlin: number = lechapt.child.result.values.Jlin;
+                const Klin: number = lechapt.result.values.Klin;
                 const fD: number = lechapt.result.values.fD;
                 lechapt.calculatedParam.singleValue = lechapt.calculatedParam.singleValue / 2;
                 expect(lechapt.CalcSerie().vCalc).toBeCloseTo(ref, 2);
                 expect(lechapt.result.values.V).toBeCloseTo(V, 3);
-                expect(lechapt.result.values.Jl).toBeCloseTo(Jl, 3);
-                expect(lechapt.result.values.Kl).toBeCloseTo(Kl, 3);
+                expect(lechapt.child.result.values.Jlin).toBeCloseTo(Jlin, 3);
+                expect(lechapt.result.values.Klin).toBeCloseTo(Klin, 3);
                 expect(lechapt.result.values.fD).toBeCloseTo(fD, 3);
             });
         }
@@ -53,7 +82,7 @@ describe("Class LechaptCalmon : ", () => {
     describe("warning on speed value -", () => {
 
         it("case 1: there should not be any warning", () => {
-            const res = lechapt.CalcSerie();
+            const res = lechapt.result;
             expect(res.log.messages.length).toBe(0);
         });
 
@@ -65,3 +94,77 @@ describe("Class LechaptCalmon : ", () => {
         });
     });
 });
+
+describe("article original", () => {
+    it("", () => {
+        const oldMaxIter = SessionSettings.maxIterations;
+        const oldPrec = SessionSettings.precision;
+
+        try {
+            SessionSettings.maxIterations = 100;
+            SessionSettings.precision = 1e-7;
+
+            const plParams = new PressureLossParams(
+                0.0085, // débit
+                0.175, // diamètre
+                0, /// perte de charge
+                1000, // longueur du toyo
+                0, // Kloc
+            );
+
+            // L,M,N : cf. pl_lechaptcalmon.ts
+            const lechaptPrms = new PL_LechaptCalmonParams(
+                1.863, // paramètre L du matériau
+                2, // paramètre M du matériau
+                5.33, // paramètre N du matériau
+            );
+
+            const lechapt = new PL_LechaptCalmon(lechaptPrms);
+            lechapt.material = LCMaterial.HydraulicallySmoothPipe005D02;
+
+            const pl: PressureLoss = new PressureLoss(plParams, lechapt);
+
+            const res = pl.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(0.784, 3);
+        }
+        finally {
+            SessionSettings.maxIterations = oldMaxIter;
+            SessionSettings.precision = oldPrec;
+        }
+    });
+});
+
+describe("specific values -", () => {
+    it("test 1", () => {
+        const pl: PressureLoss = getLechaptWith(3, 1.2, 100, 0, LCMaterial.HydraulicallySmoothPipe025D1);
+        let r = pl.result;
+        let cr = pl.child.result;
+        expect(r.vCalc).toBeCloseTo(0.295085, 6); // J
+        expect(r.values.V).toBeCloseTo(2.652582, 6);
+        expect(cr.values.Jlin).toBeCloseTo(0.295085, 6);
+        expect(r.values.Klin).toBeCloseTo(0.822826, 6);
+        expect(r.values.fD).toBeCloseTo(0.009874, 6);
+
+        const lc: PL_LechaptCalmon = pl.child as PL_LechaptCalmon;
+        lc.material = LCMaterial.UnlinedCastIronCoarseConcrete;
+        pl.CalcSerie();
+        r = pl.result;
+        cr = pl.child.result;
+        expect(r.vCalc).toBeCloseTo(0.634482, 6); // J
+        expect(r.values.V).toBeCloseTo(2.652582, 6);
+        expect(cr.values.Jlin).toBeCloseTo(0.634482, 6);
+        expect(r.values.Klin).toBeCloseTo(1.769215, 6);
+        expect(r.values.fD).toBeCloseTo(0.021231, 6);
+    });
+
+    it("test 2", () => {
+        const pl: PressureLoss = getLechaptWith(0.05, 0.5, 100, 1, LCMaterial.RolledSteelSmoothConcrete);
+        const r = pl.result;
+        const cr = pl.child.result;
+        expect(r.vCalc).toBeCloseTo(0.015625, 6); // J  
+        expect(r.values.V).toBeCloseTo(0.254648, 6);
+        expect(cr.values.Jlin).toBeCloseTo(0.012320, 6);
+        expect(r.values.Klin).toBeCloseTo(3.727563, 6);
+        expect(r.values.fD).toBeCloseTo(0.023638, 6);
+    });
+});
diff --git a/spec/pipe_flow/strickler.spec.ts b/spec/pipe_flow/strickler.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d699a8bde1c8c7aaf61178600f1e186b3494275f
--- /dev/null
+++ b/spec/pipe_flow/strickler.spec.ts
@@ -0,0 +1,84 @@
+// tslint:disable:no-console
+import { PressureLoss, SessionSettings } from "../../src/internal_modules";
+import { PL_Strickler, PL_StricklerParams } from "../../src/internal_modules";
+import { PressureLossParams } from "../../src/internal_modules";
+
+let oldMaxIter: number;
+
+describe("Loi de perte de charge Strickler : ", () => {
+
+    beforeAll(() => {
+        oldMaxIter = SessionSettings.maxIterations;
+        SessionSettings.maxIterations = 100;
+    });
+
+    afterAll(() => {
+        SessionSettings.maxIterations = oldMaxIter;
+    });
+
+    beforeEach(() => {
+        SessionSettings.precision = 1e-7; // précision
+    });
+
+    describe("Conduite d'égout, S. Bennis 'Hydraulique et hydrologie', exercice 6 :", () => {
+        it("à t=0", () => {
+            const plParams = new PressureLossParams(
+                0.2, // débit Q
+                0.61, // diamètre D
+                0.075, /// perte de charge J
+                100, // longueur du toyo Lg
+                0 // coef de perte de charge singulière Kloc
+            );
+
+            const stricklerParams = new PL_StricklerParams(
+                1 // coefficient de rugosité de Strickler Ks
+            );
+            const plStrickler = new PL_Strickler(stricklerParams);
+            const pl: PressureLoss = new PressureLoss(plParams, plStrickler);
+            pl.calculatedParam = stricklerParams.Ks;
+
+            const res = pl.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(87.546, 3);
+        });
+
+        it("à t=30 ans", () => {
+            const plParams = new PressureLossParams(
+                0.2, // débit Q
+                0.61, // diamètre D
+                0.5, /// perte de charge J
+                100, // longueur du toyo Lg
+                0 // coef de perte de charge singulière Kloc
+            );
+
+            const stricklerParams = new PL_StricklerParams(
+                1 // coefficient de rugosité de Strickler Ks
+            );
+            const plStrickler = new PL_Strickler(stricklerParams);
+            const pl: PressureLoss = new PressureLoss(plParams, plStrickler);
+            pl.calculatedParam = stricklerParams.Ks;
+
+            const res = pl.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(33.9064, 4);
+        });
+
+        it("tubage PVC", () => {
+            const plParams = new PressureLossParams(
+                0.2, // débit Q
+                0.59, // diamètre D
+                0.5, /// perte de charge J
+                100, // longueur du toyo Lg
+                0 // coef de perte de charge singulière Kloc
+            );
+
+            const stricklerParams = new PL_StricklerParams(
+                111.111 // coefficient de rugosité de Strickler Ks
+            );
+            const plStrickler = new PL_Strickler(stricklerParams);
+            const pl: PressureLoss = new PressureLoss(plParams, plStrickler);
+            pl.calculatedParam = plParams.J;
+
+            const res = pl.CalcSerie();
+            expect(res.vCalc).toBeCloseTo(0.05562, 5);
+        });
+    });
+});
diff --git a/spec/pre_barrage/pre-barrage.spec.ts b/spec/pre_barrage/pre-barrage.spec.ts
index 5ab7f0a53d084348e2217ae63fc29da26f27d8ff..054c2a10ccaa9cd8919e8510f990da3ebf727659 100644
--- a/spec/pre_barrage/pre-barrage.spec.ts
+++ b/spec/pre_barrage/pre-barrage.spec.ts
@@ -695,8 +695,7 @@ describe("Class PreBarrage:", () => {
         })
 
         it("PreBarrage must have at least one upstream wall", () => {
-            const pb = createPreBarrageTest();
-            pb.cloisonsAmont = [];
+            const pb = new PreBarrage(new PreBarrageParams(1, 101, 100), false);
             expect(() => {
                 pb.CalcSerie();
             }).toThrowError("PreBarrage.checkGeometry(): must have at least one upstream wall (has 0)");
diff --git a/spec/session/serialisation.spec.ts b/spec/session/serialisation.spec.ts
index bd4baae5eb11a7c84503bb316c7f43f1e16af74b..2a7270495e0b02bb9f9fdf7d2552e75f157d40e2 100644
--- a/spec/session/serialisation.spec.ts
+++ b/spec/session/serialisation.spec.ts
@@ -56,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 { session6Calc } from "./session-6-calc";
 import { Structure } from "../../src/structure/structure";
 
 let dever: Dever;
@@ -259,6 +260,13 @@ describe("serialising / deserialising session - ", () => {
         expect(RU.result).toBeDefined();
     });
 
+    it("serialized file should contain 6 Nubs", () => {
+        Session.getInstance().clear();
+        const res = Session.getInstance().unserialise(JSON.stringify(session6Calc));
+        expect(res.hasErrors).toBe(false);
+        expect(Session.getInstance().getNumberOfNubs()).toBe(6);
+    });
+
     it("loaded serialized Ouvrages should be calculable", () => {
         Session.getInstance().clear();
         // tslint:disable-next-line:max-line-length
@@ -352,6 +360,12 @@ describe("serialising / deserialising session - ", () => {
         expect(SessionSettings.maxIterations).toBe(94);
     });
 
+    it("variated parameter not propertly reloaded nghyd#603", () => {
+        Session.getInstance().clear();
+        const json = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-02-09T12:31:02.306Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":5},"documentation":"","session":[{"uid":"OTg2d2","props":{"calcType":"ParallelStructure","nullparams":false},"meta":{"title":"Ouvrages"},"children":[{"uid":"bHduOG","props":{"calcType":"Structure","loiDebit":"GateCem88v","structureType":"SeuilOrificeRectangulaire","nullparams":false},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"CALCUL","value":2},{"symbol":"CdGR","mode":"SINGLE","value":0.6}]}],"parameters":[{"symbol":"Q","mode":"MINMAX","min":0.25,"max":1,"step":0.0375,"extensionStrategy":0},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"SINGLE","value":101.5}]}]}`;
+        const res = Session.getInstance().unserialise(json);
+        expect(res.nubs[0].nub.prms["Q"].valueMode).toEqual(1);
+    });
 });
 
 describe("nodeType property - ", () => {
@@ -514,7 +528,7 @@ describe("PreBarrage - ", () => {
         expect(c1.bassinAmont).toBeUndefined();
         expect(c1.bassinAval).toBeUndefined();
         expect(c1.structures.length).toBe(1);
-        expect(c1.structures[0].properties.getPropValue("loiDebit")).toBe(LoiDebit.WeirSubmergedLarinier);
+        expect(c1.structures[0].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);
@@ -524,7 +538,7 @@ describe("PreBarrage - ", () => {
         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);
+        expect(c2.structures[0].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);
@@ -534,7 +548,7 @@ describe("PreBarrage - ", () => {
         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);
+        expect(c3.structures[0].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);
@@ -544,7 +558,7 @@ describe("PreBarrage - ", () => {
         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);
+        expect(c4.structures[0].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);
@@ -555,7 +569,7 @@ describe("PreBarrage - ", () => {
         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);
+        expect(c5.structures[0].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);
diff --git a/spec/session/session-6-calc.ts b/spec/session/session-6-calc.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b996d684de6c6d308a8ea1aa52adb8bec855b3f
--- /dev/null
+++ b/spec/session/session-6-calc.ts
@@ -0,0 +1,334 @@
+export const session6Calc = {
+    "session": [
+        {
+            "uid": "Zmpsej",
+            "props": {
+                "calcType": 5,
+                "nodeType": 0
+            },
+            "meta": {
+                "title": "PAB : dimensions"
+            },
+            "children": [],
+            "parameters": [
+                {
+                    "symbol": "L",
+                    "mode": "SINGLE",
+                    "value": 2
+                },
+                {
+                    "symbol": "W",
+                    "mode": "SINGLE",
+                    "value": 1
+                },
+                {
+                    "symbol": "Y",
+                    "mode": "SINGLE",
+                    "value": 0.5
+                },
+                {
+                    "symbol": "V",
+                    "mode": "CALCUL"
+                }
+            ]
+        },
+        {
+            "uid": "djBoZ3",
+            "props": {
+                "calcType": 11,
+                "nodeType": 0
+            },
+            "meta": {
+                "title": "Macro-rugo."
+            },
+            "children": [],
+            "parameters": [
+                {
+                    "symbol": "ZF1",
+                    "mode": "SINGLE",
+                    "value": 12.5
+                },
+                {
+                    "symbol": "L",
+                    "mode": "SINGLE",
+                    "value": 6
+                },
+                {
+                    "symbol": "B",
+                    "mode": "SINGLE",
+                    "value": 1
+                },
+                {
+                    "symbol": "If",
+                    "mode": "SINGLE",
+                    "value": 0.05
+                },
+                {
+                    "symbol": "Q",
+                    "mode": "CALCUL"
+                },
+                {
+                    "symbol": "Y",
+                    "mode": "SINGLE",
+                    "value": 0.6
+                },
+                {
+                    "symbol": "Ks",
+                    "mode": "SINGLE",
+                    "value": 0.01
+                },
+                {
+                    "symbol": "C",
+                    "mode": "SINGLE",
+                    "value": 0.05
+                },
+                {
+                    "symbol": "PBD",
+                    "mode": "SINGLE",
+                    "value": 0.5
+                },
+                {
+                    "symbol": "PBH",
+                    "mode": "SINGLE",
+                    "value": 0.8
+                },
+                {
+                    "symbol": "Cd0",
+                    "mode": "SINGLE",
+                    "value": 1.5
+                }
+            ]
+        },
+        {
+            "uid": "dG1hZD",
+            "props": {
+                "calcType": 8,
+                "nodeType": 0
+            },
+            "meta": {
+                "title": "Ouvrages"
+            },
+            "children": [
+                {
+                    "uid": "OW1yMH",
+                    "props": {
+                        "calcType": 7,
+                        "nodeType": 5,
+                        "structureType": 1,
+                        "loiDebit": 1
+                    },
+                    "children": [] as any[],
+                    "parameters": [
+                        {
+                            "symbol": "ZDV",
+                            "mode": "SINGLE",
+                            "value": 100
+                        },
+                        {
+                            "symbol": "W",
+                            "mode": "SINGLE",
+                            "value": 0.5
+                        },
+                        {
+                            "symbol": "L",
+                            "mode": "SINGLE",
+                            "value": 2
+                        }
+                    ]
+                }
+            ],
+            "parameters": [
+                {
+                    "symbol": "Q",
+                    "mode": "CALCUL"
+                },
+                {
+                    "symbol": "Z1",
+                    "mode": "SINGLE",
+                    "value": 102
+                },
+                {
+                    "symbol": "Z2",
+                    "mode": "SINGLE",
+                    "value": 101.5
+                }
+            ]
+        },
+        {
+            "uid": "OWpqMW",
+            "props": {
+                "calcType": 2,
+                "nodeType": 2
+            },
+            "meta": {
+                "title": "Sec. param."
+            },
+            "children": [
+                {
+                    "uid": "bGVwZH",
+                    "props": {
+                        "calcType": 14,
+                        "nodeType": 2
+                    },
+                    "children": [] as any[],
+                    "parameters": [
+                        {
+                            "symbol": "Ks",
+                            "mode": "SINGLE",
+                            "value": 40
+                        },
+                        {
+                            "symbol": "Q",
+                            "mode": "SINGLE",
+                            "value": 1.2
+                        },
+                        {
+                            "symbol": "If",
+                            "mode": "SINGLE",
+                            "value": 0.001
+                        },
+                        {
+                            "symbol": "YB",
+                            "mode": "SINGLE",
+                            "value": 1
+                        },
+                        {
+                            "symbol": "Y",
+                            "mode": "SINGLE",
+                            "value": 0.8
+                        },
+                        {
+                            "symbol": "LargeurBerge",
+                            "mode": "SINGLE",
+                            "value": 2.5
+                        }
+                    ]
+                }
+            ],
+            "parameters": [] as any[]
+        },
+        {
+            "uid": "dXNzYW",
+            "props": {
+                "methodeResolution": 0,
+                "calcType": 4,
+                "nodeType": 2
+            },
+            "meta": {
+                "title": "Remous"
+            },
+            "children": [
+                {
+                    "uid": "aGFudW",
+                    "props": {
+                        "methodeResolution": 0,
+                        "calcType": 14,
+                        "nodeType": 2
+                    },
+                    "children": [] as any[],
+                    "parameters": [
+                        {
+                            "symbol": "Ks",
+                            "mode": "SINGLE",
+                            "value": 40
+                        },
+                        {
+                            "symbol": "Q",
+                            "mode": "SINGLE",
+                            "value": 1.2
+                        },
+                        {
+                            "symbol": "If",
+                            "mode": "SINGLE",
+                            "value": 0.001
+                        },
+                        {
+                            "symbol": "YB",
+                            "mode": "SINGLE",
+                            "value": 1
+                        },
+                        {
+                            "symbol": "Y",
+                            "mode": "SINGLE",
+                            "value": 0.2863766123093061
+                        },
+                        {
+                            "symbol": "LargeurBerge",
+                            "mode": "SINGLE",
+                            "value": 2.5
+                        }
+                    ]
+                }
+            ],
+            "parameters": [
+                {
+                    "symbol": "Yamont",
+                    "mode": "SINGLE",
+                    "value": 0.15
+                },
+                {
+                    "symbol": "Yaval",
+                    "mode": "SINGLE",
+                    "value": 0.4
+                },
+                {
+                    "symbol": "Long",
+                    "mode": "SINGLE",
+                    "value": 100
+                },
+                {
+                    "symbol": "Dx",
+                    "mode": "SINGLE",
+                    "value": 5
+                }
+            ]
+        },
+        {
+            "uid": "dWpsMT",
+            "props": {
+                "calcType": 1,
+                "nodeType": 0
+            },
+            "meta": {
+                "title": "Lechapt-Calmon"
+            },
+            "children": [],
+            "parameters": [
+                {
+                    "symbol": "Q",
+                    "mode": "SINGLE",
+                    "value": 3
+                },
+                {
+                    "symbol": "D",
+                    "mode": "SINGLE",
+                    "value": 1.2
+                },
+                {
+                    "symbol": "J",
+                    "mode": "CALCUL"
+                },
+                {
+                    "symbol": "Lg",
+                    "mode": "SINGLE",
+                    "value": 100
+                },
+                {
+                    "symbol": "L",
+                    "mode": "SINGLE",
+                    "value": 1.601
+                },
+                {
+                    "symbol": "M",
+                    "mode": "SINGLE",
+                    "value": 1.975
+                },
+                {
+                    "symbol": "N",
+                    "mode": "SINGLE",
+                    "value": 5.25
+                }
+            ]
+        }
+    ]
+};
diff --git a/spec/structure/functions.ts b/spec/structure/functions.ts
index 0d771331ad79f8d6cab3541309e084f09b399a42..e5c5d2a517bd05ee8ba273c044842611c25d30c9 100644
--- a/spec/structure/functions.ts
+++ b/spec/structure/functions.ts
@@ -158,8 +158,7 @@ export function testParallelStructures(o: { ps: ParallelStructure, ld: number[]
                         beforeEach(() => {
                             originalCalculatedValue = o.ps.calculatedParam.currentValue;
                             if ( // #136 Multiple solutions for GateCem88v ZDV
-                                !(o.ps.calculatedParam.parentNub.properties
-                                    .getPropValue("loiDebit") === LoiDebit.GateCem88v
+                                !(o.ps.calculatedParam.parentNub.getPropValue("loiDebit") === LoiDebit.GateCem88v
                                     && o.ps.calculatedParam.symbol === "ZDV")
                             ) {
                                 // altering value to force looking for the solution
diff --git a/spec/structure/structure_jalhyd219_debit_nul.spec.ts b/spec/structure/structure_jalhyd219_debit_nul.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..15d0a2f76b4e1204a82f60c34af3798d6b44c929
--- /dev/null
+++ b/spec/structure/structure_jalhyd219_debit_nul.spec.ts
@@ -0,0 +1,40 @@
+import { RectangularStructureParams, StructureWeirFree } from "../../src/internal_modules";
+
+describe("jalhyd#219 cote amont d'un ouvrage dénoyé à débit nul :", () => {
+    function createStruct(z1: number, zr: number): StructureWeirFree {
+        const s: StructureWeirFree = new StructureWeirFree(
+            new RectangularStructureParams(0, // Q
+                zr, // ZDV
+                z1, // Z1
+                92, // Z2
+                1, // L
+                0.6, // Cd
+                0.8 // W
+            ),
+            false
+        );
+        s.calculatedParam = s.prms.Z1;
+        return s;
+    }
+
+    it("cote amont initiale < Zr", () => {
+        const z1: number = 90;
+        const zr: number = 100;
+        const s: StructureWeirFree = createStruct(z1, zr);
+        expect(s.CalcSerie().vCalc).toBeCloseTo(zr, 3);
+    });
+
+    it("cote amont initiale = Zr", () => {
+        const z1: number = 100;
+        const zr: number = 100;
+        const s: StructureWeirFree = createStruct(z1, zr);
+        expect(s.CalcSerie().vCalc).toBeCloseTo(zr, 3);
+    });
+
+    it("cote amont initiale > Zr", () => {
+        const z1: number = 110;
+        const zr: number = 100;
+        const s: StructureWeirFree = createStruct(z1, zr);
+        expect(s.CalcSerie().vCalc).toBeCloseTo(zr, 3);
+    });
+});
diff --git a/spec/structure/structure_weir_submerged.spec.ts b/spec/structure/structure_weir_submerged.spec.ts
index e86a30e73d2a23d25783c790c4191fb3428713b2..e73952c4d509d734af11a02c316ec254fa8d82d2 100644
--- a/spec/structure/structure_weir_submerged.spec.ts
+++ b/spec/structure/structure_weir_submerged.spec.ts
@@ -6,13 +6,13 @@ import { itCalcQ } from "../structure/functions";
 import { precDigits } from "../test_config";
 
 function getStructTest(): StructureWeirSubmerged {
-    return new StructureWeirSubmerged(new RectangularStructureParams(0, 101, 102, 101.5, 0.2, 0.9), false);
+    return new StructureWeirSubmerged(new RectangularStructureParams(0, 101, 102, 101.9, 0.2, 0.9), false);
 }
 
 describe("Class StructureWeirSubmerged: ", () => {
     describe("Calc(Q): ", () => {
         const Z1: number[] = [102];
-        const Q: number[] = [0.282];
+        const Q: number[] = [0.227];
         const mode: StructureFlowMode = StructureFlowMode.WEIR;
         const regime: StructureFlowRegime = StructureFlowRegime.SUBMERGED;
         for (let i = 0; i < Q.length; i++) {
@@ -35,10 +35,9 @@ describe("Class StructureWeirSubmerged: ", () => {
             structTest.prms.Z2.singleValue = 105;
             structTest.prms.ZDV.singleValue = 100;
             const res = structTest.CalcSerie().resultElement;
-            expect(res.log.messages.length).toBe(1);
-            expect(
-                res.log.messages[0].code
-            ).toBe(MessageCode.WARNING_WEIR_SUBMERGENCE_LOWER_THAN_08);
+            expect(res.log.messages.length).toBe(2);
+            const ok = res.log.messages[0].code === MessageCode.WARNING_WEIR_SUBMERGENCE_LOWER_THAN_08 || res.log.messages[1].code === MessageCode.WARNING_WEIR_SUBMERGENCE_LOWER_THAN_08;
+            expect(ok).toBe(true);
         });
     });
 });
diff --git a/spec/structure/structure_weir_submerged_larinier.spec.ts b/spec/structure/structure_weir_submerged_larinier.spec.ts
index 40c0e16849c710c377d8362211f64e421694fe13..ba486d4c254e5b02cf1f8fc3223866fe413f6889 100644
--- a/spec/structure/structure_weir_submerged_larinier.spec.ts
+++ b/spec/structure/structure_weir_submerged_larinier.spec.ts
@@ -54,4 +54,16 @@ describe("Class StructureWeirSubmergedLarinier: ", () => {
             ).toBe(MessageCode.WARNING_SLOT_SUBMERGENCE_NOT_BETWEEN_07_AND_09);
         });
     });
+    describe("Calcul avec h2/h1 < 0.5 (=0.4) : ", () => {
+        it("le log devrait contenir au moins un message d'erreur", () => {
+            const structTest = getStructTest();
+            structTest.prms.Z1.singleValue = 110;
+            structTest.prms.Z2.singleValue = 104;
+            structTest.prms.ZDV.singleValue = 100;
+            const res = structTest.CalcSerie().resultElement;
+            expect(res.log.messages.length).toBe(2);
+            const ok = res.log.messages[0].code === MessageCode.ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN || res.log.messages[1].code === MessageCode.ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN;
+            expect(ok).toBe(true);
+        });
+    });
 });
diff --git a/spec/value_ref/value_ref_deleted_module.spec.ts b/spec/value_ref/value_ref_deleted_module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b20904b9239c606fc95d2e5ab58ad20d83f082b3
--- /dev/null
+++ b/spec/value_ref/value_ref_deleted_module.spec.ts
@@ -0,0 +1,27 @@
+import { PabChute, PabChuteParams, ParamValueMode, Props, Session } from "../../src/index";
+
+describe("référence à un nub supprimé par la suite : ", () => {
+    it("test 1", () => {
+        // cas de figure : cf. merge request 177 (nghyd#571,jalhyd#329)
+
+        const session = Session.getInstance();
+        //        const pc1: PabChute = new PabChute(new PabChuteParams(2, 0.5, 666));
+        const props = new Props({ calcType: 12, nullParams: false });
+        const pc1: PabChute = <PabChute>session.createSessionNub(props);
+
+        let serialisedNub: string = pc1.serialise({ title: "newcalc" });
+        const pc2 = session.unserialiseSingleNub(serialisedNub).nub;
+
+        const DH_2 = pc2.getParameter("DH");
+        DH_2.defineReference(pc1, "DH");
+        session.deleteNub(pc1);
+
+        expect(DH_2.valueMode).toBe(ParamValueMode.SINGLE); // pas de but du test, mais ça mange pas de pain
+        DH_2.setCalculated();
+
+        serialisedNub = pc2.serialise({ title: "newcalc2" });
+        session.unserialiseSingleNub(serialisedNub).nub;
+
+        expect(DH_2.valueMode).toBe(ParamValueMode.CALCUL);
+    });
+});
diff --git a/spec/verificateur/verificateur.spec.ts b/spec/verificateur/verificateur.spec.ts
index 82969208cac93c1974a60882ba11dcb76edd2306..78ed594de7aee2fc04cb712d09f9e66b6420eb58 100644
--- a/spec/verificateur/verificateur.spec.ts
+++ b/spec/verificateur/verificateur.spec.ts
@@ -28,7 +28,7 @@ function createPab(): Pab {
     const cl = Session.getInstance().createNub(
         new Props({ calcType: CalculatorType.Cloisons })
     ) as Cloisons;
-    cl.parent = pab;
+    cl.setParent(pab);
     pab.children.push(cl);
     pab.children[0].structures[0] = CreateStructure(LoiDebit.WeirSubmergedLarinier, cl);
     const dw = Session.getInstance().createNub(
@@ -118,7 +118,7 @@ describe("vérificateur de franchissement −", () => {
             // contexte
             Session.getInstance().clear();
             // jets plongeants seulement
-            Session.getInstance().unserialise(`{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-04-23T08:02:44.556Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"eGx2aG","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"OGxiN3","props":{"calcType":"Cloisons"},"children":[{"uid":"cnU5bj","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.1},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":0.423},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"OXdpbm","props":{"calcType":"CloisonAval"},"children":[{"uid":"dmc0Nj","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.6},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`);
+            Session.getInstance().unserialise(`{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-04-17T10:44:42.561Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"eGx2aG","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"OGxiN3","props":{"calcType":"Cloisons"},"children":[{"uid":"YXd1ZD","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.1},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":0.5},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"OXdpbm","props":{"calcType":"CloisonAval"},"children":[{"uid":"OW04cn","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.6},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`);
             const pab = Session.getInstance().findNubByUid("eGx2aG") as Pab;
             // vérificateur
             const v = new Verificateur();
@@ -237,7 +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].setParent(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
@@ -260,7 +260,7 @@ describe("vérificateur de franchissement −", () => {
         it("Profondeur des bassins insuffisante", () => {
             // contexte
             Session.getInstance().clear();
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-04-23T12:33:41.272Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"enZvdm","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"d2llZG","props":{"calcType":"Cloisons"},"children":[{"uid":"ZDFven","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":101},{"symbol":"ZRAM","mode":"SINGLE","value":101.25},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":0.47},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":100.7}],"downWall":{"uid":"NzYwbG","props":{"calcType":"CloisonAval"},"children":[{"uid":"cmdzN2","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.75}]}}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-04-17T10:51:31.030Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"enZvdm","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"d2llZG","props":{"calcType":"Cloisons"},"children":[{"uid":"cGdmNn","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.4},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":101},{"symbol":"ZRAM","mode":"SINGLE","value":101.25},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":0.4},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"NzYwbG","props":{"calcType":"CloisonAval"},"children":[{"uid":"dW9pbD","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.75}]}}]}`;
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("enZvdm") as Pab;
             // vérificateur
@@ -312,7 +312,7 @@ describe("vérificateur de franchissement −", () => {
         it("Charge trop faible sur échancrures (surface)", () => {
             // contexte
             // jets de SURFACE seulement
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-08-11T13:16:17.677Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"Z2ZpYm","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"a2doNj","props":{"calcType":"Cloisons"},"children":[{"uid":"cTZjbD","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.8},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"eHZzc2","props":{"calcType":"Cloisons"},"children":[{"uid":"N2J4Z2","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.3},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100},{"symbol":"ZRAM","mode":"SINGLE","value":100.25},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"CALCUL","value":0.059},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"SINGLE","value":101.5}],"downWall":{"uid":"b2JobG","props":{"calcType":"CloisonAval"},"children":[{"uid":"ZnlodG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.8},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":99.75}]}}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-08-11T13:16:17.677Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"Z2ZpYm","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"a2doNj","props":{"calcType":"Cloisons"},"children":[{"uid":"cTZjbD","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirVillemonte"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.8},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"eHZzc2","props":{"calcType":"Cloisons"},"children":[{"uid":"N2J4Z2","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirVillemonte"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.3},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100},{"symbol":"ZRAM","mode":"SINGLE","value":100.25},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"CALCUL","value":0.059},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"SINGLE","value":101.5}],"downWall":{"uid":"b2JobG","props":{"calcType":"CloisonAval"},"children":[{"uid":"ZnlodG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirVillemonte"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.8},{"symbol":"L","mode":"SINGLE","value":0.4},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":99.75}]}}]}`;
             Session.getInstance().clear();
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("Z2ZpYm") as Pab;
@@ -357,7 +357,7 @@ describe("vérificateur de franchissement −", () => {
         it("Plusieurs warnings entraînent la non-franchissabilité d'une cloison", () => {
             // contexte
             Session.getInstance().clear();
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-04-29T10:00:03.138Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bjlnc2","props":{"calcType":"Espece","species":"SPECIES_CUSTOM"},"meta":{"title":"Croustibat®"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":0.35},{"symbol":"DHMaxP","mode":"SINGLE","value":0.6},{"symbol":"BMin","mode":"SINGLE","value":0.18},{"symbol":"PMinS","mode":"SINGLE","value":0.9},{"symbol":"PMinP","mode":"SINGLE","value":0.9},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":25},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3},{"symbol":"PVMaxPrec","mode":"SINGLE","value":30000},{"symbol":"PVMaxLim","mode":"SINGLE","value":50000}]},{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":98},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"cGs5OX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2.349},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":97.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGM1ZG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-04-17T12:02:45.180Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bjlnc2","props":{"calcType":"Espece","divingJetSupported":"NOT_SUPPORTED","species":"SPECIES_CUSTOM"},"meta":{"title":"Croustibat®"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":0.35},{"symbol":"DHMaxP","mode":"SINGLE","value":0.6},{"symbol":"BMin","mode":"SINGLE","value":0.18},{"symbol":"PMinS","mode":"SINGLE","value":0.9},{"symbol":"PMinP","mode":"SINGLE","value":0.9},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":25},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3}]},{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":98},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"bzM2ZG","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.1},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2.349},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":97.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGM1ZG","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.49},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`;
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("M29hc3") as Pab;
             const espece = Session.getInstance().findNubByUid("bjlnc2") as Espece;
@@ -388,7 +388,7 @@ describe("vérificateur de franchissement −", () => {
         it("Plusieurs warnings entraînent la non-franchissabilité d'une cloison (2)", () => {
             // contexte
             Session.getInstance().clear();
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-04-29T10:00:03.138Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bjlnc2","props":{"calcType":"Espece","species":"SPECIES_CUSTOM"},"meta":{"title":"Croustibat®"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":0.35},{"symbol":"DHMaxP","mode":"SINGLE","value":0.35},{"symbol":"BMin","mode":"SINGLE","value":0.3},{"symbol":"PMinS","mode":"SINGLE","value":1},{"symbol":"PMinP","mode":"SINGLE","value":1},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":2.5},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3},{"symbol":"PVMaxPrec","mode":"SINGLE","value":30000},{"symbol":"PVMaxLim","mode":"SINGLE","value":50000}]},{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":98},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"cGs5OX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2.349},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":97.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGM1ZG","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.5},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.25}]}}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-04-17T11:40:14.310Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bjlnc2","props":{"calcType":"Espece","divingJetSupported":"NOT_SUPPORTED","species":"SPECIES_CUSTOM"},"meta":{"title":"Croustibat®"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":0.35},{"symbol":"DHMaxP","mode":"SINGLE","value":0.35},{"symbol":"BMin","mode":"SINGLE","value":0.3},{"symbol":"PMinS","mode":"SINGLE","value":1},{"symbol":"PMinP","mode":"SINGLE","value":1},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":2.5},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3}]},{"uid":"M29hc3","props":{"calcType":"Pab"},"meta":{"title":"PAB 1"},"children":[{"uid":"eDllOD","props":{"calcType":"Cloisons"},"children":[{"uid":"ZGMwc3","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100.75},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"NWRpcG","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.8},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.5},{"symbol":"ZRAM","mode":"SINGLE","value":100.75},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":2},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101.2}],"downWall":{"uid":"NzBlcD","props":{"calcType":"CloisonAval"},"children":[{"uid":"cG5xdX","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"dWRhdD","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.2}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100}]}}]}`;
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("M29hc3") as Pab;
             const espece = Session.getInstance().findNubByUid("bjlnc2") as Espece;
@@ -455,7 +455,7 @@ describe("vérificateur de franchissement −", () => {
         it("Orifices (structures dont le mode d'écoulement est en charge) non franchissables", () => {
             // contexte
             Session.getInstance().clear();
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-07-31T09:17:46.283Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bzRjY3","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"c25hMW","props":{"calcType":"Cloisons"},"children":[{"uid":"MWN2aH","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]},{"uid":"bm10ZG","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":0},{"symbol":"ZRAM","mode":"SINGLE","value":0},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":1.5},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":99}],"downWall":{"uid":"cm54MW","props":{"calcType":"CloisonAval"},"children":[{"uid":"dGhleD","props":{"calcType":"Structure","loiDebit":"GateCunge80"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"CdCunge","mode":"SINGLE","value":1}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":0}]}},{"uid":"NnB5b2","props":{"calcType":"Espece","divingJetSupported":"SUPPORTED","species":"SPECIES_CUSTOM"},"meta":{"title":"Espèce"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":50},{"symbol":"DHMaxP","mode":"SINGLE","value":2},{"symbol":"BMin","mode":"SINGLE","value":0.1},{"symbol":"PMinS","mode":"SINGLE","value":1},{"symbol":"PMinP","mode":"SINGLE","value":1},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":2.5},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3},{"symbol":"PVMaxPrec","mode":"SINGLE","value":150},{"symbol":"PVMaxLim","mode":"SINGLE","value":200}]}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2023-04-17T11:54:53.352Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"bzRjY3","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"c25hMW","props":{"calcType":"Cloisons"},"children":[{"uid":"MWN2aH","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged","structureType":"Orifice"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]},{"uid":"bm10ZG","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":99},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":0},{"symbol":"ZRAM","mode":"SINGLE","value":0},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":1.5},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":99}],"downWall":{"uid":"cm54MW","props":{"calcType":"CloisonAval"},"children":[{"uid":"dGhleD","props":{"calcType":"Structure","loiDebit":"GateCunge80"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"CdCunge","mode":"SINGLE","value":1}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":0}]}},{"uid":"NnB5b2","props":{"calcType":"Espece","divingJetSupported":"SUPPORTED","species":"SPECIES_CUSTOM"},"meta":{"title":"Espèce"},"children":[],"parameters":[{"symbol":"OK","mode":"CALCUL"},{"symbol":"DHMaxS","mode":"SINGLE","value":50},{"symbol":"DHMaxP","mode":"SINGLE","value":2},{"symbol":"BMin","mode":"SINGLE","value":0.1},{"symbol":"PMinS","mode":"SINGLE","value":1},{"symbol":"PMinP","mode":"SINGLE","value":1},{"symbol":"LMinS","mode":"SINGLE","value":2.5},{"symbol":"LMinP","mode":"SINGLE","value":2.5},{"symbol":"HMin","mode":"SINGLE","value":0.3},{"symbol":"YMin","mode":"SINGLE","value":0.4},{"symbol":"VeMax","mode":"SINGLE","value":2.5},{"symbol":"YMinSB","mode":"SINGLE","value":0.2},{"symbol":"YMinPB","mode":"SINGLE","value":0.3}]}]}`;
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("bzRjY3") as Pab;
             const espece = Session.getInstance().findNubByUid("NnB5b2") as Espece;
@@ -498,7 +498,7 @@ describe("vérificateur de franchissement −", () => {
         it("jalhyd#265 (2) - charge minimale sur cloison aval régulée, avec une passe variée", () => {
             // contexte
             Session.getInstance().clear();
-            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-09-08T08:58:52.333Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"MnRyeT","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"OWEwZn","props":{"calcType":"Cloisons"},"children":[{"uid":"bHVyZ3","props":{"calcType":"Structure","loiDebit":"WeirSubmergedLarinier","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.8},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGd1MX","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged","structureType":"Orifice"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.8},{"symbol":"ZRAM","mode":"SINGLE","value":100.9},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"MINMAX","min":0.14,"max":0.3,"step":0.15,"extensionStrategy":0},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101.5}],"downWall":{"uid":"ZWxnMz","props":{"calcType":"CloisonAval"},"children":[{"uid":"ZHJwcD","props":{"calcType":"Structure","loiDebit":"VanLevVillemonte"},"children":[],"parameters":[{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.4},{"symbol":"minZDV","mode":"SINGLE","value":100.7},{"symbol":"maxZDV","mode":"SINGLE","value":101.6},{"symbol":"DH","mode":"SINGLE","value":0.2}]},{"uid":"cWw4aX","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged","structureType":"Orifice"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.7}]}},{"uid":"YXBxbn","props":{"calcType":"Verificateur","nubToVerify":"MnRyeT","speciesList":["SPECIES_7b"]},"meta":{"title":"Vérification"},"children":[],"parameters":[]}]}`;
+            const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-09-08T08:58:52.333Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"MnRyeT","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"OWEwZn","props":{"calcType":"Cloisons"},"children":[{"uid":"bHVyZ3","props":{"calcType":"Structure","loiDebit":"WeirVillemonte","structureType":"SeuilRectangulaire"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":101.8},{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWSL","mode":"SINGLE","value":0.75}]},{"uid":"aGd1MX","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged","structureType":"Orifice"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":10},{"symbol":"BB","mode":"SINGLE","value":1},{"symbol":"ZRMB","mode":"SINGLE","value":100.8},{"symbol":"ZRAM","mode":"SINGLE","value":100.9},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"MINMAX","min":0.14,"max":0.3,"step":0.15,"extensionStrategy":0},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":101.5}],"downWall":{"uid":"ZWxnMz","props":{"calcType":"CloisonAval"},"children":[{"uid":"ZHJwcD","props":{"calcType":"Structure","loiDebit":"VanLevVillemonte"},"children":[],"parameters":[{"symbol":"L","mode":"SINGLE","value":0.2},{"symbol":"CdWR","mode":"SINGLE","value":0.4},{"symbol":"minZDV","mode":"SINGLE","value":100.7},{"symbol":"maxZDV","mode":"SINGLE","value":101.6},{"symbol":"DH","mode":"SINGLE","value":0.2}]},{"uid":"cWw4aX","props":{"calcType":"Structure","loiDebit":"OrificeSubmerged","structureType":"Orifice"},"children":[],"parameters":[{"symbol":"S","mode":"SINGLE","value":0.1},{"symbol":"CdO","mode":"SINGLE","value":0.7}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":100.7}]}},{"uid":"YXBxbn","props":{"calcType":"Verificateur","nubToVerify":"MnRyeT","speciesList":["SPECIES_7b"]},"meta":{"title":"Vérification"},"children":[],"parameters":[]}]}`;
             Session.getInstance().unserialise(sess);
             const pab = Session.getInstance().findNubByUid("MnRyeT") as Pab;
             const v = Session.getInstance().findNubByUid("YXBxbn") as Verificateur;
diff --git a/src/base.ts b/src/base.ts
index 9a77b28048a31bb519dec6971f7e9a64c8cdb9f7..e1b32c23c3653fa71f7271df6dfdf49db0788ccd 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -82,7 +82,7 @@ export function isEqual(a: number, b: number, e: number = 1E-7): boolean {
         return true;
     }
     if (b === 0) { // ne pas diviser par 0
-        [ a, b ] = [ b, a ];
+        [a, b] = [b, a];
     }
     if (a === 0) { // éviter d'avoir un quotient toujours nul
         return (Math.abs(b) < e);
diff --git a/src/child_nub.ts b/src/child_nub.ts
index adef909ae4e19d2385f97289a503415fe7b62300..0059070447b2b2205ff01f0cb5c831e5bcd1f60c 100644
--- a/src/child_nub.ts
+++ b/src/child_nub.ts
@@ -1,5 +1,5 @@
-import { Nub } from "./nub";
-import { ParamDefinition } from "./param/param-definition";
+import { Nub } from "./internal_modules";
+import { ParamDefinition } from "./internal_modules";
 
 /**
  * A Nub that is meant to exist within a parent only
diff --git a/src/compute-node.ts b/src/compute-node.ts
index 7dc9278b4befd7a58f16e39c610ba92456c29559..4661c047f0f648cdaab6b49b7606a308e87c3a86 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -1,8 +1,8 @@
-import { Debug, IDebug } from "./base";
-import { JalhydObject } from "./jalhyd_object";
-import { ParamDefinition } from "./param/param-definition";
-import { IParamDefinitionIterator } from "./param/param_definition_iterator";
-import { ParamsEquation } from "./param/params-equation";
+import { Debug, IDebug } from "./internal_modules";
+import { JalhydObject } from "./internal_modules";
+import { ParamDefinition } from "./internal_modules";
+import { IParamDefinitionIterator } from "./internal_modules";
+import { ParamsEquation } from "./internal_modules";
 
 /**
  * type de calculette
@@ -42,7 +42,9 @@ export enum CalculatorType {
     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
+    Verificateur,       // Vérificateur de contraintes sur une passe pour une ou plusieurs espèces
+    PressureLoss,       // Perte de charge
+    PressureLossLaw     // Lois de perte de charge (Lechapt-Calmon, Colebrook-White, Strickler, ...)
 }
 
 /** types de sections */
@@ -65,13 +67,6 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
      */
     protected _resultsFamilies: any;
 
-    /**
-     * { symbol => string } map that defines units for extra results
-     */
-    protected _resultsUnits: any;
-
-    protected _calcType: CalculatorType;
-
     private _debug: Debug;
 
     constructor(prms: ParamsEquation, dbg: boolean = false) {
@@ -84,7 +79,6 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
         this._prms.parent = this;
 
         this.setParametersCalculability();
-        this.setResultsUnits();
         this.exposeResults();
     }
 
@@ -143,16 +137,12 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
         this._resultsFamilies = {};
     }
 
-    public get resultsFamilies()  {
+    public get resultsFamilies() {
         return this._resultsFamilies;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {};
-    }
-
-    public get resultsUnits()  {
-        return this._resultsUnits;
+    public static resultsUnits(): any {
+        return {};
     }
 
     protected abstract setParametersCalculability(): void;
diff --git a/src/devalaison/grille.ts b/src/devalaison/grille.ts
index 1d9621a43c9eb13330b2d101c13a19cec8524fee..e03b505d276c82cf6feb726db5472f39385ba616 100644
--- a/src/devalaison/grille.ts
+++ b/src/devalaison/grille.ts
@@ -1,11 +1,11 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Interval } from "../util/interval";
-import { Message, MessageCode } from "../util/message";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { GrilleParams } from "./grille_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Interval } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { GrilleParams } from "../internal_modules";
 
 export enum GrilleProfile {
     Rectangular,
@@ -21,9 +21,39 @@ export enum GrilleType {
 
 export class Grille extends Nub implements Observer {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        H: "m",
+        HG: "m",
+        S: "m²",
+        SPDG: "m²",
+        VA: "m/s",
+        VAPDG: "m/s",
+        LG: "m",
+        D: "m",
+        DG: "m",
+        SG: "m²",
+        VN: "m/s",
+        DH00: "cm",
+        DH05: "cm",
+        DH10: "cm",
+        DH15: "cm",
+        DH20: "cm",
+        DH25: "cm",
+        DH30: "cm",
+        DH35: "cm",
+        DH40: "cm",
+        DH45: "cm",
+        DH50: "cm",
+        DH55: "cm",
+        DH60: "cm"
+    }
+
     constructor(prms: GrilleParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Grille;
+        this.setCalculatorType(CalculatorType.Grille);
         this._props.addObserver(this);
         this.type = GrilleType.Inclined;
         this.profile = GrilleProfile.Rectangular;
@@ -37,19 +67,19 @@ export class Grille extends Nub implements Observer {
     }
 
     public get gridType(): GrilleType {
-        return this.properties.getPropValue("gridType");
+        return this.getPropValue("gridType");
     }
 
     public get gridProfile(): GrilleProfile {
-        return this.properties.getPropValue("gridProfile");
+        return this.getPropValue("gridProfile");
     }
 
     public set type(type: GrilleType) {
-        this.properties.setPropValue("gridType", type);
+        this.setPropValue("gridType", type);
     }
 
     public set profile(profile: GrilleProfile) {
-        this.properties.setPropValue("gridProfile", profile);
+        this.setPropValue("gridProfile", profile);
     }
 
     /** Coefficient de forme des barreaux a */
@@ -97,7 +127,7 @@ export class Grille extends Nub implements Observer {
     }
 
     public Calc(): Result {
-        this.currentResult = this.Equation();
+        this.currentResultElement = this.Equation();
         return this.result;
     }
 
@@ -291,33 +321,8 @@ export class Grille extends Nub implements Observer {
         this.prms.cIncl.calculability = ParamCalculability.FIXED;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            H: "m",
-            HG: "m",
-            S: "m²",
-            SPDG: "m²",
-            VA: "m/s",
-            VAPDG: "m/s",
-            LG: "m",
-            D: "m",
-            DG: "m",
-            SG: "m²",
-            VN: "m/s",
-            DH00: "cm",
-            DH05: "cm",
-            DH10: "cm",
-            DH15: "cm",
-            DH20: "cm",
-            DH25: "cm",
-            DH30: "cm",
-            DH35: "cm",
-            DH40: "cm",
-            DH45: "cm",
-            DH50: "cm",
-            DH55: "cm",
-            DH60: "cm"
-        }
+    public static override resultsUnits() {
+        return Grille._resultsUnits;
     }
 
     protected exposeResults() {
@@ -413,7 +418,7 @@ export class Grille extends Nub implements Observer {
             }
         }
 
-        for (const pct of [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 ]) {
+        for (const pct of [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]) {
             let KO: number;
             let XI: number;
             const VCSDG = (VAPDG * VAPDG) / (2 * g);
diff --git a/src/devalaison/grille_params.ts b/src/devalaison/grille_params.ts
index 961237ddf5a137ec3120b81c7d6d5f02da3986da..c9709c5c36d87b381488887b1e50c242af0733ae 100644
--- a/src/devalaison/grille_params.ts
+++ b/src/devalaison/grille_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class GrilleParams extends ParamsEquation {
 
diff --git a/src/devalaison/jet.ts b/src/devalaison/jet.ts
index 13e3f87e1d7e5f60af8a37347084e5a484279813..63989c173d8b46c3ba1a26edb759843e8e136db2 100644
--- a/src/devalaison/jet.ts
+++ b/src/devalaison/jet.ts
@@ -1,19 +1,31 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability, ParamFamily } from "../param/param-definition";
-import { ParamValueMode } from "../param/param-value-mode";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { JetParams } from "./jet_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability, ParamFamily } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { JetParams } from "../internal_modules";
 
 export class Jet extends Nub {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        H: "m",
+        Y: "m",
+        t: "s",
+        Vx: "m/s",
+        Vz: "m/s",
+        Vt: "m/s"
+    };
+
     /** steps for generating the trajectory */
     protected precision = 50;
 
     public constructor(prms: JetParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Jet;
+        this.setCalculatorType(CalculatorType.Jet);
         this._defaultCalculatedParam = prms.D;
         this.resetDefaultCalculatedParam();
     }
@@ -24,7 +36,7 @@ export class Jet extends Nub {
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         // omit extra results if calculation failed
         if (this.result.vCalc !== undefined) {
             // H: chute
@@ -141,7 +153,7 @@ export class Jet extends Nub {
             // H will be calculated
 
             // 1. find all extended values lists; ignore ZW (will be calculated) and D (will be reaffected)
-            for (const symbol of [ "S", "V0", "ZJ" ]) {
+            for (const symbol of ["S", "V0", "ZJ"]) {
                 const p = this.getParameter(symbol);
                 valuesLists[symbol] = [];
                 if (this.calculatedParam.symbol === symbol) { // calculated
@@ -167,7 +179,7 @@ export class Jet extends Nub {
                 if (this.result.resultElements[i].ok) {
                     // set clone params values; ignore ZW (will be calculated)
                     // and D (will be reaffected by getDAbscissae)
-                    for (const symbol of [ "S", "V0", "ZJ" ]) {
+                    for (const symbol of ["S", "V0", "ZJ"]) {
                         const val = valuesLists[symbol][i];
                         nub.getParameter(symbol).v = val;
                     }
@@ -180,7 +192,7 @@ export class Jet extends Nub {
             }
 
         } else { // nothing is varying
-            for (const symbol of [ "S", "V0", "ZJ" ]) {
+            for (const symbol of ["S", "V0", "ZJ"]) {
                 // init .v of clone
                 nub.getParameter(symbol).v = nub.getParameter(symbol).singleValue;
             }
@@ -195,7 +207,7 @@ export class Jet extends Nub {
         return (
             0.5 * g * Math.pow(this.prms.D.v, 2)
             / (Math.pow(Math.cos(this.alpha), 2) * Math.pow(this.prms.V0.v, 2)
-        ) - Math.tan(this.alpha) * this.prms.D.v);
+            ) - Math.tan(this.alpha) * this.prms.D.v);
     }
 
     /**
@@ -209,7 +221,7 @@ export class Jet extends Nub {
             nub.prms.D.v = x;
             // console.log("__computing H for x =", x, nub.prms.D.v);
             const h = nub.Calc("ZW");
-            traj.push([ x, h.vCalc ]);
+            traj.push([x, h.vCalc]);
         }
         return traj;
     }
@@ -259,15 +271,8 @@ export class Jet extends Nub {
         this.prms.D.calculability = ParamCalculability.EQUATION;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            H: "m",
-            Y: "m",
-            t: "s",
-            Vx: "m/s",
-            Vz: "m/s",
-            Vt: "m/s"
-        }
+    public static override resultsUnits() {
+        return Jet._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/devalaison/jet_params.ts b/src/devalaison/jet_params.ts
index e4bd6ccef5b9f9fd9773950f349c57a0e0817dca..83911b9c70cc697759a8e4159e8cda93b961567a 100644
--- a/src/devalaison/jet_params.ts
+++ b/src/devalaison/jet_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class JetParams extends ParamsEquation {
 
diff --git a/src/dichotomie.ts b/src/dichotomie.ts
index d90fcf869e3742b3631f1205b13c1b235df96ff0..140cc546a3709eada09cd63a8d35701d005081b5 100644
--- a/src/dichotomie.ts
+++ b/src/dichotomie.ts
@@ -1,12 +1,12 @@
-import { BoolIdentity, Debug } from "./base";
-import { Nub } from "./nub";
-import { ParamDefinition } from "./param/param-definition";
-import { ParamDomain, ParamDomainValue } from "./param/param-domain";
-import { SessionSettings } from "./session_settings";
-import { Interval } from "./util/interval";
-import { Message, MessageCode } from "./util/message";
-import { Result } from "./util/result";
-import { SearchInterval } from "./util/search_interval";
+import { BoolIdentity, Debug } from "./internal_modules";
+import { Nub } from "./internal_modules";
+import { ParamDefinition } from "./internal_modules";
+import { ParamDomain, ParamDomainValue } from "./internal_modules";
+import { SessionSettings } from "./internal_modules";
+import { Interval } from "./internal_modules";
+import { Message, MessageCode } from "./internal_modules";
+import { Result } from "./internal_modules";
+import { SearchInterval } from "./internal_modules";
 
 /**
  * calcul par dichotomie
@@ -37,6 +37,11 @@ export class Dichotomie extends Debug {
 
     private _func: () => number;
 
+    /**
+     * si > 0, un calcul dichotomique est en cours
+     */
+    private static _inDicho: number = 0;
+
     /**
      * Construction de la classe.
      * @param nub Noeud de calcul contenant la méthode de calcul Equation
@@ -68,6 +73,10 @@ export class Dichotomie extends Debug {
         this._startIntervalMaxSteps = n;
     }
 
+    public static get inDicho(): boolean {
+        return Dichotomie._inDicho > 0;
+    }
+
     public CalculX(x: number): number {
         this.vX = x;
         return this.Calcul();
@@ -80,6 +89,8 @@ export class Dichotomie extends Debug {
      * @param rInit valeur initiale approximative de x
      */
     public Dichotomie(rTarget: number, rTol: number, rInit: number): Result {
+        Dichotomie._inDicho++;
+
         this._target = rTarget;
         // console.log("-----");
         // for (let x = 0; x <= 1; x += 0.1)
@@ -109,27 +120,31 @@ export class Dichotomie extends Debug {
                     this.debug(
                         `${this.analyticalSymbol}(${this.sVarCalc}=${s.value}) = ${rTarget}`
                     );
+                    Dichotomie._inDicho--;
                     return new Result(s.value);
                 } else {
                     this.debug(
                         "Non convergence"
                     );
+                    Dichotomie._inDicho--;
                     return new Result(new Message(MessageCode.ERROR_DICHO_CONVERGE, {
                         lastApproximation: s.value
-                    }));
+                    }), this.nub);
                 }
             } else {
+                Dichotomie._inDicho--;
                 return new Result(r.res);
             }
         } catch (e) {
             // un appel à Calcul() a généré une erreur
+            Dichotomie._inDicho--;
             return this.nub.result;
         }
     }
 
     public debug(s: string) {
-        if(this.DBG) {
-            super.debug("Dichotomie: "+s);
+        if (this.DBG) {
+            super.debug("Dichotomie: " + s);
         }
     }
 
@@ -151,13 +166,13 @@ export class Dichotomie extends Debug {
      */
     private isIncreasingFunction(x: number, dom: Interval): boolean {
         let epsilon = 1e-8;
-        for(let i=0; i < 20; i++) {
+        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;
+            if (Math.abs(y2 - y1) > 1E-6) return y2 > y1;
             epsilon *= 10;
         }
         return true;
@@ -188,9 +203,9 @@ export class Dichotomie extends Debug {
             }
             intSearch.growStep(2);
             intSearch.next();
-            if(bAllowRestart) {
+            if (bAllowRestart) {
                 intSearch.checkDirection()
-            } else if(n > this._startIntervalMaxSteps / 2) {
+            } else if (n > this._startIntervalMaxSteps / 2) {
                 bAllowRestart = true;
                 intSearch.reInit();
             }
@@ -343,7 +358,7 @@ export class Dichotomie extends Debug {
      *
      */
     private uniroot<T>(func: (param: number) => number, thisArg: T, lowerLimit: number, upperLimit: number,
-                       errorTol: number = 0, maxIter?: number
+        errorTol: number = 0, maxIter?: number
     ): { found: boolean, value: number } {
         let a = lowerLimit;
         let b = upperLimit;
diff --git a/src/fish_pass.ts b/src/fish_pass.ts
index 6f17f46dc3e0028a487a7fdb1400222a0230fcd4..096b642a149dc1f3d4097c416488241b97cda9b4 100644
--- a/src/fish_pass.ts
+++ b/src/fish_pass.ts
@@ -1,4 +1,4 @@
-import { Nub } from "./nub";
+import { Nub } from "./internal_modules";
 
 /**
  * An intermediate class for all fish passes (Pab, Par, MacroRugo[Compound]…),
diff --git a/src/index.ts b/src/index.ts
index 72a9c87d76af75b95855c64e09fd9293e48f57c1..f953174b2f7ca5cfd109c2fd0ce1e065d8f2f080 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -45,6 +45,7 @@ export * from "./structure/structure";
 export * from "./structure/structure_params";
 export * from "./structure/factory_structure";
 export * from "./structure/structure_props";
+export * from "./structure/rectangular_structure";
 export * from "./linked-value";
 export * from "./jalhyd_object";
 export * from "./date_revision";
@@ -60,7 +61,12 @@ export * from "./pab/pab_nombre_params";
 export * from "./pab/pab_puissance";
 export * from "./pab/pab_puissance_params";
 export * from "./pab/cloison_aval";
-export * from "./pipe_flow/lechaptcalmon";
+export * from "./pipe_flow/pl_lechaptcalmon";
+export * from "./pipe_flow/pl_lechaptcalmon_params";
+export * from "./pipe_flow/pl_strickler";
+export * from "./pipe_flow/pl_strickler_params";
+export * from "./pipe_flow/pressureloss";
+export * from "./pipe_flow/pressureloss_law";
 export * from "./lc-material";
 export * from "./structure/dever";
 export * from "./macrorugo/macrorugo";
@@ -100,3 +106,4 @@ export * from "./prebarrage/pre_barrage_params";
 export * from "./prebarrage/pb_cloison";
 export * from "./prebarrage/pb_bassin";
 export * from "./prebarrage/pb_bassin_params";
+export * from "./units";
diff --git a/src/internal_modules.ts b/src/internal_modules.ts
new file mode 100644
index 0000000000000000000000000000000000000000..180a4c285a2b796a12492546ca8bfeecfd33c89f
--- /dev/null
+++ b/src/internal_modules.ts
@@ -0,0 +1,171 @@
+// Implementation of the "internal module pattern" to solve the "TypeError: Class extends value undefined is not a constructor or null" error
+// cf. https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
+// All imports in jalhyd are from this file only.
+// Exported modules outside jalhyd by index.ts may be different (generally a subset of this present file).
+
+export * from "./base";
+export * from "./param/param-definition";
+export * from "./jalhyd_object";
+export * from "./compute-node";
+export * from "./dichotomie";
+export * from "./nub";
+export * from "./child_nub";
+export * from "./session_settings";
+export * from "./config";
+export * from "./param/param-domain";
+export * from "./param/param-value-mode";
+export * from "./param/param-values";
+export * from "./param/param-value-iterator";
+export * from "./param/param_definition_iterator";
+export * from "./param/params-equation";
+export * from "./param/params_equation_array_iterator";
+export * from "./param/mirror-iterator";
+export * from "./linked-value";
+export * from "./util/interval";
+export * from "./util/message";
+export * from "./util/result";
+export * from "./util/resultelement";
+export * from "./util/observer";
+export * from "./util/log";
+export * from "./util/map_iterator";
+export * from "./util/search_interval";
+export * from "./util/mermaid";
+export * from "./util/array_reverse_iterator";
+export * from "./variated-details";
+export * from "./lc-material";
+
+// Calculettes
+export * from "./devalaison/grille";
+export * from "./devalaison/grille_params";
+export * from "./devalaison/jet";
+export * from "./devalaison/jet_params";
+export * from "./fish_pass";
+export * from "./macrorugo/macrorugo";
+export * from "./macrorugo/macrorugo_params";
+export * from "./macrorugo/macrorugo_compound";
+export * from "./macrorugo/macrorugo_compound_params";
+export * from "./macrorugo/concentration_blocs";
+export * from "./macrorugo/concentration_blocs_params";
+export * from "./macrorugo/mrc-inclination";
+export * from "./math/spp";
+export * from "./math/spp_params";
+export * from "./math/trigo";
+export * from "./math/trigo_params";
+export * from "./math/yaxb";
+export * from "./math/yaxb_params";
+export * from "./math/yaxn";
+export * from "./math/yaxn_params";
+export * from "./open-channel/section/section_nub";
+export * from "./open-channel/methode-resolution";
+export * from "./open-channel/remous";
+export * from "./open-channel/remous_params";
+export * from "./open-channel/section/section_type";
+export * from "./open-channel/section/newton";
+export * from "./open-channel/section/section_type_params";
+export * from "./open-channel/section/section_parametree";
+export * from "./open-channel/section/section_parametree_params";
+export * from "./open-channel/section/section_circulaire";
+export * from "./open-channel/section/section_circulaire_params";
+export * from "./open-channel/section/section_puissance";
+export * from "./open-channel/section/section_puissance_params";
+export * from "./open-channel/section/section_rectang";
+export * from "./open-channel/section/section_rectang_params";
+export * from "./open-channel/section/section_trapez";
+export * from "./open-channel/section/section_trapez_params";
+export * from "./open-channel/section/hauteur_conjuguee";
+export * from "./open-channel/section/hauteur_correspondante";
+export * from "./open-channel/section/hauteur_critique";
+export * from "./open-channel/section/hauteur_normale";
+export * from "./open-channel/bief";
+export * from "./open-channel/bief_params";
+export * from "./open-channel/pente";
+export * from "./open-channel/pente_params";
+export * from "./open-channel/regime_uniforme";
+export * from "./par/par";
+export * from "./par/par_params";
+export * from "./par/par_simulation";
+export * from "./par/par_simulation_params";
+export * from "./par/par_type";
+export * from "./par/par_type_pf";
+export * from "./par/par_type_fatou";
+export * from "./par/par_type_sc";
+export * from "./par/par_type_chevron";
+export * from "./par/par_type_plane";
+export * from "./par/par_type_superactive";
+export * from "./structure/structure";
+export * from "./structure/structure_params";
+export * from "./structure/parallel_structure";
+export * from "./structure/parallel_structure_params";
+export * from "./structure/dever";
+export * from "./structure/dever_params";
+export * from "./structure/factory_structure";
+export * from "./structure/structure_props";
+export * from "./structure/rectangular_structure";
+export * from "./structure/rectangular_structure_params";
+export * from "./structure/structure_gate_cem88d";
+export * from "./structure/structure_gate_cem88v";
+export * from "./structure/structure_gate_cunge80";
+export * from "./structure/structure_kivi";
+export * from "./structure/structure_kivi_params";
+export * from "./structure/structure_orifice_free";
+export * from "./structure/structure_orifice_free_params";
+export * from "./structure/structure_orifice_submerged";
+export * from "./structure/structure_orifice_submerged_params";
+export * from "./structure/structure_rectangular_orifice_free";
+export * from "./structure/structure_rectangular_orifice_submerged";
+export * from "./structure/structure_triangular_trunc_weir";
+export * from "./structure/structure_triangular_trunc_weir_params";
+export * from "./structure/structure_triangular_weir_free";
+export * from "./structure/structure_triangular_weir";
+export * from "./structure/structure_triangular_weir_params";
+export * from "./structure/structure_triangular_weir_broad";
+export * from "./structure/structure_weir_submerged";
+export * from "./structure/structure_weir_submerged_larinier";
+export * from "./structure/structure_weir_free";
+export * from "./structure/structure_weir_villemonte";
+export * from "./structure/structure_vanlev_params";
+export * from "./structure/structure_vanlev_larinier";
+export * from "./structure/structure_vanlev_villemonte";
+export * from "./structure/structure_weir_cem88d";
+export * from "./structure/structure_weir_cem88v";
+export * from "./structure/structure_weir_cunge80";
+export * from "./structure/villemonte";
+export * from "./pab/pab";
+export * from "./pab/pab_params";
+export * from "./pab/cloison_aval";
+export * from "./pab/cloison_aval_params";
+export * from "./pab/cloisons";
+export * from "./pab/cloisons_params";
+export * from "./pab/pab_chute";
+export * from "./pab/pab_chute_params";
+export * from "./pab/pab_dimension";
+export * from "./pab/pab_dimensions_params";
+export * from "./pab/pab_nombre";
+export * from "./pab/pab_nombre_params";
+export * from "./pab/pab_puissance";
+export * from "./pab/pab_puissance_params";
+export * from "./pipe_flow/cond_distri";
+export * from "./pipe_flow/cond_distri_params";
+export * from "./pipe_flow/pressureloss";
+export * from "./pipe_flow/pressureloss_params";
+export * from "./pipe_flow/pressureloss_law";
+export * from "./pipe_flow/pressureloss_law_params";
+export * from "./pipe_flow/pl_lechaptcalmon";
+export * from "./pipe_flow/pl_lechaptcalmon_params";
+export * from "./pipe_flow/pl_strickler";
+export * from "./pipe_flow/pl_strickler_params";
+export * from "./prebarrage/pb_bassin";
+export * from "./prebarrage/pb_bassin_params";
+export * from "./prebarrage/pb_cloison";
+export * from "./prebarrage/pre_barrage";
+export * from "./prebarrage/pre_barrage_params";
+export * from "./solveur/solveur";
+export * from "./solveur/solveur_params";
+export * from "./verification/diving-jet-support";
+export * from "./verification/espece";
+export * from "./verification/espece_params";
+export * from "./verification/fish_species";
+export * from "./verification/verificateur";
+export * from "./verification/verificateur_params";
+export * from "./props";
+export * from "./session";
diff --git a/src/jalhyd_object.ts b/src/jalhyd_object.ts
index e15a97ff854a4d7055828c0dbc60ac24c9c7e549..fe5df0d25023b716b022a7a1a363c18cea744f4d 100644
--- a/src/jalhyd_object.ts
+++ b/src/jalhyd_object.ts
@@ -1,4 +1,4 @@
-import { ParamFamily } from "./param/param-definition";
+import { ParamFamily } from "./internal_modules";
 
 import * as base64 from "base-64";
 
diff --git a/src/linked-value.ts b/src/linked-value.ts
index 1fb7f99c488b6bcca3dd28d405ca942d4768bf59..783d51123d574614392fa9affe8aab168df80bf7 100644
--- a/src/linked-value.ts
+++ b/src/linked-value.ts
@@ -1,8 +1,8 @@
-import { Nub } from "./nub";
-import { ParamDefinition } from "./param/param-definition";
-import { INamedIterableValues } from "./param/param-value-iterator";
-import { ParamValueMode } from "./param/param-value-mode";
-import { ParamValues } from "./param/param-values";
+import { Nub } from "./internal_modules";
+import { ParamDefinition } from "./internal_modules";
+import { INamedIterableValues } from "./internal_modules";
+import { ParamValueMode } from "./internal_modules";
+import { ParamValues } from "./internal_modules";
 
 export class LinkedValue {
     /** linked value metadata (ex: calculator title for GUI) */
@@ -80,7 +80,7 @@ export class LinkedValue {
         return (
             this.nub !== undefined
             && this.symbol !== undefined
-            && ! this.isParameter()
+            && !this.isParameter()
         );
     }
 
@@ -143,7 +143,7 @@ export class LinkedValue {
             if (targetParam.valueMode === ParamValueMode.CALCUL) {
                 // if already computed, expose handmade fake param values for iterability
                 if (this.nub.result) {
-                    if (! this._paramValues) {
+                    if (!this._paramValues) {
                         this._paramValues = new ParamValues();
                         // populate
                         if (targetParam.hasMultipleValues) {
@@ -171,7 +171,7 @@ export class LinkedValue {
             // is result available ?
             if (this.nub.result) {
                 // expose handmade fake param values for iterability
-                if (! this._paramValues) {
+                if (!this._paramValues) {
                     this._paramValues = new ParamValues();
                     // populate
                     if (this.nub.resultHasMultipleValues()) {
diff --git a/src/macrorugo/concentration_blocs.ts b/src/macrorugo/concentration_blocs.ts
index b06a60a4c5eef8b0a15d9df5f8a298ba45da7b8a..3f9f97a73f558172a24f3f88878c1ee797d742a0 100644
--- a/src/macrorugo/concentration_blocs.ts
+++ b/src/macrorugo/concentration_blocs.ts
@@ -1,16 +1,26 @@
-import { floatDivAndMod, isEqual } from "../base";
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { ConcentrationBlocsParams } from "./concentration_blocs_params";
+import { floatDivAndMod, isEqual } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ConcentrationBlocsParams } from "../internal_modules";
 
 export class ConcentrationBlocs extends Nub {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        ax: "m",
+        R: "m",
+        AXB: "m",
+        AXH: "m"
+    };
+
     constructor(prms: ConcentrationBlocsParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.ConcentrationBlocs;
+        this.setCalculatorType(CalculatorType.ConcentrationBlocs);
         this._defaultCalculatedParam = prms.C;
         this.resetDefaultCalculatedParam();
     }
@@ -24,7 +34,7 @@ export class ConcentrationBlocs extends Nub {
      */
     public Equation(sVarCalc: string): Result {
         let rounded = false;
-        if (sVarCalc !== "N" && ! Number.isInteger(this.prms.N.v)) {
+        if (sVarCalc !== "N" && !Number.isInteger(this.prms.N.v)) {
             this.prms.N.v = Math.round(this.prms.N.v);
             rounded = true;
         }
@@ -56,7 +66,7 @@ export class ConcentrationBlocs extends Nub {
                     v++;
                 }
                 // harmonisation ?
-                if (! isEqual(R, 0, 1e-2)) {
+                if (!isEqual(R, 0, 1e-2)) {
                     // vers le bas
                     if (v > 0) {
                         NB = v;
@@ -129,13 +139,8 @@ export class ConcentrationBlocs extends Nub {
         this.prms.D.calculability = ParamCalculability.EQUATION;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            ax: "m",
-            R: "m",
-            AXB: "m",
-            AXH: "m"
-        }
+    public static override resultsUnits() {
+        return ConcentrationBlocs._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/macrorugo/concentration_blocs_params.ts b/src/macrorugo/concentration_blocs_params.ts
index 8bb42420bcc182e483dd73a359722e86822e819e..0003e56779bb90c2bb34a07a450cb87a704b3e2f 100644
--- a/src/macrorugo/concentration_blocs_params.ts
+++ b/src/macrorugo/concentration_blocs_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class ConcentrationBlocsParams extends ParamsEquation {
 
@@ -18,10 +18,10 @@ export class ConcentrationBlocsParams extends ParamsEquation {
 
     constructor(rC: number, rN: number, rL: number, rD: number, nullParams: boolean = false) {
         super();
-        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), undefined, rC, undefined, undefined, nullParams);
+        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), undefined, rC, ParamFamily.BLOCKCONCENTRATION, undefined, nullParams);
         this._N = new ParamDefinition(this, "N", ParamDomainValue.POS, undefined, rN, undefined, undefined, nullParams);
         this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, "m", rL, ParamFamily.WIDTHS, undefined, nullParams);
-        this._D = new ParamDefinition(this, "D", new ParamDomain(ParamDomainValue.INTERVAL, 0, 2), "m", rD, undefined, undefined, nullParams);
+        this._D = new ParamDefinition(this, "D", new ParamDomain(ParamDomainValue.INTERVAL, 0, 2), "m", rD, ParamFamily.DIAMETERS, undefined, nullParams);
 
         this.addParamDefinition(this._C);
         this.addParamDefinition(this._N);
diff --git a/src/macrorugo/macrorugo.ts b/src/macrorugo/macrorugo.ts
index cdd326052671b0de068687f82ed281eb3d007250..1015d3ad1620dfd57b20a5c508a47e933ecdf703 100644
--- a/src/macrorugo/macrorugo.ts
+++ b/src/macrorugo/macrorugo.ts
@@ -1,14 +1,14 @@
-import { CalculatorType } from "../compute-node";
-import { Dichotomie } from "../dichotomie";
-import { MacrorugoCompound } from "../index";
-import { ParamCalculability, ParamFamily } from "../param/param-definition";
-import { ParamValueMode } from "../param/param-value-mode";
-import { SessionSettings } from "../session_settings";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { MacrorugoParams } from "./macrorugo_params";
-import { MRCInclination } from "./mrc-inclination";
-import { FishPass } from "../fish_pass";
+import { CalculatorType } from "../internal_modules";
+import { Dichotomie } from "../internal_modules";
+import { MacrorugoCompound } from "../internal_modules";
+import { ParamCalculability, ParamFamily } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { SessionSettings } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { MacrorugoParams } from "../internal_modules";
+import { MRCInclination } from "../internal_modules";
+import { FishPass } from "../internal_modules";
 
 export enum MacroRugoFlowType {
     EMERGENT,
@@ -54,10 +54,22 @@ export class MacroRugo extends FishPass {
     /** true: Cd0 * min(3, fh), false : min(6, Cd0 * fh) */
     private paramCdNewVersion: boolean = true;
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        PV: "W/m³",
+        Vdeb: "m/s",
+        Vmax: "m/s",
+        Vg: "m/s",
+        ZF2: "m",
+        Strickler: "SI"
+    };
+
     constructor(prms: MacrorugoParams, dbg: boolean = false) {
         super(prms, dbg);
         this._cache = {};
-        this._calcType = CalculatorType.MacroRugo;
+        this.setCalculatorType(CalculatorType.MacroRugo);
         this._defaultCalculatedParam = this.prms.Q;
         this._intlType = "MacroRugo";
         this.resetDefaultCalculatedParam();
@@ -89,15 +101,16 @@ export class MacroRugo extends FishPass {
             this.parent === undefined
             || (
                 this.parent instanceof MacrorugoCompound
-                && this.parent.properties.getPropValue("inclinedApron") === MRCInclination.NOT_INCLINED
+                && this.parent.getPropValue("inclinedApron") === MRCInclination.NOT_INCLINED
             )
         ) {
             const ax: number = this.prms.PBD.v / Math.sqrt(this.prms.C.v);
-            if (this.prms.B.v < ax - 0.001) { // B < ax, with a little tolerance
+            const tol = 0.01; // tolérance avant avertissement (1 cm)
+            if (this.prms.B.v < ax - tol) { // B < ax, with a little tolerance
                 const m = new Message(MessageCode.WARNING_RAMP_WIDTH_LOWER_THAN_PATTERN_WIDTH);
                 m.extraVar.pattern = ax;
                 r.resultElement.log.add(m);
-            } else if (this.prms.B.v % (ax / 2) > 0.001 && this.prms.B.v % (ax / 2) < ax / 2 - 0.001) {
+            } else if (this.prms.B.v % (ax / 2) > tol && this.prms.B.v % (ax / 2) < ax / 2 - tol) {
                 const m = new Message(MessageCode.WARNING_RAMP_WIDTH_NOT_MULTIPLE_OF_HALF_PATTERN_WIDTH);
                 m.extraVar.halfPattern = ax / 2;
                 m.extraVar.lower = Math.floor(this.prms.B.v / ax * 2) * (ax / 2);
@@ -108,7 +121,7 @@ export class MacroRugo extends FishPass {
 
         // La concentration est-elle dans les valeurs admissibles 8-20% (#284)
         if (this.parent === undefined) {
-            if(this.prms.C.V < 0.08 || this.prms.C.V > 0.2) {
+            if (this.prms.C.V < 0.08 || this.prms.C.V > 0.2) {
                 r.resultElement.log.add(
                     new Message(MessageCode.WARNING_MACRORUGO_CONCENTRATION_OUT_OF_BOUNDS)
                 );
@@ -126,7 +139,7 @@ export class MacroRugo extends FishPass {
         r.resultElement.values.Vdeb = resVdeb;
         if (this.flowType !== MacroRugoFlowType.SUBMERGED) {
             // Froude
-            r.resultElement.values.Vg =  r.resultElement.values.Vdeb / (1 - Math.sqrt(MacroRugo.fracAxAy * this.prms.C.v));
+            r.resultElement.values.Vg = r.resultElement.values.Vdeb / (1 - Math.sqrt(MacroRugo.fracAxAy * this.prms.C.v));
             let resFr = r.resultElement.values.Vg / Math.sqrt(MacroRugo.g * this.prms.Y.v);
             if (isNaN(resFr)) { // if Y == 0
                 resFr = 0;
@@ -187,15 +200,8 @@ export class MacroRugo extends FishPass {
         this.prms.Cd0.calculability = ParamCalculability.FREE;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            PV: "W/m³",
-            Vdeb: "m/s",
-            Vmax: "m/s",
-            Vg: "m/s",
-            ZF2: "m",
-            Strickler: "SI"
-        }
+    public static override resultsUnits() {
+        return MacroRugo._resultsUnits;
     }
 
     protected exposeResults() {
@@ -300,7 +306,7 @@ export class MacroRugo extends FishPass {
      */
     private get Cd(): number {
         if (this._cache.Cd === undefined) {
-            if(this.paramCdNewVersion) {
+            if (this.paramCdNewVersion) {
                 this._cache.Cd = this.prms.Cd0.v * Math.min(this.paramMaxCd, (this.paramFhStar[0] + this.paramFhStar[1] / Math.pow(this.prms.Y.v / this.prms.PBD.v, this.paramFhStar[2])));
             } else {
                 this._cache.Cd = Math.min(this.paramMaxCd, this.prms.Cd0.v * (this.paramFhStar[0] + this.paramFhStar[1] / Math.pow(this.prms.Y.v / this.prms.PBD.v, this.paramFhStar[2])));
@@ -464,7 +470,7 @@ export class MacroRugo extends FishPass {
         const Fr = U0 /
             (1 - Math.sqrt(MacroRugo.fracAxAy * this.prms.C.v)) /
             Math.sqrt(MacroRugo.g * this.prms.Y.v);
-            return Math.max(1, Math.pow(Math.min(r / (1 - Math.pow(Fr, 2) / 4), Math.pow(Fr, -2 / 3)), 2));
+        return Math.max(1, Math.pow(Math.min(r / (1 - Math.pow(Fr, 2) / 4), Math.pow(Fr, -2 / 3)), 2));
     }
 }
 
@@ -487,7 +493,7 @@ export class MacroRugo extends FishPass {
  *
  */
 function uniroot<T>(func: (param: number) => number, thisArg: T, lowerLimit: number, upperLimit: number,
-                    errorTol: number = 0, maxIter: number = 1000
+    errorTol: number = 0, maxIter: number = 1000
 ) {
     let a = lowerLimit;
     let b = upperLimit;
diff --git a/src/macrorugo/macrorugo_compound.ts b/src/macrorugo/macrorugo_compound.ts
index 021e1eb267fa84fdb81a471b50ab47471fad6c44..a9cdad1e5f0787e65183403294c63cc5708bd77f 100644
--- a/src/macrorugo/macrorugo_compound.ts
+++ b/src/macrorugo/macrorugo_compound.ts
@@ -1,14 +1,14 @@
-import { round } from "../base";
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability } from "../param/param-definition";
-import { Props } from "../props";
-import { Session } from "../session";
-import { Message, MessageCode } from "../util/message";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { MacroRugo } from "./macrorugo";
-import { MacrorugoCompoundParams } from "./macrorugo_compound_params";
-import { MRCInclination } from "./mrc-inclination";
+import { round } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Props } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { MacroRugo } from "../internal_modules";
+import { MacrorugoCompoundParams } from "../internal_modules";
+import { MRCInclination } from "../internal_modules";
 
 export class MacrorugoCompound extends MacroRugo implements Observer {
 
@@ -24,21 +24,21 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
 
     constructor(prms: MacrorugoCompoundParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.MacroRugoCompound;
+        this.setCalculatorType(CalculatorType.MacroRugoCompound);
         this._props.addObserver(this);
         this.inclinedApron = MRCInclination.NOT_INCLINED;
     }
 
     public get inclinedApron(): MRCInclination {
-        return this.properties.getPropValue("inclinedApron");
+        return this.getPropValue("inclinedApron");
     }
 
     public set inclinedApron(i: MRCInclination) {
-        this.properties.setPropValue("inclinedApron", i);
+        this.setPropValue("inclinedApron", i);
     }
 
     public CalcSerie(rInit?: number): Result {
-        if (this.properties.getPropValue("inclinedApron") === MRCInclination.INCLINED) {
+        if (this.getPropValue("inclinedApron") === MRCInclination.INCLINED) {
             // important to regenerate it here, at every iteration of CalcSerie()
             this.generateInclinedFishway();
         }
@@ -52,7 +52,7 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
                     valsZ1 = this.prms.Z1.getInferredValuesList();
                 } else {
                     valsZ1 = new Array(child.prms.ZF1.getInferredValuesList().length)
-                    .fill(this.prms.Z1.singleValue);
+                        .fill(this.prms.Z1.singleValue);
                 }
                 if (child.prms.ZF1.hasMultipleValues) {
                     valsChildZF1 = child.prms.ZF1.getInferredValuesList();
@@ -91,19 +91,20 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
             throw new Error("MacrorugoCompound.Calc() : invalid parameter " + sVarCalc);
         }
         this.copyPrmsToChildren();
-        this.currentResult = this.Equation(sVarCalc);
+        this.currentResultElement = this.Equation(sVarCalc);
 
         // lateral inclination for inclined aprons
-        if (this.properties.getPropValue("inclinedApron") === MRCInclination.INCLINED) {
+        if (this.getPropValue("inclinedApron") === MRCInclination.INCLINED) {
             // extraResult : inclination
             this.result.resultElement.values.LIncl = (this.prms.ZRL.v - this.prms.ZRR.v) / this.prms.BR.v;
             // La largeur de la rampe inclinée est-elle adéquate par rapport à la largeur de motif ax ?
             const ax: number = this.prms.PBD.v / Math.sqrt(this.prms.C.v);
-            if (this.prms.BR.v - ax < -0.001) { // BR < ax, with a little tolerance
+            const tol = 0.01; // tolérance avant avertissement (1 cm)
+            if (this.prms.BR.v - ax < -tol) { // BR < ax, with a little tolerance
                 const m = new Message(MessageCode.WARNING_RAMP_WIDTH_LOWER_THAN_PATTERN_WIDTH);
                 m.extraVar.pattern = ax;
                 this._result.resultElement.log.add(m);
-            } else if (this.prms.BR.v % (ax / 2) > 0.001 && this.prms.BR.v % (ax / 2) < ax / 2 - 0.001) {
+            } else if (this.prms.BR.v % (ax / 2) > tol && this.prms.BR.v % (ax / 2) < ax / 2 - tol) {
                 const m = new Message(MessageCode.WARNING_RAMP_WIDTH_NOT_MULTIPLE_OF_HALF_PATTERN_WIDTH);
                 m.extraVar.halfPattern = ax / 2;
                 m.extraVar.lower = Math.floor(this.prms.BR.v / ax * 2) * (ax / 2);
@@ -112,7 +113,7 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
             }
         }
         // Check block concentration bounds
-        if(this.prms.C.v < 0.08 || this.prms.C.v > 0.2) {
+        if (this.prms.C.v < 0.08 || this.prms.C.v > 0.2) {
             this._result.resultElement.log.add(
                 new Message(MessageCode.WARNING_MACRORUGO_CONCENTRATION_OUT_OF_BOUNDS)
             );
@@ -125,7 +126,7 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
         const res = new Result(0);
         for (const child of this.children) {
             child.Calc(sVarCalc);
-            if(!child.result.ok) {
+            if (!child.result.ok) {
                 const m = new Message(MessageCode.ERROR_SOMETHING_FAILED_IN_CHILD);
                 m.extraVar.number = String(child.findPositionInParent() + 1);
                 return new Result(m);
@@ -260,7 +261,7 @@ export class MacrorugoCompound extends MacroRugo implements Observer {
             this.children[this.children.length - 1].prms.ZF1.singleValue = round(
                 this.prms.ZRR.singleValue + xCenter / this.prms.BR.singleValue
                 * (this.prms.ZRL.singleValue - this.prms.ZRR.singleValue)
-            , 3);
+                , 3);
             this.children[this.children.length - 1].prms.B.singleValue = round((xCenter - lastBorder) * 2, 3);
             lastBorder += this.children[this.children.length - 1].prms.B.singleValue;
         }
diff --git a/src/macrorugo/macrorugo_compound_params.ts b/src/macrorugo/macrorugo_compound_params.ts
index 2813f7f04f4809b4e135411440f0e83df4c5a67b..13e588d2c467663dda06f13d3234d8f329194a38 100644
--- a/src/macrorugo/macrorugo_compound_params.ts
+++ b/src/macrorugo/macrorugo_compound_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { MacrorugoParams } from "./macrorugo_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { MacrorugoParams } from "../internal_modules";
 
 export class MacrorugoCompoundParams extends MacrorugoParams {
 
diff --git a/src/macrorugo/macrorugo_params.ts b/src/macrorugo/macrorugo_params.ts
index 310b27b7dd26499d5220f39c33414e2acfb94400..d36b2f9915d5671c0a9d3e36f4f683a1771818a8 100644
--- a/src/macrorugo/macrorugo_params.ts
+++ b/src/macrorugo/macrorugo_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class MacrorugoParams extends ParamsEquation {
 
@@ -77,10 +77,10 @@ export class MacrorugoParams extends ParamsEquation {
         this._Ks = new ParamDefinition(this, "Ks", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "m", rRF, ParamFamily.STRICKLERS, undefined, nullParams);
         this.addParamDefinition(this._Ks);
 
-        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "", rCB, undefined, undefined, nullParams);
+        this._C = new ParamDefinition(this, "C", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), "", rCB, ParamFamily.BLOCKCONCENTRATION, undefined, nullParams);
         this.addParamDefinition(this._C);
 
-        this._PBD = new ParamDefinition(this, "PBD", new ParamDomain(ParamDomainValue.INTERVAL, 0, 2), "m", rPBD, undefined, undefined, nullParams);
+        this._PBD = new ParamDefinition(this, "PBD", new ParamDomain(ParamDomainValue.INTERVAL, 0, 2), "m", rPBD, ParamFamily.DIAMETERS, undefined, nullParams);
         this.addParamDefinition(this._PBD);
 
         this._PBH = new ParamDefinition(this, "PBH", ParamDomainValue.POS, "m", rPBH, ParamFamily.HEIGHTS, undefined, nullParams);
diff --git a/src/math/spp.ts b/src/math/spp.ts
index aaffa17878ac04440144fc0025c2999bde72d11d..de128ce77aec989b39b711574e9bb2bf8454be36 100644
--- a/src/math/spp.ts
+++ b/src/math/spp.ts
@@ -1,10 +1,10 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { SPPParams } from "./spp_params";
-import { YAXN } from "./yaxn";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { SPPParams } from "../internal_modules";
+import { YAXN } from "../internal_modules";
 
 export enum SPPOperation {
     SUM,        // Somme
@@ -19,7 +19,7 @@ export class SPP extends Nub {
 
     constructor(prms: SPPParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.SPP;
+        this.setCalculatorType(CalculatorType.SPP);
         this._defaultCalculatedParam = prms.Y;
         this.resetDefaultCalculatedParam();
         this.operation = SPPOperation.SUM;
@@ -31,11 +31,11 @@ export class SPP extends Nub {
     }
 
     public get operation(): SPPOperation {
-        return this.properties.getPropValue("sppOperation");
+        return this.getPropValue("sppOperation");
     }
 
     public set operation(o: SPPOperation) {
-        this.properties.setPropValue("sppOperation", o);
+        this.setPropValue("sppOperation", o);
     }
 
     /**
@@ -45,12 +45,12 @@ export class SPP extends Nub {
      */
     public Calc(sVarCalc: string | any, rInit?: number): Result {
         // if Calc() is called outside of CalcSerie(), _result might not be initialized
-        if (! this.result) {
+        if (!this.result) {
             this.initNewResultElement();
         }
         switch (sVarCalc) {
             case "Y":
-                this.currentResult = super.Calc(sVarCalc, rInit);
+                this.currentResultElement = super.Calc(sVarCalc, rInit);
                 if (this.result.ok) {
                     this.getParameter(sVarCalc).v = this.result.resultElement.vCalc;
                 }
diff --git a/src/math/spp_params.ts b/src/math/spp_params.ts
index a6b80ae1ce2331aca1454526a7719f4af469ad93..75a8d0c1481c61a7e74e14cd43b2452c8a114a77 100644
--- a/src/math/spp_params.ts
+++ b/src/math/spp_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Y = Σ ou π (a1.x1^p1, … an.xn^pn)
diff --git a/src/math/trigo.ts b/src/math/trigo.ts
index 13e6cad8a2849b30c21b3a7f7807b119ef25856e..286169998997726711b76af3ba71777267f52ea6 100644
--- a/src/math/trigo.ts
+++ b/src/math/trigo.ts
@@ -1,10 +1,10 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { TrigoParams } from "./trigo_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { TrigoParams } from "../internal_modules";
 
 export enum TrigoOperation {
     COS,
@@ -27,10 +27,10 @@ export class Trigo extends Nub implements Observer {
 
     constructor(prms: TrigoParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Trigo;
+        this.setCalculatorType(CalculatorType.Trigo);
         this._defaultCalculatedParam = prms.Y;
         this.resetDefaultCalculatedParam();
-        this.properties.addObserver(this);
+        this._props.addObserver(this);
         this.operation = TrigoOperation.COS;
         this.unit = TrigoUnit.DEG;
     }
@@ -41,19 +41,19 @@ export class Trigo extends Nub implements Observer {
     }
 
     public get operation(): TrigoOperation {
-        return this.properties.getPropValue("trigoOperation");
+        return this.getPropValue("trigoOperation");
     }
 
     public set operation(o: TrigoOperation) {
-        this.properties.setPropValue("trigoOperation", o);
+        this.setPropValue("trigoOperation", o);
     }
 
     public get unit(): TrigoUnit {
-        return this.properties.getPropValue("trigoUnit");
+        return this.getPropValue("trigoUnit");
     }
 
     public set unit(u: TrigoUnit) {
-        this.properties.setPropValue("trigoUnit", u);
+        this.setPropValue("trigoUnit", u);
     }
 
     public Equation(sVarCalc: string): Result {
diff --git a/src/math/trigo_params.ts b/src/math/trigo_params.ts
index cf448ec199c1b06237b2665fa45ab8d3c368bba4..a4cc6c0cc1fc112991562d35539beb1357e0e84e 100644
--- a/src/math/trigo_params.ts
+++ b/src/math/trigo_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Y = f(X)
diff --git a/src/math/yaxb.ts b/src/math/yaxb.ts
index 3dbb19b3f5c45e28999cf9d71d6816401da811b0..80fb6aeef4fec2658d31774d98b5e98114cd7fd0 100644
--- a/src/math/yaxb.ts
+++ b/src/math/yaxb.ts
@@ -1,9 +1,9 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { YAXBParams } from "./yaxb_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { YAXBParams } from "../internal_modules";
 
 /**
  * Y = A.X + B
@@ -12,7 +12,7 @@ export class YAXB extends Nub {
 
     constructor(prms: YAXBParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.YAXB;
+        this.setCalculatorType(CalculatorType.YAXB);
         this._defaultCalculatedParam = prms.Y;
         this.resetDefaultCalculatedParam();
     }
diff --git a/src/math/yaxb_params.ts b/src/math/yaxb_params.ts
index 6eaadca835118334729c0735ff3c73c9b10f6070..56b95a2e9eae927b5838a7b85ac0709f8708ab69 100644
--- a/src/math/yaxb_params.ts
+++ b/src/math/yaxb_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Y = A.X + B
diff --git a/src/math/yaxn.ts b/src/math/yaxn.ts
index 0c05407e3adf230af8df5f505b28e5e1b830305c..604b9c473b5a1a1e6f49f1b240947f530e33d393 100644
--- a/src/math/yaxn.ts
+++ b/src/math/yaxn.ts
@@ -1,9 +1,9 @@
-import { ChildNub } from "../child_nub";
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { YAXNParams } from "./yaxn_params";
+import { ChildNub } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { YAXNParams } from "../internal_modules";
 
 /**
  * Y = A.X^N
@@ -12,7 +12,7 @@ export class YAXN extends ChildNub {
 
     constructor(prms: YAXNParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.YAXN;
+        this.setCalculatorType(CalculatorType.YAXN);
         this._defaultCalculatedParam = prms.Y;
         this._intlType = "Puissance";
         this.resetDefaultCalculatedParam();
@@ -28,7 +28,7 @@ export class YAXN extends ChildNub {
 
         switch (sVarCalc) {
             case "Y":
-                if (this.prms.X.v < 0 && ! Number.isInteger(this.prms.N.v)) {
+                if (this.prms.X.v < 0 && !Number.isInteger(this.prms.N.v)) {
                     const m = new Message(MessageCode.ERROR_NON_INTEGER_POWER_ON_NEGATIVE_NUMBER);
                     m.extraVar.X = this.prms.X.v;
                     m.extraVar.N = this.prms.N.v;
diff --git a/src/math/yaxn_params.ts b/src/math/yaxn_params.ts
index 30f176969cbb808ba0461d8e0210db4de319b617..026c9779cbf3be29e833f48d59229f9395522841 100644
--- a/src/math/yaxn_params.ts
+++ b/src/math/yaxn_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Y = A.X^N
diff --git a/src/nub.ts b/src/nub.ts
index 77ef5d81fb21b72a65fe5b40bc9e6d901d337732..64e31c46d91211303adee731364c877dcbe67499 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,25 +1,67 @@
-import { CalculatorType, ComputeNode } from "./compute-node";
-import { Dichotomie } from "./dichotomie";
-import { acSection, MacrorugoCompound, Pab, ParamDefinition, ParamsEquation,
-         Session, Solveur, Structure, Verificateur } from "./index";
-import { LinkedValue } from "./linked-value";
-import { ParamCalculability, ParamFamily } from "./param/param-definition";
-import { ParamValueMode } from "./param/param-value-mode";
-import { IParamDefinitionIterator } from "./param/param_definition_iterator";
-import { ParamsEquationArrayIterator } from "./param/params_equation_array_iterator";
-import { Props } from "./props";
-import { SessionSettings } from "./session_settings";
-import { Message, MessageCode, MessageSeverity } from "./util/message";
-import { IObservable, Observable, Observer } from "./util/observer";
-import { Result } from "./util/result";
-import { ResultElement } from "./util/resultelement";
-import { VariatedDetails } from "./variated-details";
+import { CalculatorType, ComputeNode, IProperties } from "./internal_modules";
+import { Dichotomie } from "./internal_modules";
+import {
+    acSection, MacrorugoCompound, Pab, ParamDefinition, ParamsEquation,
+    Session, Solveur, Structure, Verificateur
+} from "./internal_modules";
+import { LinkedValue } from "./internal_modules";
+import { ParamCalculability, ParamFamily } from "./internal_modules";
+import { ParamValueMode } from "./internal_modules";
+import { IParamDefinitionIterator } from "./internal_modules";
+import { ParamsEquationArrayIterator } from "./internal_modules";
+import { Props } from "./internal_modules";
+import { SessionSettings } from "./internal_modules";
+import { Message, MessageCode } from "./internal_modules";
+import { Observable, Observer } from "./internal_modules";
+import { Result } from "./internal_modules";
+import { ResultElement } from "./internal_modules";
+import { VariatedDetails } from "./internal_modules";
+
+class NubIterator implements IterableIterator<Nub> {
+    private _nubs: Nub[];
+    private _index: number;
+
+    constructor(n: Nub) {
+        this._nubs = [];
+        this.fill(n);
+        this._index = 0;
+    }
+
+    private fill(n: Nub) {
+        this._nubs.push(n);
+        for (const c of n.getChildren()) {
+            this.fill(c);
+        }
+    }
+
+    // interface IterableIterator
+
+    public next(): IteratorResult<Nub> {
+        const i = this._index;
+        if (this._index < this._nubs.length) {
+            this._index = i + 1;
+            return {
+                done: false,
+                value: this._nubs[i]
+            };
+        } else {
+            return {
+                done: true,
+                value: undefined
+            };
+        }
+    }
+
+    [Symbol.iterator](): IterableIterator<Nub> {
+        return this;
+    }
+}
 
 /**
  * Classe abstraite de Noeud de calcul dans une session :
  * classe de base pour tous les calculs
  */
-export abstract class Nub extends ComputeNode implements IObservable {
+export abstract class Nub extends ComputeNode implements IProperties {
 
     /**
      * Find longest series, BUT: if any varying parameter is a calculation result,
@@ -28,8 +70,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * @param variated list of variated parameter/valuesList pairs to examinate
      */
     public static findVariatedSize(variated: VariatedDetails[])
-        : { size: number, longest: number, minLinkedResultParam: VariatedDetails }
-    {
+        : { size: number, longest: number, minLinkedResultParam: VariatedDetails } {
         if (variated.length > 0) {
             let minLinkedResultParam;
             let minLinkedResultsSize = Infinity;
@@ -76,7 +117,15 @@ export abstract class Nub extends ComputeNode implements IObservable {
     public dichoStartIntervalMaxSteps: number = 100;
 
     /** pointer to parent Nub */
-    public parent: Nub;
+    private _parent: Nub;
+
+    public get parent(): Nub {
+        return this._parent;
+    }
+
+    public setParent(p: Nub) {
+        this._parent = p;
+    }
 
     /**
      * Used by GUI for translation of the nub type in ngHyd (snackbar, ...).
@@ -95,24 +144,17 @@ export abstract class Nub extends ComputeNode implements IObservable {
     }
 
     /**
-     * Local setter to set results of Equation() / Solve() / …  as current
+     * Local setter to set result element of Equation() / Solve() / …  as current
      * ResultElement, instead of overwriting the whole Result object
      * (used by CalcSerie with varying parameters)
      */
-    protected set currentResult(r: Result) {
-        if (! this._result) {
+    protected set currentResultElement(r: Result) {
+        if (!this._result) {
             this.initNewResultElement();
         }
         this._result.resultElement = r.resultElement;
     }
 
-    /** Returns Props object (observable set of key-values) associated to this Nub */
-    public get properties(): Props {
-        // completes props with calcType if not already set
-        this._props.setPropValue("calcType", this.calcType);
-        return this._props;
-    }
-
     public set properties(props: Props) {
         this.setProperties(props);
     }
@@ -184,7 +226,16 @@ export abstract class Nub extends ComputeNode implements IObservable {
     }
 
     public get calcType(): CalculatorType {
-        return this._calcType;
+        return this.getPropValue("calcType");
+    }
+
+    /**
+     * set Nub calculator type.
+     * give children the opportunity to react to assignment
+     * @see Structure
+     */
+    protected setCalculatorType(ct: CalculatorType) {
+        this.setPropValue("calcType", ct);
     }
 
     public get calculatedParam(): ParamDefinition {
@@ -255,7 +306,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
     }
 
     // move code out of setter to ease inheritance
-    public setProperties(props: Props, resetProps: boolean = false) {
+    public setProperties(props: IProperties, resetProps: boolean = false) {
         // copy observers
         const observers = this._props.getObservers();
         // empty props
@@ -268,18 +319,18 @@ export abstract class Nub extends ComputeNode implements IObservable {
         }
         // set new props values
         let error: Error;
-        for (const p of Object.keys(props.props)) {
+        for (const p of props.keys) {
             // try properties one by one so that if an error is thrown,
             // remaining properties are still copied
             let oldValue: any;
             try {
                 // keep old value to restore it in case of an error, or else it breaks fixTargets()
-                oldValue = this._props.getPropValue(p); // should always be undefined but who knows
-                this._props.setPropValue(p, props.getPropValue(p));
-            } catch(e) {
+                oldValue = this.getPropValue(p); // should always be undefined but who knows
+                this.setPropValue(p, props.getPropValue(p));
+            } catch (e) {
                 error = e;
                 // no one will notice ^^
-                this._props.setPropValue(p, oldValue);
+                this.setPropValue(p, oldValue);
             }
         }
         // throw caught error if any
@@ -373,10 +424,10 @@ export abstract class Nub extends ComputeNode implements IObservable {
     public findFirstCalculableParameter(otherThan?: ParamDefinition) {
         for (const p of this.parameterIterator) {
             if (
-                [ ParamCalculability.EQUATION, ParamCalculability.DICHO ].includes(p.calculability)
+                [ParamCalculability.EQUATION, ParamCalculability.DICHO].includes(p.calculability)
                 && p.visible
                 && p !== otherThan
-                && [ ParamValueMode.SINGLE, ParamValueMode.MINMAX, ParamValueMode.LISTE ].includes(p.valueMode)
+                && [ParamValueMode.SINGLE, ParamValueMode.MINMAX, ParamValueMode.LISTE].includes(p.valueMode)
             ) {
                 return p;
             }
@@ -405,7 +456,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      */
     public EquationFirstAnalyticalParameter(): number {
         const res = this.Equation(this.firstAnalyticalPrmSymbol);
-        if (! res.ok) {
+        if (!res.ok) {
             this._result = res;
             throw new Error(this.constructor.name + ".EquationFirstAnalyticalParameter(): fail");
         }
@@ -431,14 +482,14 @@ export abstract class Nub extends ComputeNode implements IObservable {
             rInit = computedVar.initValue;
         }
         if (computedVar.isAnalytical()) {
-            this.currentResult = this.Equation(sVarCalc);
+            this.currentResultElement = this.Equation(sVarCalc);
             this._result.symbol = sVarCalc;
             return this._result;
         }
 
         const resSolve: Result = this.Solve(sVarCalc, rInit);
         if (!resSolve.ok) {
-            this.currentResult = resSolve;
+            this.currentResultElement = resSolve;
             this._result.symbol = sVarCalc;
             return this._result;
         }
@@ -447,7 +498,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         const res: Result = this.Equation(sAnalyticalPrm);
         res.vCalc = resSolve.vCalc;
 
-        this.currentResult = res;
+        this.currentResultElement = res;
         this._result.symbol = sVarCalc;
 
         this.notifyResultUpdated();
@@ -513,7 +564,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
                     || (
                         p.valueMode === ParamValueMode.LINK
                         && p.isReferenceDefined()
-                        && ! p.referencedValue.hasMultipleValues()
+                        && !p.referencedValue.hasMultipleValues()
                     )
                 )
             ) {
@@ -558,7 +609,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         stats = this._result.resultElementsLogStats(0, stats);
 
         let sn = 1;
-        const it = this.allChildNubIterator();
+        const it = this.directChildNubIterator();
         let icn = it.next();
         while (!icn.done) {
             stats = icn.value.result.resultElementsLogStats(sn++, stats);
@@ -716,7 +767,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
             this._children.push(child);
         }
         // add reference to parent collection (this)
-        child.parent = this;
+        child.setParent(this);
         // postprocessing
         this.adjustChildParameters(child);
     }
@@ -725,15 +776,18 @@ export abstract class Nub extends ComputeNode implements IObservable {
         return this._children;
     }
 
-    public getParent(): Nub {
-        return this.parent;
+    /**
+     * @returns iterator on direct child nubs (may include extra nubs, see Pab nub)
+     */
+    public directChildNubIterator() {
+        return this._children[Symbol.iterator]();
     }
 
     /**
-     * @returns iterator on all child nubs (may include extra nubs, see Pab nub)
+     * @returns iterator on all child nubs (recursively)
      */
-    public allChildNubIterator() {
-        return this._children[Symbol.iterator]();
+    public get allChildNubIterator() {
+        return new NubIterator(this);
     }
 
     /**
@@ -771,13 +825,13 @@ export abstract class Nub extends ComputeNode implements IObservable {
         // no linking is possible at all.
         // Different Structures in the same parent can get linked to each other.
         if (
-            ! this.isParentOrChildOf(src.nubUid)
+            !this.isParentOrChildOf(src.nubUid)
             && ( // check grand-parent for PreBarrage special case @TODO find a generic way
-                 // to perform both tests (synthesise .nubUid and .originNub.uid)
-                ! (this._calcType === CalculatorType.PreBarrage)
-                || ! this.isParentOrChildOf(src.originNub.uid)
+                // to perform both tests (synthesise .nubUid and .originNub.uid)
+                !(this.calcType === CalculatorType.PreBarrage)
+                || !this.isParentOrChildOf(src.originNub.uid)
             )
-         ) {
+        ) {
             // 1. own parameters
             for (const p of this._prms) {
                 // if symbol and Nub type are identical
@@ -799,7 +853,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 ) {
                     // if variability doesn't cause any problem (a non-variable
                     // parameter cannot be linked to a variating one)
-                    if (src.calculability !== ParamCalculability.FIXED || ! p.hasMultipleValues) {
+                    if (src.calculability !== ParamCalculability.FIXED || !p.hasMultipleValues) {
                         // if it is safe to link p's value to src
                         if (p.isLinkableTo(src)) {
                             // if p is a CALC param of a Structure other than "Q"
@@ -809,8 +863,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
                             // expose its parent
                             if (
                                 (
-                                (this instanceof Structure && p.symbol !== "Q" && ! this.isSiblingOf(src.nubUid))
-                                || this instanceof acSection
+                                    (this instanceof Structure && p.symbol !== "Q" && !this.isSiblingOf(src.nubUid))
+                                    || this instanceof acSection
                                 )
                                 && (p.valueMode === ParamValueMode.CALCUL)
                             ) {
@@ -836,7 +890,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
             // 2. extra results
             if (this._resultsFamilies) {
                 // if I don't depend on your result, you may depend on mine !
-                if (! this.dependsOnNubResult(src.parentNub)) {
+                if (!this.dependsOnNubResult(src.parentNub)) {
                     const erk = Object.keys(this._resultsFamilies);
                     // browse extra results
                     for (const erSymbol of erk) {
@@ -865,15 +919,15 @@ export abstract class Nub extends ComputeNode implements IObservable {
 
         // 3. children Nubs, except for PAB and MRC and PreBarrage
         if (
-            ! (this instanceof MacrorugoCompound)
+            !(this instanceof MacrorugoCompound)
             && ( // meta-except, if source param in a PAB's Cloison (should only apply to QA)
-                ! (this instanceof Pab)
+                !(this instanceof Pab)
                 || (
                     src.originNub instanceof Pab
                     && src.symbol === "QA"
                 )
             )
-            && this._calcType !== CalculatorType.PreBarrage
+            && this.calcType !== CalculatorType.PreBarrage
         ) {
             for (const cn of this.getChildren()) {
                 res = res.concat(cn.getLinkableValues(src));
@@ -893,8 +947,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         if (this.uid === uid) {
             return true;
         }
-        const parent = this.getParent();
-        if (parent && parent.uid === uid) {
+        if (this._parent && this._parent.uid === uid) {
             return true;
         }
         for (const c of this.getChildren()) {
@@ -914,9 +967,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
         if (this.uid === uid) {
             return true;
         }
-        const parent = this.getParent();
-        if (parent) {
-            for (const c of parent.getChildren()) {
+        if (this._parent) {
+            for (const c of this._parent.getChildren()) {
                 if (c.uid === uid) {
                     return true;
                 }
@@ -934,7 +986,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
     public getRequiredNubs(visited: string[] = []): Nub[] {
         let requiredNubs: Nub[] = [];
         // prevent loops
-        if (! visited.includes(this.uid)) {
+        if (!visited.includes(this.uid)) {
             visited.push(this.uid);
 
             // inspect all target Nubs
@@ -962,7 +1014,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 if (rn.uid !== rn2.uid) {
                     keep = (
                         keep
-                        && ! rn2.dependsOnNubResult(rn, true)
+                        && !rn2.dependsOnNubResult(rn, true)
                     );
                 }
             }
@@ -997,7 +1049,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
     public getTargettedNubs(visited: string[] = []) {
         const targettedNubs: Nub[] = [];
         // prevent loops
-        if (! visited.includes(this.uid)) {
+        if (!visited.includes(this.uid)) {
             visited.push(this.uid);
 
             // inspect all target Nubs
@@ -1027,9 +1079,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
      */
     public dependsOnNubResult(nub: Nub, followLinksChain: boolean = true): boolean {
         let thisFamily: Nub[] = [this];
-        const tp = this.getParent();
-        if (tp) {
-            thisFamily = thisFamily.concat(tp);
+        if (this._parent) {
+            thisFamily = thisFamily.concat(this._parent);
         }
         thisFamily = thisFamily.concat(this.getChildren());
 
@@ -1065,9 +1116,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
      */
     public dependsOnParameter(src: ParamDefinition) {
         let thisFamily: Nub[] = [this];
-        const tp = this.getParent();
-        if (tp) {
-            thisFamily = thisFamily.concat(tp);
+        if (this._parent) {
+            thisFamily = thisFamily.concat(this._parent);
         }
         thisFamily = thisFamily.concat(this.getChildren());
 
@@ -1119,7 +1169,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
         includeValuesLinks: boolean = false,
         includeOtherDependencies: boolean = false
     ): boolean {
-        if (uid !== this.uid && ! visited.includes(this.uid)) {
+        if (uid !== this.uid && !visited.includes(this.uid)) {
             visited.push(this.uid);
 
             // does any of our parameters depend on the target Nub ?
@@ -1131,9 +1181,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
                 }
             }
             // does any of our parent's parameters depend on the target Nub ?
-            const parent = this.getParent();
-            if (parent) {
-                if (parent.resultDependsOnNub(uid, visited, symbol, includeValuesLinks, includeOtherDependencies)) {
+            if (this._parent) {
+                if (this._parent.resultDependsOnNub(uid, visited, symbol, includeValuesLinks, includeOtherDependencies)) {
                     return true;
                 }
             }
@@ -1246,16 +1295,16 @@ export abstract class Nub extends ComputeNode implements IObservable {
     public objectRepresentation(extra?: object, nubUidsInSession?: string[]): object {
         let ret: any = {
             uid: this.uid,
-            props: Session.invertEnumKeysAndValuesInProperties(this.properties.props),
+            props: this.invertedPropertiesEnumAndValues(),
         };
 
         if (extra) {
-            ret =  {...ret, ...{ meta: extra } }; // merge properties
+            ret = { ...ret, ...{ meta: extra } }; // merge properties
         }
-        ret = {...ret, ...{  children: [], parameters: [] } }; // extend here to make "parameters" the down-most key
+        ret = { ...ret, ...{ children: [], parameters: [] } }; // extend here to make "parameters" the down-most key
 
         // iterate over local parameters
-        const localParametersIterator =  new ParamsEquationArrayIterator([this._prms]);
+        const localParametersIterator = new ParamsEquationArrayIterator([this._prms]);
         for (const p of localParametersIterator) {
             if (p.visible) {
                 ret.parameters.push(p.objectRepresentation(nubUidsInSession));
@@ -1310,11 +1359,11 @@ export abstract class Nub extends ComputeNode implements IObservable {
         if (obj.children && Array.isArray(obj.children)) {
             for (const s of obj.children) {
                 // decode properties
-                const props = Session.invertEnumKeysAndValuesInProperties(s.props, true);
+                const props = Props.invertEnumKeysAndValuesInProperties(s.props, true);
                 // create the Nub
                 const subNub = Session.getInstance().createNub(new Props(props), this);
                 // try to keep the original ID
-                if (! Session.getInstance().uidAlreadyUsed(s.uid)) {
+                if (!Session.getInstance().uidAlreadyUsed(s.uid)) {
                     subNub.setUid(s.uid);
                 } else {
                     ret.changedUids[s.uid] = subNub.uid;
@@ -1407,7 +1456,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * @param keepParametersState if true, mode and value of parameters will be kept between old and new section
      */
     public replaceChild(index: number, child: Nub, resetCalcParam: boolean = false,
-                        keepParametersState: boolean = true
+        keepParametersState: boolean = true
     ) {
         if (index > -1 && index < this._children.length) {
             const hasOldChild = (this._children[index] !== undefined);
@@ -1437,7 +1486,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
             }
         } else {
             throw new Error(`${this.constructor.name}.replaceChild invalid index ${index}`
-                          + ` (children length: ${this._children.length})`);
+                + ` (children length: ${this._children.length})`);
         }
         // postprocessing
         this.adjustChildParameters(child);
@@ -1446,7 +1495,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
             this.resetDefaultCalculatedParam();
         }
         // add reference to parent collection (this)
-        child.parent = this;
+        child.setParent(this);
     }
 
     /**
@@ -1577,7 +1626,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * the same for all children
      */
     public initNewResultElement() {
-        if (! this._result) {
+        if (!this._result) {
             this._result = new Result(undefined, this);
         }
         // push empty result element for further affectation va set currentResult()
@@ -1599,6 +1648,41 @@ export abstract class Nub extends ComputeNode implements IObservable {
         }
     }
 
+    /**
+     * @returns true if results for this nub and all its children do not contain errors
+     */
+    public get allResultsOk(): boolean {
+        for (const n of this.allChildNubIterator) {
+            if (!n.result.ok) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @returns true if all messages in nub hierarchy have the same code
+     */
+    public hasOnlyMessage(code: MessageCode): boolean {
+        for (const n of this.allChildNubIterator) {
+            if (!n.result.hasOnlyMessage(code)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public get uniqueMessageCodes(): MessageCode[] {
+        let res: MessageCode[] = [];
+        for (const n of this.allChildNubIterator) {
+            if (n.uid === "MDZ3aH") {
+                debugger
+            }
+            res = res.concat(n.result.uniqueMessageCodes);
+        }
+        return res;
+    }
+
     // interface IObservable
 
     /**
@@ -1661,8 +1745,8 @@ export abstract class Nub extends ComputeNode implements IObservable {
             return p.unit;
         }
         // is it a result ?
-        if (symbol in this.resultsUnits) {
-            return this.resultsUnits[symbol]; // might be undefined
+        if (symbol in Nub.resultsUnits()) {
+            return Nub.resultsUnits()[symbol]; // might be undefined
         }
         // give up
         return undefined;
@@ -1769,7 +1853,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * Optional postprocessing after adding / replacing a child
      */
     // tslint:disable-next-line:no-empty
-    protected adjustChildParameters(child: Nub) {}
+    protected adjustChildParameters(child: Nub) { }
 
     /**
      * Résoud l'équation par une méthode numérique
@@ -1783,4 +1867,82 @@ export abstract class Nub extends ComputeNode implements IObservable {
         return dicho.Dichotomie(target.v, SessionSettings.precision, rInit);
     }
 
+    // /**
+    //   * print all messages of this nub and its children
+    //   * @param m header string
+    //   * @param ident identation
+    //   */
+    // public printMessages(m?: string, ident: number = 0) {
+    //     const idnt = " ".repeat(ident);
+    //     console.log("");
+    //     console.log(idnt + "--- " + this.constructor.name + " " + this.uid + " --- " + m);
+    //     const errs = this.getMessages(ident);
+    //     if (errs.length > 0) {
+    //         errs.forEach(m => {
+    //             console.log(m);
+    //         });
+    //     }
+    // }
+
+    // /**
+    //  * get all messages of this nub and its children
+    //  */
+    // private getMessages(ident: number = 0): string[] {
+    //     let hasMessages = false;
+    //     let res: string[] = []
+    //     const idnt = " ".repeat(ident);
+    //     if (this.result.log.messages.length > 0) {
+    //         hasMessages = true;
+    //         for (const m of this.result.log.messages) {
+    //             res.push(idnt + m.toString());
+    //         }
+    //     }
+    //     for (const c of this._children) {
+    //         const subMsgs = c.getMessages(ident + 2);
+    //         if (subMsgs.length > 0) {
+    //             hasMessages = true;
+    //             res = res.concat(subMsgs);
+    //         }
+    //     }
+    //     if (hasMessages) {
+    //         return res;
+    //     }
+    //     return [];
+    // }
+
+    public invertedPropertiesEnumAndValues(forceNumbers: boolean = false) {
+        return this._props.invertEnumKeysAndValues(forceNumbers);
+    }
+
+    public addPropertiesObserver(o: Observer) {
+        this._props.addObserver(o);
+    }
+
+    protected childHasProperty(key: string, nth?: number): boolean {
+        if (this._children.length > 0) {
+            const n = nth ?? 0;
+            if (n < this._children.length) {
+                return this._children[n].hasProperty(key);
+            }
+        }
+        return false;
+    }
+
+    // interface IProperties
+
+    public hasProperty(key: string): boolean {
+        return true;
+    }
+
+    public get keys(): string[] {
+        return this._props.keys;
+    }
+
+    public getPropValue(key: string): any {
+        return this._props.getPropValue(key);
+    }
+
+    public setPropValue(key: string, val: any, sender?: any): boolean {
+        return this._props.setPropValue(key, val, sender);
+    }
 }
diff --git a/src/open-channel/bief.ts b/src/open-channel/bief.ts
index c5fba684ba10d7994ec81dc97ddcecc5b8f2dfd2..9448017779fb6416ef373a581fc361ba0fb36c4d 100644
--- a/src/open-channel/bief.ts
+++ b/src/open-channel/bief.ts
@@ -1,16 +1,16 @@
-import { CalculatorType, SectionType } from "../compute-node";
-import { ParamCalculability } from "../param/param-definition";
-import { ParamValues } from "../param/param-values";
-import { Session } from "../session";
-import { Message, MessageCode } from "../util/message";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { BiefParams, BiefRegime } from "./bief_params";
-import { MethodeResolution } from "./methode-resolution";
-import { CourbeRemous, ITrYResult } from "./remous";
-import { CourbeRemousParams } from "./remous_params";
-import { SectionNub } from "./section/section_nub";
-import { acSection } from "./section/section_type";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { ParamValues } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { BiefParams, BiefRegime } from "../internal_modules";
+import { MethodeResolution } from "../internal_modules";
+import { CourbeRemous, ITrYResult } from "../internal_modules";
+import { CourbeRemousParams } from "../internal_modules";
+import { SectionNub } from "../internal_modules";
+import { acSection } from "../internal_modules";
 
 export class Bief extends SectionNub implements Observer {
 
@@ -18,7 +18,7 @@ export class Bief extends SectionNub implements Observer {
 
     constructor(s: acSection, bp: BiefParams, dbg: boolean = false) {
         super(bp, dbg);
-        this._calcType = CalculatorType.Bief;
+        this.setCalculatorType(CalculatorType.Bief);
         this.setSection(s);
         this._props.addObserver(this);
         this.regime = BiefRegime.Fluvial;
@@ -40,7 +40,7 @@ export class Bief extends SectionNub implements Observer {
     }
 
     public set regime(regime: BiefRegime) {
-        this.properties.setPropValue("regime", regime);
+        this.setPropValue("regime", regime);
     }
 
     public Calc(sVarCalc?: string, rInit?: number): Result {
@@ -74,13 +74,13 @@ export class Bief extends SectionNub implements Observer {
 
         if (
             this.calculatedParam === this.prms.Z1
-            && this.properties.getPropValue("regime") === BiefRegime.Torrentiel
+            && this.getPropValue("regime") === BiefRegime.Torrentiel
         ) {
             throw new Error("Bief.Equation() : cannot calculate Z1 in Torrential regime");
         }
         if (
             this.calculatedParam === this.prms.Z2
-            && this.properties.getPropValue("regime") === BiefRegime.Fluvial
+            && this.getPropValue("regime") === BiefRegime.Fluvial
         ) {
             throw new Error("Bief.Equation() : cannot calculate Z2 in Fluvial regime");
         }
@@ -97,7 +97,7 @@ export class Bief extends SectionNub implements Observer {
         xValues.setValues(0, l, dx);
 
         // in Dichotomie mode, update sandbox value of calculated param
-        if (! this.calculatedParam.isAnalytical()) {
+        if (!this.calculatedParam.isAnalytical()) {
             // we're calculating Ks or Q, in section
             this.courbeRemous.section.getParameter(this.calculatedParam.symbol).v = this.calculatedParam.v;
         }
diff --git a/src/open-channel/bief_params.ts b/src/open-channel/bief_params.ts
index ed84bd477acf4e29df104577f4a6665d1a0c89c6..007b5dd62f9072399d09fc1ffd5ac5b3701dd35c 100644
--- a/src/open-channel/bief_params.ts
+++ b/src/open-channel/bief_params.ts
@@ -1,4 +1,4 @@
-import { CourbeRemousParams } from "./remous_params";
+import { CourbeRemousParams } from "../internal_modules";
 
 export enum BiefRegime {
     Fluvial,
diff --git a/src/open-channel/pente.ts b/src/open-channel/pente.ts
index 28407d0a51a6fe3f1d83cf4ecb6bad1c48420c83..a4b68aeaafff29c8e9b82ad85fccbd6831d03c1d 100644
--- a/src/open-channel/pente.ts
+++ b/src/open-channel/pente.ts
@@ -1,14 +1,14 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { PenteParams } from "./pente_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PenteParams } from "../internal_modules";
 
 export class Pente extends Nub {
 
     constructor(prms: PenteParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Pente;
+        this.setCalculatorType(CalculatorType.Pente);
         this._defaultCalculatedParam = prms.I;
         this.resetDefaultCalculatedParam();
     }
diff --git a/src/open-channel/pente_params.ts b/src/open-channel/pente_params.ts
index f47737d26bbcf531f8fb0bb8305ddef3ffe6fc6c..db8ba8bc5d122e09679d6062d04bd7ced37ac0ae 100644
--- a/src/open-channel/pente_params.ts
+++ b/src/open-channel/pente_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PenteParams extends ParamsEquation {
 
diff --git a/src/open-channel/regime_uniforme.ts b/src/open-channel/regime_uniforme.ts
index 45be61ca176c93e28a42867c8ff1ea3e0a296083..3437cb832f4189fa141abbad4cc54d99e3baab46 100644
--- a/src/open-channel/regime_uniforme.ts
+++ b/src/open-channel/regime_uniforme.ts
@@ -1,18 +1,25 @@
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability, ParamFamily } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { SectionNub } from "./section/section_nub";
-import { SectionParams } from "./section/section_parametree_params";
-import { acSection } from "./section/section_type";
-import { cSnCirc } from "./section/section_circulaire";
-import { isGreaterThan } from "../base";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability, ParamFamily } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { SectionNub } from "../internal_modules";
+import { SectionParams } from "../internal_modules";
+import { acSection } from "../internal_modules";
+import { cSnCirc } from "../internal_modules";
+import { isGreaterThan } from "../internal_modules";
 
 export class RegimeUniforme extends SectionNub {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        V: "m/s"
+    };
+
     constructor(s: acSection, dbg: boolean = false) {
         super(new SectionParams(), dbg);
-        this._calcType = CalculatorType.RegimeUniforme;
+        this.setCalculatorType(CalculatorType.RegimeUniforme);
         this.setSection(s);
     }
 
@@ -72,7 +79,7 @@ export class RegimeUniforme extends SectionNub {
             && this.section.prms.YB.v >= this.section.prms.D.v
             && isGreaterThan(this.section.prms.Y.v, this.section.prms.D.v, 1e-3)
         ) {
-            this.currentResult = new Result(new Message(MessageCode.ERROR_RU_CIRC_LEVEL_TOO_HIGH));
+            this.currentResultElement = new Result(new Message(MessageCode.ERROR_RU_CIRC_LEVEL_TOO_HIGH));
             return this.result;
         }
 
@@ -95,10 +102,8 @@ export class RegimeUniforme extends SectionNub {
         this.section.prms.YB.calculability = ParamCalculability.FREE;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            V: "m/s"
-        }
+    public static override resultsUnits() {
+        return RegimeUniforme._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/open-channel/remous.ts b/src/open-channel/remous.ts
index f3be273953964158fc045e2edb4a09af19aaabc8..7eab9c0c23ed1d8b7e9691b29f30874fd70dd649 100644
--- a/src/open-channel/remous.ts
+++ b/src/open-channel/remous.ts
@@ -1,19 +1,19 @@
-import { round, XOR } from "../base";
-import { CalculatorType } from "../compute-node";
-import { Dichotomie } from "../dichotomie";
-import { MirrorIterator } from "../param/mirror-iterator";
-import { ParamCalculability } from "../param/param-definition";
-import { INumberIterator } from "../param/param-value-iterator";
-import { ParamValues } from "../param/param-values";
-import { SessionSettings } from "../session_settings";
-import { cLog } from "../util/log";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { ResultElement } from "../util/resultelement";
-import { MethodeResolution } from "./methode-resolution";
-import { CourbeRemousParams } from "./remous_params";
-import { SectionNub } from "./section/section_nub";
-import { acSection } from "./section/section_type";
+import { round, XOR } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Dichotomie } from "../internal_modules";
+import { MirrorIterator } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { INumberIterator } from "../internal_modules";
+import { ParamValues } from "../internal_modules";
+import { SessionSettings } from "../internal_modules";
+import { cLog } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { MethodeResolution } from "../internal_modules";
+import { CourbeRemousParams } from "../internal_modules";
+import { SectionNub } from "../internal_modules";
+import { acSection } from "../internal_modules";
 
 export interface ITrYResult {
     trY: { [key: number]: number; };
@@ -38,7 +38,7 @@ export class CourbeRemous extends SectionNub {
         dbg: boolean = false
     ) {
         super(crp, dbg);
-        this._calcType = CalculatorType.CourbeRemous;
+        this.setCalculatorType(CalculatorType.CourbeRemous);
         this.setSection(s);
         this.methodeResolution = method;
         // no calculated parameter
@@ -46,11 +46,11 @@ export class CourbeRemous extends SectionNub {
     }
 
     public get methodeResolution(): MethodeResolution {
-        return this.properties.getPropValue("methodeResolution");
+        return this.getPropValue("methodeResolution");
     }
 
     public set methodeResolution(m: MethodeResolution) {
-        this.properties.setPropValue("methodeResolution", m);
+        this.setPropValue("methodeResolution", m);
     }
 
     public setSection(s: acSection) {
@@ -445,9 +445,10 @@ export class CourbeRemous extends SectionNub {
             } else {
                 ligneDeau = Math.max(crbFlu[x], crbTor[x]);
             }
-            const re = new ResultElement({ Y: ligneDeau + this.getCoteFond(x) });
+            const re = new ResultElement({ ZW: ligneDeau + this.getCoteFond(x) });
 
             re.addExtraResult("X", x);
+            re.addExtraResult("Y", ligneDeau);
 
             if (crbFlu[x]) {
                 re.addExtraResult("flu", crbFlu[x] + this.getCoteFond(x));
@@ -527,7 +528,7 @@ export class CourbeRemous extends SectionNub {
      * @param sDonnee éventuel symbole / paire symbole-uid du paramètre à calculer
      */
     public CalcSerie(rInit?: number): Result {
-        const varCalc = this.properties.getPropValue("varCalc");
+        const varCalc = this.getPropValue("varCalc");
         const res = this.calculRemous(varCalc);
         return res;
     }
@@ -546,6 +547,16 @@ export class CourbeRemous extends SectionNub {
         return this._prms as CourbeRemousParams;
     }
 
+    public isComputable(): boolean {
+        if (super.isComputable()) {
+            // au moins Z1 ou Z2 doit être défini
+            const z1 = this.prms.Z1;
+            const z2 = this.prms.Z2;
+            return z1.isDefined || z2.isDefined;
+        }
+        return false;
+    }
+
     /**
      * Retourne la cote de fond à l'abscisse x
      * @param x abscisse en m (0 = amont)
@@ -746,7 +757,7 @@ export class CourbeRemous extends SectionNub {
         }
 
         // let k2 = this.Calc_dYdX(Y + Dx / 2 * k1);
-        const rDXDY2: Result = this.Calc_dYdX(Y + rDx / 2 * k1);
+        const rDXDY2: Result = this.Calc_dYdX(Math.max(Y + rDx / 2 * k1, 0));
         if (!rDXDY2.ok) {
             return rDXDY2;
         }
@@ -757,7 +768,7 @@ export class CourbeRemous extends SectionNub {
         }
 
         // let k3 = this.Calc_dYdX(Y + Dx / 2 * k2);
-        const rDXDY3: Result = this.Calc_dYdX(Y + rDx / 2 * k2);
+        const rDXDY3: Result = this.Calc_dYdX(Math.max(Y + rDx / 2 * k2, 0));
         if (!rDXDY3.ok) {
             return rDXDY3;
         }
@@ -768,14 +779,14 @@ export class CourbeRemous extends SectionNub {
         }
 
         // let k4 = this.Calc_dYdX(Y + Dx * k3);
-        const rDXDY4: Result = this.Calc_dYdX(Y + rDx * k3);
+        const rDXDY4: Result = this.Calc_dYdX(Math.max(Y + rDx * k3, 0));
         if (!rDXDY4.ok) {
             return rDXDY4;
         }
         const k4 = rDXDY4.vCalc;
 
         // tslint:disable-next-line:variable-name
-        const Yout = Y + rDx / 6 * (k1 + 2 * (k2 + k3) + k4);
+        const Yout = Math.max(Y + rDx / 6 * (k1 + 2 * (k2 + k3) + k4), 0);
 
         // if ($this ->rDx > 0 xor !($Yout < $this ->oSect ->rHautCritique)) { return false; }
         if (XOR(rDx > 0, !(Yout < hc))) {
@@ -833,7 +844,7 @@ export class CourbeRemous extends SectionNub {
         // let funcCalcY = 'Calc_Y_' + Resolution;
         // return this[funcCalcY](Y);
         let res: Result;
-        const methodeResolution: MethodeResolution = this.properties.getPropValue("methodeResolution");
+        const methodeResolution: MethodeResolution = this.getPropValue("methodeResolution");
         switch (methodeResolution) {
             case MethodeResolution.Trapezes:
                 res = this.Calc_Y_Trapez(Y);
diff --git a/src/open-channel/remous_params.ts b/src/open-channel/remous_params.ts
index ffacb2190cdaa7243d94df028d04ae5136dff69e..6e86a08f4c92a0e91c2d21ae45d4970eea301e88 100644
--- a/src/open-channel/remous_params.ts
+++ b/src/open-channel/remous_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamDomain, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * paramètres pour les courbes de remous
diff --git a/src/open-channel/section/hauteur_conjuguee.ts b/src/open-channel/section/hauteur_conjuguee.ts
index 44dc3068fe0c33b712537c9d4b8055d612966f2c..e9ab2695cfd78ceaeffd31faf3e6738a33c4251a 100644
--- a/src/open-channel/section/hauteur_conjuguee.ts
+++ b/src/open-channel/section/hauteur_conjuguee.ts
@@ -1,8 +1,8 @@
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { acNewton } from "./newton";
-import { acSection } from "./section_type";
-import { ParamsSection } from "./section_type_params";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { acNewton } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 /**
  * Calcul de la hauteur conjuguée (Impulsion égale)
diff --git a/src/open-channel/section/hauteur_correspondante.ts b/src/open-channel/section/hauteur_correspondante.ts
index 2bf1e507542696255a9a65d8e3b525d0551d915a..984501163d2571c0945ef57555f2171d641100ad 100644
--- a/src/open-channel/section/hauteur_correspondante.ts
+++ b/src/open-channel/section/hauteur_correspondante.ts
@@ -1,8 +1,8 @@
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { acNewton } from "./newton";
-import { acSection } from "./section_type";
-import { ParamsSection } from "./section_type_params";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { acNewton } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 /**
  * Calcul de la hauteur correspondante (charge égale)
diff --git a/src/open-channel/section/hauteur_critique.ts b/src/open-channel/section/hauteur_critique.ts
index d369c58dc2bcaa99d53bde668290775cf4b6eeec..e827d6f513f1710e196232e02c62c09ad37972e3 100644
--- a/src/open-channel/section/hauteur_critique.ts
+++ b/src/open-channel/section/hauteur_critique.ts
@@ -1,8 +1,8 @@
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { acNewton } from "./newton";
-import { acSection } from "./section_type";
-import { ParamsSection } from "./section_type_params";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { acNewton } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 /**
  * Calcul de la hauteur critique
diff --git a/src/open-channel/section/hauteur_normale.ts b/src/open-channel/section/hauteur_normale.ts
index 579a60b0009ffcedf4d1239801174f84525b48fb..0b674bebb21b2befdb0c397a4762e305b2d9becb 100644
--- a/src/open-channel/section/hauteur_normale.ts
+++ b/src/open-channel/section/hauteur_normale.ts
@@ -1,6 +1,6 @@
-import { Result } from "../../util/result";
-import { acNewton } from "./newton";
-import { acSection } from "./section_type";
+import { Result } from "../../internal_modules";
+import { acNewton } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Calcul de la hauteur normale
diff --git a/src/open-channel/section/newton.ts b/src/open-channel/section/newton.ts
index 1f5a623cd1c8f0737fbeb2a5b44de72716ebc477..3f5ea1bbf04248e0c3051e5938617461e046e245 100644
--- a/src/open-channel/section/newton.ts
+++ b/src/open-channel/section/newton.ts
@@ -1,9 +1,9 @@
-import { Debug, XOR } from "../../base";
-import { SessionSettings } from "../../session_settings";
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { ResultElement } from "../../util/resultelement";
-import { ParamsSection } from "./section_type_params";
+import { Debug, XOR } from "../../internal_modules";
+import { SessionSettings } from "../../internal_modules";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { ResultElement } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 // tslint:disable-next-line:class-name
 export abstract class acNewton extends Debug {
diff --git a/src/open-channel/section/section_circulaire.ts b/src/open-channel/section/section_circulaire.ts
index e522e80857fcc47057bb76c8f8062119a05a3c5f..a04d2353ecc52bfa9a070ffc4d1a899e29ec4d86 100644
--- a/src/open-channel/section/section_circulaire.ts
+++ b/src/open-channel/section/section_circulaire.ts
@@ -1,9 +1,9 @@
-import { SectionType } from "../../compute-node";
-import { ParamCalculability } from "../../param/param-definition";
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { ParamsSectionCirc } from "./section_circulaire_params";
-import { acSection } from "./section_type";
+import { SectionType } from "../../internal_modules";
+import { ParamCalculability } from "../../internal_modules";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { ParamsSectionCirc } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Calculs de la section circulaire
@@ -18,7 +18,7 @@ export class cSnCirc extends acSection {
 
     constructor(prms: ParamsSectionCirc, dbg: boolean = false) {
         super(prms, dbg);
-        this._nodeType = SectionType.SectionCercle;
+        this.nodeType = SectionType.SectionCercle;
         // commenté car si D est la variable à déterminer, il peut valoir n'importe
         // quoi... if (prms.YB.v > D) { prms.YB.v = D; } // On place la berge au sommet du cercle
 
diff --git a/src/open-channel/section/section_circulaire_params.ts b/src/open-channel/section/section_circulaire_params.ts
index 4bf5fa3d54c06f5ddf34753b95bbda9ab9cdb263..b5a954c02976ccacb2637ac1d120f9de0def08cc 100644
--- a/src/open-channel/section/section_circulaire_params.ts
+++ b/src/open-channel/section/section_circulaire_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../../param/param-definition";
-import { ParamDomainValue } from "../../param/param-domain";
-import { ParamsSection } from "./section_type_params";
+import { ParamDefinition, ParamFamily } from "../../internal_modules";
+import { ParamDomainValue } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 export class ParamsSectionCirc extends ParamsSection {
 	private _D: ParamDefinition;          // Diamètre du cercle
@@ -14,9 +14,9 @@ export class ParamsSectionCirc extends ParamsSection {
 		this.LargeurBerge.visible = false; // or else something might get linked to it although it is undefined
 	}
 
-    /**
-     * Diamètre du cercle
-     */
+	/**
+	 * Diamètre du cercle
+	 */
 	get D(): ParamDefinition {
 		return this._D;
 	}
diff --git a/src/open-channel/section/section_nub.ts b/src/open-channel/section/section_nub.ts
index a563f418222ed10bb70d498be9f6707b0f2704b8..f33df5aacd1a94d32a4bfd7baedbca0a04d62d49 100644
--- a/src/open-channel/section/section_nub.ts
+++ b/src/open-channel/section/section_nub.ts
@@ -1,9 +1,9 @@
-import { Session } from "../../index";
-import { Nub } from "../../nub";
-import { ParamDefinition } from "../../param/param-definition";
-import { ParamsEquation } from "../../param/params-equation";
-import { Props } from "../../props";
-import { acSection } from "./section_type";
+import { Session } from "../../internal_modules";
+import { Nub } from "../../internal_modules";
+import { ParamDefinition } from "../../internal_modules";
+import { ParamsEquation } from "../../internal_modules";
+import { Props } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * A Nub that contains an acSection (ex: RegimeUniforme, SectionParametree, Remous)
@@ -27,18 +27,6 @@ export abstract class SectionNub extends Nub {
         this._sectionVars = {};
     }
 
-    /** Returns Props object (observable set of key-values) associated to this Nub */
-    public get properties(): Props {
-        // completes props with calcType if not already set
-        this._props.setPropValue("calcType", this.calcType);
-        return this._props;
-    }
-
-    // setter is not inherited from Nub if getter is redefined :/
-    public set properties(props: Props) {
-        super.setProperties(props);
-    }
-
     public getParameter(name: string): ParamDefinition {
         if (typeof name !== "string") {
             // dirty hack because calculated param descriptor for section params is an object { uid: , symbol: }
@@ -104,10 +92,27 @@ export abstract class SectionNub extends Nub {
                 this._children[0] = undefined;
             }
             this.replaceChild(0, s);
+            this._props.removeProp("nodeType"); // because this property belongs to child section and is set as long as section is not defined
             /**
              * Y linkability managed in child classes through 'visible' flag
              * @see Bief,CourbeRemous
              */
         }
     }
+
+    // interface IProperties
+
+    public getPropValue(key: string): any {
+        if (this.childHasProperty(key)) {
+            return this.section.getPropValue(key);
+        }
+        return this._props.getPropValue(key);
+    }
+
+    public setPropValue(key: string, val: any, sender?: any): boolean {
+        if (this.childHasProperty(key)) {
+            return this.section.setPropValue(key, val, sender);
+        }
+        return this._props.setPropValue(key, val, sender);
+    }
 }
diff --git a/src/open-channel/section/section_parametree.ts b/src/open-channel/section/section_parametree.ts
index dcd8c599dcb9738cfec884907d5045a000d92e61..12e4293d551d3593565d34582b61cc492ab9a4f4 100644
--- a/src/open-channel/section/section_parametree.ts
+++ b/src/open-channel/section/section_parametree.ts
@@ -1,11 +1,11 @@
-import { CalculatorType } from "../../compute-node";
-import { ParamCalculability, ParamDefinition, ParamFamily } from "../../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../../param/param-domain";
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { SectionNub } from "./section_nub";
-import { SectionParams } from "./section_parametree_params";
-import { acSection } from "./section_type";
+import { CalculatorType } from "../../internal_modules";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../../internal_modules";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { SectionNub } from "../../internal_modules";
+import { SectionParams } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Nub sur les sections paramétrées
@@ -14,7 +14,7 @@ export class SectionParametree extends SectionNub {
 
     constructor(s: acSection, dbg: boolean = false) {
         super(new SectionParams(), dbg);
-        this._calcType = CalculatorType.SectionParametree;
+        this.setCalculatorType(CalculatorType.SectionParametree);
         this.setSection(s);
         this.initSectionVars();
         // no calculated parameter
@@ -81,7 +81,7 @@ export class SectionParametree extends SectionNub {
         // par les appels successifs car c'est en même temps un paramètre et une variable temporaire)
         const Y = this.getParameter("Y").v;
 
-        if (! this.result) {
+        if (!this.result) {
             this.initNewResultElement();
         }
 
@@ -181,7 +181,7 @@ export class SectionParametree extends SectionNub {
     }
 
     // tslint:disable-next-line:no-empty
-    protected adjustChildParameters(): void {}
+    protected adjustChildParameters(): void { }
 
     protected exposeResults() {
         this._resultsFamilies = {
diff --git a/src/open-channel/section/section_parametree_params.ts b/src/open-channel/section/section_parametree_params.ts
index 3de86f5d6a4b24e8e130bd645929dbc5f1d3af9f..6d046f3243ca9e2ac62aff0c234a0dd0b387a639 100644
--- a/src/open-channel/section/section_parametree_params.ts
+++ b/src/open-channel/section/section_parametree_params.ts
@@ -1,4 +1,4 @@
-import { ParamsEquation } from "../../param/params-equation";
+import { ParamsEquation } from "../../internal_modules";
 
 // dummy ParamsEquation for code consistency
-export class SectionParams extends ParamsEquation {}
+export class SectionParams extends ParamsEquation { }
diff --git a/src/open-channel/section/section_puissance.ts b/src/open-channel/section/section_puissance.ts
index eafb2f4b108d9317d2b474649d3b374ab4d2fd07..3e73cc2d0af0722d722f9e4b5a877e3b25f3682f 100644
--- a/src/open-channel/section/section_puissance.ts
+++ b/src/open-channel/section/section_puissance.ts
@@ -1,8 +1,8 @@
-import { SectionType } from "../../compute-node";
-import { ParamCalculability } from "../../param/param-definition";
-import { Result } from "../../util/result";
-import { ParamsSectionPuiss } from "./section_puissance_params";
-import { acSection } from "./section_type";
+import { SectionType } from "../../internal_modules";
+import { ParamCalculability } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { ParamsSectionPuiss } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Calculs de la section parabolique ou "puissance"
@@ -13,7 +13,7 @@ export class cSnPuiss extends acSection {
 
     constructor(prms: ParamsSectionPuiss, dbg: boolean = false) {
         super(prms, dbg);
-        this._nodeType = SectionType.SectionPuissance;
+        this.nodeType = SectionType.SectionPuissance;
     }
 
     protected setParametersCalculability() {
diff --git a/src/open-channel/section/section_puissance_params.ts b/src/open-channel/section/section_puissance_params.ts
index 745ba78d088750bfc4aeb9e12e3732e6411316a9..13f6e6d97f0d42c59a793b842bb8d998d42455bc 100644
--- a/src/open-channel/section/section_puissance_params.ts
+++ b/src/open-channel/section/section_puissance_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition } from "../../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../../param/param-domain";
-import { ParamsSection } from "./section_type_params";
+import { ParamDefinition } from "../../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 /**
  * Paramètres de la section parabolique ou "puissance"
@@ -12,17 +12,17 @@ export class ParamsSectionPuiss extends ParamsSection {
         rIf: number, rYB: number, nullParams: boolean = false) {
 
         super(rY, rLargeurBerge, rKs, rQ, rIf, rYB, nullParams);
-            this._k = new ParamDefinition(
-                this, "k", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), undefined, rk, undefined, undefined, nullParams
-            );
+        this._k = new ParamDefinition(
+            this, "k", new ParamDomain(ParamDomainValue.INTERVAL, 0, 1), undefined, rk, undefined, undefined, nullParams
+        );
 
-            this.addParamDefinition(this._k);
+        this.addParamDefinition(this._k);
     }
 
     /**
      * Coefficient de forme compris entre 0 et 1
      */
     get k(): ParamDefinition {
-            return this._k;
+        return this._k;
     }
 }
diff --git a/src/open-channel/section/section_rectang.ts b/src/open-channel/section/section_rectang.ts
index 5aff1413768e324bfd2d193cbbbb5c707653e803..83d89747d4019e78ea60cd1a68a4f62d2b9cb6bc 100644
--- a/src/open-channel/section/section_rectang.ts
+++ b/src/open-channel/section/section_rectang.ts
@@ -1,7 +1,7 @@
-import { SectionType } from "../../compute-node";
-import { Result } from "../../util/result";
-import { ParamsSectionRectang } from "./section_rectang_params";
-import { acSection } from "./section_type";
+import { SectionType } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { ParamsSectionRectang } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Calculs de la section rectangulaire
@@ -10,7 +10,7 @@ import { acSection } from "./section_type";
 export class cSnRectang extends acSection {
     constructor(prms: ParamsSectionRectang, dbg: boolean = false) {
         super(prms, dbg);
-        this._nodeType = SectionType.SectionRectangle;
+        this.nodeType = SectionType.SectionRectangle;
     }
 
     get prms(): ParamsSectionRectang {
diff --git a/src/open-channel/section/section_rectang_params.ts b/src/open-channel/section/section_rectang_params.ts
index a4c1092256befa76043b294dd0636d217d707b29..18217f49f102c0602fbac495ae13ed286493007f 100644
--- a/src/open-channel/section/section_rectang_params.ts
+++ b/src/open-channel/section/section_rectang_params.ts
@@ -1,4 +1,4 @@
-import { ParamsSection } from "./section_type_params";
+import { ParamsSection } from "../../internal_modules";
 
 export class ParamsSectionRectang extends ParamsSection {
     constructor(rY: number, rLargeurFond: number, rKs: number, rQ: number, rIf: number, rYB: number, nullParams: boolean = false) {
diff --git a/src/open-channel/section/section_trapez.ts b/src/open-channel/section/section_trapez.ts
index 5112111b0f831362c4555bbdc8a5875d1ac4ace1..8dfd4fb4d8b5359a92e818c00bc73c70380f468e 100644
--- a/src/open-channel/section/section_trapez.ts
+++ b/src/open-channel/section/section_trapez.ts
@@ -1,8 +1,8 @@
-import { SectionType } from "../../compute-node";
-import { ParamCalculability } from "../../param/param-definition";
-import { Result } from "../../util/result";
-import { ParamsSectionTrapez } from "./section_trapez_params";
-import { acSection } from "./section_type";
+import { SectionType } from "../../internal_modules";
+import { ParamCalculability } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { ParamsSectionTrapez } from "../../internal_modules";
+import { acSection } from "../../internal_modules";
 
 /**
  * Calculs de la section trapézoïdale
@@ -15,7 +15,7 @@ export class cSnTrapez extends acSection {
     }
     constructor(prms: ParamsSectionTrapez, dbg: boolean = false) {
         super(prms, dbg);
-        this._nodeType = SectionType.SectionTrapeze;
+        this.nodeType = SectionType.SectionTrapeze;
     }
 
     protected setParametersCalculability() {
@@ -169,7 +169,7 @@ export class cSnTrapez extends acSection {
         const g = ParamsSectionTrapez.G;
         const B = this.prms.LargeurFond.v;
         const Qstar = 4 * Math.pow(Math.pow(z, 3) * Math.pow(Q, 2) / g / Math.pow(B, 5), 1 / 3);
-        const Yc_star = Math.pow( 1 + 1.161 * Qstar * (1 + 2/3 * Math.pow(Qstar, 1.041), 0.374), 0.144);
+        const Yc_star = Math.pow(1 + 1.161 * Qstar * (1 + 2 / 3 * Math.pow(Qstar, 1.041), 0.374), 0.144);
         const nu = - 0.5 + 0.5 *
             Math.pow((5 * Math.pow(Yc_star, 6) + 1) / (6 * Math.pow(Yc_star, 5) - Qstar), 3);
         const Yc = nu * B / z;
diff --git a/src/open-channel/section/section_trapez_params.ts b/src/open-channel/section/section_trapez_params.ts
index 7d97fb01aaa3522da1be9c9cafcc57977c4f434b..7ee5cbfcaee4ca615e1c3fe0df34adc56818a120 100644
--- a/src/open-channel/section/section_trapez_params.ts
+++ b/src/open-channel/section/section_trapez_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../../param/param-definition";
-import { ParamDomainValue } from "../../param/param-domain";
-import { ParamsSection } from "./section_type_params";
+import { ParamDefinition, ParamFamily } from "../../internal_modules";
+import { ParamDomainValue } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 export class ParamsSectionTrapez extends ParamsSection {
     private _LargeurFond: ParamDefinition; // Largeur au fond
diff --git a/src/open-channel/section/section_type.ts b/src/open-channel/section/section_type.ts
index 78a6ca7e7d928ad04463808ff4a06b542e93d2e8..ae0e8c6e523446807c58a50103a55845809e03ec 100644
--- a/src/open-channel/section/section_type.ts
+++ b/src/open-channel/section/section_type.ts
@@ -1,15 +1,15 @@
-import { CalculatorType, SectionType } from "../../compute-node";
-import { Nub } from "../../nub";
-import { ParamCalculability, ParamDefinition } from "../../param/param-definition";
-import { Props } from "../../props";
-import { SessionSettings } from "../../session_settings";
-import { Message, MessageCode } from "../../util/message";
-import { Result } from "../../util/result";
-import { cHautConjuguee } from "./hauteur_conjuguee";
-import { cHautCorrespondante } from "./hauteur_correspondante";
-import { cHautCritique } from "./hauteur_critique";
-import { cHautNormale } from "./hauteur_normale";
-import { ParamsSection } from "./section_type_params";
+import { CalculatorType, SectionType } from "../../internal_modules";
+import { Nub } from "../../internal_modules";
+import { ParamCalculability, ParamDefinition } from "../../internal_modules";
+import { Props } from "../../internal_modules";
+import { SessionSettings } from "../../internal_modules";
+import { Message, MessageCode } from "../../internal_modules";
+import { Result } from "../../internal_modules";
+import { cHautConjuguee } from "../../internal_modules";
+import { cHautCorrespondante } from "../../internal_modules";
+import { cHautCritique } from "../../internal_modules";
+import { cHautNormale } from "../../internal_modules";
+import { ParamsSection } from "../../internal_modules";
 
 /**
  * Gestion commune pour les différents types de section.
@@ -52,8 +52,6 @@ export abstract class acSection extends Nub {
     protected bSnFermee: boolean = false;
     protected arCalcGeo: { [key: string]: number } = {}; /// Données ne dépendant pas de la cote de l'eau
 
-    protected _nodeType: SectionType;
-
     private _hautCritique: Result;  // Tirant d'eau critique
 
     /**
@@ -89,7 +87,7 @@ export abstract class acSection extends Nub {
      */
     constructor(prms: ParamsSection, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Section;
+        this.setCalculatorType(CalculatorType.Section);
         this._newtonDbg = dbg;
         this._intlType = "Section";
     }
@@ -99,22 +97,11 @@ export abstract class acSection extends Nub {
     }
 
     public get nodeType() {
-        return this._nodeType;
-    }
-
-    /** Returns Props object (observable set of key-values) associated to this Nub */
-    public get properties(): Props {
-        // completes props with calcType and nodeType if not already set
-        this._props.setPropValue("calcType", this.calcType);
-        if (this._props.getPropValue("nodeType") === undefined) {
-            this._props.setPropValue("nodeType", this.nodeType);
-        }
-        return this._props;
+        return this._props.getPropValue("nodeType");
     }
 
-    // setter is not inherited from Nub if getter is redefined :/
-    public set properties(props: Props) {
-        super.setProperties(props);
+    protected set nodeType(nt: SectionType) {
+        this._props.setPropValue("nodeType", nt);
     }
 
     /**
@@ -166,7 +153,7 @@ export abstract class acSection extends Nub {
      * (used by triggerChainCalculation)
      */
     public CalcSerie(rInit?: number): Result {
-        this.currentResult = this.parent.CalcSerie(rInit);
+        this.currentResultElement = this.parent.CalcSerie(rInit);
         return this.result;
     }
 
@@ -828,4 +815,10 @@ export abstract class acSection extends Nub {
         const v = 1000 * (this.prms.Q.v * rV.vCalc + ParamsSection.G * rSYG.vCalc);
         return new Result(v);
     }
+
+    // interface IProperties
+
+    public hasProperty(key: string): boolean {
+        return key === "nodeType";
+    }
 }
diff --git a/src/open-channel/section/section_type_params.ts b/src/open-channel/section/section_type_params.ts
index adec79dc0047ac37ac3ba1a88d19f362159e9ebc..15025ea7dfaa191f6c8920f3a28f24b551b634ba 100644
--- a/src/open-channel/section/section_type_params.ts
+++ b/src/open-channel/section/section_type_params.ts
@@ -1,7 +1,7 @@
-import { ParamDefinition, ParamFamily } from "../../param/param-definition";
-import { ParamDomainValue } from "../../param/param-domain";
-import { ParamsEquation } from "../../param/params-equation";
-import { SessionSettings } from "../../session_settings";
+import { ParamDefinition, ParamFamily } from "../../internal_modules";
+import { ParamDomainValue } from "../../internal_modules";
+import { ParamsEquation } from "../../internal_modules";
+import { SessionSettings } from "../../internal_modules";
 
 export abstract class ParamsSection extends ParamsEquation {
 
diff --git a/src/pab/cloison_aval.ts b/src/pab/cloison_aval.ts
index 880198d6f79b7db6e1ebfa2a141a0c3855a6d209..39c48c4a489c53a0cbe52efaee8a5eedabe10b02 100644
--- a/src/pab/cloison_aval.ts
+++ b/src/pab/cloison_aval.ts
@@ -1,18 +1,18 @@
-import { CalculatorType, Structure } from "../index";
-import { ParamCalculability } from "../param/param-definition";
-import { ParallelStructure } from "../structure/parallel_structure";
-import { loiAdmissiblesCloisonAval, LoiDebit } from "../structure/structure_props";
-import { StructureVanLevLarinier } from "../structure/structure_vanlev_larinier";
-import { StructureVanLevVillemonte } from "../structure/structure_vanlev_villemonte";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { CloisonsAvalParams } from "./cloison_aval_params";
+import { CalculatorType, Structure } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { loiAdmissiblesCloisonAval, LoiDebit } from "../internal_modules";
+import { StructureVanLevLarinier } from "../internal_modules";
+import { StructureVanLevVillemonte } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { CloisonsAvalParams } from "../internal_modules";
 
 export class CloisonAval extends ParallelStructure {
 
     constructor(prms: CloisonsAvalParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.CloisonAval;
+        this.setCalculatorType(CalculatorType.CloisonAval);
         this._intlType = "Cloison";
     }
 
@@ -22,7 +22,7 @@ export class CloisonAval extends ParallelStructure {
     public get indexVanneLevante(): number {
         for (let i = 0; i < this.structures.length; i++) {
             if (loiAdmissiblesCloisonAval.VanneLevante.includes(
-                this.structures[i].properties.getPropValue("loiDebit"))
+                this.structures[i].getPropValue("loiDebit"))
             ) {
                 return i;
             }
@@ -52,14 +52,14 @@ export class CloisonAval extends ParallelStructure {
             throw new Error("CloisonAval sVarCalc should be Z1");
         }
         if (!this.checkVanneLevante()) {
-            this.currentResult.addMessage(new Message(MessageCode.ERROR_CLOISON_AVAL_UN_OUVRAGE_REGULE));
+            this.currentResultElement.addMessage(new Message(MessageCode.ERROR_CLOISON_AVAL_UN_OUVRAGE_REGULE));
             return this.result;
         }
         let m: Message;
         if (this.hasVanneLevante()) {
             const s = this.structures[this.indexVanneLevante] as StructureVanLevVillemonte | StructureVanLevLarinier;
             this.prms.Z1.v = this.prms.Z2.v + s.getParameter("DH").v;
-            this.currentResult = this.CalcStructPrm(this.indexVanneLevante, "ZDV");
+            this.currentResultElement = this.CalcStructPrm(this.indexVanneLevante, "ZDV");
             if (this.result.ok) {
                 s.prms.ZDV.v = this.result.vCalc;
             }
@@ -74,7 +74,7 @@ export class CloisonAval extends ParallelStructure {
         }
         if (!this.hasVanneLevante() || this.result.ok) {
             // Calculation of Z1 with the new ZDV in case of existing vanne levante
-            this.currentResult = super.Calc("Z1", rInit);
+            this.currentResultElement = super.Calc("Z1", rInit);
             if (this.result.ok) {
                 this.getParameter(sVarCalc).v = this.result.vCalc;
                 // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires
@@ -119,7 +119,7 @@ export class CloisonAval extends ParallelStructure {
     public checkVanneLevante() {
         let n: number = 0;
         for (const st of this.structures) {
-            if (loiAdmissiblesCloisonAval.VanneLevante.includes(st.properties.getPropValue("loiDebit"))) {
+            if (loiAdmissiblesCloisonAval.VanneLevante.includes(st.getPropValue("loiDebit"))) {
                 n += 1;
             }
         }
diff --git a/src/pab/cloison_aval_params.ts b/src/pab/cloison_aval_params.ts
index dc243866162a6ee89c7c5b4f5005d9bc816fa719..5fd9fa02c8aef734d57bbbc33400231f66226ef7 100644
--- a/src/pab/cloison_aval_params.ts
+++ b/src/pab/cloison_aval_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParallelStructureParams } from "../structure/parallel_structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParallelStructureParams } from "../internal_modules";
 
 export class CloisonsAvalParams extends ParallelStructureParams {
 
diff --git a/src/pab/cloisons.ts b/src/pab/cloisons.ts
index 1c4a2c735c7202cb412a0da99e44f7a3189d92ed..88a036fd7e75064ad62a683cfab6af5c448c7c5d 100644
--- a/src/pab/cloisons.ts
+++ b/src/pab/cloisons.ts
@@ -1,18 +1,27 @@
-import { CalculatorType } from "../compute-node";
-import { Nub, Pab, Structure, StructureParams } from "../index";
-import { ParamCalculability } from "../param/param-definition";
-import { ParallelStructure } from "../structure/parallel_structure";
-import { StructureKiviParams } from "../structure/structure_kivi_params";
-import { loiAdmissiblesCloisons, LoiDebit } from "../structure/structure_props";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { CloisonsParams } from "./cloisons_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub, Pab, Structure, StructureParams } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { StructureKiviParams } from "../internal_modules";
+import { loiAdmissiblesCloisons, LoiDebit } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { CloisonsParams } from "../internal_modules";
 
 export class Cloisons extends ParallelStructure {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        PV: "W/m³",
+        ZRAM: "m",
+        ZRMB: "m"
+    };
+
     constructor(prms: CloisonsParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Cloisons;
+        this.setCalculatorType(CalculatorType.Cloisons);
         this._intlType = "Cloison";
     }
 
@@ -79,7 +88,7 @@ export class Cloisons extends ParallelStructure {
                 s.result.resultElement.addExtraResult("ZDV", this.prms.Z1.v - s.prms.h1.v);
             }
             // calcul de la pelle
-            if(s.properties.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
+            if (s.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
                 const pelle = s.prms.ZDV.v - this.prms.ZRAM.v;
                 s.result.resultElement.values.P = pelle;
                 if (pelle < -1E-7) { // si c'est enfoncé d'un dixième de micron ça va
@@ -134,12 +143,8 @@ export class Cloisons extends ParallelStructure {
         this.prms.QA.calculability = ParamCalculability.FREE;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            PV: "W/m³",
-            ZRAM: "m",
-            ZRMB: "m"
-        }
+    public static override resultsUnits() {
+        return Cloisons._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/pab/cloisons_params.ts b/src/pab/cloisons_params.ts
index d39d15cc0323f9c9ee2c9a841725a36eb3be5674..a6de143fb1632dbe2350a6dd5b343868e00f36ac 100644
--- a/src/pab/cloisons_params.ts
+++ b/src/pab/cloisons_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParallelStructureParams } from "../structure/parallel_structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParallelStructureParams } from "../internal_modules";
 
 /**
  * Common parameters of hydraulic structure equations
diff --git a/src/pab/pab.ts b/src/pab/pab.ts
index 1698e9d1b2e68f0c2e34f4bebcf799ccbfce4746..727ea2495ea2d5c9ab8aa7a8871cee5426426046 100644
--- a/src/pab/pab.ts
+++ b/src/pab/pab.ts
@@ -1,22 +1,22 @@
-import { CalculatorType } from "../compute-node";
-import { Session, JalhydObject } from "../index";
-import { ParamValueMode } from "../index";
-import { Nub } from "../nub";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
-import { IParamDefinitionIterator } from "../param/param_definition_iterator";
-import { ParamsEquation } from "../param/params-equation";
-import { ParamsEquationArrayIterator } from "../param/params_equation_array_iterator";
-import { Props } from "../props";
-import { ParallelStructure } from "../structure/parallel_structure";
-import { StructureTriangularTruncWeirFree } from "../structure/structure_triangular_trunc_weir";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { ResultElement } from "../util/resultelement";
-import { CloisonAval } from "./cloison_aval";
-import { CloisonsAvalParams } from "./cloison_aval_params";
-import { Cloisons } from "./cloisons";
-import { PabParams } from "./pab_params";
-import { FishPass } from "../fish_pass";
+import { CalculatorType } from "../internal_modules";
+import { Session, JalhydObject } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability, ParamDefinition } from "../internal_modules";
+import { IParamDefinitionIterator } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
+import { ParamsEquationArrayIterator } from "../internal_modules";
+import { Props } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { StructureTriangularTruncWeirFree } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { CloisonAval } from "../internal_modules";
+import { CloisonsAvalParams } from "../internal_modules";
+import { Cloisons } from "../internal_modules";
+import { PabParams } from "../internal_modules";
+import { FishPass } from "../internal_modules";
 
 export class Pab extends FishPass {
 
@@ -36,9 +36,9 @@ export class Pab extends FishPass {
 
     /**
     * @returns iterator on all child nubs (may include extra nubs, see Pab nub)
-    * @see Nub.allChildNubIterator()
+    * @see Nub.directChildNubIterator()
     */
-    public allChildNubIterator() {
+    public directChildNubIterator() {
         // clone children array
         const arr = Object.assign([], this.children);
         // append wall at downstream
@@ -55,7 +55,7 @@ export class Pab extends FishPass {
     constructor(prms: PabParams, downWall: CloisonAval, dbg: boolean = false) {
         super(prms, dbg);
         this.downWall = downWall;
-        this._calcType = CalculatorType.Pab;
+        this.setCalculatorType(CalculatorType.Pab);
     }
 
     public get downWall() {
@@ -65,7 +65,7 @@ export class Pab extends FishPass {
     public set downWall(dw: CloisonAval) {
         this._downWall = dw;
         if (dw) { // might be undefined
-            dw.parent = this; // important
+            dw.setParent(this); // important
             // postprocessing
             this.adjustDownwallParameters(this.downWall);
         }
@@ -84,7 +84,7 @@ export class Pab extends FishPass {
 
         // Generate an image of the object for multiplication
         // Use 2nd param as a trick to break links and copy values
-        const serialisedCloisonModel = cloisonModel.serialise(undefined, [ cloisonModel.uid ]);
+        const serialisedCloisonModel = cloisonModel.serialise(undefined, [cloisonModel.uid]);
         for (let i = 0; i < n; i++) {
             const cl: Cloisons =
                 Session.getInstance().unserialiseSingleNub(serialisedCloisonModel, false).nub as Cloisons;
@@ -147,7 +147,7 @@ export class Pab extends FishPass {
             }
         }
         if (r.hasErrorMessages()) {
-            this.currentResult = r;
+            this.currentResultElement = r;
             return this.result;
         }
         return super.Calc(sVarCalc, rInit);
@@ -292,7 +292,7 @@ export class Pab extends FishPass {
         // load downwall if any
         if (obj.downWall) {
             // decode properties
-            const props = Session.invertEnumKeysAndValuesInProperties(obj.downWall.props, true);
+            const props = Props.invertEnumKeysAndValuesInProperties(obj.downWall.props, true);
             // create the Nub
             const dw = Session.getInstance().createNub(new Props(props), this) as CloisonAval;
             // try to keep the original ID
diff --git a/src/pab/pab_chute.ts b/src/pab/pab_chute.ts
index a494221ca33ee31dcd69655de7242d622fe4ca7c..2a8c6a438d5fb003a3aaeaf65e04fd5969bc754c 100644
--- a/src/pab/pab_chute.ts
+++ b/src/pab/pab_chute.ts
@@ -1,14 +1,14 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { PabChuteParams } from "./pab_chute_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PabChuteParams } from "../internal_modules";
 
 export class PabChute extends Nub {
     constructor(prms: PabChuteParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PabChute;
+        this.setCalculatorType(CalculatorType.PabChute);
         this._defaultCalculatedParam = prms.DH;
         this.resetDefaultCalculatedParam();
     }
@@ -23,7 +23,7 @@ export class PabChute extends Nub {
     public Equation(sVarCalc: string): Result {
         let v: number;
 
-        if (! [ "Z1", "Z2" ].includes(sVarCalc) && this.prms.Z1.v <= this.prms.Z2.v) {
+        if (!["Z1", "Z2"].includes(sVarCalc) && this.prms.Z1.v <= this.prms.Z2.v) {
             const m = new Message(MessageCode.ERROR_ELEVATION_ZI_LOWER_THAN_Z2);
             m.extraVar.Z1 = this.prms.Z1.v;
             m.extraVar.Z2 = this.prms.Z2.v;
diff --git a/src/pab/pab_chute_params.ts b/src/pab/pab_chute_params.ts
index c6943fae4fd48ccdd313e315040b937c4f377be0..1c11ccb8b3072710792e13f1ba6a2bb35700ee20 100644
--- a/src/pab/pab_chute_params.ts
+++ b/src/pab/pab_chute_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PabChuteParams extends ParamsEquation {
 
diff --git a/src/pab/pab_dimension.ts b/src/pab/pab_dimension.ts
index 0cbc8af6f3902ca2bceb3894a12a7efb04115e8b..7da9d5786d327e86c9930948a05b869ce72a2049 100644
--- a/src/pab/pab_dimension.ts
+++ b/src/pab/pab_dimension.ts
@@ -1,13 +1,13 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { PabDimensionParams } from "./pab_dimensions_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PabDimensionParams } from "../internal_modules";
 
 export class PabDimension extends Nub {
     constructor(prms: PabDimensionParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PabDimensions;
+        this.setCalculatorType(CalculatorType.PabDimensions);
     }
 
     /**
diff --git a/src/pab/pab_dimensions_params.ts b/src/pab/pab_dimensions_params.ts
index 16538e1de2997d58085cea45ad26d0fdba1ee7e5..f448e4991210b53e12ba0b39e4969fa5ad7e9753 100644
--- a/src/pab/pab_dimensions_params.ts
+++ b/src/pab/pab_dimensions_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PabDimensionParams extends ParamsEquation {
 
diff --git a/src/pab/pab_nombre.ts b/src/pab/pab_nombre.ts
index 0d79c90801cf940f33bc3658d33cc07b3b8b98e9..4ccf9cdb80fb75f77a92f9ccd88b10be5ffe750b 100644
--- a/src/pab/pab_nombre.ts
+++ b/src/pab/pab_nombre.ts
@@ -1,15 +1,25 @@
-import { floatDivAndMod, isEqual } from "../base";
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { PabNombreParams } from "./pab_nombre_params";
+import { floatDivAndMod, isEqual } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PabNombreParams } from "../internal_modules";
 
 export class PabNombre extends Nub {
+
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        DHR: "m",
+        DHB: "m",
+        DHH: "m"
+    }
+
     constructor(prms: PabNombreParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PabNombre;
+        this.setCalculatorType(CalculatorType.PabNombre);
         this._defaultCalculatedParam = prms.N;
         this.resetDefaultCalculatedParam();
     }
@@ -23,7 +33,7 @@ export class PabNombre extends Nub {
 
     public Equation(sVarCalc: string): Result {
         let rounded = false;
-        if (sVarCalc !== "N" && ! Number.isInteger(this.prms.N.v)) {
+        if (sVarCalc !== "N" && !Number.isInteger(this.prms.N.v)) {
             this.prms.N.v = Math.round(this.prms.N.v);
             rounded = true;
         }
@@ -45,7 +55,7 @@ export class PabNombre extends Nub {
                 v = divAndMod.q;
                 DHR = divAndMod.r;
                 // harmonisation ?
-                if (! isEqual(DHR, 0)) {
+                if (!isEqual(DHR, 0)) {
                     // vers le bas
                     if (v > 0) {
                         NB = v;
@@ -101,12 +111,8 @@ export class PabNombre extends Nub {
         this.prms.DH.calculability = ParamCalculability.EQUATION;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            DHR: "m",
-            DHB: "m",
-            DHH: "m"
-        }
+    public static override resultsUnits() {
+        return PabNombre._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/pab/pab_nombre_params.ts b/src/pab/pab_nombre_params.ts
index 9bec54080b6dba172ce4277bf409a3eb238e0f27..a5d47b6fb6f8aa43d653bcf8a10cb6c97582d14a 100644
--- a/src/pab/pab_nombre_params.ts
+++ b/src/pab/pab_nombre_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PabNombreParams extends ParamsEquation {
 
diff --git a/src/pab/pab_params.ts b/src/pab/pab_params.ts
index 3483a010c5f68f8c2aa97b3143e69ed96dec2ebb..0aaa35e885287b5c0f50068fcc43989519b78f09 100644
--- a/src/pab/pab_params.ts
+++ b/src/pab/pab_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Parameters of a fish ladder
diff --git a/src/pab/pab_puissance.ts b/src/pab/pab_puissance.ts
index a7e98e3a623354c34fe54007297893bd974d2c0f..a7f2f506f312a4b9c5332ac325c9bf566c19c8e2 100644
--- a/src/pab/pab_puissance.ts
+++ b/src/pab/pab_puissance.ts
@@ -1,13 +1,13 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { PabPuissanceParams } from "./pab_puissance_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PabPuissanceParams } from "../internal_modules";
 
 export class PabPuissance extends Nub {
     constructor(prms: PabPuissanceParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PabPuissance;
+        this.setCalculatorType(CalculatorType.PabPuissance);
     }
 
     /**
diff --git a/src/pab/pab_puissance_params.ts b/src/pab/pab_puissance_params.ts
index 06bf1510c0e269991907d0f89d84d277a3e12187..78b4ebc692b7829443ae607c8d623b0e636ec450 100644
--- a/src/pab/pab_puissance_params.ts
+++ b/src/pab/pab_puissance_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PabPuissanceParams extends ParamsEquation {
 
diff --git a/src/par/par.ts b/src/par/par.ts
index 85ab0450cb437f66b9fc26fa85e1d015b41510cf..9821ec1414e947ca80d76932421eb28322a98277 100644
--- a/src/par/par.ts
+++ b/src/par/par.ts
@@ -1,17 +1,17 @@
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability } from "../param/param-definition";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { ParParams } from "./par_params";
-import { ParTypeAbstract } from "./par_type";
-import { ParTypePlane } from "./par_type_plane";
-import { ParTypeFatou } from "./par_type_fatou";
-import { ParTypeSuperactive } from "./par_type_superactive";
-import { ParTypeChevron } from "./par_type_chevron";
-import { Message, MessageCode } from "../util/message";
-import { ResultElement } from "../util/resultelement";
-import { isLowerThan, isGreaterThan } from "../base";
-import { FishPass } from "../fish_pass";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ParParams } from "../internal_modules";
+import { ParTypeAbstract } from "../internal_modules";
+import { ParTypePlane } from "../internal_modules";
+import { ParTypeFatou } from "../internal_modules";
+import { ParTypeSuperactive } from "../internal_modules";
+import { ParTypeChevron } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { isLowerThan, isGreaterThan } from "../internal_modules";
+import { FishPass } from "../internal_modules";
 
 /** Type de Passe à Ralentisseurs */
 export enum ParType {
@@ -23,11 +23,33 @@ export enum ParType {
 
 export class Par extends FishPass implements Observer {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        h: "m",
+        qStar: "m³/s",
+        V: "m/s",
+        ZD1: "m",
+        ZR1: "m",
+        ZD2: "m",
+        ZR2: "m",
+        ZM: "m",
+        LPI: "m",
+        LPH: "m",
+        B: "m",
+        C: "m",
+        D: "m",
+        H: "m",
+        Hmin: "m",
+        Hmax: "m"
+    };
+
     protected parCalc: ParTypeAbstract;
 
     constructor(prms: ParParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Par;
+        this.setCalculatorType(CalculatorType.Par);
         this._defaultCalculatedParam = prms.Q;
         this.resetDefaultCalculatedParam();
         this._props.addObserver(this);
@@ -39,11 +61,11 @@ export class Par extends FishPass implements Observer {
     }
 
     public get parType(): ParType {
-        return this.properties.getPropValue("parType");
+        return this.getPropValue("parType");
     }
 
     public set parType(e: ParType) {
-        this.properties.setPropValue("parType", e);
+        this.setPropValue("parType", e);
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
@@ -74,7 +96,7 @@ export class Par extends FishPass implements Observer {
         }
 
         // Check that input data is in the range given by abacuses
-        switch(this.calculatedParam) {
+        switch (this.calculatedParam) {
             case this.prms.ha:
                 // check qStar
                 const qStar = this.parCalc.CalcQStar();
@@ -97,7 +119,7 @@ export class Par extends FishPass implements Observer {
 
         // if any fatal error occurred
         if (hasError) {
-            this.currentResult = r;
+            this.currentResultElement = r;
             return this.result;
         }
 
@@ -108,7 +130,7 @@ export class Par extends FishPass implements Observer {
             this.result.resultElement.addMessage(m);
         }
 
-        if(!this.result.ok) return this.result;
+        if (!this.result.ok) return this.result;
 
         // extra results
         this.parCalc.addExtraResults(this.result);
@@ -201,9 +223,9 @@ export class Par extends FishPass implements Observer {
     }
 
     protected updateParamsVisibility() {
-        this.prms.L.visible = ([ ParType.PLANE, ParType.FATOU ].includes(this.parType));
-        this.prms.a.visible = ([ ParType.SUPERACTIVE, ParType.CHEVRON ].includes(this.parType));
-        this.prms.N.visible = ([ ParType.SUPERACTIVE, ParType.CHEVRON ].includes(this.parType));
+        this.prms.L.visible = ([ParType.PLANE, ParType.FATOU].includes(this.parType));
+        this.prms.a.visible = ([ParType.SUPERACTIVE, ParType.CHEVRON].includes(this.parType));
+        this.prms.N.visible = ([ParType.SUPERACTIVE, ParType.CHEVRON].includes(this.parType));
         this.prms.M.visible = (this.parType === ParType.CHEVRON);
     }
 
@@ -212,25 +234,8 @@ export class Par extends FishPass implements Observer {
         this.prms.ha.calculability = ParamCalculability.EQUATION;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            h: "m",
-            qStar: "m³/s",
-            V: "m/s",
-            ZD1: "m",
-            ZR1: "m",
-            ZD2: "m",
-            ZR2: "m",
-            ZM: "m",
-            LPI: "m",
-            LPH: "m",
-            B: "m",
-            C: "m",
-            D: "m",
-            H: "m",
-            Hmin: "m",
-            Hmax: "m"
-        }
+    public static override resultsUnits() {
+        return Par._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/par/par_params.ts b/src/par/par_params.ts
index 97b8494484acec409d59d64d089d6bddc3e4e2cc..b8133785e605b3f975ca10f93a5d7bc6fcdc6b3e 100644
--- a/src/par/par_params.ts
+++ b/src/par/par_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class ParParams extends ParamsEquation {
 
diff --git a/src/par/par_simulation.ts b/src/par/par_simulation.ts
index 75c26fbdbff96199d1db2a29b872df5680f3c774..773107687ca74f729bef2541c08cdd4deb5ec2bd 100644
--- a/src/par/par_simulation.ts
+++ b/src/par/par_simulation.ts
@@ -1,12 +1,12 @@
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { ParSimulationParams } from "./par_simulation_params";
-import { Message, MessageCode } from "../util/message";
-import { ResultElement } from "../util/resultelement";
-import { ParType, Par } from "./par";
-import { isEqual, round, isGreaterThan, isLowerThan } from "../base";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability, ParamDefinition } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ParSimulationParams } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { ParType, Par } from "../internal_modules";
+import { isEqual, round, isGreaterThan, isLowerThan } from "../internal_modules";
 
 export enum ParFlowRegime {
     /** Free flow (unsubmerged) */
@@ -19,7 +19,7 @@ export class ParSimulation extends Par implements Observer {
 
     constructor(prms: ParSimulationParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.ParSimulation;
+        this.setCalculatorType(CalculatorType.ParSimulation);
         this.prms.ha.visible = false; // show ZD1 instead
     }
 
@@ -28,11 +28,11 @@ export class ParSimulation extends Par implements Observer {
     }
 
     public get parType(): ParType {
-        return this.properties.getPropValue("parType");
+        return this.getPropValue("parType");
     }
 
     public set parType(e: ParType) {
-        this.properties.setPropValue("parType", e);
+        this.setPropValue("parType", e);
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
@@ -77,7 +77,7 @@ export class ParSimulation extends Par implements Observer {
         }
 
         // Check Nb
-        const nb = this.CalcNb(czRes1.expectedZD, czRes2.expectedZD) ; // reference value
+        const nb = this.CalcNb(czRes1.expectedZD, czRes2.expectedZD); // reference value
         if (this.prms.Nb.v === undefined) {
             this.prms.Nb.v = nb;
             this.prms.Nb.singleValue = round(nb, 3);
@@ -112,14 +112,14 @@ export class ParSimulation extends Par implements Observer {
 
         // if any fatal error occurred
         if (hasError) {
-            this.currentResult = r;
+            this.currentResultElement = r;
             return this.result;
         }
 
         this.nubCalc(sVarCalc, rInit);
 
         // add checkInput()'s non fatal warnings to current result
-        if (! status.fatal) {
+        if (!status.fatal) {
             for (const m of status.messages) {
                 this.result.resultElement.addMessage(m);
             }
@@ -176,7 +176,7 @@ export class ParSimulation extends Par implements Observer {
         let expectedZD: number;
         if (ZR.v === undefined && ZD.v === undefined) {
             message = new Message(MessageCode.ERROR_AT_LEAST_ONE_OF_THOSE_MUST_BE_DEFINED);
-            message.extraVar.variables = [ ZR.symbol, ZD.symbol ];
+            message.extraVar.variables = [ZR.symbol, ZD.symbol];
         } else {
             // calculate missing value
             let zrDef = true;
@@ -197,7 +197,7 @@ export class ParSimulation extends Par implements Observer {
             if (zrDef && zdDef) {
                 expectedZR = this.parCalc.CalcZRFromZD(ZD.V);
                 expectedZD = this.parCalc.CalcZDFromZR(ZR.V);
-                if (! isEqual(ZR.v, expectedZR, 1E-3)) {
+                if (!isEqual(ZR.v, expectedZR, 1E-3)) {
                     message = new Message(MessageCode.ERROR_PAR_ZR_ZD_MISMATCH);
                     message.extraVar.var_ZR = ZR.symbol;
                     message.extraVar.var_ZD = ZD.symbol;
@@ -225,7 +225,7 @@ export class ParSimulation extends Par implements Observer {
         }
         const rLs = (realZD1 - realZD2) * Math.sqrt(1 + this.prms.S.v * this.prms.S.v) / this.prms.S.v;
         const nb = Math.floor((rLs + 0.01) / this.parCalc.P)
-        switch(this.parType) {
+        switch (this.parType) {
             case ParType.PLANE:
             case ParType.FATOU:
                 return nb + 1;
diff --git a/src/par/par_simulation_params.ts b/src/par/par_simulation_params.ts
index ce2c29a40021f14d062d27c7e7854aceba6e349a..436813c1c5c5bc4717bf890dd3785ff05338aad7 100644
--- a/src/par/par_simulation_params.ts
+++ b/src/par/par_simulation_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParParams } from "./par_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParParams } from "../internal_modules";
 
 export class ParSimulationParams extends ParParams {
 
diff --git a/src/par/par_type.ts b/src/par/par_type.ts
index 42ea8566d364dbe0e8b57e419b71e620e9f07d14..63933ef69413eb66476e4d2020320758e52f35b3 100644
--- a/src/par/par_type.ts
+++ b/src/par/par_type.ts
@@ -1,9 +1,9 @@
-import { ParParams } from "./par_params";
-import { Result } from "../util/result";
-import { ParamValueMode } from "../param/param-value-mode";
-import { ParType } from "./par";
-import { Message } from "../util/message";
-import { ParSimulationParams } from "./par_simulation_params";
+import { ParParams } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { Message } from "../internal_modules";
+import { ParSimulationParams } from "../internal_modules";
 
 export abstract class ParTypeAbstract {
 
@@ -160,8 +160,8 @@ export abstract class ParTypeAbstract {
 
     /** coefficients for calculating c(0|1|2)ha? @see getCoeff */
     protected abstract get coef(): {
-        [key:string]: {
-            [key:string]: number[]
+        [key: string]: {
+            [key: string]: number[]
         }
     }
 
diff --git a/src/par/par_type_chevron.ts b/src/par/par_type_chevron.ts
index 8ffc30cd26d36ca2f459755df3e54612b548334c..45bdadc0cd2d07f3cb1589633c43a9897677f416 100644
--- a/src/par/par_type_chevron.ts
+++ b/src/par/par_type_chevron.ts
@@ -1,8 +1,8 @@
-import { Result } from "../util/result";
-import { ParTypeSC } from "./par_type_sc";
-import { ParParams } from "./par_params";
-import { ParType } from "./par";
-import { Message, MessageCode } from "../util/message";
+import { Result } from "../internal_modules";
+import { ParTypeSC } from "../internal_modules";
+import { ParParams } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
 
 export class ParTypeChevron extends ParTypeSC {
 
@@ -61,14 +61,14 @@ export class ParTypeChevron extends ParTypeSC {
     protected get coef() {
         return {
             "h": {
-                "c0": [ 0,  -4.97686,     1.30546    ],
-                "c1": [ 0,   0.176261,    0.661656   ],
-                "c2": [ 0,  -0.0733832,  -0.00839864 ]
+                "c0": [0, -4.97686, 1.30546],
+                "c1": [0, 0.176261, 0.661656],
+                "c2": [0, -0.0733832, -0.00839864]
             },
             "ha": {
-                "c0": [ 0,   5.02138,     0.709434   ],
-                "c1": [ 0,  -2.47998,     1.25363    ],
-                "c2": [ 0,   0.188324,   -0.0427461  ]
+                "c0": [0, 5.02138, 0.709434],
+                "c1": [0, -2.47998, 1.25363],
+                "c2": [0, 0.188324, -0.0427461]
             }
         };
     }
diff --git a/src/par/par_type_fatou.ts b/src/par/par_type_fatou.ts
index b20de3af765e1bc01d1acdb15fb6fa648f3fe0a0..cc6fbc7886dfd86b4f5481849e11e8cd44b52bce 100644
--- a/src/par/par_type_fatou.ts
+++ b/src/par/par_type_fatou.ts
@@ -1,10 +1,9 @@
-import { Result } from "../util/result";
-import { ParTypePF } from "./par_type_pf";
-import { ParType } from "./par";
-import { ParParams } from "./par_params";
-import { Message, MessageCode } from "../util/message";
-import { ParamDefinition } from "../param/param-definition";
-import { isLowerThan, isGreaterThan } from "../base";
+import { Result } from "../internal_modules";
+import { ParTypePF } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { ParParams } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { isLowerThan, isGreaterThan } from "../internal_modules";
 
 export class ParTypeFatou extends ParTypePF {
 
@@ -69,14 +68,14 @@ export class ParTypeFatou extends ParTypePF {
     protected get coef() {
         return {
             "h": {
-                "c0": [  -3.56494,   0.450262,   0.0407576 ],
-                "c1": [  42.4113,  -24.4941,     8.84146   ],
-                "c2": [ -73.4829,   54.6733,   -14.0622    ]
+                "c0": [-3.56494, 0.450262, 0.0407576],
+                "c1": [42.4113, -24.4941, 8.84146],
+                "c2": [-73.4829, 54.6733, -14.0622]
             },
             "ha": {
-                "c0": [   15.8096,    -5.19282,   0.465827 ],
-                "c1": [  302.623,   -106.203,    13.2957   ],
-                "c2": [ -783.592,    269.991,   -25.2637   ]
+                "c0": [15.8096, -5.19282, 0.465827],
+                "c1": [302.623, -106.203, 13.2957],
+                "c2": [-783.592, 269.991, -25.2637]
             }
         };
     }
diff --git a/src/par/par_type_pf.ts b/src/par/par_type_pf.ts
index 47b47718a3e6796199ef52b7abf42b3e6dde77e0..10d8a3cbcea6ca1371b31e0f3e0cd08f378d0ace 100644
--- a/src/par/par_type_pf.ts
+++ b/src/par/par_type_pf.ts
@@ -1,6 +1,6 @@
-import { ParTypeAbstract } from "./par_type";
-import { Message, MessageCode } from "../util/message";
-import { ParamValueMode } from "../param/param-value-mode";
+import { ParTypeAbstract } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
 
 /**
  * Intermediate class for common stuff between PLANE and FATOU pass types
diff --git a/src/par/par_type_plane.ts b/src/par/par_type_plane.ts
index 0bfbd6c4f126914f1181524fa13301a78d27d140..a7891a1426b26ee549bd37167951c5c2d7be78ba 100644
--- a/src/par/par_type_plane.ts
+++ b/src/par/par_type_plane.ts
@@ -1,10 +1,9 @@
-import { Result } from "../util/result";
-import { ParTypePF } from "./par_type_pf";
-import { ParType } from "./par";
-import { ParParams } from "./par_params";
-import { Message, MessageCode } from "../util/message";
-import { ParamDefinition } from "../param/param-definition";
-import { isLowerThan, isGreaterThan } from "../base";
+import { Result } from "../internal_modules";
+import { ParTypePF } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { ParParams } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { isLowerThan, isGreaterThan } from "../internal_modules";
 
 export class ParTypePlane extends ParTypePF {
 
@@ -35,7 +34,7 @@ export class ParTypePlane extends ParTypePF {
     }
 
     public CalcP(): number {
-        return (2/3) * this.prms.L.V;
+        return (2 / 3) * this.prms.L.V;
     }
 
     public addExtraResults(res: Result): void {
@@ -69,14 +68,14 @@ export class ParTypePlane extends ParTypePF {
     protected get coef() {
         return {
             "h": {
-                "c0": [   16.7218,   -6.09624,  0.834851  ],
-                "c1": [ -139.382,    47.2186,   0.0547598 ],
-                "c2": [  347.368,  -130.698,    8.14521   ]
+                "c0": [16.7218, -6.09624, 0.834851],
+                "c1": [-139.382, 47.2186, 0.0547598],
+                "c2": [347.368, -130.698, 8.14521]
             },
             "ha": {
-                "c0": [   15.2115,   -5.22606,   0.633654 ],
-                "c1": [ -184.043,    59.7073,   -0.530737 ],
-                "c2": [  315.110,  -115.164,     6.85371  ]
+                "c0": [15.2115, -5.22606, 0.633654],
+                "c1": [-184.043, 59.7073, -0.530737],
+                "c2": [315.110, -115.164, 6.85371]
             }
         };
     }
diff --git a/src/par/par_type_sc.ts b/src/par/par_type_sc.ts
index 2c0999a4475571d0b77cc8a129d2adde152675e0..9ec8700906bc9e4e36619672e430c6ba155edb5b 100644
--- a/src/par/par_type_sc.ts
+++ b/src/par/par_type_sc.ts
@@ -1,7 +1,6 @@
-import { ParTypeAbstract } from "./par_type";
-import { Message, MessageCode } from "../util/message";
-import { ParamValueMode } from "../param/param-value-mode";
-import { isLowerThan, isGreaterThan } from "../base";
+import { ParTypeAbstract } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { isLowerThan, isGreaterThan } from "../internal_modules";
 
 /**
  * Intermediate class for common stuff between SUPERACTIVE and CHEVRON pass types
diff --git a/src/par/par_type_superactive.ts b/src/par/par_type_superactive.ts
index 1f9b17a1da6f4e65461de93c8592da31de397395..260d2a1e5eeff40aa0aec26cbd24207f84279ceb 100644
--- a/src/par/par_type_superactive.ts
+++ b/src/par/par_type_superactive.ts
@@ -1,7 +1,7 @@
-import { Result } from "../util/result";
-import { ParTypeSC } from "./par_type_sc";
-import { ParType } from "./par";
-import { ParParams } from "./par_params";
+import { Result } from "../internal_modules";
+import { ParTypeSC } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { ParParams } from "../internal_modules";
 
 export class ParTypeSuperactive extends ParTypeSC {
 
@@ -41,14 +41,14 @@ export class ParTypeSuperactive extends ParTypeSC {
     protected get coef() {
         return {
             "h": {
-                "c0": [ 0,  -2.62712,    0.601348    ],
-                "c1": [ 0,   1.15807,    1.07554     ],
-                "c2": [ 0,  -0.559218,   0.000504060 ]
+                "c0": [0, -2.62712, 0.601348],
+                "c1": [0, 1.15807, 1.07554],
+                "c2": [0, -0.559218, 0.000504060]
             },
             "ha": {
-                "c0": [ 0,  -2.22434,    0.596682    ],
-                "c1": [ 0,   0.514953,   1.25460     ],
-                "c2": [ 0,  -0.354624,  -0.0153156   ]
+                "c0": [0, -2.22434, 0.596682],
+                "c1": [0, 0.514953, 1.25460],
+                "c2": [0, -0.354624, -0.0153156]
             }
         };
     }
diff --git a/src/param/mirror-iterator.ts b/src/param/mirror-iterator.ts
index 2c9b0abe8040d44c3483a29c962fe7e1cd490501..6939a9fed3e69279c388b59887f0bba3166851f0 100644
--- a/src/param/mirror-iterator.ts
+++ b/src/param/mirror-iterator.ts
@@ -1,5 +1,5 @@
-import { INumberIterator } from "./param-value-iterator";
-import { ParamValues } from "./param-values";
+import { INumberIterator } from "../internal_modules";
+import { ParamValues } from "../internal_modules";
 
 /**
  * Itérateur miroir sur les (ou la) valeurs prises par un ParamValues.
@@ -61,7 +61,7 @@ export class MirrorIterator implements INumberIterator {
     public next(): IteratorResult<number> {
         if (this.hasNext) {
             this._current = this._valuesList[this._index];
-            this._index ++;
+            this._index++;
             return {
                 done: false,
                 value: this._current
diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts
index 03e8059211c181bca799ad12fcc05e1f5904e277..42e706c9de50cb3f57487038a2add8b15cdf9feb 100644
--- a/src/param/param-definition.ts
+++ b/src/param/param-definition.ts
@@ -1,16 +1,16 @@
-import { CalculatorType, ComputeNode } from "../compute-node";
-import { Session } from "../index";
-import { LinkedValue } from "../linked-value";
-import { Nub } from "../nub";
-import { acSection } from "../open-channel/section/section_type";
-import { Interval } from "../util/interval";
-import { Message, MessageCode } from "../util/message";
-import { IObservable, Observable, Observer } from "../util/observer";
-import { ParamDomain, ParamDomainValue } from "./param-domain";
-import { INamedIterableValues, INumberIterator } from "./param-value-iterator";
-import { ParamValueMode } from "./param-value-mode";
-import { ParamValues } from "./param-values";
-import { ParamsEquation } from "./params-equation";
+import { CalculatorType, ComputeNode } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { LinkedValue } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { acSection } from "../internal_modules";
+import { Interval } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { IObservable, Observable, Observer } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { INamedIterableValues, INumberIterator } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { ParamValues } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Calculabilité du paramètre
@@ -42,7 +42,8 @@ export enum ParamFamily {
     FLOWS, // débit
     DIAMETERS,
     SPEEDS, // vitesses, seulement des résultats
-    STRICKLERS
+    STRICKLERS,
+    BLOCKCONCENTRATION // concentrations de blocs
 }
 
 /**
@@ -171,7 +172,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
      * when param value was set to undefined before
      */
     public set initValue(v: number) {
-        if (v !== undefined && ! isNaN(v) && v !== null) {
+        if (v !== undefined && !isNaN(v) && v !== null) {
             this._initValue = v;
         } else {
             if (this._initValue === undefined || isNaN(this._initValue) || this._initValue === null) {
@@ -622,7 +623,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
                 break;
 
             case ParamDomainValue.INTEGER:
-                if (! Number.isInteger(v)) {
+                if (!Number.isInteger(v)) {
                     const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTEGER);
                     f.extraVar.symbol = this.symbol;
                     f.extraVar.value = v;
@@ -901,7 +902,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
         // consistency when setting calculatedParam afterwards
         if (mode !== ParamValueMode.CALCUL || setCalcMode) {
             try {
-                this.valueMode = mode;
+                this.setValueMode(mode, setCalcMode);
             } catch (err) {
                 // silent fail : impossible to determine if this is an error, because
                 // at this time, it is possible that no candidate for calculatedParam can
@@ -1061,7 +1062,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable {
             // direct, parent or children reference ?
             if (
                 (ref.nub.uid === uid)
-                || (ref.nub.getParent() && ref.nub.getParent().uid === uid)
+                || (ref.nub.parent && ref.nub.parent.uid === uid)
                 || (ref.nub.getChildren().map((c) => c.uid).includes(uid))
             ) {
                 linked = (
diff --git a/src/param/param-domain.ts b/src/param/param-domain.ts
index 64d07a7236ce5d873b8d702d6baae694238e01f3..85aa837ba5a9bf496a8c69faa5f7e941f0b0d2f3 100644
--- a/src/param/param-domain.ts
+++ b/src/param/param-domain.ts
@@ -1,5 +1,5 @@
-import { Interval } from "../util/interval";
-import { Message, MessageCode } from "../util/message";
+import { Interval } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
 
 /**
  * domaine de définition du paramètre
diff --git a/src/param/param-value-iterator.ts b/src/param/param-value-iterator.ts
index d2c6ec24526df4d7c929ec46836b01df72765424..56835873c88b6cfe7e8ee624a984d5ce9cc97236 100644
--- a/src/param/param-value-iterator.ts
+++ b/src/param/param-value-iterator.ts
@@ -1,8 +1,8 @@
-import { isEqual } from "../base";
-import { INamedObject, IObjectWithFamily } from "../jalhyd_object";
-import { ExtensionStrategy } from "./param-definition";
-import { ParamValueMode } from "./param-value-mode";
-import { ParamValues } from "./param-values";
+import { isEqual } from "../internal_modules";
+import { INamedObject, IObjectWithFamily } from "../internal_modules";
+import { ExtensionStrategy } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { ParamValues } from "../internal_modules";
 
 /**
  * itérateur sur des nombres
@@ -173,7 +173,7 @@ export class ParamValueIterator implements INumberIterator {
      */
     public nextValue(): IteratorResult<number> {
         const res = this.next();
-        if (! res.done) {
+        if (!res.done) {
             this._param.setCurrentValueFromIterator(res.value);
         }
         return res;
@@ -187,7 +187,7 @@ export class ParamValueIterator implements INumberIterator {
                     if (this.hasNext) {
                         this._current = this._param.singleValue;
                         this._index++;
-                        this._xindex ++;
+                        this._xindex++;
                         return {
                             done: false,
                             value: this._current
@@ -202,7 +202,7 @@ export class ParamValueIterator implements INumberIterator {
                 case ParamValueMode.LISTE:
                     if (this.hasNextWithoutExtension) { // default case
                         this._current = this._param.valueList[this._index++]; // what about _reverse ?
-                        this._xindex ++; // count values for possible extension
+                        this._xindex++; // count values for possible extension
                         return {
                             done: false,
                             value: this._current
@@ -210,7 +210,7 @@ export class ParamValueIterator implements INumberIterator {
                     } else { // no more real values
                         if (this._extendTo && this.hasNext) {
                             // extend
-                            this._index ++;
+                            this._index++;
                             switch (this._param.extensionStrategy) {
                                 case ExtensionStrategy.REPEAT_LAST:
                                     // repeat last real value (do not change this._current)
@@ -268,14 +268,14 @@ export class ParamValueIterator implements INumberIterator {
                                 this._index += this._param.step;
                             }
                         }
-                        this._xindex ++; // count values for possible extension
+                        this._xindex++; // count values for possible extension
                         return {
                             done: false,
                             value: this._current
                         };
                     } else { // no more real values
                         if (this._extendTo && this.hasNext) {
-                            this._xindex ++; // count values for possible extension
+                            this._xindex++; // count values for possible extension
                             switch (this._param.extensionStrategy) {
                                 case ExtensionStrategy.REPEAT_LAST:
                                     // repeat last real value (do not change this._current)
@@ -286,7 +286,7 @@ export class ParamValueIterator implements INumberIterator {
 
                                 case ExtensionStrategy.RECYCLE:
                                     // loop over real values using a local iterator that does not extend
-                                    if (this._locExIt === undefined || ! this._locExIt.hasNext) {
+                                    if (this._locExIt === undefined || !this._locExIt.hasNext) {
                                         // create / rewind iterator
                                         this._locExIt = this._param.getValuesIterator(
                                             this._reverse, undefined, this._addLastStep
@@ -347,7 +347,7 @@ export class ParamValueIterator implements INumberIterator {
                 return this._index === 0;
 
             case ParamValueMode.LISTE:
-                if (this._extendTo && ! ignoreExtension) {
+                if (this._extendTo && !ignoreExtension) {
                     return this._index < this._extendTo;
                 } else {
                     return this._index < this._param.valueList.length;
@@ -355,11 +355,11 @@ export class ParamValueIterator implements INumberIterator {
 
             case ParamValueMode.MINMAX:
                 // si extension, compter le nombre de valeurs
-                if (this._extendTo && ! ignoreExtension) {
+                if (this._extendTo && !ignoreExtension) {
                     return this._xindex < this._extendTo;
                 } else {
                     // sinon, s'il y a un dernier pas à faire
-                    return ! this.minMaxLastValueReached();
+                    return !this.minMaxLastValueReached();
                 }
 
             default:
@@ -381,7 +381,7 @@ export class ParamValueIterator implements INumberIterator {
      * Returns true if last value was reached in MINMAX mode
      */
     protected minMaxLastValueReached() {
-        if (! this._minMaxLastValueReached) {
+        if (!this._minMaxLastValueReached) {
             // update flag
             if (this._addLastStep) {
                 this._minMaxLastValueReached = this._reverse ?
diff --git a/src/param/param-values.ts b/src/param/param-values.ts
index 3e60df5b18a8117b61c84339a1114e990f4a7a39..01e27181eed68745869eb8a2ceee243aadb842fe 100644
--- a/src/param/param-values.ts
+++ b/src/param/param-values.ts
@@ -1,6 +1,6 @@
-import { ExtensionStrategy } from "./param-definition";
-import { INumberIterator, IterableValues, ParamValueIterator } from "./param-value-iterator";
-import { ParamValueMode } from "./param-value-mode";
+import { ExtensionStrategy } from "../internal_modules";
+import { INumberIterator, IterableValues, ParamValueIterator } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
 
 /**
  * Represents the value(s) taken by a Parameter, along with and depending on
@@ -128,7 +128,7 @@ export class ParamValues implements IterableValues {
      * taking in account reverse, extendTo and addLastStep if defined
      */
     public getInferredValuesList(reverse: boolean = false, extendTo?: number, addLastStep: boolean = false) {
-        if ([ ParamValueMode.MINMAX, ParamValueMode.LISTE ].includes(this.valueMode)) {
+        if ([ParamValueMode.MINMAX, ParamValueMode.LISTE].includes(this.valueMode)) {
             if (
                 (this.valueMode === ParamValueMode.LISTE)
                 || (
diff --git a/src/param/param_definition_iterator.ts b/src/param/param_definition_iterator.ts
index f7f272492eb11a972b04061fa29f994a7e3607fb..852f9d2f8fac8d69032c8bbe631133e3eceed975 100644
--- a/src/param/param_definition_iterator.ts
+++ b/src/param/param_definition_iterator.ts
@@ -1,6 +1,6 @@
-import { MapIterator } from "../util/map_iterator";
-import { ParamDefinition } from "./param-definition";
-import { ParamsEquation } from "./params-equation";
+import { MapIterator } from "../internal_modules";
+import { ParamDefinition } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export interface IParamDefinitionIterator extends IterableIterator<ParamDefinition> {
 }
diff --git a/src/param/params-equation.ts b/src/param/params-equation.ts
index 5e2549fdf4561bf92ddb1e75901ef6fff81da188..16849b018000482904c4bed241a1cce47a0c38fc 100644
--- a/src/param/params-equation.ts
+++ b/src/param/params-equation.ts
@@ -1,6 +1,6 @@
-import { ComputeNode } from "../compute-node";
-import { ParamDefinition } from "./param-definition";
-import { IParamDefinitionIterator, ParamDefinitionIterator } from "./param_definition_iterator";
+import { ComputeNode } from "../internal_modules";
+import { ParamDefinition } from "../internal_modules";
+import { IParamDefinitionIterator, ParamDefinitionIterator } from "../internal_modules";
 
 /**
  * liste des paramètres d'une équation
@@ -20,7 +20,7 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> {
     }
 
     get nubUid() {
-        if (! this.parent) {
+        if (!this.parent) {
             throw new Error("ParamsEquation.nubUid : equation has no parent Nub !");
         }
         return this.parent.uid;
diff --git a/src/param/params_equation_array_iterator.ts b/src/param/params_equation_array_iterator.ts
index 02cd6ade25da5b3ee0cbbdbadf87db707eb66d17..aee816be91f568d0d18653e7fc77aa02f651a753 100644
--- a/src/param/params_equation_array_iterator.ts
+++ b/src/param/params_equation_array_iterator.ts
@@ -1,7 +1,7 @@
-import { MapIterator } from "../util/map_iterator";
-import { ParamDefinition } from "./param-definition";
-import { IParamDefinitionIterator } from "./param_definition_iterator";
-import { ParamsEquation } from "./params-equation";
+import { MapIterator } from "../internal_modules";
+import { ParamDefinition } from "../internal_modules";
+import { IParamDefinitionIterator } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * itérateur sur les paramètres d'un tableau de de ParamsEquation
diff --git a/src/pipe_flow/cond_distri.ts b/src/pipe_flow/cond_distri.ts
index 3ca4d58d4ea7800bc7047ad246cd29c9f30ded0d..4ea0fe9ca295b48f3a51ca56b89638a0d04eca0e 100644
--- a/src/pipe_flow/cond_distri.ts
+++ b/src/pipe_flow/cond_distri.ts
@@ -1,8 +1,8 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { ConduiteDistribParams } from "./cond_distri_params";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ConduiteDistribParams } from "../internal_modules";
 
 /**
  * classe de calcul sur la conduite distributrice
@@ -11,7 +11,7 @@ export class ConduiteDistrib extends Nub {
 
     constructor(prms: ConduiteDistribParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.ConduiteDistributrice;
+        this.setCalculatorType(CalculatorType.ConduiteDistributrice);
     }
 
     /**
diff --git a/src/pipe_flow/cond_distri_params.ts b/src/pipe_flow/cond_distri_params.ts
index ea1cb884724b1c4fa10be405e4fb0411f1e768a4..43a01047eba050a9956e89222695b90831803ea8 100644
--- a/src/pipe_flow/cond_distri_params.ts
+++ b/src/pipe_flow/cond_distri_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * paramètres pour la conduite distributrice
diff --git a/src/pipe_flow/lechaptcalmon_params.ts b/src/pipe_flow/lechaptcalmon_params.ts
deleted file mode 100644
index c10163a437cb466487b6ec219aeb1b1931f489e3..0000000000000000000000000000000000000000
--- a/src/pipe_flow/lechaptcalmon_params.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
-
-/**
- * paramètres pour le calcul Lechapt et Calmon
- */
-export class LechaptCalmonParams extends ParamsEquation {
-    /** Débit */
-    private _Q: ParamDefinition;
-
-    /** Diamètre */
-    private _D: ParamDefinition;
-
-    /** Perte de charge */
-    private _J: ParamDefinition;
-
-    /** Longueur de la conduite */
-    private _Lg: ParamDefinition;
-
-    /** Paramètre de rugosité L */
-    private _L: ParamDefinition;
-
-    /** Paramètre de rugosité M */
-    private _M: ParamDefinition;
-
-    /** Paramètre de rugosité N */
-    private _N: ParamDefinition;
-
-    /** Perte de charge singulière Ks */
-    private _Ks: ParamDefinition;
-
-    constructor(rQ: number, rD: number, rJ: number, rLg: number, rL: number, rM: number, rN: number, rKs: number,
-        nullParams: boolean = false) {
-        super();
-        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, "m³/s", rQ, ParamFamily.FLOWS, undefined, nullParams);
-        this._D = new ParamDefinition(
-            this, "D", new ParamDomain(ParamDomainValue.INTERVAL, 0, 20), "m", rD, ParamFamily.DIAMETERS, undefined, nullParams
-        );
-        this._J = new ParamDefinition(this, "J", ParamDomainValue.POS_NULL, "m", rJ, undefined, undefined, nullParams);
-        this._Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, "m", rLg, ParamFamily.LENGTHS, undefined, nullParams);
-        this._L = new ParamDefinition(this, "L", new ParamDomain(ParamDomainValue.INTERVAL, 0.8, 2), undefined, rL,
-            undefined, false, nullParams);
-        this._M = new ParamDefinition(this, "M", new ParamDomain(ParamDomainValue.INTERVAL, 1.5, 2.5), undefined, rM,
-            undefined, false, nullParams);
-        this._N = new ParamDefinition(this, "N", new ParamDomain(ParamDomainValue.INTERVAL, 4.5, 5.5), undefined, rN,
-            undefined, false, nullParams);
-        this._Ks = new ParamDefinition(this, "Ks", ParamDomainValue.POS_NULL, undefined, rKs, ParamFamily.STRICKLERS, undefined, nullParams);
-
-        this.addParamDefinition(this._Q);
-        this.addParamDefinition(this._D);
-        this.addParamDefinition(this._J);
-        this.addParamDefinition(this._Lg);
-        this.addParamDefinition(this._L);
-        this.addParamDefinition(this._M);
-        this.addParamDefinition(this._N);
-        this.addParamDefinition(this._Ks);
-    }
-
-    get Q() {
-        return this._Q;
-    }
-
-    get D() {
-        return this._D;
-    }
-
-    get J() {
-        return this._J;
-    }
-
-    get Lg() {
-        return this._Lg;
-    }
-
-    get L() {
-        return this._L;
-    }
-
-    get M() {
-        return this._M;
-    }
-
-    get N() {
-        return this._N;
-    }
-
-    get Ks() {
-        return this._Ks;
-    }
-}
diff --git a/src/pipe_flow/lechaptcalmon.ts b/src/pipe_flow/pl_lechaptcalmon.ts
similarity index 59%
rename from src/pipe_flow/lechaptcalmon.ts
rename to src/pipe_flow/pl_lechaptcalmon.ts
index 0de549712f8540fd119f97013ef8b62bae790172..553dbdfb041a822c16e0b691956a749d763212e1 100644
--- a/src/pipe_flow/lechaptcalmon.ts
+++ b/src/pipe_flow/pl_lechaptcalmon.ts
@@ -1,16 +1,16 @@
-import { CalculatorType } from "../compute-node";
-import { LCMaterial } from "../lc-material";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { LechaptCalmonParams } from "./lechaptcalmon_params";
+import { CalculatorType, PressureLossParams } from "../internal_modules";
+import { LCMaterial } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PL_LechaptCalmonParams } from "../internal_modules";
+import { PressureLossLaw, PressureLossType } from "../internal_modules";
 
 /**
  * Calcul des pertes de charge dans un tube à partir des tables de Lechapt et Calmon
  */
-export class LechaptCalmon extends Nub implements Observer {
+export class PL_LechaptCalmon extends PressureLossLaw implements Observer {
 
     private static _materials: { L: number, M: number, N: number, title: string }[] = [
         {
@@ -69,58 +69,55 @@ export class LechaptCalmon extends Nub implements Observer {
         }
     ];
 
-    constructor(prms: LechaptCalmonParams, dbg: boolean = false) {
+    constructor(prms: PL_LechaptCalmonParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.LechaptCalmon;
+        this.pressureLossType = PressureLossType.LechaptCalmon;
         this._props.addObserver(this);
         this.material = LCMaterial.PVCPolyethylene;
+        this._intlType = "LechaptCalmon";
     }
 
     public static get materials() {
-        return LechaptCalmon._materials;
+        return PL_LechaptCalmon._materials;
     }
 
     public get material(): LCMaterial {
-        return this.properties.getPropValue("material");
+        return this.getPropValue("material");
     }
 
     public set material(m: LCMaterial) {
-        this.properties.setPropValue("material", m);
-    }
-
-    /**
-     * paramètres castés au bon type
-     */
-    get prms(): LechaptCalmonParams {
-        return this._prms as LechaptCalmonParams;
-    }
-
-    public Calc(sVarCalc: string, rInit?: number): Result {
-        const r = super.Calc(sVarCalc, rInit);
-        const V2 = Math.pow(r.values.V, 2);
-        r.values.Kl = 19.62 * r.values.Jl / V2;
-        r.values.fD = this.prms.J.V / this.prms.Lg.V / V2 * 19.62 * this.prms.D.V;
-        return r;
+        this.setPropValue("material", m);
     }
 
     public Equation(sVarCalc: string): Result {
-
-        if (sVarCalc !== "J") {
-            throw new Error("LechaptCalmon.Equation() : invalid variable name " + sVarCalc);
+        if (sVarCalc !== undefined && sVarCalc !== "Jlin") {
+            throw new Error("PL_LechaptCalmon.Equation() : invalid variable name " + sVarCalc);
         }
+        const r: Result = this._result;
 
-        const r: Result = new Result(0, this);
+        // récupération des paramètres Q,D et Lg dans le parent
+        const parentPrms = this.parent.prms as PressureLossParams;
+        const Q = parentPrms.Q.v;
+        const D = parentPrms.D.v;
+        const Lg = parentPrms.Lg.v;
+
+        // Calcul de la perte de charge linéaire spécifique à chaque module de perte de charge.
+        r.values.Jlin = this.prms.L.v * Math.pow(Q, this.prms.M.v) / Math.pow(D, this.prms.N.v) * (Lg / 1000);
+
+        return r;
+    }
 
-        r.values.V = this.prms.Q.v / (Math.PI * Math.pow(this.prms.D.v / 2, 2));
+    public finalChecks(r: Result) {
         if (r.values.V < 0.4 || r.values.V > 2) {
             r.resultElement.log.add(new Message(MessageCode.WARNING_LECHAPT_CALMON_SPEED_OUTSIDE_04_2));
         }
-        r.values.Jl = this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v)
-        / Math.pow(this.prms.D.v, this.prms.N.v) * (this.prms.Lg.v / 1000);
-
-        r.vCalc = r.values.Jl + this.prms.Ks.v / 19.62 * Math.pow(r.values.V, 2);
+    }
 
-        return r;
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PL_LechaptCalmonParams {
+        return this._prms as PL_LechaptCalmonParams;
     }
 
     // interface Observer
@@ -135,11 +132,6 @@ export class LechaptCalmon extends Nub implements Observer {
      * paramétrage de la calculabilité des paramètres
      */
     protected setParametersCalculability() {
-        this.prms.Q.calculability = ParamCalculability.DICHO;
-        this.prms.D.calculability = ParamCalculability.DICHO;
-        this.prms.J.calculability = ParamCalculability.EQUATION;
-        this.prms.Lg.calculability = ParamCalculability.DICHO;
-        this.prms.Ks.calculability = ParamCalculability.DICHO;
         this.prms.L.calculability = ParamCalculability.FIXED;
         this.prms.M.calculability = ParamCalculability.FIXED;
         this.prms.N.calculability = ParamCalculability.FIXED;
@@ -147,10 +139,10 @@ export class LechaptCalmon extends Nub implements Observer {
 
     protected exposeResults() {
         this._resultsFamilies = {
-            Kl: undefined,
+            Klin: undefined,
             fD: undefined,
             V: undefined,
-            Jl: undefined
+            Jlin: undefined
         };
     }
 
@@ -159,10 +151,20 @@ export class LechaptCalmon extends Nub implements Observer {
      * according to this._materials presets
      */
     private applyMaterialPreset() {
-        const m = this.properties.getPropValue("material");
-        const values = LechaptCalmon._materials[m];
+        const m = this.getPropValue("material");
+        const values = PL_LechaptCalmon._materials[m];
         this.prms.L.singleValue = values.L;
         this.prms.M.singleValue = values.M;
         this.prms.N.singleValue = values.N;
     }
+
+    // interface IProperties
+
+    public hasProperty(key: string): boolean {
+        if (super.hasProperty(key)) {
+            return true;
+        }
+
+        return key === "material";
+    }
 }
diff --git a/src/pipe_flow/pl_lechaptcalmon_params.ts b/src/pipe_flow/pl_lechaptcalmon_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..040984826f438337effe11d403dcb9286bbdda0f
--- /dev/null
+++ b/src/pipe_flow/pl_lechaptcalmon_params.ts
@@ -0,0 +1,44 @@
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { PressureLossLawParams } from "../internal_modules";
+
+/**
+ * paramètres pour le calcul Lechapt et Calmon
+ */
+export class PL_LechaptCalmonParams extends PressureLossLawParams {
+
+    /** Paramètre de rugosité L */
+    private _L: ParamDefinition;
+
+    /** Paramètre de rugosité M */
+    private _M: ParamDefinition;
+
+    /** Paramètre de rugosité N */
+    private _N: ParamDefinition;
+
+    constructor(rL: number, rM: number, rN: number, nullParams: boolean = false) {
+        super();
+        this._L = new ParamDefinition(this, "L", new ParamDomain(ParamDomainValue.INTERVAL, 0.8, 2), undefined, rL,
+            undefined, false, nullParams);
+        this._M = new ParamDefinition(this, "M", new ParamDomain(ParamDomainValue.INTERVAL, 1.5, 2.5), undefined, rM,
+            undefined, false, nullParams);
+        this._N = new ParamDefinition(this, "N", new ParamDomain(ParamDomainValue.INTERVAL, 4.5, 5.5), undefined, rN,
+            undefined, false, nullParams);
+
+        this.addParamDefinition(this._L);
+        this.addParamDefinition(this._M);
+        this.addParamDefinition(this._N);
+    }
+
+    get L() {
+        return this._L;
+    }
+
+    get M() {
+        return this._M;
+    }
+
+    get N() {
+        return this._N;
+    }
+}
diff --git a/src/pipe_flow/pl_strickler.ts b/src/pipe_flow/pl_strickler.ts
new file mode 100644
index 0000000000000000000000000000000000000000..716aa797afd3078e978696a4e758542886e3970b
--- /dev/null
+++ b/src/pipe_flow/pl_strickler.ts
@@ -0,0 +1,46 @@
+import { PL_StricklerParams, PressureLossParams, PressureLossType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PressureLossLaw } from "../internal_modules";
+
+/**
+ * Calcul des pertes de charge par la loi de Strickler
+ */
+export class PL_Strickler extends PressureLossLaw {
+
+    constructor(prms: PL_StricklerParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this.pressureLossType = PressureLossType.Strickler;
+        this._intlType = "Strickler";
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PL_StricklerParams {
+        return this._prms as PL_StricklerParams;
+    }
+
+    public Equation(sVarCalc: string): Result {
+        if (sVarCalc !== undefined && sVarCalc !== "Jlin") {
+            throw new Error("PL_Strickler.Equation() : invalid variable name " + sVarCalc);
+        }
+        const r: Result = this._result;
+
+        // récupération des paramètres Q,D et Lg dans le parent
+        const parentPrms = this.parent.prms as PressureLossParams;
+        const Q = parentPrms.Q.v;
+        const D = parentPrms.D.v;
+        const Lg = parentPrms.Lg.v;
+
+        r.values.Jlin = Lg * Math.pow(Q, 2)
+            / Math.pow(this.prms.Ks.v * Math.PI * Math.pow(D, 2) / 4, 2)
+            / Math.pow(D / 4, 4 / 3);
+
+        return r;
+    }
+
+    protected setParametersCalculability(): void {
+        this.prms.Ks.calculability = ParamCalculability.DICHO;
+    }
+}
diff --git a/src/pipe_flow/pl_strickler_params.ts b/src/pipe_flow/pl_strickler_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a0b134dc0a9f6743add2a1625ab787a6033bf9ec
--- /dev/null
+++ b/src/pipe_flow/pl_strickler_params.ts
@@ -0,0 +1,22 @@
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { PressureLossLawParams } from "../internal_modules";
+
+/**
+ * paramètres pour le calcul de la loi de Strickler
+ */
+export class PL_StricklerParams extends PressureLossLawParams {
+
+    /** coefficient de rugosité de Strickler Ks */
+    private _Ks: ParamDefinition;
+
+    constructor(rKs: number, nullParams: boolean = false) {
+        super();
+        this._Ks = new ParamDefinition(this, "Ks", ParamDomainValue.POS, "SI", rKs, ParamFamily.STRICKLERS, undefined, nullParams);
+        this.addParamDefinition(this._Ks);
+    }
+
+    get Ks() {
+        return this._Ks;
+    }
+}
diff --git a/src/pipe_flow/pressureloss.ts b/src/pipe_flow/pressureloss.ts
new file mode 100644
index 0000000000000000000000000000000000000000..faed7118ce6ccaeb293a171f0dde1b6a39b257b1
--- /dev/null
+++ b/src/pipe_flow/pressureloss.ts
@@ -0,0 +1,150 @@
+import { Nub, ParamCalculability, ParamDefinition } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { PressureLossParams } from "../internal_modules";
+import { PressureLossLaw } from "../internal_modules";
+
+export class PressureLoss extends Nub {
+
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        Q: "m³/s",
+        D: "m",
+        J: "m/m",
+        Lg: "m"
+    };
+
+    constructor(prms: PressureLossParams, law: PressureLossLaw, dbg: boolean = false) {
+        super(prms, dbg);
+        this.setCalculatorType(CalculatorType.PressureLoss);
+        this.calculatedParam = prms.J;
+        this.setLaw(law);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PressureLossParams {
+        return this._prms as PressureLossParams;
+    }
+
+    public get child(): PressureLossLaw {
+        return this._children[0] as PressureLossLaw;
+    }
+
+    public getParameter(name: string): ParamDefinition {
+        if (typeof name !== "string") {
+            // dirty hack because calculated param descriptor for section params is an object { uid: , symbol: }
+            name = (name as any).symbol;
+        }
+
+        return super.getParameter(name); // includes child parameters
+    }
+
+    /**
+     * Set/replaces the current section
+     */
+    public setLaw(pll: PressureLossLaw) {
+        if (pll) {
+            // prevent index out of bounds at first time
+            if (this._children.length === 0) {
+                this._children[0] = undefined;
+            }
+            this.replaceChild(0, pll);
+            this._props.removeProp("pressureLossType"); // because this property belongs to child pressure loss law and is set as long as law is not defined
+            this._props.removeProp("material"); // because this property belongs to child Lechapt-Calmon law and is set as long as law is not defined
+            /**
+             * Y linkability managed in child classes through 'visible' flag
+             * @see Bief,CourbeRemous
+             */
+        }
+    }
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.Q.calculability = ParamCalculability.DICHO;
+        this.prms.D.calculability = ParamCalculability.DICHO;
+        this.prms.J.calculability = ParamCalculability.EQUATION;
+        this.prms.Lg.calculability = ParamCalculability.DICHO;
+        this.prms.Kloc.calculability = ParamCalculability.DICHO;
+    }
+
+    public Calc(sVarCalc: any, rInit?: number): Result {
+        if (typeof sVarCalc !== "string") {
+            // sVarCalc may be a calculated parameter descriptor (cf. Nub.calculatedParamDescriptor)
+            if (sVarCalc.uid !== this.uid && sVarCalc.uid !== this.child.uid) {
+                throw new Error("invalid nub");
+            }
+            sVarCalc = sVarCalc.symbol;
+        }
+
+        const r: Result = super.Calc(sVarCalc, rInit);
+
+        const V2 = Math.pow(r.values.V, 2);
+        const Jlin = this.child.result.values.Jlin;
+        r.values.Klin = 19.62 * Jlin / V2;
+        r.values.fD = this.prms.J.V / this.prms.Lg.V / V2 * 19.62 * this.prms.D.V;
+
+        this.child.finalChecks(r);
+
+        return r;
+    }
+
+    public Equation(sVarCalc: string): Result {
+        if (sVarCalc !== "J") {
+            throw new Error("PressureLoss.Equation() : invalid variable name " + sVarCalc);
+        }
+
+        if (this._result === undefined) {
+            this.initNewResultElement();
+        }
+
+        const r: Result = this._result;
+
+        // vitesse
+        r.values.V = this.prms.Q.v / (Math.PI * Math.pow(this.prms.D.v / 2, 2));
+
+        // perte de charge linéaire propre à chaque module
+        const rc: Result = this.child.Equation("Jlin");
+        if (!rc.ok) {
+            r.addLog(rc.log);
+            return r;
+        }
+
+        // perte de charge totale (J)
+        r.vCalc = rc.values.Jlin + this.prms.Kloc.v / 19.62 * Math.pow(r.values.V, 2);
+
+        return r;
+    }
+
+    public get result(): Result {
+        return this._result;  // redéfini (à l'identique) car on a redéfini le setter (et un setter seul fait que le getter n'est pas hérité)
+    }
+
+    public set result(r: Result) {
+        throw new Error("PressureLoss.set result() called!");
+    }
+
+    public static override resultsUnits() {
+        return PressureLoss._resultsUnits;
+    }
+
+    // interface IProperties
+
+    public getPropValue(key: string): any {
+        if (this.childHasProperty(key)) {
+            return this.child.getPropValue(key);
+        }
+        return this._props.getPropValue(key);
+    }
+
+    public setPropValue(key: string, val: any, sender?: any): boolean {
+        if (this.childHasProperty(key)) {
+            return this.child.setPropValue(key, val, sender);
+        }
+        return this._props.setPropValue(key, val, sender);
+    }
+}
diff --git a/src/pipe_flow/pressureloss_law.ts b/src/pipe_flow/pressureloss_law.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9e6ecb5ba150cf80d71520e8b40b5a9e1da00e4
--- /dev/null
+++ b/src/pipe_flow/pressureloss_law.ts
@@ -0,0 +1,47 @@
+import { CalculatorType, ChildNub, Nub, PressureLossLawParams } from "../internal_modules";
+import { Result } from "../internal_modules";
+
+/**
+ * Lois de perte de charge
+ */
+export enum PressureLossType {
+    LechaptCalmon,
+    Strickler
+}
+
+/**
+ * generic pressure loss law (analogous to acSection with respect to SectionParametree nub)
+ */
+export abstract class PressureLossLaw extends ChildNub {
+    constructor(prms: PressureLossLawParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this.setCalculatorType(CalculatorType.PressureLossLaw);
+    }
+
+    public get pressureLossType(): PressureLossType {
+        return this.getPropValue("pressureLossType");
+    }
+
+    public set pressureLossType(plt: PressureLossType) {
+        this.setPropValue("pressureLossType", plt);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): PressureLossLawParams {
+        return this._prms as PressureLossLawParams;
+    }
+
+    /**
+     * vérifications post-calcul
+     */
+    public finalChecks(r: Result) {
+    }
+
+    // interface IProperties
+
+    public hasProperty(key: string): boolean {
+        return key === "pressureLossType";
+    }
+}
diff --git a/src/pipe_flow/pressureloss_law_params.ts b/src/pipe_flow/pressureloss_law_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..154da09bd38a1f44213b43c8aee1878fa8925e50
--- /dev/null
+++ b/src/pipe_flow/pressureloss_law_params.ts
@@ -0,0 +1,7 @@
+import { ParamDefinition, ParamDomain, ParamDomainValue, ParamsEquation } from "../internal_modules";
+
+/**
+ * generic pressure loss law parameters
+ */
+export class PressureLossLawParams extends ParamsEquation {
+}
diff --git a/src/pipe_flow/pressureloss_params.ts b/src/pipe_flow/pressureloss_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53ff48faaca7c28a946b1d7f48ab694ea202ef79
--- /dev/null
+++ b/src/pipe_flow/pressureloss_params.ts
@@ -0,0 +1,55 @@
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
+
+export class PressureLossParams extends ParamsEquation {
+    /** Débit */
+    private _Q: ParamDefinition;
+
+    /** Diamètre */
+    private _D: ParamDefinition;
+
+    /** Perte de charge */
+    private _J: ParamDefinition;
+
+    /** Longueur de la conduite */
+    private _Lg: ParamDefinition;
+
+    /** Coefficient de perte de charge singulière Kloc */
+    private _Kloc: ParamDefinition;
+
+    constructor(rQ: number, rD: number, rJ: number, rLg: number, rKloc: number, nullParams: boolean = false) {
+        super();
+        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, "m³/s", rQ, ParamFamily.FLOWS, undefined, nullParams);
+        this._D = new ParamDefinition(this, "D", new ParamDomain(ParamDomainValue.INTERVAL, 0, 20), "m", rD, ParamFamily.DIAMETERS, undefined, nullParams);
+        this._J = new ParamDefinition(this, "J", ParamDomainValue.POS_NULL, "m", rJ, undefined, undefined, nullParams);
+        this._Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, "m", rLg, ParamFamily.LENGTHS, undefined, nullParams);
+        this._Kloc = new ParamDefinition(this, "Kloc", ParamDomainValue.POS_NULL, undefined, rKloc, undefined, undefined, nullParams);
+
+        this.addParamDefinition(this._Q);
+        this.addParamDefinition(this._D);
+        this.addParamDefinition(this._J);
+        this.addParamDefinition(this._Lg);
+        this.addParamDefinition(this._Kloc);
+    }
+
+    get Q() {
+        return this._Q;
+    }
+
+    get D() {
+        return this._D;
+    }
+
+    get J() {
+        return this._J;
+    }
+
+    get Lg() {
+        return this._Lg;
+    }
+
+    get Kloc() {
+        return this._Kloc;
+    }
+}
diff --git a/src/prebarrage/pb_bassin.ts b/src/prebarrage/pb_bassin.ts
index ba68be6a9e13a1be701064d61fd2ad237dc5c948..d99bbdfcc1a0a0c8bab9304e7d7d5a3458bba2d2 100644
--- a/src/prebarrage/pb_bassin.ts
+++ b/src/prebarrage/pb_bassin.ts
@@ -1,13 +1,13 @@
-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{
+import { Nub } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PbBassinParams } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { PbCloison } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { PreBarrage } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+
+export interface IPbBassinZstat {
     moy: number,
     min: number,
     max: number
@@ -20,8 +20,6 @@ export class PbBassin extends Nub {
     /** Liste des cloisons aval */
     public cloisonsAval: PbCloison[];
 
-    public parent: PreBarrage;
-
     /** Débit transitant dans le bassin en m³/s */
     public Q: number;
 
@@ -30,7 +28,7 @@ export class PbBassin extends Nub {
 
     constructor(prms: PbBassinParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PbBassin;
+        this.setCalculatorType(CalculatorType.PbBassin);
         this.cloisonsAmont = [];
         this.cloisonsAval = [];
         this._intlType = "Bassin";
@@ -45,7 +43,7 @@ export class PbBassin extends Nub {
 
     public Calc(sVarCalc?: string | any, rInit?: number): Result {
         // if Calc() is called outside of CalcSerie(), _result might not be initialized
-        if (! this.result) {
+        if (!this.result) {
             this.initNewResultElement();
         }
         const r = this.result;
@@ -66,7 +64,7 @@ export class PbBassin extends Nub {
     }
 
     public Equation(sVarCalc: string): Result {
-        switch(sVarCalc) {
+        switch (sVarCalc) {
             case "Q":
             case "Z":
                 const r = new Result();
@@ -86,9 +84,13 @@ export class PbBassin extends Nub {
         this.prms.ZF.calculability = ParamCalculability.FREE;
     }
 
+    public get parent(): PreBarrage {
+        return super.parent as PreBarrage;
+    }
+
     public CalcQ(): number {
         this.Q = 0;
-        for(const c of this.cloisonsAmont) {
+        for (const c of this.cloisonsAmont) {
             this.Q += Math.max(0, c.prms.Q.v);
         }
         return this.Q;
@@ -117,4 +119,4 @@ export class PbBassin extends Nub {
             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
index 88d0d812c71900684e75b5334bc5df3fbfd632cc..87b9da78c4a0aa977f244ed5b50c454418e6c016 100644
--- a/src/prebarrage/pb_bassin_params.ts
+++ b/src/prebarrage/pb_bassin_params.ts
@@ -1,6 +1,6 @@
-import { ParamsEquation } from "../param/params-equation";
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../internal_modules";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
 
 export class PbBassinParams extends ParamsEquation {
 
diff --git a/src/prebarrage/pb_cloison.ts b/src/prebarrage/pb_cloison.ts
index a8044fac4fe218a3b0d61799e4fdb5bee7e29bea..11db86a6f574575cf997d5c8be0e67f52d418f63 100644
--- a/src/prebarrage/pb_cloison.ts
+++ b/src/prebarrage/pb_cloison.ts
@@ -1,29 +1,31 @@
-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";
+import { ParallelStructure } from "../internal_modules";
+import { PbBassin } from "../internal_modules";
+import { PreBarrage } from "../internal_modules";
+import { ParallelStructureParams } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { LoiDebit, loiAdmissiblesOuvrages } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
 
 export class PbCloison extends ParallelStructure {
 
-    /** pointer to parent Nub */
-    public parent: PreBarrage;
-
     constructor(bassinAmont: PbBassin, bassinAval: PbBassin, dbg: boolean = false, nullParams: boolean = false) {
         super(new ParallelStructureParams(0, 0, 0, nullParams), 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;
+        this.setPropValue("upstreamBasin", bassinAmont === undefined ? "" : bassinAmont.uid);
+        this.setPropValue("downstreamBasin", bassinAval === undefined ? "" : bassinAval.uid);
+        this.setCalculatorType(CalculatorType.PbCloison);
         this._intlType = "Cloison";
     }
 
+    /** pointer to parent Nub */
+    public get parent(): PreBarrage {
+        return super.parent as PreBarrage;
+    }
+
     /** Bassin à l'amont de la cloison ou undefined pour condition limite amont */
     public get bassinAmont(): PbBassin {
         let basin: PbBassin;
@@ -43,7 +45,7 @@ export class PbCloison extends ParallelStructure {
         if (b !== undefined) {
             uid = b.uid;
         }
-        this.properties.setPropValue("upstreamBasin", uid);
+        this.setPropValue("upstreamBasin", uid);
         this.parent.updatePointers();
     }
 
@@ -66,12 +68,12 @@ export class PbCloison extends ParallelStructure {
         if (b !== undefined) {
             uid = b.uid;
         }
-        this.properties.setPropValue("downstreamBasin", uid);
+        this.setPropValue("downstreamBasin", uid);
         this.parent.updatePointers();
     }
 
     public get Z1(): number {
-        if(this.bassinAmont !== undefined) {
+        if (this.bassinAmont !== undefined) {
             return this.bassinAmont.Z;
         } else {
             return this.parent.prms.Z1.v;
@@ -79,7 +81,7 @@ export class PbCloison extends ParallelStructure {
     }
 
     public get Z2(): number {
-        if(this.bassinAval !== undefined) {
+        if (this.bassinAval !== undefined) {
             return this.bassinAval.Z;
         } else {
             return this.parent.prms.Z2.v;
@@ -89,7 +91,7 @@ export class PbCloison extends ParallelStructure {
     public Calc(sVarCalc?: string, rInit?: number): Result {
         this.updateZ1Z2();
         const r = super.Calc(sVarCalc, rInit);
-        switch(sVarCalc) {
+        switch (sVarCalc) {
             case "Z1":
                 // Upstream water elevation should be at least equal minZDV
                 r.vCalc = Math.max(this.getMinZDV(), r.vCalc);
@@ -120,9 +122,9 @@ export class PbCloison extends ParallelStructure {
      */
     public getMinZDV(): number {
         let minZDV: number;
-        for(const s of this.structures) {
-            if(s.prms.ZDV.visible) {
-                if(minZDV === undefined) {
+        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);
diff --git a/src/prebarrage/pre_barrage.ts b/src/prebarrage/pre_barrage.ts
index 30bf43f856c9cbe06e6460b2ac0eae33d3e36bba..0edb292950d255a656fccc7f5c80d18f244881cd 100644
--- a/src/prebarrage/pre_barrage.ts
+++ b/src/prebarrage/pre_barrage.ts
@@ -1,20 +1,22 @@
-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";
-import { MermaidUtil } from "../util/mermaid";
+import { Nub, Structure } from "../internal_modules";
+import { ParamCalculability, ParamDefinition } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { PreBarrageParams } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { PbBassin, IPbBassinZstat } from "../internal_modules";
+import { PbCloison } from "../internal_modules";
+import { SessionSettings } from "../internal_modules";
+import { MessageCode, Message, MessageSeverity } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { MermaidUtil } from "../internal_modules";
+import { cLog } from "../internal_modules";
 
 export class PreBarrage extends Nub {
 
     /** Liste des cloisons amont */
-    public cloisonsAmont: PbCloison[];
+    private _cloisonsAmont: PbCloison[];
 
+    // public pour pouvoir le modifier depuis les tests
     public maxIterations: number;
 
     /** Pointeurs vers les bassins dans this.children */
@@ -28,10 +30,9 @@ export class PreBarrage extends Nub {
 
     constructor(prms: PreBarrageParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.PreBarrage;
-        this.cloisonsAmont = [];
+        this.setCalculatorType(CalculatorType.PreBarrage);
+        this._cloisonsAmont = [];
         this._bassins = [];
-        this.maxIterations = SessionSettings.maxIterations;
         //this._intlType = "Cloison";
     }
 
@@ -53,6 +54,10 @@ export class PreBarrage extends Nub {
         return this._bassins;
     }
 
+    get cloisonsAmont(): PbCloison[] {
+        return this._cloisonsAmont;
+    }
+
     /**
      * Removes a child, along with all features (basins or walls) that are
      * related only to it, and pointers to it
@@ -88,11 +93,11 @@ export class PreBarrage extends Nub {
         let ok = false;
         // starting at river upstream ?
         if (startWall === undefined) {
-            if (this.cloisonsAmont.length === 0) {
+            if (this._cloisonsAmont.length === 0) {
                 return false;
             }
             // browse graph downwards
-            for (const ca of this.cloisonsAmont) {
+            for (const ca of this._cloisonsAmont) {
                 ok = ok || this.hasUpDownConnection(ca, 0, visited);
             }
         } else {
@@ -103,7 +108,7 @@ export class PreBarrage extends Nub {
                 // browse graph downwards
                 for (const ca of startWall.bassinAval.cloisonsAval) {
                     // prevent loops @TODO detect loops instead, and throw an error ?
-                    if (! visited.includes(ca)) {
+                    if (!visited.includes(ca)) {
                         visited.push(ca);
                         ok = ok || this.hasUpDownConnection(ca, nbBasins + 1, visited);
                     }
@@ -243,7 +248,7 @@ export class PreBarrage extends Nub {
             this.mergeDuplicateWalls(b);
         }
         // walls between upstream and another basin
-        for (const b of this.cloisonsAmont.map((ca) => ca.bassinAval)) {
+        for (const b of this._cloisonsAmont.map((ca) => ca.bassinAval)) {
             if (b !== undefined) {
                 this.mergeDuplicateWalls(b, false);
             }
@@ -328,7 +333,18 @@ export class PreBarrage extends Nub {
             return this.result;
         }
 
+        for (const c of this._children) {
+            if (c instanceof PbCloison) {
+                c.inhibitSubmergenceError = true;
+            }
+        }
         const res = super.Calc(sVarCalc, rInit);
+        for (const c of this._children) {
+            if (c instanceof PbCloison) {
+                c.inhibitSubmergenceError = false;
+            }
+        }
+
         // calculate basins so that they have a proper .result
         for (const b of this._bassins) {
             b.Calc();
@@ -336,7 +352,11 @@ export class PreBarrage extends Nub {
         // calculate Q on all walls so that their result shows Q and not Z1
         for (const c of this._children) {
             if (c instanceof PbCloison) {
+                // sauvegarde des messages générés pendant les itérations de dichotomie
+                const logBackup: cLog = c.result.resultElement.log.cloneErrors();
                 c.finalCalc();
+                // restitution des messages sauvés
+                c.result.resultElement.log.addLog(logBackup);
             }
         }
 
@@ -347,6 +367,15 @@ export class PreBarrage extends Nub {
             }
         }
 
+        // if an error occurred in any nub, remove all results
+        // except if it's a dichotomy convergence error (and only this error)
+
+        if (!this.allResultsOk && !this.hasOnlyMessage(MessageCode.ERROR_DICHO_CONVERGE)) {
+            for (const c of this.allChildNubIterator) {
+                c.result.resultElement.removeValues();
+            }
+        }
+
         return res;
     }
 
@@ -355,18 +384,23 @@ export class PreBarrage extends Nub {
      * @param sVarCalc ignoré: Z1 uniquement
      */
     public Equation(sVarCalc: string): Result {
+        const maxIter = this.maxIterations !== undefined ? this.maxIterations : SessionSettings.maxIterations;
+        if (maxIter === undefined || maxIter < 1) {
+            throw new Error("invalid iteration count");
+        }
+
         // Initialisation des cotes sur les bassins et la CL amont
         if (this.isMeshed()) {
-            for(const b of this.bassins) {
+            for (const b of this.bassins) {
                 const zB = b.getMinZDV();
-                if(zB !== undefined) {
+                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) {
+            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;
@@ -381,13 +415,13 @@ export class PreBarrage extends Nub {
                 }
             }
         }
-        let iter: number = this.maxIterations;
+        let iter: number = maxIter;
         let bConverged;
         let z1stat: IPbBassinZstat;
         // const tZ1: IPbBassinZstat[] = [];
         // const tQ: number[][] = [];
         while (iter-- > 0) {
-            this._relax = Math.pow(iter / this.maxIterations, 3) * 0.25 + 0.05;
+            this._relax = Math.pow(iter / maxIter, 3) * 0.25 + 0.05;
             this.debug(`***** Iteration n°${iter} relax=${this._relax} *****`);
             bConverged = true;
             if (this.isMeshed()) {
@@ -395,7 +429,7 @@ export class PreBarrage extends Nub {
                 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);
+                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) {
@@ -406,23 +440,23 @@ export class PreBarrage extends Nub {
             // 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);
+                this.debug("Bassin " + i);
                 const zStat = this.bassins[i].CalcZ();
                 bConverged = bConverged && (zStat.max - zStat.min) < this._precision;
             }
             this.debug("Cloison amont");
-            z1stat = this.CalcZ1Cloisons(this.cloisonsAmont);
+            z1stat = this.CalcZ1Cloisons(this._cloisonsAmont);
             this.prms.Z1.v = z1stat.moy;
             // tZ1.push(z1stat);
             bConverged = bConverged && (z1stat.max - z1stat.min) < this._precision
-            if(bConverged) {
+            if (bConverged) {
                 break;
             }
         }
         // console.debug(tQ);
         // console.debug(tZ1);
-        const r = new Result(this.prms.Z1.v);
-        if(!bConverged) {
+        const r = new Result(this.prms.Z1.v, this);
+        if (!bConverged) {
             r.resultElement.addMessage(new Message(MessageCode.WARNING_PREBARRAGE_NON_CONVERGENCE, {
                 precision: (z1stat.max - z1stat.min)
             }));
@@ -446,11 +480,11 @@ export class PreBarrage extends Nub {
         // 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.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()) {
+        if (!this.hasUpDownConnection()) {
             throw new Error("PreBarrage.checkGeometry(): must have at least one path from upstream to downstream");
         }
 
@@ -499,21 +533,21 @@ export class PreBarrage extends Nub {
     /** Clears basins list then builds it again fom children list */
     public updatePointers() {
         this._bassins = [];
-        this.cloisonsAmont = [];
+        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);
+                    this._cloisonsAmont.push(c);
                 }
                 if (c.bassinAmont !== undefined) {
-                    if (! c.bassinAmont.cloisonsAval.includes(c)) {
+                    if (!c.bassinAmont.cloisonsAval.includes(c)) {
                         c.bassinAmont.cloisonsAval.push(c);
                     }
                 }
                 if (c.bassinAval !== undefined) {
-                    if (! c.bassinAval.cloisonsAmont.includes(c)) {
+                    if (!c.bassinAval.cloisonsAmont.includes(c)) {
                         c.bassinAval.cloisonsAmont.push(c);
                     }
                 }
@@ -522,7 +556,7 @@ export class PreBarrage extends Nub {
     }
 
     private isMeshed(): boolean {
-        if (this.cloisonsAmont.length > 1) {
+        if (this._cloisonsAmont.length > 1) {
             return true;
         }
         for (const bassin of this.bassins) {
@@ -540,19 +574,19 @@ export class PreBarrage extends Nub {
             c.prms.Q.initValue = Math.max(0, c.prms.Q.v);
             c.Calc("Q");
             // Relax! On ne prend pas toute la modification proposée !
-            if(c.prms.Q.v > 0) {
+            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: 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}`);}
+        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) {
+            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;
@@ -565,13 +599,13 @@ export class PreBarrage extends Nub {
     }
 
     public CalcZ1Cloisons(cloisons: PbCloison[]): IPbBassinZstat {
-        const zStat: IPbBassinZstat = {moy : 0, min: Infinity, max: -Infinity};
+        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) {
+            if (c.prms.Q.v >= 1E-6) {
                 const r = c.Calc("Z1")
-                if(r.ok) {
+                if (r.ok) {
                     Z1 = r.vCalc;
                 } else {
                     Z1 = c.prms.Z2.v;
@@ -582,7 +616,7 @@ export class PreBarrage extends Nub {
             } else {
                 // Nul flow in submerged flow: Z1 = Z2
                 c.updateZ1Z2();
-                if(c.prms.Z2.v > c.getMinZDV()) {
+                if (c.prms.Z2.v > c.getMinZDV()) {
                     Z1 = c.prms.Z2.v;
                     zStat.moy += Z1;
                     n++;
@@ -590,12 +624,12 @@ export class PreBarrage extends Nub {
                     c.prms.Q.v = 0;
                 }
             }
-            if(Z1 !== undefined) {
+            if (Z1 !== undefined) {
                 zStat.min = Math.min(zStat.min, Z1);
                 zStat.max = Math.max(zStat.max, Z1);
             }
         }
-        if(n > 0) {
+        if (n > 0) {
             zStat.moy = zStat.moy / n;
         } else {
             // Nul flow on all cloisons which are all in free flow => Z1 = ZminZDV
@@ -603,16 +637,16 @@ export class PreBarrage extends Nub {
             zStat.min = zStat.moy;
             zStat.max = zStat.moy;
         }
-        this.debug(`CalcZ1Cloisons: Z= ${zStat.moy} [${(zStat.max-zStat.min)}]`);
+        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) {
+        for (const c of cloisons) {
             const minZDVCloison = c.getMinZDV();
-            if(minZDVCloison !== undefined) {
-                if(minZDV === undefined) {
+            if (minZDVCloison !== undefined) {
+                if (minZDV === undefined) {
                     minZDV = minZDVCloison
                 } else {
                     minZDV = Math.min(minZDV, minZDVCloison);
@@ -636,10 +670,10 @@ export class PreBarrage extends Nub {
             if (c instanceof PbCloison) {
                 for (const k of Object.keys(ret.changedUids)) {
                     // find basins having the changed UID
-                    if (c.properties.props.upstreamBasin === k) {
+                    if (c.getPropValue("upstreamBasin") === k) {
                         c.bassinAmont = this.findChild(ret.changedUids[k]) as PbBassin;
                     }
-                    if (c.properties.props.downstreamBasin === k) {
+                    if (c.getPropValue("downstreamBasin") === k) {
                         c.bassinAval = this.findChild(ret.changedUids[k]) as PbBassin;
                     }
                 }
diff --git a/src/prebarrage/pre_barrage_params.ts b/src/prebarrage/pre_barrage_params.ts
index 5cc04e51b4ead4475e4b3342a5d7555d1cb2a401..e3f91d22dd22fee1a911fb6c7a45c96bb267c43d 100644
--- a/src/prebarrage/pre_barrage_params.ts
+++ b/src/prebarrage/pre_barrage_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 export class PreBarrageParams extends ParamsEquation {
 
diff --git a/src/props.ts b/src/props.ts
index fb50383859fa82474664fdfc3d6806a25794cbb4..01743005bfdd85440e6dbe2fc701d1a321e2f236 100644
--- a/src/props.ts
+++ b/src/props.ts
@@ -1,67 +1,147 @@
-import { IObservable, Observable, Observer } from "./util/observer";
+import { cloneDeep } from "lodash";
+
+import { BiefRegime, CalculatorType, DivingJetSupport, FishSpecies, GrilleProfile, GrilleType, IObservable, LCMaterial, LoiDebit, MRCInclination, MethodeResolution, Observable, Observer, ParType, PressureLossType, SPPOperation, SectionType, StructureType, TrigoOperation, TrigoUnit, isNumeric } from "./internal_modules";
 
 /**
- * special property names
+ * get enum numerical value from enum class name and value as a string
+ * @param enumClass enum class name
+ * @param enumValueName enum value as a string
+ * @returns enum numerical value
  */
+export function enumValueFromString(enumClass: string, enumValueName: string): any {
+    // !! property names must be unique throughout JaLHyd !!
+    const enumValues = Props.enumFromProperty[enumClass];
+    if (enumValues) {
+        return enumValues[enumValueName];
+    }
+    throw new Error("unknown enum class ${enumClass}");
+}
 
 /**
  * represents a boolean: true if provided value at parameter creation must be ignore (@see nghyd/enableEmptyFieldsOnFormInit)
  */
 export const Prop_NullParameters: string = "nullparams";
 
+/**
+ * Interface permettant de propager de manière transparente des opérations sur des propriétés en encapsulant celles ci
+ * (implémentée par Props et les classes possédant directement ou indirectement un membre de type Props, par ex Nub)
+ */
+export interface IProperties extends IObservable {
+    /**
+     * get property value
+     * @param key property name
+     */
+    getPropValue(key: string): any;
+
+    /**
+     * set property value
+     * @param key property name
+     * @param val property value to set
+     * @param sender object from which modification originates
+     */
+    setPropValue(key: string, val: any, sender?: any): boolean;
+
+    /**
+     * determine if this object directly or indirectly has a given property
+     * @param key property name
+     */
+    hasProperty(key: string): boolean;
+
+    /**
+     * list of properties keys
+    */
+    readonly keys: string[];
+}
+
 /**
  * gestion d'un ensemble de propriétés (clé/valeur) qui prévient quand
  * l'une d'entre-elles change
  */
-export class Props implements IObservable {
+export class Props implements IProperties {
+
+    /** correspondance entre les noms de propriétés et les enum associés */
+    public static readonly enumFromProperty: any = {
+        calcType: CalculatorType,
+        divingJetSupported: DivingJetSupport,
+        gridProfile: GrilleProfile,
+        gridType: GrilleType,
+        inclinedApron: MRCInclination,
+        loiDebit: LoiDebit,
+        material: LCMaterial,
+        methodeResolution: MethodeResolution,
+        nodeType: SectionType,
+        parType: ParType,
+        pressureLossType: PressureLossType,
+        regime: BiefRegime,
+        species: FishSpecies,
+        sppOperation: SPPOperation,
+        structureType: StructureType,
+        trigoOperation: TrigoOperation,
+        trigoUnit: TrigoUnit
+    };
+
     // implémentation de IObservable par délégation
     private _observable: Observable;
 
-    constructor(private _props: any = {}) {
+    // object literal representing properties keys and values
+    private _map: any = {};
+
+    constructor(prps?: any | IProperties) {
         this._observable = new Observable();
+
+        if (prps !== undefined) {
+            if (Props.implementsIProperties(prps)) {
+                this.copyIProperties(prps);
+            }
+            else
+                this._map = cloneDeep(prps);
+        }
+    }
+
+    /**
+     * @returns true if an object implements the IProperties interface
+     */
+    public static implementsIProperties(o: any): boolean {
+        return "getPropValue" in o && "setPropValue" in o && "hasProperty" in o && "keys" in o;
+    }
+
+    /**
+     * set properties map from an IProperties
+     */
+    private copyIProperties(p: IProperties) {
+        this._map = {};
+        for (const k of p.keys) {
+            this._map[k] = p.getPropValue(k);
+        }
+    }
+
+    public get keys(): string[] {
+        return Object.keys(this._map);
     }
 
     public getPropValue(key: string): any {
-        return this._props[key];
+        return this._map[key];
     }
 
     public setPropValue(key: string, val: any, sender?: any): boolean {
-        const oldValue = this._props[key];
+        if (key === undefined) {
+            throw new Error("setPropValue : undefined key!");
+        }
+        const oldValue = this._map[key];
         const changed = oldValue !== val;
         if (changed) {
-            this._props[key] = val;
+            this._map[key] = val;
             this.notifyPropChange(key, val, sender);
         }
         return changed;
     }
 
-    /**
-     * fixe la valeur de toutes les propriétés
-     * @param props nouvelles valeurs
-     * @param sender objet modificateur
-     */
-    public setProps(props: {}, sender?: any) {
-        let p;
-        if (props instanceof Props) {
-            p = props._props;
-        } else {
-            p = props;
-        }
-        const changed = this.compareObjects(this._props, p);
-        if (changed) {
-            this._props = {};
-            for (const k in p) {
-                if (p.hasOwnProperty(k)) {
-                    this._props[k] = p[k];
-                }
-            }
-
-            this.notifyPropsChange(sender);
-        }
+    public removeProp(key: string) {
+        delete this._map[key];
     }
 
-    public get props() {
-        return this._props;
+    public hasProperty(key: string): boolean {
+        return true;
     }
 
     public getObservers(): Observer[] {
@@ -72,31 +152,24 @@ export class Props implements IObservable {
      * Remove all properties, does not notify of any change
      */
     public reset() {
-        this._props = {};
+        this._map = {};
     }
 
     /**
      * Clones properties into a new Props object
      */
     public clone(): Props {
-        const res = new Props();
-        // copy values
-        for (const k in this._props) {
-            if (this._props.hasOwnProperty(k)) {
-                res._props[k] = this._props[k];
-            }
-        }
-        return res;
+        return new Props(this);
     }
 
     public toString(): string {
         let res = "[";
-        for (const k in this._props) {
-            if (this._props.hasOwnProperty(k)) {
+        for (const k in this._map) {
+            if (this._map.hasOwnProperty(k)) {
                 if (res !== "[") {
                     res += ", ";
                 }
-                res += `${k}:${this._props[k]}`;
+                res += `${k}:${this._map[k]}`;
             }
         }
         res += "]";
@@ -126,16 +199,6 @@ export class Props implements IObservable {
         this._observable.notifyObservers(data, sender);
     }
 
-    /**
-     * notification de changement de la valeur de toutes les propriétés
-     * @param sender objet ayant changé les valeurs
-     */
-    private notifyPropsChange(sender: any) {
-        this.notifyObservers({
-            action: "propertiesChange",
-        }, sender);
-    }
-
     /**
      * notification de changement de la valeur d'une propriété
      * @param prop nom de la propriété modifiée
@@ -151,32 +214,22 @@ export class Props implements IObservable {
     }
 
     /**
-     * compare 2 objets (clés et valeurs)
-     * @return true s'il existe une différence
+     * Returns a copy of given map, inverting enum keys and values
      */
-    private compareObjects(o1: { [key: string]: any }, o2: { [key: string]: any }) {
-        const oldKeys: string[] = Object.keys(o1).sort();
-        const newKeys: string[] = Object.keys(o2).sort();
-
-        // nombre de clés
-        const changed = oldKeys.length !== newKeys.length;
-        if (changed) {
-            return true;
-        }
-        // nom des clés
-        for (const i in oldKeys) {
-            if (oldKeys[i] !== newKeys[i]) {
-                return true;
-            }
-        }
-        // valeurs
-        for (const i in o1) {
-            if (o1[i] !== o2[i]) {
-                return true;
+    public static invertEnumKeysAndValuesInProperties(stringProps: any, forceNumbers: boolean = false) {
+        const res = JSON.parse(JSON.stringify(stringProps)); // clone
+        for (const k in res) {
+            if (!forceNumbers || !isNumeric(res[k])) {
+                if (Object.keys(Props.enumFromProperty).includes(k)) {
+                    const enumClass = Props.enumFromProperty[k];
+                    res[k] = enumClass[res[k]];
+                }
             }
         }
-
-        return false;
+        return res;
     }
 
+    public invertEnumKeysAndValues(forceNumbers: boolean = false) {
+        return Props.invertEnumKeysAndValuesInProperties(this._map, forceNumbers);
+    }
 }
diff --git a/src/session.ts b/src/session.ts
index 31f5cdcebdc95a30520eb6a7be7f72b0f8e24baf..7c714cfac59b4ff7e6d5a7586271068159eda14d 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -1,115 +1,92 @@
-import { isNumeric } from "./base";
-import { CalculatorType, SectionType } from "./compute-node";
-import { config } from "./config";
-import { LCMaterial } from "./lc-material";
-import { LinkedValue } from "./linked-value";
-import { Nub } from "./nub";
-import { ParamDefinition } from "./param/param-definition";
-import { Props, Prop_NullParameters } from "./props";
-import { SessionSettings } from "./session_settings";
+import { CalculatorType, IProperties, PL_Strickler, PL_StricklerParams, PressureLossParams, SectionType } from "./internal_modules";
+import { config } from "./internal_modules";
+import { LinkedValue } from "./internal_modules";
+import { Nub } from "./internal_modules";
+import { ParamDefinition } from "./internal_modules";
+import { Props, Prop_NullParameters } from "./internal_modules";
+import { SessionSettings } from "./internal_modules";
 
 // Calculettes
-import { Grille, GrilleProfile, GrilleType } from "./devalaison/grille";
-import { GrilleParams } from "./devalaison/grille_params";
-import { Jet } from "./devalaison/jet";
-import { JetParams } from "./devalaison/jet_params";
-import { ConcentrationBlocs } from "./macrorugo/concentration_blocs";
-import { ConcentrationBlocsParams } from "./macrorugo/concentration_blocs_params";
-import { MacroRugo } from "./macrorugo/macrorugo";
-import { MacrorugoCompound } from "./macrorugo/macrorugo_compound";
-import { MacrorugoCompoundParams } from "./macrorugo/macrorugo_compound_params";
-import { MacrorugoParams } from "./macrorugo/macrorugo_params";
-import { MRCInclination } from "./macrorugo/mrc-inclination";
-import { SPP, SPPOperation } from "./math/spp";
-import { SPPParams } from "./math/spp_params";
-import { Trigo, TrigoOperation, TrigoUnit } from "./math/trigo";
-import { TrigoParams } from "./math/trigo_params";
-import { YAXB } from "./math/yaxb";
-import { YAXBParams } from "./math/yaxb_params";
-import { YAXN } from "./math/yaxn";
-import { YAXNParams } from "./math/yaxn_params";
-import { Bief } from "./open-channel/bief";
-import { BiefParams, BiefRegime } from "./open-channel/bief_params";
-import { MethodeResolution } from "./open-channel/methode-resolution";
-import { Pente } from "./open-channel/pente";
-import { PenteParams } from "./open-channel/pente_params";
-import { RegimeUniforme } from "./open-channel/regime_uniforme";
-import { CourbeRemous } from "./open-channel/remous";
-import { CourbeRemousParams } from "./open-channel/remous_params";
-import { cSnCirc } from "./open-channel/section/section_circulaire";
-import { ParamsSectionCirc } from "./open-channel/section/section_circulaire_params";
-import { SectionParametree } from "./open-channel/section/section_parametree";
-import { cSnPuiss } from "./open-channel/section/section_puissance";
-import { ParamsSectionPuiss } from "./open-channel/section/section_puissance_params";
-import { cSnRectang } from "./open-channel/section/section_rectang";
-import { ParamsSectionRectang } from "./open-channel/section/section_rectang_params";
-import { cSnTrapez } from "./open-channel/section/section_trapez";
-import { ParamsSectionTrapez } from "./open-channel/section/section_trapez_params";
-import { acSection } from "./open-channel/section/section_type";
-import { CloisonAval } from "./pab/cloison_aval";
-import { CloisonsAvalParams } from "./pab/cloison_aval_params";
-import { Cloisons } from "./pab/cloisons";
-import { CloisonsParams } from "./pab/cloisons_params";
-import { Pab } from "./pab/pab";
-import { PabChute } from "./pab/pab_chute";
-import { PabChuteParams } from "./pab/pab_chute_params";
-import { PabDimension } from "./pab/pab_dimension";
-import { PabDimensionParams } from "./pab/pab_dimensions_params";
-import { PabNombre } from "./pab/pab_nombre";
-import { PabNombreParams } from "./pab/pab_nombre_params";
-import { PabParams } from "./pab/pab_params";
-import { PabPuissance } from "./pab/pab_puissance";
-import { PabPuissanceParams } from "./pab/pab_puissance_params";
-import { ConduiteDistrib } from "./pipe_flow/cond_distri";
-import { ConduiteDistribParams } from "./pipe_flow/cond_distri_params";
-import { LechaptCalmon } from "./pipe_flow/lechaptcalmon";
-import { LechaptCalmonParams } from "./pipe_flow/lechaptcalmon_params";
-import { Solveur } from "./solveur/solveur";
-import { SolveurParams } from "./solveur/solveur_params";
-import { Dever } from "./structure/dever";
-import { DeverParams } from "./structure/dever_params";
-import { CreateStructure } from "./structure/factory_structure";
-import { ParallelStructure } from "./structure/parallel_structure";
-import { ParallelStructureParams } from "./structure/parallel_structure_params";
-import { LoiDebit, StructureType } from "./structure/structure_props";
-import { Par, ParType } from "./par/par";
-import { ParParams } from "./par/par_params";
-import { ParSimulation } from "./par/par_simulation";
-import { ParSimulationParams } from "./par/par_simulation_params";
-import { FishSpecies } from "./verification/fish_species";
-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";
-import { ParamValueMode } from "./param/param-value-mode";
+import { Grille } from "./internal_modules";
+import { GrilleParams } from "./internal_modules";
+import { Jet } from "./internal_modules";
+import { JetParams } from "./internal_modules";
+import { ConcentrationBlocs } from "./internal_modules";
+import { ConcentrationBlocsParams } from "./internal_modules";
+import { MacroRugo } from "./internal_modules";
+import { MacrorugoCompound } from "./internal_modules";
+import { MacrorugoCompoundParams } from "./internal_modules";
+import { MacrorugoParams } from "./internal_modules";
+import { SPP } from "./internal_modules";
+import { SPPParams } from "./internal_modules";
+import { Trigo } from "./internal_modules";
+import { TrigoParams } from "./internal_modules";
+import { YAXB } from "./internal_modules";
+import { YAXBParams } from "./internal_modules";
+import { YAXN } from "./internal_modules";
+import { YAXNParams } from "./internal_modules";
+import { Bief } from "./internal_modules";
+import { BiefParams } from "./internal_modules";
+import { MethodeResolution } from "./internal_modules";
+import { Pente } from "./internal_modules";
+import { PenteParams } from "./internal_modules";
+import { RegimeUniforme } from "./internal_modules";
+import { CourbeRemous } from "./internal_modules";
+import { CourbeRemousParams } from "./internal_modules";
+import { cSnCirc } from "./internal_modules";
+import { ParamsSectionCirc } from "./internal_modules";
+import { SectionParametree } from "./internal_modules";
+import { cSnPuiss } from "./internal_modules";
+import { ParamsSectionPuiss } from "./internal_modules";
+import { cSnRectang } from "./internal_modules";
+import { ParamsSectionRectang } from "./internal_modules";
+import { cSnTrapez } from "./internal_modules";
+import { ParamsSectionTrapez } from "./internal_modules";
+import { acSection } from "./internal_modules";
+import { CloisonAval } from "./internal_modules";
+import { CloisonsAvalParams } from "./internal_modules";
+import { Cloisons } from "./internal_modules";
+import { CloisonsParams } from "./internal_modules";
+import { Pab } from "./internal_modules";
+import { PabChute } from "./internal_modules";
+import { PabChuteParams } from "./internal_modules";
+import { PabDimension } from "./internal_modules";
+import { PabDimensionParams } from "./internal_modules";
+import { PabNombre } from "./internal_modules";
+import { PabNombreParams } from "./internal_modules";
+import { PabParams } from "./internal_modules";
+import { PabPuissance } from "./internal_modules";
+import { PabPuissanceParams } from "./internal_modules";
+import { ConduiteDistrib } from "./internal_modules";
+import { ConduiteDistribParams } from "./internal_modules";
+import { PL_LechaptCalmon } from "./internal_modules";
+import { PL_LechaptCalmonParams } from "./internal_modules";
+import { Solveur } from "./internal_modules";
+import { SolveurParams } from "./internal_modules";
+import { Dever } from "./internal_modules";
+import { DeverParams } from "./internal_modules";
+import { CreateStructure } from "./internal_modules";
+import { ParallelStructure } from "./internal_modules";
+import { ParallelStructureParams } from "./internal_modules";
+import { LoiDebit } from "./internal_modules";
+import { Par } from "./internal_modules";
+import { ParParams } from "./internal_modules";
+import { ParSimulation } from "./internal_modules";
+import { ParSimulationParams } from "./internal_modules";
+import { Espece } from "./internal_modules";
+import { EspeceParams } from "./internal_modules";
+import { Verificateur } from "./internal_modules";
+import { PreBarrage } from "./internal_modules";
+import { PreBarrageParams } from "./internal_modules";
+import { PbCloison } from "./internal_modules";
+import { PbBassin } from "./internal_modules";
+import { PbBassinParams } from "./internal_modules";
+import { ParamValueMode } from "./internal_modules";
+import { PressureLoss } from "./internal_modules";
+import { PressureLossLaw, PressureLossType } from "./internal_modules";
 
 export class Session {
 
-    /** correspondance entre les noms des propriétés et les enum associés */
-    public static enumFromProperty: any = {
-        loiDebit: LoiDebit,
-        methodeResolution: MethodeResolution,
-        material: LCMaterial,
-        gridProfile: GrilleProfile,
-        gridType: GrilleType,
-        regime: BiefRegime,
-        trigoOperation: TrigoOperation,
-        trigoUnit: TrigoUnit,
-        sppOperation: SPPOperation,
-        nodeType: SectionType,
-        calcType: CalculatorType,
-        structureType: StructureType,
-        inclinedApron: MRCInclination,
-        parType: ParType,
-        species: FishSpecies,
-        divingJetSupported: DivingJetSupport
-    };
-
     public static getInstance(): Session {
         if (Session._instance === undefined) {
             Session._instance = new Session();
@@ -117,22 +94,6 @@ export class Session {
         return Session._instance;
     }
 
-    /**
-     * Returns a copy of given map, inverting enum keys and values
-     */
-    public static invertEnumKeysAndValuesInProperties(stringProps: any, forceNumbers: boolean = false) {
-        const res = JSON.parse(JSON.stringify(stringProps)); // clone
-        for (const k in res) {
-            if (!forceNumbers || !isNumeric(res[k])) {
-                if (Object.keys(Session.enumFromProperty).includes(k)) {
-                    const enumClass = Session.enumFromProperty[k];
-                    res[k] = enumClass[res[k]];
-                }
-            }
-        }
-        return res;
-    }
-
     /** instance pour le pattern singleton */
     private static _instance: Session;
 
@@ -237,7 +198,7 @@ export class Session {
             maxIterations: SessionSettings.maxIterations
         };
         if (settings) {
-            sessionSettings = {...sessionSettings, ...settings};
+            sessionSettings = { ...sessionSettings, ...settings };
         }
         // nubs in session
         let ids: string[];
@@ -361,6 +322,59 @@ export class Session {
         return foundNub;
     }
 
+    private static parameterIndex(obj: any, symbol: string): number {
+        let i;
+        const prms = obj["parameters"];
+        for (i in prms) {
+            if (prms[i]["symbol"] === symbol) {
+                return +i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Calcule le type de calculette compatible et modifie les propriétés en conséquence.
+     * Permet de charger des fichiers session avec une version antérieure.
+     * Par ex : Lechapt-Calmon -> PressureLoss
+     */
+    private compatibleCalculator(obj: any): any {
+        switch (obj["props"]["calcType"]) {
+            case CalculatorType.LechaptCalmon:
+                // create parent PressureLoss nub
+                const plProps = new Props();
+                plProps.setPropValue("calcType", CalculatorType.PressureLoss);
+                const pl = this.createNub(plProps);
+
+                // JSON representation
+                let res: any = pl.objectRepresentation();
+
+                // set Lechapt-Calmon as child
+                res["children"] = [obj];
+
+                // move PressureLoss parameters from Lechapt-Calmon
+                const movedParams = ["Q", "D", "J", "Lg", "Kloc"];
+                for (const p of movedParams) {
+                    // if child has parameter
+                    const cp = Session.parameterIndex(obj, p);
+                    if (cp !== -1) {
+                        const pp = Session.parameterIndex(res, p);
+                        if (pp === -1) {
+                            res["parameters"].push(obj["parameters"][cp]);
+                        } else {
+                            res["parameters"][pp] = obj["parameters"][cp];
+                        }
+                        // delete obj["parameters"][pp];
+                        obj["parameters"].splice(cp, 1);
+                    }
+                }
+                return res;
+
+            default:
+                return obj;
+        }
+    }
+
     /**
      * Crée un Nub à partir d'une description (Props)
      * @param params propriétés à partir desquelles on détermine la classe du Nub à créer
@@ -371,15 +385,14 @@ export class Session {
      *    définies dans le constructeur du Nub créé
      * @param dbg activer débogage
      */
-    public createNub(params: Props, parentNub?: Nub, dbg: boolean = false): Nub {
-        const calcType: CalculatorType = params.getPropValue("calcType");
-
+    public createNub(params: IProperties, parentNub?: Nub, dbg: boolean = false): Nub {
         // true if provided values to parameter creation must be ignored
         const nullParams: boolean = params.getPropValue(Prop_NullParameters) === undefined ? false : params.getPropValue(Prop_NullParameters);
 
         let nub: Nub;
         let prms: any;
 
+        const calcType: CalculatorType = params.getPropValue("calcType");
         switch (calcType) {
             case CalculatorType.ConduiteDistributrice:
                 prms = new ConduiteDistribParams(
@@ -394,18 +407,13 @@ export class Session {
                 break;
 
             case CalculatorType.LechaptCalmon:
-                prms = new LechaptCalmonParams(
-                    3, // débit
-                    1.2, // diamètre
-                    0.6, /// perte de charge
-                    100, // longueur du toyo
+                prms = new PL_LechaptCalmonParams(
                     1.863, // paramètre L du matériau
                     2, // paramètre M du matériau
                     5.33, // paramètre N du matériau
-                    0, // Ks Perte de charge singulière
                     nullParams
                 );
-                nub = new LechaptCalmon(prms, dbg);
+                nub = new PL_LechaptCalmon(prms, dbg);
                 break;
 
             case CalculatorType.SectionParametree:
@@ -549,16 +557,16 @@ export class Session {
                 break;
 
             case CalculatorType.CloisonAval: {
-                    prms = new CloisonsAvalParams(
-                        0.5, // Q
-                        102, // Z1
-                        101.5, // Z2
-                        0, // ZRAM
-                        nullParams
-                    );
-                    nub = new CloisonAval(prms, dbg);
-                    break;
-                }
+                prms = new CloisonsAvalParams(
+                    0.5, // Q
+                    102, // Z1
+                    101.5, // Z2
+                    0, // ZRAM
+                    nullParams
+                );
+                nub = new CloisonAval(prms, dbg);
+                break;
+            }
 
             case CalculatorType.MacroRugoCompound:
                 nub = new MacrorugoCompound(
@@ -800,6 +808,26 @@ export class Session {
                 nub = new PbCloison(undefined, undefined, undefined, nullParams);
                 break;
 
+            case CalculatorType.PressureLoss:
+                const plParams = new PressureLossParams(
+                    3, // débit
+                    1.2, // diamètre
+                    0.6, /// perte de charge
+                    100, // longueur du toyo
+                    0, // Kloc Perte de charge singulière
+                    nullParams
+                );
+                const lossType: PressureLossType = params.getPropValue("pressureLossType") ?? PressureLossType.LechaptCalmon;
+                nub = new PressureLoss(plParams, undefined, dbg);
+                nub.setPropValue("pressureLossType", lossType);
+                break;
+
+            case CalculatorType.PressureLossLaw:
+                const lt = params.getPropValue("pressureLossType") ?? PressureLossType.LechaptCalmon;
+                nub = this.createPressureLossLaw(lt, dbg, nullParams);
+                nub.setPropValue("pressureLossType", lt);
+                break;
+
             default:
                 throw new Error(
                     `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge`
@@ -808,12 +836,12 @@ export class Session {
 
         // propagate properties
         try {
-            nub.properties = params;
+            nub.setProperties(params);
         } catch (e) {
             // loading Solveur properties when unserialising a session might fail because target
             // Nub / param do not exist yet; silent fail in this case, and Solveur.fixTargets()
             // might fix it later
-            if (! (nub instanceof Solveur)) {
+            if (!(nub instanceof Solveur)) {
                 throw e;
             }
         }
@@ -832,7 +860,7 @@ export class Session {
                 alreadyUsed = true;
                 break;
             }
-            if (! alreadyUsed) {
+            if (!alreadyUsed) {
                 alreadyUsed = this.uidAlreadyUsed(uid, n.getChildren());
             }
         }
@@ -928,6 +956,18 @@ export class Session {
         return res;
     }
 
+    /**
+     * @returns true if parameter is a link target in any session nub
+     */
+    public isParameterLinkTarget(p: ParamDefinition): boolean {
+        for (const n of this._nubs) {
+            if (n.dependsOnParameter(p)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Crée un Nub de type Section
      * @param nt SectionType
@@ -991,6 +1031,29 @@ export class Session {
         }
     }
 
+    /**
+     * Crée un Nub de type loi de perte de charge
+     */
+    public createPressureLossLaw(plt: PressureLossType, dbg: boolean = false, nullParams: boolean = false): PressureLossLaw {
+        switch (plt) {
+            case PressureLossType.LechaptCalmon:
+                const prms = new PL_LechaptCalmonParams(
+                    1.863, // paramètre L du matériau
+                    2, // paramètre M du matériau
+                    5.33, // paramètre N du matériau
+                    nullParams
+                );
+                return new PL_LechaptCalmon(prms, dbg);
+
+            case PressureLossType.Strickler:
+                const sp = new PL_StricklerParams(1, nullParams);
+                return new PL_Strickler(sp);
+
+            default:
+                throw new Error(`type de perte de charge ${PressureLossType[plt]} non pris en charge`);
+        }
+    }
+
     /**
      * Creates a Nub from an object representation and adds it to the current session; returns
      * a pointer to the Nub and its JSON metadata
@@ -1006,8 +1069,10 @@ export class Session {
             meta: undefined,
             hasErrors: false
         };
+        // get upward compatible calculator
+        obj = this.compatibleCalculator(obj);
         // decode properties
-        const props = Session.invertEnumKeysAndValuesInProperties(obj.props, true);
+        const props = Props.invertEnumKeysAndValuesInProperties(obj.props, true);
         // create the Nub
         let newNub;
         if (register) {
diff --git a/src/session_settings.ts b/src/session_settings.ts
index b4a2a0f08cdd0f10213fb4fb014e696395623565..8925a51d4632c8ec3bf6bb05cce9ebb03f95938f 100644
--- a/src/session_settings.ts
+++ b/src/session_settings.ts
@@ -1,8 +1,74 @@
-export class SessionSettings {
+import { IObservable, Observable, Observer } from "./internal_modules";
+import { Props } from "./internal_modules";
+
+export class SessionSettings implements IObservable {
+    private static _instance: SessionSettings;
 
     /** session-wide calculation precision, used by all Nubs */
-    public static precision = 1e-7;
+    public static readonly defaultComputePrecision = 1e-7;
 
     /** session-wide maximum number of iterations, used by all Nubs in Newton() and Dichotomie() */
-    public static maxIterations = 100;
+    public static readonly defaultMaxIterations = 100;
+
+    // properties
+    private _props: Props;
+
+    // property names
+    private static readonly ComputePrecisionProp = "computePrecision";
+
+    private static readonly MaxIterationsProp = "maxIterations";
+
+    /**
+     * IObservable delegation.
+     * Do not use Props IObservable interface to make notifications specific to SessionSettings
+     * and to not disturb observers.
+     */
+    private _observable: Observable;
+
+    private constructor() {
+        this._props = new Props();
+        this._observable = new Observable();
+        this._props.setPropValue(SessionSettings.ComputePrecisionProp, SessionSettings.defaultComputePrecision);
+        this._props.setPropValue(SessionSettings.MaxIterationsProp, SessionSettings.defaultMaxIterations);
+    }
+
+    public static get instance(): SessionSettings {
+        if (SessionSettings._instance === undefined) {
+            SessionSettings._instance = new SessionSettings();
+        }
+        return SessionSettings._instance;
+    }
+
+    public static get precision(): number {
+        return SessionSettings.instance._props.getPropValue(SessionSettings.ComputePrecisionProp);
+    }
+
+    public static set precision(p: number) {
+        SessionSettings.instance._props.setPropValue(SessionSettings.ComputePrecisionProp, p, this._instance);
+        SessionSettings.instance.notifyObservers(SessionSettings.ComputePrecisionProp);
+    }
+
+    public static get maxIterations(): number {
+        return SessionSettings.instance._props.getPropValue(SessionSettings.MaxIterationsProp);
+    }
+
+    public static set maxIterations(n: number) {
+        SessionSettings.instance._props.setPropValue(SessionSettings.MaxIterationsProp, n, this._instance);
+        SessionSettings.instance.notifyObservers(SessionSettings.MaxIterationsProp);
+    }
+
+    // IObserver interface
+
+    addObserver(o: Observer): void {
+        this._observable.addObserver(o);
+    }
+
+    removeObserver(o: Observer): void {
+        this._observable.removeObserver(o);
+    }
+
+    notifyObservers(data: any, sender?: any): void {
+        // use SessionSettings._instance and not this to be able to use instanceof operator
+        this._observable.notifyObservers(data, SessionSettings._instance);
+    }
 }
diff --git a/src/solveur/solveur.ts b/src/solveur/solveur.ts
index 8fd138a899b8f5f151163cb102182958a0f4f838..78d5727b581226225dc9efcc10c43d18039bee03 100644
--- a/src/solveur/solveur.ts
+++ b/src/solveur/solveur.ts
@@ -1,13 +1,13 @@
-import { CalculatorType } from "../compute-node";
-import { Nub } from "../nub";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
-import { ParamValueMode } from "../param/param-value-mode";
-import { Session } from "../session";
-import { Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { ResultElement } from "../util/resultelement";
-import { SolveurParams } from "./solveur_params";
-import { Message, MessageCode } from "../util/message";
+import { CalculatorType } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability, ParamDefinition } from "../internal_modules";
+import { ParamValueMode } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { SolveurParams } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
 
 export class Solveur extends Nub implements Observer {
 
@@ -36,9 +36,9 @@ export class Solveur extends Nub implements Observer {
         return searchableParams;
     }
 
-    constructor(prms: SolveurParams, dbg: boolean = false)  {
+    constructor(prms: SolveurParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Solveur;
+        this.setCalculatorType(CalculatorType.Solveur);
         this._props.addObserver(this);
         this.prms.addObserver(this);
         // UID of Session Nub to calculate, the result of the which must be this.prms.Ytarget.singleValue
@@ -77,7 +77,7 @@ export class Solveur extends Nub implements Observer {
         if (n !== undefined) {
             uid = n.uid;
         }
-        this.properties.setPropValue("nubToCalculate", uid);
+        this.setPropValue("nubToCalculate", uid);
     }
 
     public get targettedResult(): string {
@@ -126,7 +126,7 @@ export class Solveur extends Nub implements Observer {
         if (p !== undefined) {
             sp = p.nubUid + "/" + p.symbol;
         }
-        this.properties.setPropValue("searchedParameter", sp);
+        this.setPropValue("searchedParameter", sp);
     }
 
     /**
@@ -136,7 +136,7 @@ export class Solveur extends Nub implements Observer {
         const r: Result = new Result(new ResultElement());
         if (this.nubToCalculate.resultHasMultipleValues()) {
             r.resultElement.addMessage(new Message(MessageCode.ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED));
-            this.currentResult = r;
+            this.currentResultElement = r;
             return this.result;
         }
         return super.Calc(sVarCalc, rInit);
@@ -193,7 +193,7 @@ export class Solveur extends Nub implements Observer {
                 const t = this.targettedResult;
                 const p = this.searchedParameter;
                 if (n !== undefined && p !== undefined) {
-                    if (n !== p.parentNub && ! n.dependsOnNubResult(p.parentNub)) {
+                    if (n !== p.parentNub && !n.dependsOnNubResult(p.parentNub)) {
                         throw new Error(
                             "Solveur.update(): Nub to calculate is not linked to result of searchedParameter parent Nub"
                         );
@@ -204,10 +204,6 @@ export class Solveur extends Nub implements Observer {
                         if (n.resultHasMultipleValues()) {
                             throw new Error("Solveur.update(): Nub to calculate must not have multiple values");
                         }
-                        // update Ytarget
-                        if (this.prms.Ytarget.singleValue === undefined) {
-                            this.prms.Ytarget.singleValue = n.calculatedParam.singleValue;
-                        }
                         // reset targetted result
                         this.targettedResult = undefined;
                     }
@@ -225,7 +221,7 @@ export class Solveur extends Nub implements Observer {
                     if (t !== undefined && t !== "") {
                         if (
                             n.resultsFamilies
-                            && ! Object.keys(n.resultsFamilies).includes(t)
+                            && !Object.keys(n.resultsFamilies).includes(t)
                         ) {
                             throw new Error("Solveur.update(): targetted result T is not a declared extra result of Nub to calculate");
                         }
@@ -255,8 +251,8 @@ export class Solveur extends Nub implements Observer {
         };
         try {
             // do not use setters, to allow setting directly the string UIDs
-            this.properties.setPropValue("nubToCalculate", obj.props.nubToCalculate);
-            this.properties.setPropValue("searchedParameter", obj.props.searchedParameter);
+            this.setPropValue("nubToCalculate", obj.props.nubToCalculate);
+            this.setPropValue("searchedParameter", obj.props.searchedParameter);
         } catch (e) {
             ret.hasErrors = true;
         }
diff --git a/src/solveur/solveur_params.ts b/src/solveur/solveur_params.ts
index 2d2831361e1fbdf7b44890c15d4a88286ed2b0b3..f996de7c03511d217d16ec76a4579684c922fc79 100644
--- a/src/solveur/solveur_params.ts
+++ b/src/solveur/solveur_params.ts
@@ -1,7 +1,7 @@
-import { ParamDefinition } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
-import { IObservable, Observable, Observer } from "../util/observer";
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
+import { IObservable, Observable, Observer } from "../internal_modules";
 
 /**
  * Y = f(X)
diff --git a/src/structure/dever.ts b/src/structure/dever.ts
index 44efef9c86957cc1ae48d18aca6480b52718b040..f627c9ff78d84067716a6252b2e25b08101cc59a 100644
--- a/src/structure/dever.ts
+++ b/src/structure/dever.ts
@@ -1,20 +1,28 @@
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability } from "../param/param-definition";
-import { SessionSettings } from "../session_settings";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { DeverParams } from "./dever_params";
-import { ParallelStructure } from "./parallel_structure";
-import { loiAdmissiblesDever, LoiDebit } from "./structure_props";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { SessionSettings } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { DeverParams } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { loiAdmissiblesDever, LoiDebit } from "../internal_modules";
 
 export class Dever extends ParallelStructure {
 
+    /**
+     * { symbol => string } map that defines units for extra results
+     */
+    private static _resultsUnits = {
+        Ec: "m",
+        V: "m/s"
+    };
+
     private bQcorrected: boolean;
     private bZcorrected: boolean;
 
     constructor(prms: DeverParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Dever;
+        this.setCalculatorType(CalculatorType.Dever);
     }
 
     /**
@@ -37,14 +45,14 @@ export class Dever extends ParallelStructure {
      */
     public Calc(sVarCalc: string | any, rInit?: number): Result {
         if (["Q", "Z1"].includes(sVarCalc)) {
-        this.bQcorrected = true;
+            this.bQcorrected = true;
         } else {
             this.bQcorrected = false;
         }
         this.bZcorrected = true;
         this.prms.Q.v = (this.prms.Q.V !== undefined && !isNaN(this.prms.Q.V)) ? this.prms.Q.V : 0;
         const r = super.Calc(sVarCalc, rInit);
-        if(!r.ok) {
+        if (!r.ok) {
             return r;
         }
         const QT = this.prms.Q.V;
@@ -86,8 +94,8 @@ export class Dever extends ParallelStructure {
                 r = super.CalcQ(iExcept);
                 i--;
             } while (i && Math.abs(r.vCalc - this.prms.Q.v) > SessionSettings.precision);
-            if(i===0) {
-                r = new Result(new Message(MessageCode.ERROR_DICHO_CONVERGE, {lastApproximation: r.vCalc}));
+            if (i === 0) {
+                r = new Result(new Message(MessageCode.ERROR_DICHO_CONVERGE, { lastApproximation: r.vCalc }));
             }
             return r;
         } else {
@@ -121,11 +129,8 @@ export class Dever extends ParallelStructure {
         this.prms.Z2.visible = false;
     }
 
-    protected setResultsUnits() {
-        this._resultsUnits = {
-            Ec: "m",
-            V: "m/s"
-        }
+    public static override resultsUnits() {
+        return Dever._resultsUnits;
     }
 
     protected exposeResults() {
diff --git a/src/structure/dever_params.ts b/src/structure/dever_params.ts
index 7a186626c5ee63c0aa321760d657982ce0af69f4..25fa465e83b214ab4daee31d553cfac20c2d5ec7 100644
--- a/src/structure/dever_params.ts
+++ b/src/structure/dever_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParallelStructureParams } from "./parallel_structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParallelStructureParams } from "../internal_modules";
 
 /**
  * Common parameters of hydraulic structure equations
diff --git a/src/structure/factory_structure.ts b/src/structure/factory_structure.ts
index f3bb70f810dbc631d318ced19f52458e8a799f86..9c9d641d139108ce851232f227206c9078839aa6 100755
--- a/src/structure/factory_structure.ts
+++ b/src/structure/factory_structure.ts
@@ -1,38 +1,37 @@
-import { ParallelStructure } from "./parallel_structure";
+import { ParallelStructure } from "../internal_modules";
 
 // Classes générales sur les structures
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure } from "./structure";
-import { LoiDebit, StructureProperties } from "./structure_props";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure } from "../internal_modules";
+import { LoiDebit, StructureProperties } from "../internal_modules";
 
 // Equations de débit
-import { StructureGateCem88d } from "./structure_gate_cem88d";
-import { StructureGateCem88v } from "./structure_gate_cem88v";
-import { StructureGateCunge80 } from "./structure_gate_cunge80";
-import { StructureKivi } from "./structure_kivi";
-import { StructureKiviParams } from "./structure_kivi_params";
-import { StructureOrificeFree } from "./structure_orifice_free";
-import { StructureOrificeFreeParams } from "./structure_orifice_free_params";
-import { StructureOrificeSubmerged } from "./structure_orifice_submerged";
-import { StructureOrificeSubmergedParams } from "./structure_orifice_submerged_params";
-import { StructureRectangularOrificeFree } from "./structure_rectangular_orifice_free";
-import { StructureRectangularOrificeSubmerged } from "./structure_rectangular_orifice_submerged";
-import { StructureTriangularTruncWeirFree } from "./structure_triangular_trunc_weir";
-import { TriangularTruncStructureParams } from "./structure_triangular_trunc_weir_params";
-import { StructureTriangularWeir } from "./structure_triangular_weir";
-import { StructureTriangularWeirBroad } from "./structure_triangular_weir_broad";
-import { TriangularStructureParams } from "./structure_triangular_weir_params";
-import { StructureVanLevLarinier } from "./structure_vanlev_larinier";
-import { StructureVanLevParams } from "./structure_vanlev_params";
-import { StructureVanLevVillemonte } from "./structure_vanlev_villemonte";
-import { StructureWeirCem88d } from "./structure_weir_cem88d";
-import { StructureWeirCem88v } from "./structure_weir_cem88v";
-import { StructureWeirCunge80 } from "./structure_weir_cunge80";
-import { StructureWeirFree } from "./structure_weir_free";
-import { StructureWeirSubmerged } from "./structure_weir_submerged";
-import { StructureWeirSubmergedLarinier } from "./structure_weir_submerged_larinier";
-import { StructureWeirVillemonte } from "./structure_weir_villemonte";
-import { SessionSettings } from "../session_settings";
+import { StructureGateCem88d } from "../internal_modules";
+import { StructureGateCem88v } from "../internal_modules";
+import { StructureGateCunge80 } from "../internal_modules";
+import { StructureKivi } from "../internal_modules";
+import { StructureKiviParams } from "../internal_modules";
+import { StructureOrificeFree } from "../internal_modules";
+import { StructureOrificeFreeParams } from "../internal_modules";
+import { StructureOrificeSubmerged } from "../internal_modules";
+import { StructureOrificeSubmergedParams } from "../internal_modules";
+import { StructureRectangularOrificeFree } from "../internal_modules";
+import { StructureRectangularOrificeSubmerged } from "../internal_modules";
+import { StructureTriangularTruncWeirFree } from "../internal_modules";
+import { TriangularTruncStructureParams } from "../internal_modules";
+import { StructureTriangularWeir } from "../internal_modules";
+import { StructureTriangularWeirBroad } from "../internal_modules";
+import { TriangularStructureParams } from "../internal_modules";
+import { StructureVanLevLarinier } from "../internal_modules";
+import { StructureVanLevParams } from "../internal_modules";
+import { StructureVanLevVillemonte } from "../internal_modules";
+import { StructureWeirCem88d } from "../internal_modules";
+import { StructureWeirCem88v } from "../internal_modules";
+import { StructureWeirCunge80 } from "../internal_modules";
+import { StructureWeirFree } from "../internal_modules";
+import { StructureWeirSubmerged } from "../internal_modules";
+import { StructureWeirSubmergedLarinier } from "../internal_modules";
+import { StructureWeirVillemonte } from "../internal_modules";
 
 export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructure,
     dbg: boolean = false, nullParams: boolean = false
@@ -110,8 +109,8 @@ export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructur
             if (!nullParams) {
                 rectStructPrms.L.singleValue = 0.2;
                 rectStructPrms.CdWSL.singleValue = 0.75;
-                rectStructPrms.ZDV.singleValue = 101;
-                rectStructPrms.h1.singleValue = 1;
+                rectStructPrms.ZDV.singleValue = 100;
+                rectStructPrms.h1.singleValue = 2;
             }
             ret = new StructureWeirSubmergedLarinier(rectStructPrms, dbg);
             break;
@@ -151,7 +150,7 @@ export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructur
                 Infinity, // W = Infinity par défaut pour un seuil
                 nullParams
             );
-            if(loiDebit === LoiDebit.TriangularWeirFree) {
+            if (loiDebit === LoiDebit.TriangularWeirFree) {
                 ret = new StructureTriangularWeir(structTriangPrms, dbg);
             } else {
                 ret = new StructureTriangularWeirBroad(structTriangPrms, dbg);
@@ -223,9 +222,9 @@ export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructur
 
     // set reference to parent
     if (parentNub) {
-        ret.parent = parentNub;
+        ret.setParent(parentNub);
         // Set Structure Type
-        ret.properties.setPropValue("structureType", StructureProperties.findCompatibleStructure(loiDebit, parentNub));
+        ret.setPropValue("structureType", StructureProperties.findCompatibleStructure(loiDebit, parentNub));
     }
 
     return ret;
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index 057e012d661b00079e5e3610f41022f76676a1df..94346fb5074a6955715c91279416078a8907a0b9 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -1,13 +1,13 @@
-import { CalculatorType } from "../compute-node";
-import { Session } from "../index";
-import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
-import { ParamsEquation } from "../param/params-equation";
-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";
+import { CalculatorType } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { ParallelStructureParams } from "../internal_modules";
+import { Structure } from "../internal_modules";
+import { loiAdmissiblesOuvrages, LoiDebit } from "../internal_modules";
+import { MessageCode, Message } from "../internal_modules";
 
 /**
  * Calcul de une ou plusieurs structures hydrauliques en parallèles
@@ -18,7 +18,7 @@ export class ParallelStructure extends Nub {
 
     constructor(prms: ParamsEquation, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.ParallelStructure;
+        this.setCalculatorType(CalculatorType.ParallelStructure);
     }
 
     /** children casting */
@@ -29,10 +29,17 @@ export class ParallelStructure extends Nub {
     public set structures(structures: Structure[]) {
         this._children = structures;
         this._children.forEach((s) => {
-            s.parent = this;
+            s.setParent(this);
         });
     }
 
+    /**
+     * true to inhibit emission of ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN error in Structure calculations and
+     * WARNING_SLOT_SUBMERGENCE_NOT_BETWEEN_07_AND_09 warning in StructureWeirSubmergedLarinier.
+     * Used during predams calculations.
+     */
+    public inhibitSubmergenceError: boolean = false;
+
     /**
      * paramètres castés au bon type
      */
@@ -104,6 +111,9 @@ export class ParallelStructure extends Nub {
         for (let i = 0; i < this._children.length; i++) {
             if (i !== iExcept) {
                 const res: Result = this._children[i].Calc("Q");
+                if (!res.ok) {
+                    return res;
+                }
                 qTot += res.vCalc;
                 // merge logs
                 calcRes.resultElement.log.addLog(res.log);
@@ -123,14 +133,14 @@ export class ParallelStructure extends Nub {
      */
     public Calc(sVarCalc: string | any, rInit?: number): Result {
         // if Calc() is called outside of CalcSerie(), _result might not be initialized
-        if (! this.result) {
+        if (!this.result) {
             this.initNewResultElement();
         }
         switch (sVarCalc) {
             case "Z1":
             case "Z2":
             case "Q":
-                this.currentResult = super.Calc(sVarCalc, rInit);
+                this.currentResultElement = super.Calc(sVarCalc, rInit);
                 if (this.result.ok) {
                     this.getParameter(sVarCalc).v = this.result.resultElement.vCalc;
                 }
diff --git a/src/structure/parallel_structure_params.ts b/src/structure/parallel_structure_params.ts
index ec401c849506c3d0e725e3575e29685a1db07b09..6492a2e6344da4cd75fac8fddb811031103b4f03 100644
--- a/src/structure/parallel_structure_params.ts
+++ b/src/structure/parallel_structure_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Common parameters of hydraulic structure equations
diff --git a/src/structure/rectangular_structure.ts b/src/structure/rectangular_structure.ts
index 075e956ca703738865dcee6eae8fbd1a86e7c361..ec77126d3b3b49b65fb4ded443ace042fdff4603 100644
--- a/src/structure/rectangular_structure.ts
+++ b/src/structure/rectangular_structure.ts
@@ -1,6 +1,6 @@
-import { ParamCalculability } from "../param/param-definition";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure } from "./structure";
+import { ParamCalculability } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure } from "../internal_modules";
 
 /**
  * Classe mère pour toutes les structures ayant une base rectangulaire (vannes, seuils)
diff --git a/src/structure/rectangular_structure_params.ts b/src/structure/rectangular_structure_params.ts
index 8a5b005ccac0181288091d0848e50ea09a6f2450..ab68adfd042153a314b419c6604a2c950cd51f50 100644
--- a/src/structure/rectangular_structure_params.ts
+++ b/src/structure/rectangular_structure_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "./structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 /**
  * Parameters for rectangular structures (common for all rectangular structure equations)
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index d8d4dadc24419cdf4d63b6f8d0299f9aef9559ca..7cb91b8cf4c57d00f55a34b7ae191ba5faaa83bc 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -1,13 +1,14 @@
-import { ChildNub } from "../child_nub";
-import { CalculatorType } from "../compute-node";
-import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
-import { Props } from "../props";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { StructureParams } from "./structure_params";
-import { LoiDebit, StructureProperties } from "./structure_props";
-import { ParallelStructure } from "./parallel_structure";
-import { round } from "../base";
+import { ChildNub, Dichotomie } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../internal_modules";
+import { Props } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
+import { LoiDebit, StructureProperties } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { round } from "../internal_modules";
+import { Nub } from "../internal_modules";
 
 /**
  * Flow mode: weir or orifice flow
@@ -76,17 +77,54 @@ export abstract class Structure extends ChildNub {
         return 100;
     }
 
+    /**
+     * méthode générique de vérification que l'ennoiement est supérieur à une valeur donnée
+     * @param min valeur minimum de l'ennoiement
+     */
+    protected checkSubmergenceMin(res: Result, min: number) {
+        // on fait le test si on est pas dans un calcul par dichotomie
+        if (!Dichotomie.inDicho && !(this.parent as ParallelStructure)?.inhibitSubmergenceError) {
+            const h2h1ratio = this.prms.h2.v / this.prms.h1.v;
+            if (h2h1ratio < min) {
+                res.resultElement.addMessage(new Message(
+                    // this._result.globalLog.add(new Message(
+                    MessageCode.ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN,
+                    {
+                        submergencePerc: this.computeSubmergencePercentage().toString(),
+                        min: min * 100
+                    }
+                ));
+            }
+        }
+    }
+
+    /**
+     * fonction appelée dans Calc() pour vérifier l'ennoiement (cf. classes dérivées)
+     */
+    public checkSubmergence(res: Result) {
+    }
+
+
+    // si une erreur d'ennoiement est survenue, on annule les résultats
+    public static filterResultsOnSubmergenceError(res: Result): boolean {
+        if (res.resultElement.hasMessage(MessageCode.ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN)) {
+            res.resultElement.removeValues();
+            return true;
+        }
+        return false;
+    }
+
     /** Constante utile : Racine de 2g */
     protected static readonly R2G: number = Math.sqrt(2 * 9.81);
 
     /** Peut-on calculer ZDV ? */
     protected _isZDVcalculable: boolean;
 
-    protected _loiDebit: LoiDebit;
+    private _loiDebit: LoiDebit;
 
     constructor(prms: StructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Structure;
+        this.setCalculatorType(CalculatorType.Structure);
         this._isZDVcalculable = true;
         // Q is always the only calculated variable; setting another parameter
         // of a Structure to CALC mode makes it the calculated variable of the
@@ -95,22 +133,13 @@ export abstract class Structure extends ChildNub {
         this._intlType = "Ouvrage";
     }
 
-    /** Returns Props object (observable set of key-values) associated to this Nub */
-    public get properties(): Props {
-        // 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;
-    }
-
-    // setter is not inherited from Nub if getter is redefined :/
-    public set properties(props: Props) {
-        super.setProperties(props);
+    /**
+     * true si la structure est une vanne levante
+     * @see StructureVanLevLarinier
+     * @see StructureVanLevVillemonte
+     */
+    protected get isVanneLevante(): boolean {
+        return false;
     }
 
     public get isZDVcalculable(): boolean {
@@ -136,6 +165,27 @@ export abstract class Structure extends ChildNub {
         return this._loiDebit;
     }
 
+    protected setLoiDebit(ld: LoiDebit) {
+        if (ld === undefined) {
+            throw new Error("invalid null LoiDebit");
+        }
+        // completes props with structureType and loiDebit
+        this._loiDebit = ld;
+        this._props.setPropValue("loiDebit", this._loiDebit);
+        this.updateStructureType();
+    }
+
+    public setParent(p: Nub): void {
+        super.setParent(p);
+        this.updateStructureType();
+    }
+
+    private updateStructureType() {
+        if (this._loiDebit !== undefined && this.parent !== undefined) {
+            this._props.setPropValue("structureType", StructureProperties.findCompatibleStructure(this._loiDebit, this.parent as ParallelStructure));
+        }
+    }
+
     /**
      * Returns the nth visible parameter (used in nghyd/PabTable)
      */
@@ -183,26 +233,29 @@ export abstract class Structure extends ChildNub {
         };
         if (sVarCalc === "Q") {
             if (this.prms.h1.v <= 1E-20 || Math.abs(this.prms.h1.v - this.prms.h2.v) < 1E-20 || this.W <= 1E-20) {
-                this.currentResult = new Result(0, this, flagsNull);
+                this.currentResultElement = new Result(0, this, flagsNull);
                 return this._result;
             }
         } else if (this.prms.Q.v === 0) {
             // Débit nul <=> tirant d'eau amont = tirant d'eau aval ou tout autre paramètre nul
             switch (sVarCalc) {
                 case "Z1":
-                    this.currentResult = new Result(this.prms.Z2.v, this, flagsNull);
+                    // max(Z2,ZDV) dans le cas dénoyé et noyé
+                    // on met Z1 à ZDV pour faciliter les calculs sur les prébarrages
+                    this.currentResultElement = new Result(Math.max(this.prms.Z2.v, this.prms.ZDV.v), this, flagsNull);
                     return this._result;
                 case "Z2":
-                    this.currentResult = new Result(this.prms.Z1.v, this, flagsNull);
+                    // max(Z1,ZDV) dans le cas dénoyé et noyé
+                    this.currentResultElement = new Result(Math.max(this.prms.Z1.v, this.prms.ZDV.v), this, flagsNull);
                     return this._result;
                 default:
                     // Est-ce toujours vrai ? Nécessitera peut-être d'étendre la méthode
-                this.currentResult = new Result(0, this, flagsNull);
-                return this._result;
+                    this.currentResultElement = new Result(0, this, flagsNull);
+                    return this._result;
             }
         } else if (this.W === 0 && sVarCalc === "Z1") {
             // Si la vanne est fermée la cote amont est infinie
-            this.currentResult = new Result(Infinity, this, flagsNull);
+            this.currentResultElement = new Result(Infinity, this, flagsNull);
             return this._result;
         }
 
@@ -228,7 +281,7 @@ export abstract class Structure extends ChildNub {
                     res = new Result(new Message(MessageCode.ERROR_STRUCTURE_Q_TROP_ELEVE), this, flagsNull);
                 }
                 res.vCalc = rPrm;
-                this.currentResult = res;
+                this.currentResultElement = res;
 
                 // "Les cotes et le débit ne sont pas cohérents => fermeture de l'ouvrage
                 return res;
@@ -240,12 +293,15 @@ export abstract class Structure extends ChildNub {
             [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
             const res: Result = super.Calc(sVarCalc, rInit);
             [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
-            this.currentResult = res;
+            this.currentResultElement = res;
             return res;
         }
 
         // Calcul normal hors débit nul
-        return super.Calc(sVarCalc, rInit);
+        const res = super.Calc(sVarCalc, rInit);
+        this.checkSubmergence(res);
+        Structure.filterResultsOnSubmergenceError(res);
+        return res;
     }
 
     /**
diff --git a/src/structure/structure_gate_cem88d.ts b/src/structure/structure_gate_cem88d.ts
index 0cbd201999a83588b9b5a2bf80da6a53a9593dca..071d25e345a4b4b1de2f68130e14cb8dda066a88 100644
--- a/src/structure/structure_gate_cem88d.ts
+++ b/src/structure/structure_gate_cem88d.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation CEM88D : déversoir / orifice (pelle importante) Cemagref 1988
@@ -12,7 +12,7 @@ export class StructureGateCem88d extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.GateCem88d;
+        this.setLoiDebit(LoiDebit.GateCem88d);
         this._isZDVcalculable = false;
         this.prms.W.visible = true;
         this.prms.CdWR.visible = true;
diff --git a/src/structure/structure_gate_cem88v.ts b/src/structure/structure_gate_cem88v.ts
index eea96f17f0aabde2e3618f90131deb17d7f40c17..9af9b0ab57a1ced30ce401bebe8e1fcf2ceb2742 100644
--- a/src/structure/structure_gate_cem88v.ts
+++ b/src/structure/structure_gate_cem88v.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation CEM88V : déversoir / vanne de fond (pelle faible) Cemagref 1988
@@ -12,7 +12,7 @@ export class StructureGateCem88v extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.GateCem88v;
+        this.setLoiDebit(LoiDebit.GateCem88v);
         this.prms.W.visible = true;
         this.prms.CdGR.visible = true;
     }
@@ -78,7 +78,7 @@ export class StructureGateCem88v extends RectangularStructure {
     /**
      * Give the flow regime for Equation CEM88V : free, partially submerged or submerged flow
      */
-    protected getFlowRegime(): StructureFlowRegime  {
+    protected getFlowRegime(): StructureFlowRegime {
         const mode: StructureFlowMode = this.getFlowMode();
         // Weir have only two flow regimes: free and submerged flow
         let alfa: number;
@@ -87,7 +87,7 @@ export class StructureGateCem88v extends RectangularStructure {
                 alfa = 0.75;
                 break;
             case StructureFlowMode.ORIFICE:
-                alfa =  this.getAlfa(this.prms.h2.v);
+                alfa = this.getAlfa(this.prms.h2.v);
                 break;
         }
         if (this.prms.h2.v <= alfa * this.prms.h1.v) {
@@ -102,7 +102,7 @@ export class StructureGateCem88v extends RectangularStructure {
                 && this.prms.h2.v <= alfa * this.prms.h1.v + (1 - alfa) * this.W
             ) {
                 this.debug(
-                    "StructureWeirCem88v.getFlowRegime(h1="  + this.prms.h1.v
+                    "StructureWeirCem88v.getFlowRegime(h1=" + this.prms.h1.v
                     + ",h2=" + this.prms.h2.v + ",W=" + this.W + ")=PARTIAL");
                 return StructureFlowRegime.PARTIAL;
             } else {
diff --git a/src/structure/structure_gate_cunge80.ts b/src/structure/structure_gate_cunge80.ts
index 698bd507f1bc45cad1c62a65cc8713b24287ea0a..da72f2612780475bab55b58626da71cf552ac89a 100644
--- a/src/structure/structure_gate_cunge80.ts
+++ b/src/structure/structure_gate_cunge80.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation Cunge80
@@ -16,7 +16,7 @@ export class StructureGateCunge80 extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.GateCunge80;
+        this.setLoiDebit(LoiDebit.GateCunge80);
         if (prms.W.v !== Infinity) {
             this._isZDVcalculable = false;
         }
@@ -41,7 +41,7 @@ export class StructureGateCunge80 extends RectangularStructure {
                 } else {
                     // Cd from Henderson, F.M., 1966. Open channel flow. MacMillan, New York.
                     // tslint:disable-next-line:variable-name
-                    const Cd = StructureGateCunge80.Cc / Math.sqrt( 1 + StructureGateCunge80.Cc * this.W / this.prms.h1.v)
+                    const Cd = StructureGateCunge80.Cc / Math.sqrt(1 + StructureGateCunge80.Cc * this.W / this.prms.h1.v)
                     v = this.prms.CdCunge.v * Cd * this.prms.L.v * Structure.R2G
                         * this.W * Math.pow(this.prms.h1.v, 0.5);
                     this.debug("StructureCunge80.Equation ORIFICE FREE Q=" + v);
diff --git a/src/structure/structure_kivi.ts b/src/structure/structure_kivi.ts
index 77c7cb1986161dda7555ee9781194aaede72a589..a3751174eaee24ddecf13bdfd3bce11afdf66d27 100644
--- a/src/structure/structure_kivi.ts
+++ b/src/structure/structure_kivi.ts
@@ -1,16 +1,16 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { StructureKiviParams } from "./structure_kivi_params";
-import { LoiDebit } from "./structure_props";
-import { Villemonte } from "./villemonte";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { StructureKiviParams } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
+import { Villemonte } from "../internal_modules";
 
 export class StructureKivi extends Structure {
 
     constructor(prms: StructureKiviParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.KIVI;
+        this.setLoiDebit(LoiDebit.KIVI);
     }
 
     /**
@@ -53,7 +53,7 @@ export class StructureKivi extends Structure {
 
     }
 
-     protected getFlowRegime(): StructureFlowRegime {
+    protected getFlowRegime(): StructureFlowRegime {
         if (this.prms.h2.v > 0) {
             return StructureFlowRegime.SUBMERGED;
         } else {
diff --git a/src/structure/structure_kivi_params.ts b/src/structure/structure_kivi_params.ts
index 4ca8791cf0e08b63f4cd910533a3ec36eff0e07c..8174efa1cb94ffd1154a1c020c37c7228fdd63a9 100644
--- a/src/structure/structure_kivi_params.ts
+++ b/src/structure/structure_kivi_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "./structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 /**
  * Paramètres pour une équation de seuil rectangulaire Kindsvater-Carter & Villemonte (KIVI)
diff --git a/src/structure/structure_orifice_free.ts b/src/structure/structure_orifice_free.ts
index afa7181113d867f15d42638ca95306a29d357f3b..b3e00ae74ec11c9f8ee8e834c3b3af322c62b379 100644
--- a/src/structure/structure_orifice_free.ts
+++ b/src/structure/structure_orifice_free.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "../structure/structure";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { StructureOrificeFreeParams } from "./structure_orifice_free_params";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { StructureOrificeFreeParams } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation classique orifice dénoyé
@@ -12,7 +12,7 @@ export class StructureOrificeFree extends Structure {
 
     constructor(prms: StructureOrificeFreeParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.OrificeFree;
+        this.setLoiDebit(LoiDebit.OrificeFree);
         this._isZDVcalculable = false;
     }
 
@@ -24,8 +24,8 @@ export class StructureOrificeFree extends Structure {
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
-        if (this._loiDebit === LoiDebit.OrificeFree && this.prms.Z2.v > this.prms.Zco.v) {
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
+        if (this.loiDebit === LoiDebit.OrificeFree && this.prms.Z2.v > this.prms.Zco.v) {
             this._result.resultElement.addMessage(new Message(
                 MessageCode.WARNING_ORIFICE_FREE_DOWNSTREAM_ELEVATION_POSSIBLE_SUBMERSION,
                 {
diff --git a/src/structure/structure_orifice_free_params.ts b/src/structure/structure_orifice_free_params.ts
index 8515b299cacc6b1d91e14291f173ac771ac6901c..a373231b9272505a91075970d647906a4d3e8d71 100644
--- a/src/structure/structure_orifice_free_params.ts
+++ b/src/structure/structure_orifice_free_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "../structure/structure_params";
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 export class StructureOrificeFreeParams extends StructureParams {
 
diff --git a/src/structure/structure_orifice_submerged.ts b/src/structure/structure_orifice_submerged.ts
index df3878b2141c6d0fc8f33de905e5649b8d8b5a64..781f323b1df4ec534842030f343f4fa2351c9686 100644
--- a/src/structure/structure_orifice_submerged.ts
+++ b/src/structure/structure_orifice_submerged.ts
@@ -1,8 +1,8 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "../structure/structure";
-import { Result } from "../util/result";
-import { StructureOrificeSubmergedParams } from "./structure_orifice_submerged_params";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { StructureOrificeSubmergedParams } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation classique orifice noyé
@@ -11,7 +11,7 @@ export class StructureOrificeSubmerged extends Structure {
 
     constructor(prms: StructureOrificeSubmergedParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.OrificeSubmerged;
+        this.setLoiDebit(LoiDebit.OrificeSubmerged);
         this._isZDVcalculable = false;
     }
 
diff --git a/src/structure/structure_orifice_submerged_params.ts b/src/structure/structure_orifice_submerged_params.ts
index 55158a7d1d2e7b2e33ae5d8b86392c01d686df12..5eaf169e658fac5b571dfbebbb7e0e49b05e5f6b 100644
--- a/src/structure/structure_orifice_submerged_params.ts
+++ b/src/structure/structure_orifice_submerged_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "../structure/structure_params";
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 /**
  * Parameters for rectangular structures (common for all rectangular structure equations)
diff --git a/src/structure/structure_params.ts b/src/structure/structure_params.ts
index 8a667f58e5050c2d34149db4c3d01017b4d9d0d5..a9a4828225ab41cd7579c730c945f03c00154eb7 100644
--- a/src/structure/structure_params.ts
+++ b/src/structure/structure_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { ParamsEquation } from "../param/params-equation";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { ParamsEquation } from "../internal_modules";
 
 /**
  * Common parameters of hydraulic structure equations
diff --git a/src/structure/structure_props.ts b/src/structure/structure_props.ts
index a6fc2b01c5c8d94f45bc465f546713cd36bc6d9b..ffe82a92cf80094be7a0cbaded85b9a9a2972adb 100644
--- a/src/structure/structure_props.ts
+++ b/src/structure/structure_props.ts
@@ -1,4 +1,4 @@
-import { ParallelStructure } from "./parallel_structure";
+import { ParallelStructure } from "../internal_modules";
 
 export enum StructureType {
     SeuilRectangulaire,
@@ -140,7 +140,7 @@ export class StructureProperties {
      * 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();
+        const loisAdmissibles = parentNub?.getLoisAdmissibles();
         for (const st in loisAdmissibles) {
             if (loisAdmissibles.hasOwnProperty(st)) {
                 const lds: LoiDebit[] = loisAdmissibles[st];
diff --git a/src/structure/structure_rectangular_orifice_free.ts b/src/structure/structure_rectangular_orifice_free.ts
index 0a91a37d10a93831aa02452366be597e07fce465..3b092e7946b4d73c9431f0b175d276f245c87238 100644
--- a/src/structure/structure_rectangular_orifice_free.ts
+++ b/src/structure/structure_rectangular_orifice_free.ts
@@ -1,10 +1,10 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation classique orifice dénoyé ("Vanne dénoyé")
@@ -13,13 +13,13 @@ export class StructureRectangularOrificeFree extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.RectangularOrificeFree;
+        this.setLoiDebit(LoiDebit.RectangularOrificeFree);
         this.prms.W.visible = true;
         this.prms.CdGR.visible = true;
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         if (this.prms.h2.v > 0) {
             this._result.resultElement.addMessage(new Message(
                 MessageCode.WARNING_DOWNSTREAM_ELEVATION_POSSIBLE_SUBMERSION,
diff --git a/src/structure/structure_rectangular_orifice_submerged.ts b/src/structure/structure_rectangular_orifice_submerged.ts
index 9182c6156ef6365f78dc7a4591f07e7c0134fe00..2c09ae1d80c9afe78b115e638044689077c83d0a 100644
--- a/src/structure/structure_rectangular_orifice_submerged.ts
+++ b/src/structure/structure_rectangular_orifice_submerged.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules"
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation classique orifice noyé ("Vanne noyé")
@@ -12,7 +12,7 @@ export class StructureRectangularOrificeSubmerged extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.RectangularOrificeSubmerged;
+        this.setLoiDebit(LoiDebit.RectangularOrificeSubmerged);
         if (prms.W.v !== Infinity) {
             this._isZDVcalculable = false;
         }
diff --git a/src/structure/structure_triangular_trunc_weir.ts b/src/structure/structure_triangular_trunc_weir.ts
index 7b72b299bbce63fa6a888f996e8e8772f3f92b8b..f65b03dc3d56c5cf4c86e0f316dfb10e06c35c57 100644
--- a/src/structure/structure_triangular_trunc_weir.ts
+++ b/src/structure/structure_triangular_trunc_weir.ts
@@ -1,9 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
-import { TriangularTruncStructureParams } from "./structure_triangular_trunc_weir_params";
-import { Villemonte } from "./villemonte";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
+import { TriangularTruncStructureParams } from "../internal_modules";
+import { Villemonte } from "../internal_modules";
 
 /**
  * Equation classique seuil triangulaire (Villemonte)
@@ -12,7 +12,7 @@ export class StructureTriangularTruncWeirFree extends Structure {
 
     constructor(prms: TriangularTruncStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.TriangularTruncWeirFree;
+        this.setLoiDebit(LoiDebit.TriangularTruncWeirFree);
     }
 
     /**
diff --git a/src/structure/structure_triangular_trunc_weir_params.ts b/src/structure/structure_triangular_trunc_weir_params.ts
index a41c7dea9e14927c23a8447bc66bb1cda11e349a..71325476228db304b7f92d48e0bcc8a378c9eee3 100644
--- a/src/structure/structure_triangular_trunc_weir_params.ts
+++ b/src/structure/structure_triangular_trunc_weir_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "./structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 /**
  * Parameters for rectangular structures (common for all rectangular structure equations)
diff --git a/src/structure/structure_triangular_weir.ts b/src/structure/structure_triangular_weir.ts
index 02798fbb8b2723a0057659359c91399129d77cb2..00b98f8406a2a615789a16989167b5f718f5fd42 100644
--- a/src/structure/structure_triangular_weir.ts
+++ b/src/structure/structure_triangular_weir.ts
@@ -1,10 +1,9 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
-import { TriangularStructureParams } from "./structure_triangular_weir_params";
-import { Villemonte } from "./villemonte";
-import { StructureTriangularWeirFree } from "./structure_triangular_weir_free";
+import { Result } from "../internal_modules";
+import { StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
+import { TriangularStructureParams } from "../internal_modules";
+import { Villemonte } from "../internal_modules";
+import { StructureTriangularWeirFree } from "../internal_modules";
 
 /**
  * Equation classique seuil triangulaire + Ennoiement Villemonte
@@ -13,7 +12,7 @@ export class StructureTriangularWeir extends StructureTriangularWeirFree {
 
     constructor(prms: TriangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.TriangularWeirFree; // First name of the law for backward compatibility
+        this.setLoiDebit(LoiDebit.TriangularWeirFree); // First name of the law for backward compatibility
     }
 
     /**
diff --git a/src/structure/structure_triangular_weir_broad.ts b/src/structure/structure_triangular_weir_broad.ts
index 46581dcffbd8dea739fff5a69a74d42e77ae1265..f34f931c494167c63c67ca542949bfcbdc0cd95e 100644
--- a/src/structure/structure_triangular_weir_broad.ts
+++ b/src/structure/structure_triangular_weir_broad.ts
@@ -1,10 +1,8 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
-import { TriangularStructureParams } from "./structure_triangular_weir_params";
-import { Villemonte } from "./villemonte";
-import { StructureTriangularWeirFree } from "./structure_triangular_weir_free";
+import { Result } from "../internal_modules";
+import { StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
+import { TriangularStructureParams } from "../internal_modules";
+import { StructureTriangularWeirFree } from "../internal_modules";
 
 /**
  * Equation classique seuil triangulaire + Ennoiement Villemonte
@@ -13,7 +11,7 @@ export class StructureTriangularWeirBroad extends StructureTriangularWeirFree {
 
     constructor(prms: TriangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.TriangularWeirBroad; // First name of the law for backward compatibility
+        this.setLoiDebit(LoiDebit.TriangularWeirBroad); // First name of the law for backward compatibility
     }
 
     /**
diff --git a/src/structure/structure_triangular_weir_free.ts b/src/structure/structure_triangular_weir_free.ts
index 15fee12233d36a2f3e82b0cc4190080626d33d4e..57a561863a0a30e254eb544c184e6dbd7036dedb 100644
--- a/src/structure/structure_triangular_weir_free.ts
+++ b/src/structure/structure_triangular_weir_free.ts
@@ -1,7 +1,7 @@
-import { ParamCalculability } from "../param/param-definition";
-import { Result } from "../util/result";
-import { Structure, StructureFlowMode } from "./structure";
-import { TriangularStructureParams } from "./structure_triangular_weir_params";
+import { ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { Structure, StructureFlowMode } from "../internal_modules";
+import { TriangularStructureParams } from "../internal_modules";
 
 /**
  * Equation classique seuil triangulaire + Ennoiement Villemonte
diff --git a/src/structure/structure_triangular_weir_params.ts b/src/structure/structure_triangular_weir_params.ts
index 559f92bca8975fb768e12b27745f09ae85dcf9c1..6da256d5a5d62ee190652ae810bb4fb85f380eca 100644
--- a/src/structure/structure_triangular_weir_params.ts
+++ b/src/structure/structure_triangular_weir_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition } from "../param/param-definition";
-import { ParamDomain, ParamDomainValue } from "../param/param-domain";
-import { StructureParams } from "./structure_params";
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomain, ParamDomainValue } from "../internal_modules";
+import { StructureParams } from "../internal_modules";
 
 /**
  * Parameters for rectangular structures (common for all rectangular structure equations)
diff --git a/src/structure/structure_vanlev_larinier.ts b/src/structure/structure_vanlev_larinier.ts
index 33342264b54ab73f42d874491f825bdeda8ff3b3..0f01035454a1d4242b766b388fc235b3ea36b430 100644
--- a/src/structure/structure_vanlev_larinier.ts
+++ b/src/structure/structure_vanlev_larinier.ts
@@ -1,12 +1,12 @@
-import { LoiDebit } from "./structure_props";
-import { StructureVanLevParams } from "./structure_vanlev_params";
-import { StructureWeirSubmergedLarinier } from "./structure_weir_submerged_larinier";
+import { LoiDebit } from "../internal_modules";
+import { StructureVanLevParams } from "../internal_modules";
+import { StructureWeirSubmergedLarinier } from "../internal_modules";
 
 export class StructureVanLevLarinier extends StructureWeirSubmergedLarinier {
 
     constructor(prms: StructureVanLevParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.VanLevLarinier;
+        this.setLoiDebit(LoiDebit.VanLevLarinier);
     }
 
     /**
@@ -15,4 +15,8 @@ export class StructureVanLevLarinier extends StructureWeirSubmergedLarinier {
     get prms(): StructureVanLevParams {
         return this._prms as StructureVanLevParams;
     }
+
+    protected get isVanneLevante(): boolean {
+        return true;
+    }
 }
diff --git a/src/structure/structure_vanlev_params.ts b/src/structure/structure_vanlev_params.ts
index b9eec0bc29bfd5e7d33b82273bfe95e2070297bb..70afa608f14d8b6446e6453cd68143f263a15a51 100644
--- a/src/structure/structure_vanlev_params.ts
+++ b/src/structure/structure_vanlev_params.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition, ParamFamily } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
-import { RectangularStructureParams } from "./rectangular_structure_params";
+import { ParamDefinition, ParamFamily } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
 
 /**
  * Parameters of an automatic weir with crest elevation regulation
diff --git a/src/structure/structure_vanlev_villemonte.ts b/src/structure/structure_vanlev_villemonte.ts
index 07e186e7faad776c91f1f361a96bf5eeef8ee0f1..9c01ef9f5fe638c286806d1c7203b9438739eefe 100644
--- a/src/structure/structure_vanlev_villemonte.ts
+++ b/src/structure/structure_vanlev_villemonte.ts
@@ -1,12 +1,12 @@
-import { LoiDebit } from "./structure_props";
-import { StructureVanLevParams } from "./structure_vanlev_params";
-import { StructureWeirVillemonte } from "./structure_weir_villemonte";
+import { LoiDebit } from "../internal_modules";
+import { StructureVanLevParams } from "../internal_modules";
+import { StructureWeirVillemonte } from "../internal_modules";
 
 export class StructureVanLevVillemonte extends StructureWeirVillemonte {
 
     constructor(prms: StructureVanLevParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.VanLevVillemonte;
+        this.setLoiDebit(LoiDebit.VanLevVillemonte);
     }
 
     /**
@@ -15,4 +15,8 @@ export class StructureVanLevVillemonte extends StructureWeirVillemonte {
     get prms(): StructureVanLevParams {
         return this._prms as StructureVanLevParams;
     }
+
+    protected get isVanneLevante(): boolean {
+        return true;
+    }
 }
diff --git a/src/structure/structure_weir_cem88d.ts b/src/structure/structure_weir_cem88d.ts
index 4ca6ff9889b2798fcad1a850057bb3716f49f4d8..783bf749d9bbda20403587e98cacb2350162bda3 100644
--- a/src/structure/structure_weir_cem88d.ts
+++ b/src/structure/structure_weir_cem88d.ts
@@ -1,13 +1,13 @@
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { StructureFlowMode } from "./structure";
-import { StructureGateCem88d } from "./structure_gate_cem88d";
-import { LoiDebit } from "./structure_props";
+import { RectangularStructureParams } from "../internal_modules";
+import { StructureFlowMode } from "../internal_modules";
+import { StructureGateCem88d } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 export class StructureWeirCem88d extends StructureGateCem88d {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirCem88d;
+        this.setLoiDebit(LoiDebit.WeirCem88d);
         this._isZDVcalculable = true;
         // Gestion de l'affichage l'ouverture de vanne
         this.prms.W.visible = false;
diff --git a/src/structure/structure_weir_cem88v.ts b/src/structure/structure_weir_cem88v.ts
index f4c44d3319cb49ae12ee67f71599e4b6f7985ffa..96d9eb485b9bfa34f5e3e7c3ef6d62d0a9294700 100644
--- a/src/structure/structure_weir_cem88v.ts
+++ b/src/structure/structure_weir_cem88v.ts
@@ -1,13 +1,13 @@
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { StructureFlowMode } from "./structure";
-import { StructureGateCem88v } from "./structure_gate_cem88v";
-import { LoiDebit } from "./structure_props";
+import { RectangularStructureParams } from "../internal_modules";
+import { StructureFlowMode } from "../internal_modules";
+import { StructureGateCem88v } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 export class StructureWeirCem88v extends StructureGateCem88v {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirCem88v;
+        this.setLoiDebit(LoiDebit.WeirCem88v);
         this.prms.W.visible = false;
     }
 
diff --git a/src/structure/structure_weir_cunge80.ts b/src/structure/structure_weir_cunge80.ts
index c46ffb635ccc40c96e2d61c44f21bdbaeff48adf..a74a02236dd25d1682e9fe3c8515a7d16eb1f4ae 100644
--- a/src/structure/structure_weir_cunge80.ts
+++ b/src/structure/structure_weir_cunge80.ts
@@ -1,13 +1,13 @@
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { StructureFlowMode } from "./structure";
-import { StructureGateCunge80 } from "./structure_gate_cunge80";
-import { LoiDebit } from "./structure_props";
+import { RectangularStructureParams } from "../internal_modules";
+import { StructureFlowMode } from "../internal_modules";
+import { StructureGateCunge80 } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 export class StructureWeirCunge80 extends StructureGateCunge80 {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirCunge80;
+        this.setLoiDebit(LoiDebit.WeirCunge80);
         this.prms.W.visible = false;
     }
 
diff --git a/src/structure/structure_weir_free.ts b/src/structure/structure_weir_free.ts
index 3ac77c7a453228dd00e546097ceb011c7f932076..04269e83f962ff67745a12456af6f739bf03e132 100644
--- a/src/structure/structure_weir_free.ts
+++ b/src/structure/structure_weir_free.ts
@@ -1,9 +1,9 @@
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation classique seuil dénoyé
@@ -12,14 +12,14 @@ export class StructureWeirFree extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirFree;
+        this.setLoiDebit(LoiDebit.WeirFree);
         this.prms.CdWR.visible = true;
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         // do not check h2 for derived classes (ex: StructureWeirVillemonte)
-        if (this._loiDebit === LoiDebit.WeirFree && this.prms.h2.v > 0) {
+        if (this.loiDebit === LoiDebit.WeirFree && this.prms.h2.v > 0) {
             this._result.resultElement.addMessage(new Message(
                 MessageCode.WARNING_DOWNSTREAM_ELEVATION_POSSIBLE_SUBMERSION,
                 {
diff --git a/src/structure/structure_weir_submerged.ts b/src/structure/structure_weir_submerged.ts
index 6fbd5e3c1f26f4be0acf9ad9141d763dc208c88c..f462873096fb7d6ee68bf68094525ad90c65d984 100644
--- a/src/structure/structure_weir_submerged.ts
+++ b/src/structure/structure_weir_submerged.ts
@@ -1,9 +1,9 @@
-import { Message, MessageCode, ParamCalculability } from "../index";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { Message, MessageCode, ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation de la fente noyée
@@ -15,12 +15,19 @@ export class StructureWeirSubmerged extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirSubmerged;
+        this.setLoiDebit(LoiDebit.WeirSubmerged);
         this.prms.CdWS.visible = true;
     }
 
+    /**
+     * vérification que l'ennoiement est supérieur à une valeur donnée
+     */
+    public checkSubmergence(res: Result) {
+        this.checkSubmergenceMin(res, 0.6);
+    }
+
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         const h2h1ratio = this.prms.h2.v / this.prms.h1.v;
         if (h2h1ratio < 0.8) {
             this._result.resultElement.addMessage(new Message(
diff --git a/src/structure/structure_weir_submerged_larinier.ts b/src/structure/structure_weir_submerged_larinier.ts
index c865175927b752ab8fb4800c070a0cdca84b9d5f..2051e77959bccbaefecd25d756772b6ab571f294 100644
--- a/src/structure/structure_weir_submerged_larinier.ts
+++ b/src/structure/structure_weir_submerged_larinier.ts
@@ -1,9 +1,9 @@
-import { Message, MessageCode, ParamCalculability } from "../index";
-import { Result } from "../util/result";
-import { RectangularStructure } from "./rectangular_structure";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
+import { Message, MessageCode, ParallelStructure, ParamCalculability } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructure } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
 
 /**
  * Equation de la fente noyé
@@ -14,7 +14,7 @@ export class StructureWeirSubmergedLarinier extends RectangularStructure {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirSubmergedLarinier;
+        this.setLoiDebit(LoiDebit.WeirSubmergedLarinier);
         this.prms.CdWSL.visible = true;
     }
 
@@ -25,17 +25,25 @@ export class StructureWeirSubmergedLarinier extends RectangularStructure {
         return this._prms as RectangularStructureParams;
     }
 
+    /**
+     * vérification que l'ennoiement est supérieur à une valeur donnée
+     */
+    public checkSubmergence(res: Result) {
+        this.checkSubmergenceMin(res, 0.5);
+    }
+
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         const h2h1ratio = this.prms.h2.v / this.prms.h1.v;
-        if (h2h1ratio < 0.7 || h2h1ratio > 0.9) {
-            this._result.resultElement.addMessage(new Message(
-                MessageCode.WARNING_SLOT_SUBMERGENCE_NOT_BETWEEN_07_AND_09,
-                {
-                    submergencePerc: this.computeSubmergencePercentage().toString()
-                }
-            ));
-        }
+        if (!(this.parent as ParallelStructure)?.inhibitSubmergenceError)
+            if (h2h1ratio < 0.7 || h2h1ratio > 0.9) {
+                this._result.resultElement.addMessage(new Message(
+                    MessageCode.WARNING_SLOT_SUBMERGENCE_NOT_BETWEEN_07_AND_09,
+                    {
+                        submergencePerc: this.computeSubmergencePercentage().toString()
+                    }
+                ));
+            }
         return this._result;
     }
 
diff --git a/src/structure/structure_weir_villemonte.ts b/src/structure/structure_weir_villemonte.ts
index 8df8423584701d6d6d8c20b91199d5cb9d5a91d2..eace90c79ceab4639ec0af7c829e670b4ccec3a0 100644
--- a/src/structure/structure_weir_villemonte.ts
+++ b/src/structure/structure_weir_villemonte.ts
@@ -1,20 +1,20 @@
-import { Message, MessageCode } from "../util/message";
-import { Result } from "../util/result";
-import { RectangularStructureParams } from "./rectangular_structure_params";
-import { StructureFlowRegime } from "./structure";
-import { LoiDebit } from "./structure_props";
-import { StructureWeirFree } from "./structure_weir_free";
-import { Villemonte } from "./villemonte";
+import { Message, MessageCode } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { StructureFlowRegime } from "../internal_modules";
+import { LoiDebit } from "../internal_modules";
+import { StructureWeirFree } from "../internal_modules";
+import { Villemonte } from "../internal_modules";
 
 export class StructureWeirVillemonte extends StructureWeirFree {
 
     constructor(prms: RectangularStructureParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._loiDebit = LoiDebit.WeirVillemonte;
+        this.setLoiDebit(LoiDebit.WeirVillemonte);
     }
 
     public Calc(sVarCalc: string, rInit?: number): Result {
-        this.currentResult = super.Calc(sVarCalc, rInit);
+        this.currentResultElement = super.Calc(sVarCalc, rInit);
         if ((this.prms.h2.v / this.prms.h1.v) > 0.7) {
             this._result.resultElement.addMessage(new Message(
                 MessageCode.WARNING_NOTCH_SUBMERGENCE_GREATER_THAN_07,
diff --git a/src/units.ts b/src/units.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f072fe21f2024c04a270368b36d2cf3d5fba5f86
--- /dev/null
+++ b/src/units.ts
@@ -0,0 +1,35 @@
+import { CalculatorType } from "./compute-node";
+import { Cloisons, ConcentrationBlocs, Dever, Grille, Jet, MacroRugo, PabNombre, Par, RegimeUniforme } from "./index";
+import { PressureLoss } from "./internal_modules";
+
+/**
+ * correspondance type de calculette - classe de Nub
+ */
+const nubClasses = new Map<CalculatorType, any>([
+    [CalculatorType.Grille, Grille],
+    [CalculatorType.ConcentrationBlocs, ConcentrationBlocs],
+    [CalculatorType.Jet, Jet],
+    [CalculatorType.MacroRugo, MacroRugo],
+    [CalculatorType.RegimeUniforme, RegimeUniforme],
+    [CalculatorType.Cloisons, Cloisons],
+    [CalculatorType.PabNombre, PabNombre],
+    [CalculatorType.Par, Par],
+    [CalculatorType.Dever, Dever],
+    [CalculatorType.PressureLoss, PressureLoss]
+]);
+
+/**
+ * détermine l'unité d'un paramètre de résultat
+ * @param nubType Nub contenant le paramètre de résultat
+ * @param symbol symbole du paramètre
+ * @returns unité du paramètre
+ */
+export function getNubResultUnit(nubType: CalculatorType, symbol: string) {
+    const cl = nubClasses.get(nubType);
+    if (cl !== undefined && "resultsUnits" in cl) {
+        const f = cl.resultsUnits;
+        const units = f();
+        return units[symbol];
+    }
+    return undefined;
+}
diff --git a/src/util/enum.ts b/src/util/enum.ts
index 1df6488ae4e8ede949d28f399f3e69047abc5977..d3c7dcbec424152a4ba22b4056f8950b9aa48892 100644
--- a/src/util/enum.ts
+++ b/src/util/enum.ts
@@ -17,6 +17,9 @@
  *  }
  */
 // tslint:disable-next-line:max-line-length
+
+import { Session } from "../internal_modules";
+
 // see https://stackoverflow.com/questions/21293063/how-to-programmatically-enumerate-an-enum-type-in-typescript-0-9-5#21294925
 export class EnumEx {
     /**
diff --git a/src/util/interval.ts b/src/util/interval.ts
index 0f630c03b0c9a6cbbdf9723433b62f7f57199ff6..f7ca744577f38ab5850958cdc1e48b100b4fb17b 100644
--- a/src/util/interval.ts
+++ b/src/util/interval.ts
@@ -1,5 +1,5 @@
-import { Message, MessageCode } from "./message";
-import { Debug } from "../base";
+import { Message, MessageCode } from "../internal_modules";
+import { Debug } from "../internal_modules";
 
 /**
  * Couple de valeurs ordonnées
@@ -8,7 +8,7 @@ export class Interval extends Debug {
 
     constructor(public val1: number, public val2: number, dbg: boolean = false) {
         super(dbg);
-     }
+    }
 
     public setValues(v1: number, v2: number) {
         this.val1 = v1;
diff --git a/src/util/log.ts b/src/util/log.ts
index 2f5b9f4f4db6f18ebaac8c53e1cd3bcf3f8f611b..8c682c26173005bb43be5c1a9b0091792b1d7c75 100644
--- a/src/util/log.ts
+++ b/src/util/log.ts
@@ -1,5 +1,5 @@
-import { Message, MessageCode, MessageSeverity } from "./message";
-import { Result } from "./result";
+import { Message, MessageCode, MessageSeverity } from "../internal_modules";
+import { Result } from "../internal_modules";
 
 // tslint:disable-next-line:class-name
 export class cLog {
@@ -26,7 +26,7 @@ export class cLog {
     public add(m: Message) {
         // add pointer to the current log as message's parent, unless the message
         // already has a parent, and unless the current log has no pointer to a result
-        if (m.parent === undefined && this.parent !== undefined) {
+        if (m.parent === undefined) {
             m.parent = this;
         }
         this._messages.push(m);
@@ -66,6 +66,30 @@ export class cLog {
         return this._messages;
     }
 
+    /**
+     * @return a clone of "this" (clone error messages only)
+     */
+    public cloneErrors(): cLog {
+        const res: cLog = new cLog();
+        for (const m of this._messages) {
+            if (m.getSeverity() === MessageSeverity.ERROR) {
+                res.add(m);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * @return a clone of "this" (do not clone messages, keep references to original messages)
+     */
+    public clone(): cLog {
+        const res: cLog = new cLog();
+        for (const m of this._messages) {
+            res.add(m);
+        }
+        return res;
+    }
+
     public toString(): string {
         return this._messages.join("\n");
     }
@@ -83,6 +107,49 @@ export class cLog {
         return false;
     }
 
+    public getMessage(mc: MessageCode): Message {
+        for (const m of this.messages) {
+            if (m.code === mc) {
+                return m;
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * @returns true if all messages have the same code
+     */
+    public hasOnlyMessage(code: MessageCode): boolean {
+        for (const m of this.messages) {
+            if (m.code !== code) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @returns true if given message exactly matches one of the messages
+     */
+    private hasMessage(m: Message): boolean {
+        for (const msg of this._messages) {
+            if (m.equals(msg, true)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public get uniqueMessageCodes(): MessageCode[] {
+        const res: MessageCode[] = [];
+        for (const m of this.messages) {
+            if (res.indexOf(m.code) === -1) {
+                res.push(m.code);
+            }
+        }
+        return res;
+    }
+
     /**
      * compute error, warning, info count in a message list
      */
diff --git a/src/util/message.ts b/src/util/message.ts
index 2d032ccb25110013b1e2fc8bfbc33c6bdc0374a2..5925cb864306e5f8da4cab2233d9c598e8606c26 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -1,4 +1,5 @@
-import { cLog } from "./log";
+import { cLog } from "../internal_modules";
+import { Nub } from "../internal_modules";
 
 export enum MessageCode {
 
@@ -192,7 +193,7 @@ export enum MessageCode {
     /** PAB : Erreur de calcul de la cote amont de la cloison %n% */
     ERROR_PAB_CALC_Z1_CLOISON,
 
-/** PAB : Erreur de calcul de la cote amont de la cloison aval */
+    /** PAB : Erreur de calcul de la cote amont de la cloison aval */
     ERROR_PAB_CALC_Z1_CLOISON_DW,
 
     /** Aucune ligne d'eau ne peut être calculée (aucun tirant d'eau à l'amont ni nà l'aval) */
@@ -511,6 +512,11 @@ export enum MessageCode {
      */
     ERROR_STRUCTURE_Z_EGAUX_Q_NON_NUL,
 
+    /**
+     * Structure : l'ennoiement %submergencePerc% est inférieur à %min%
+     */
+    ERROR_STRUCTURE_SUBMERGENCE_LOWER_THAN,
+
     /**
      * Il faut au moins un ouvrage dans une structure
      */
@@ -739,7 +745,53 @@ export class Message {
         throw new Error("Message.getSeverity() : valeur de code '" + this._code + "' invalide");
     }
 
+    public get sourceNub(): Nub {
+        return this.parent?.parent?.sourceNub;
+    }
+
     public toString(): string {
-        return MessageCode[this._code] + " " + JSON.stringify(this.extraVar);
+        const sourceNub = this.sourceNub;
+        return MessageCode[this._code] + " " + JSON.stringify(this.extraVar) + (sourceNub === undefined ? "" : " parentnub " + sourceNub.constructor.name);
+    }
+
+    public equals(m: Message, includeSourceNub: boolean): boolean {
+        if (this._code !== m._code)
+            return false;
+
+        const keys1 = Object.keys(this.extraVar);
+        const keys2 = Object.keys(m.extraVar);
+        if (keys1.length !== keys2.length)
+            return false;
+
+        if (keys1.length === 0) {
+            return true;
+        }
+
+        for (const k of keys1) {
+            if (!keys2.includes(k)) {
+                return false;
+            }
+            if (this.extraVar[k] !== m.extraVar[k]) {
+                return false;
+            }
+        }
+
+        // to be sure all keys are shared, do the same thing the other way around
+        for (const k of keys2) {
+            if (!keys1.includes(k)) {
+                return false;
+            }
+            if (this.extraVar[k] !== m.extraVar[k]) {
+                return false;
+            }
+        }
+
+        if (includeSourceNub) {
+            if (this.sourceNub !== undefined && (this.sourceNub.uid !== m.sourceNub?.uid)) {
+                return false;
+            }
+        }
+
+        return true;
     }
 }
diff --git a/src/util/number_array_iterator.ts b/src/util/number_array_iterator.ts
index e0e65c91bfef36b74dde43eec0f82e6806f58d7a..ff29835c4e176cc3d24d2eb8f2038d25aabffa2a 100644
--- a/src/util/number_array_iterator.ts
+++ b/src/util/number_array_iterator.ts
@@ -1,4 +1,4 @@
-import { INumberIterator } from "../param/param-value-iterator";
+import { INumberIterator } from "../internal_modules";
 
 /**
  * itérateur sur les valeurs prises par un tableau
diff --git a/src/util/number_array_reverse_iterator.ts b/src/util/number_array_reverse_iterator.ts
index 41e3fd56aeda9b5a67812379704718c56a4f8dff..2a33accac020da3e145084a53e8b7b4035f8a14d 100644
--- a/src/util/number_array_reverse_iterator.ts
+++ b/src/util/number_array_reverse_iterator.ts
@@ -1,5 +1,5 @@
-import { INumberIterator } from "../param/param-value-iterator";
-import { ArrayReverseIterator } from "../util/array_reverse_iterator";
+import { INumberIterator } from "../internal_modules";
+import { ArrayReverseIterator } from "../internal_modules";
 
 /**
  * itérateur sur les valeurs prises par un tableau (parcourues depuis la fin)
diff --git a/src/util/result.ts b/src/util/result.ts
index a5e5d79f586e51713bf380b0e6394fb4ec5edecf..cba512d9e577696839624e314d4317fd690cbf7d 100644
--- a/src/util/result.ts
+++ b/src/util/result.ts
@@ -1,8 +1,8 @@
-import { JalhydObject } from "../jalhyd_object";
-import { Nub } from "../nub";
-import { cLog } from "./log";
-import { Message, MessageSeverity } from "./message";
-import { ResultElement } from "./resultelement";
+import { JalhydObject, MessageCode } from "../internal_modules";
+import { Nub } from "../internal_modules";
+import { cLog } from "../internal_modules";
+import { Message, MessageSeverity } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
 
 /**
  * Result of a calculation.
@@ -88,7 +88,7 @@ export class Result extends JalhydObject {
         /* if (this._resultElements.length === 0) {
             throw new Error("Result.resultElement() : there are no result elements");
         } */
-        return this._resultElements[ this._resultElements.length - 1 ];
+        return this._resultElements[this._resultElements.length - 1];
     }
 
     /**
@@ -98,7 +98,7 @@ export class Result extends JalhydObject {
         if (this._resultElements.length === 0) {
             this._resultElements.push(r);
         } else {
-            this._resultElements[ this._resultElements.length - 1 ] = r;
+            this._resultElements[this._resultElements.length - 1] = r;
         }
         r.parent = this;
     }
@@ -132,7 +132,7 @@ export class Result extends JalhydObject {
         if (re !== undefined) {
             res.push(re);
         }
-        const it: Iterator<Nub> = this._sourceNub.allChildNubIterator();
+        const it: Iterator<Nub> = this._sourceNub.directChildNubIterator();
         let inub = it.next()
         while (!inub.done) {
             let re = inub.value.result._resultElements[index];
@@ -265,13 +265,63 @@ export class Result extends JalhydObject {
      */
     public get hasOnlyErrors(): boolean {
         for (const r of this._resultElements) {
-            if (! r.hasErrorMessages()) {
+            if (!r.hasErrorMessages()) {
                 return false;
             }
         }
         return true;
     }
 
+    /**
+     * determine if a message is present in result
+     * @param code message code to find
+     * @param recurs if true, search into nub children
+     */
+    public hasMessage(code: MessageCode, recurs: boolean = false): boolean {
+        if (this._globalLog.contains(code)) {
+            return true;
+        }
+
+        for (const r of this._resultElements) {
+            if (r.log.contains(code)) {
+                return true;
+            }
+        }
+
+        if (recurs && this._sourceNub !== undefined) {
+            for (const n of this._sourceNub.directChildNubIterator()) {
+                if (n.result.hasMessage(code, true)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * determine if all messages have the same code
+     * @param code message code to find
+     */
+    public hasOnlyMessage(code: MessageCode): boolean {
+        if (!this._globalLog.hasOnlyMessage(code)) {
+            return false;
+        }
+
+        if (!this.resultElement.log.hasOnlyMessage(code)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public get uniqueMessageCodes(): MessageCode[] {
+        let res: MessageCode[] = [];
+        res = res.concat(this._globalLog.uniqueMessageCodes);
+        res = res.concat(this.resultElement.log.uniqueMessageCodes);
+        return res;
+    }
+
     /**
      * compute log stats (# of error, warning, info) on all result element
      */
diff --git a/src/util/resultelement.ts b/src/util/resultelement.ts
index a89a3f56c017f903f9ecee870b0888220a1002d7..72b4c02d12e7a54f18966f2fa8e3ad84b511cc02 100644
--- a/src/util/resultelement.ts
+++ b/src/util/resultelement.ts
@@ -1,6 +1,6 @@
-import { cLog } from "./log";
-import { Message, MessageCode, MessageSeverity } from "./message";
-import { Result } from "./result";
+import { MessageCode, cLog } from "../internal_modules";
+import { Message, MessageSeverity } from "../internal_modules";
+import { Result } from "../internal_modules";
 
 /**
  * Calculation result for one iteration.
@@ -75,7 +75,7 @@ export class ResultElement {
     }
 
     public setVCalc(r: number, keepSymbol: boolean = false) {
-        if (! keepSymbol && this.parent && this.parent.symbol) {
+        if (!keepSymbol && this.parent && this.parent.symbol) {
             this._vCalcSymbol = this.parent.symbol;
         }
         this._values[this._vCalcSymbol] = r;
@@ -86,7 +86,7 @@ export class ResultElement {
      * after Equation() returned a ResultElement
      */
     public updateVCalcSymbol(s: string) {
-        if (! this.hasValues) {
+        if (!this.hasValues) {
             throw new Error("updateVCalcSymbol() : values map is empty");
         }
         const tmp = this.vCalc;
@@ -192,6 +192,13 @@ export class ResultElement {
         }
     }
 
+    /**
+     * Removes all values
+     */
+    public removeValues() {
+        this._values = {};
+    }
+
     public toString(): string {
         if (this.vCalc !== undefined) {
             return String(this.vCalc);
@@ -234,6 +241,15 @@ export class ResultElement {
         return false;
     }
 
+    public hasMessage(code: MessageCode): boolean {
+        for (const m of this.log.messages) {
+            if (m.code === code) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * compute error, warning, info count on all log messages
      */
diff --git a/src/util/search_interval.ts b/src/util/search_interval.ts
index 1085d2e716008429eca98352e700018f6f6262f4..b3fae44f0739c81295d184063d6497951621aa99 100644
--- a/src/util/search_interval.ts
+++ b/src/util/search_interval.ts
@@ -1,12 +1,12 @@
-import { Dichotomie } from "../dichotomie";
-import { Interval } from "./interval";
-import { Message, MessageCode } from "./message";
+import { Dichotomie } from "../internal_modules";
+import { Interval } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
 
 export class SearchInterval extends Interval {
 
     private _initialValue: number;
 
-    private  _initialStep: number;
+    private _initialStep: number;
 
     private _step: number;
 
@@ -33,13 +33,13 @@ export class SearchInterval extends Interval {
     }
 
     public debug(s: string) {
-        if(this.DBG) {
-            super.debug("SearchInterval: "+s);
+        if (this.DBG) {
+            super.debug("SearchInterval: " + s);
         }
     }
 
     public reInit(rInit?: number) {
-        if(rInit !== undefined) {
+        if (rInit !== undefined) {
             this.val1 = rInit;
         } else {
             this.val1 = this._initialValue;
@@ -81,8 +81,8 @@ export class SearchInterval extends Interval {
     }
 
     public checkDirection() {
-        if(this._signDeltaTargets) { // !== undefined and !== 0
-            if(Math.sign(this.targets.val1 - this.targets.val2) !== this._signDeltaTargets) {
+        if (this._signDeltaTargets) { // !== undefined and !== 0
+            if (Math.sign(this.targets.val1 - this.targets.val2) !== this._signDeltaTargets) {
                 this.debug(this.toString() + " = [" + this.targets.val1 + "," + this.targets.val2 + "] sign changed!");
                 // We have gone too far, let's start again the search from here
                 if (this._step > 0) {
@@ -95,8 +95,8 @@ export class SearchInterval extends Interval {
             }
         }
         this._signDeltaTargets = Math.sign(this.targets.val1 - this.targets.val2)
-        this.debug(this.toString() + " = [" + this.targets.val1 + "," + this.targets.val2 + "]" + (this._signDeltaTargets > 0)?">0":"<0");
-        this.debug("_signDeltaTargets="+this._signDeltaTargets);
+        this.debug(this.toString() + " = [" + this.targets.val1 + "," + this.targets.val2 + "]" + (this._signDeltaTargets > 0) ? ">0" : "<0");
+        this.debug("_signDeltaTargets=" + this._signDeltaTargets);
     }
 
     public hasTargetValue(targ: number) {
@@ -109,7 +109,7 @@ export class SearchInterval extends Interval {
     }
 
     public updateTargets(bFatal: boolean = true) {
-        try{
+        try {
             let t1 = this.targets.val1;
             if (t1 === undefined || isNaN(t1)) {
                 t1 = this._dicho.CalculX(this.val1);
@@ -124,8 +124,8 @@ export class SearchInterval extends Interval {
                 this.debug(`updateTargets 2: f(${this.val2})=${t2}`)
             }
             this.targets.setValues(t1, t2);
-        } catch(e) {
-            if(bFatal) {
+        } catch (e) {
+            if (bFatal) {
                 throw e;
             } else {
                 this.reInit(this._lastGoodValue);
diff --git a/src/variated-details.ts b/src/variated-details.ts
index 5f0047927f7bf9f44471b1bd6bcc11df6210e12d..52949afcf84764726215c779c18fcbcccaea16f6 100644
--- a/src/variated-details.ts
+++ b/src/variated-details.ts
@@ -1,6 +1,6 @@
-import { ParamDefinition } from "./param/param-definition";
-import { ParamValues } from "./param/param-values";
-import { INumberIterator } from "./param/param-value-iterator";
+import { ParamDefinition } from "./internal_modules";
+import { ParamValues } from "./internal_modules";
+import { INumberIterator } from "./internal_modules";
 
 export interface VariatedDetails {
     param: ParamDefinition;
diff --git a/src/verification/espece.ts b/src/verification/espece.ts
index 14efc95a58f85ec6550277083958c5e5bd7f189f..25d43cad7f07cc1fc8500759f83b5993409ff9b4 100644
--- a/src/verification/espece.ts
+++ b/src/verification/espece.ts
@@ -1,26 +1,26 @@
-import { Nub } from "../nub";
-import { EspeceParams } from "./espece_params";
-import { CalculatorType } from "../compute-node";
-import { Observer } from "../util/observer";
-import { ParamCalculability } from "../param/param-definition";
-import { FishSpecies } from "./fish_species";
-import { Result } from "../util/result";
-import { FishPass } from "../fish_pass";
-import { StructureJetType, StructureFlowMode } from "../structure/structure";
-import { Message, MessageCode } from "../util/message";
-import { ParSimulation } from "../par/par_simulation";
-import { ParType } from "../par/par";
-import { MacroRugo, MacroRugoFlowType } from "../macrorugo/macrorugo";
-import { ResultElement } from "../util/resultelement";
-import { MacrorugoCompound } from "../macrorugo/macrorugo_compound";
-import { Pab } from "../pab/pab";
-import { LoiDebit, loiAdmissiblesCloisonAval } from "../structure/structure_props";
-import { RectangularStructureParams } from "../structure/rectangular_structure_params";
-import { ParallelStructure } from "../structure/parallel_structure";
-import { StructureOrificeSubmergedParams } from "../structure/structure_orifice_submerged_params";
-import { Cloisons } from "../pab/cloisons";
-import { isLowerThan, isGreaterThan } from "../base";
-import { DivingJetSupport } from "./diving-jet-support";
+import { Nub } from "../internal_modules";
+import { EspeceParams } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Observer } from "../internal_modules";
+import { ParamCalculability } from "../internal_modules";
+import { FishSpecies } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { FishPass } from "../internal_modules";
+import { StructureJetType, StructureFlowMode } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { ParSimulation } from "../internal_modules";
+import { ParType } from "../internal_modules";
+import { MacroRugo, MacroRugoFlowType } from "../internal_modules";
+import { ResultElement } from "../internal_modules";
+import { MacrorugoCompound } from "../internal_modules";
+import { Pab } from "../internal_modules";
+import { LoiDebit, loiAdmissiblesCloisonAval } from "../internal_modules";
+import { RectangularStructureParams } from "../internal_modules";
+import { ParallelStructure } from "../internal_modules";
+import { StructureOrificeSubmergedParams } from "../internal_modules";
+import { Cloisons } from "../internal_modules";
+import { isLowerThan, isGreaterThan } from "../internal_modules";
+import { DivingJetSupport } from "../internal_modules";
 
 /**
  * Settings for a given fish species (or custom settings), to verify crossing capacities on fish passes.
@@ -45,7 +45,7 @@ export class Espece extends Nub implements Observer {
 
     constructor(prms: EspeceParams, dbg: boolean = false) {
         super(prms, dbg);
-        this._calcType = CalculatorType.Espece;
+        this.setCalculatorType(CalculatorType.Espece);
         this._props.addObserver(this);
         // Diving jets in PAB are not supported by default
         this.divingJetSupported = DivingJetSupport.NOT_SUPPORTED;
@@ -87,15 +87,15 @@ export class Espece extends Nub implements Observer {
             DivingJetSupported: DivingJetSupport.SUPPORTED
         };
         this.presets[CalculatorType.Pab][FishSpecies.SPECIES_3a] =
-        this.presets[CalculatorType.Pab][FishSpecies.SPECIES_3b] = {
-            DHMaxS: 0.3,
-            BMin: 0.4,
-            PMinS: 1,
-            HMin: 0.4,
-            LMinS: 3.5,
-            PVMaxPrec: 150,
-            PVMaxLim: 200
-        };
+            this.presets[CalculatorType.Pab][FishSpecies.SPECIES_3b] = {
+                DHMaxS: 0.3,
+                BMin: 0.4,
+                PMinS: 1,
+                HMin: 0.4,
+                LMinS: 3.5,
+                PVMaxPrec: 150,
+                PVMaxLim: 200
+            };
         this.presets[CalculatorType.Pab][FishSpecies.SPECIES_3c] = {
             DHMaxS: 0.3,
             BMin: 0.15,
@@ -214,7 +214,7 @@ export class Espece extends Nub implements Observer {
             PVMaxPrec: 130,
             PVMaxLim: 150
         };
-        this.presets[CalculatorType.Pab][FishSpecies.SPECIES_9b] ={
+        this.presets[CalculatorType.Pab][FishSpecies.SPECIES_9b] = {
             DHMaxS: 0.2,
             BMin: 0.15,
             PMinS: 0.5,
@@ -289,10 +289,10 @@ export class Espece extends Nub implements Observer {
             VeMax: 2.5
         };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3a] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3b] = {
-            YMin: 0.4,
-            VeMax: 2
-        };
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3b] = {
+                YMin: 0.4,
+                VeMax: 2
+            };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3c] = {
             YMin: 0.15,
             VeMax: 2
@@ -306,28 +306,28 @@ export class Espece extends Nub implements Observer {
             VeMax: 2
         };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_5] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_6] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_7a] = {
-            YMin: 0.3,
-            VeMax: 2
-        };
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_6] =
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_7a] = {
+                YMin: 0.3,
+                VeMax: 2
+            };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_7b] = {
             YMin: 0.15,
             VeMax: 2
         };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8a] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8b] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8c] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8d] = {
-            YMin: 0.3,
-            VeMax: 1.5
-        };
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8b] =
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8c] =
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8d] = {
+                YMin: 0.3,
+                VeMax: 1.5
+            };
         this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_9a] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_9b] =
-        this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_10] = {
-            YMin: 0.2,
-            VeMax: 1.5
-        };
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_9b] =
+            this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_10] = {
+                YMin: 0.2,
+                VeMax: 1.5
+            };
     }
 
     public get prms(): EspeceParams {
@@ -340,7 +340,7 @@ export class Espece extends Nub implements Observer {
 
     /** Changing the fish species will load adequate predefined values */
     public set species(s: FishSpecies) {
-        this.properties.setPropValue("species", s);
+        this.setPropValue("species", s);
     }
 
     public set passToCheck(p: FishPass) {
@@ -349,11 +349,11 @@ export class Espece extends Nub implements Observer {
     }
 
     public get divingJetSupported(): DivingJetSupport {
-        return this.properties.getPropValue("divingJetSupported");
+        return this.getPropValue("divingJetSupported");
     }
 
     public set divingJetSupported(i: DivingJetSupport) {
-        this.properties.setPropValue("divingJetSupported", i);
+        this.setPropValue("divingJetSupported", i);
     }
 
     /**
@@ -422,12 +422,12 @@ export class Espece extends Nub implements Observer {
                     hasAtLeastOneDivingJet = hasAtLeastOneDivingJet || this.hasJet(passB.downWall, StructureJetType.PLONGEANT);
 
                     let cpRetPAB: Result;
-                    let criteriaToCheck: string[] = [ /* "PVMaxPrec", "PVMaxLim", */ "HMin", "BMin" ];
+                    let criteriaToCheck: string[] = [ /* "PVMaxPrec", "PVMaxLim", */ "HMin", "BMin"];
                     if (hasAtLeastOneSurfaceJet) {
-                        criteriaToCheck = criteriaToCheck.concat([ "DHMaxS", "PMinS", "LMinS" ]);
+                        criteriaToCheck = criteriaToCheck.concat(["DHMaxS", "PMinS", "LMinS"]);
                     }
                     if (hasAtLeastOneDivingJet && this.divingJetSupported === DivingJetSupport.SUPPORTED) {
-                        criteriaToCheck = criteriaToCheck.concat([ "DHMaxP", "PMinP", "LMinP" ]);
+                        criteriaToCheck = criteriaToCheck.concat(["DHMaxP", "PMinP", "LMinP"]);
                     }
                     if (criteriaToCheck.length > 0) {
                         cpRetPAB = this.checkCriteriaPresence(criteriaToCheck);
@@ -499,7 +499,7 @@ export class Espece extends Nub implements Observer {
                         for (const devC of wca) {
                             ok = ok || devC;
                         }
-                        if (! ok) {
+                        if (!ok) {
                             const m = new Message(MessageCode.ERROR_VERIF_PAB_WALL_NOT_CROSSABLE);
                             m.extraVar.N = String(cloisonNumber); // keep the "+1" for readability
                             res.log.add(m);
@@ -533,7 +533,7 @@ export class Espece extends Nub implements Observer {
                     for (const devC of dwca) {
                         okDw = okDw || devC;
                     }
-                    if (! okDw) {
+                    if (!okDw) {
                         const m = new Message(MessageCode.ERROR_VERIF_PAB_DW_NOT_CROSSABLE);
                         res.log.add(m);
                     }
@@ -545,10 +545,10 @@ export class Espece extends Nub implements Observer {
 
                     // Check criteria presence, depending on baffle type
                     let parCriteria: string[] = [];
-                    if ([ ParType.PLANE, ParType.FATOU ].includes(passR.parType)) {
-                        parCriteria = [ "YMinPB" ];
-                    } else if ([ ParType.SUPERACTIVE, ParType.CHEVRON ].includes(passR.parType)) {
-                        parCriteria = [ "YMinSB" ];
+                    if ([ParType.PLANE, ParType.FATOU].includes(passR.parType)) {
+                        parCriteria = ["YMinPB"];
+                    } else if ([ParType.SUPERACTIVE, ParType.CHEVRON].includes(passR.parType)) {
+                        parCriteria = ["YMinSB"];
                     }
                     if (parCriteria.length > 0) {
                         const cpRetPAR = this.checkCriteriaPresence(parCriteria);
@@ -558,15 +558,15 @@ export class Espece extends Nub implements Observer {
                     }
 
                     // 1. species groups 3a, 3b, 7b are discouraged
-                    if ([ FishSpecies.SPECIES_3a, FishSpecies.SPECIES_3b, FishSpecies.SPECIES_7b ].includes(this.species)) {
+                    if ([FishSpecies.SPECIES_3a, FishSpecies.SPECIES_3b, FishSpecies.SPECIES_7b].includes(this.species)) {
                         res.log.add(new Message(MessageCode.WARNING_VERIF_PAR_SPECIES_GROUP));
                     }
 
                     // 2. water level
                     let minY = 0; // if this.prms.YMin(P|S)B is undefined, "skip test"
-                    if ([ ParType.PLANE, ParType.FATOU ].includes(passR.parType)) {
+                    if ([ParType.PLANE, ParType.FATOU].includes(passR.parType)) {
                         minY = this.prms.YMinPB.singleValue;
-                    } else if ([ ParType.SUPERACTIVE, ParType.CHEVRON ].includes(passR.parType)) {
+                    } else if ([ParType.SUPERACTIVE, ParType.CHEVRON].includes(passR.parType)) {
                         minY = this.prms.YMinSB.singleValue;
                     }
                     if (isLowerThan(r.values.h, minY, 1e-3)) {
@@ -583,7 +583,7 @@ export class Espece extends Nub implements Observer {
                     const passMRC = this._passToCheck as MacrorugoCompound;
 
                     // Check criteria presence
-                    const cpRetMRC = this.checkCriteriaPresence([ "YMin", "VeMax" ]);
+                    const cpRetMRC = this.checkCriteriaPresence(["YMin", "VeMax"]);
                     if (cpRetMRC !== undefined) {
                         return cpRetMRC;
                     }
@@ -607,7 +607,7 @@ export class Espece extends Nub implements Observer {
                         }
                         apronNumber++;
                     }
-                    if (! atLeastOneOK) {
+                    if (!atLeastOneOK) {
                         res.vCalc = 0;
                         res.log.add(new Message(MessageCode.ERROR_VERIF_MRC_AT_LEAST_ONE_APRON));
                     } else {
@@ -630,7 +630,7 @@ export class Espece extends Nub implements Observer {
 
                 case CalculatorType.MacroRugo:
                     // Check criteria presence
-                    const cpRetMR = this.checkCriteriaPresence([ "YMin", "VeMax" ]);
+                    const cpRetMR = this.checkCriteriaPresence(["YMin", "VeMax"]);
                     if (cpRetMR !== undefined) {
                         return cpRetMR;
                     }
@@ -835,18 +835,18 @@ export class Espece extends Nub implements Observer {
         let structureNumber = 1;
         for (const device of wall.structures) {
             const hasOtherDevicesThanWeirs = (
-                this.hasJet(wall, [ StructureJetType.PLONGEANT ])
-                || (this.getDevicesHavingLaw(wall, [ LoiDebit.WeirVillemonte, LoiDebit.WeirSubmergedLarinier ]).length < wall.structures.length)
+                this.hasJet(wall, [StructureJetType.PLONGEANT])
+                || (this.getDevicesHavingLaw(wall, [LoiDebit.WeirVillemonte, LoiDebit.WeirSubmergedLarinier]).length < wall.structures.length)
             );
             const hasOtherDevicesThanOrifice = (
-                this.hasJet(wall, [ StructureJetType.PLONGEANT ])
+                this.hasJet(wall, [StructureJetType.PLONGEANT])
                 || (this.getDevicesHavingLaw(wall, LoiDebit.OrificeSubmerged).length < wall.structures.length)
             );
             const iRes = device.result.resultElements[this.indexToCheck];
             const jt = iRes.values.ENUM_StructureJetType;
             if (jt !== StructureJetType.PLONGEANT) {
                 // Surface jets: for "Villemonte 1947" ("échancrure") or "Fente noyée (Larinier 1992)" ("fente") only
-                if ([ LoiDebit.WeirVillemonte, LoiDebit.WeirSubmergedLarinier ].includes(device.loiDebit)) {
+                if ([LoiDebit.WeirVillemonte, LoiDebit.WeirSubmergedLarinier].includes(device.loiDebit)) {
                     const structParams = device.prms as RectangularStructureParams;
                     if (this.prms.BMin.singleValue !== undefined && isLowerThan(structParams.L.v, this.prms.BMin.singleValue, 1e-3)) {
                         let m: Message;
@@ -898,7 +898,7 @@ export class Espece extends Nub implements Observer {
         for (const device of wall.structures) {
             let zdv = device.prms.ZDV.singleValue;
             // if device is a regulated weir, get calculated ZDV at current iteration from parent downWall
-            if (loiAdmissiblesCloisonAval.VanneLevante.includes(device.properties.getPropValue("loiDebit"))) {
+            if (loiAdmissiblesCloisonAval.VanneLevante.includes(device.getPropValue("loiDebit"))) {
                 zdv = device.parent.result.resultElements[this.indexToCheck].values.ZDV;
             }
             // do not use device.prms.h1.v, that contains only the latest calculated value if pass is variyng
@@ -968,8 +968,8 @@ export class Espece extends Nub implements Observer {
      * Returns true if given wall has at least one device with a jet type among given jetTypes
      */
     protected hasJet(wall: ParallelStructure, jetTypes: StructureJetType | StructureJetType[]): boolean {
-        if (! Array.isArray(jetTypes)) {
-            jetTypes = [ jetTypes ];
+        if (!Array.isArray(jetTypes)) {
+            jetTypes = [jetTypes];
         }
         for (const device of wall.structures) {
             const deviceJetType = device.result.resultElements[this.indexToCheck].values.ENUM_StructureJetType;
@@ -1003,8 +1003,8 @@ export class Espece extends Nub implements Observer {
      */
     protected getDevicesHavingLaw(wall: ParallelStructure, l: LoiDebit | LoiDebit[]): number[] {
         const idxs: number[] = [];
-        if (! Array.isArray(l)) {
-            l = [ l ];
+        if (!Array.isArray(l)) {
+            l = [l];
         }
         for (let i = 0; i < wall.structures.length; i++) {
             if (l.includes(wall.structures[i].loiDebit)) {
@@ -1127,7 +1127,7 @@ export class Espece extends Nub implements Observer {
                 found = false;
                 for (const pt of Object.keys(this.presets)) {
                     const preset = this.presets[pt];
-                    if (! found && preset !== undefined && preset[sp] !== undefined && preset[sp][p.symbol] !== undefined) {
+                    if (!found && preset !== undefined && preset[sp] !== undefined && preset[sp][p.symbol] !== undefined) {
                         found = true;
                         // if (preset[sp][p.symbol] !== undefined) console.log(`-> setting ${p.symbol} to ${preset[sp][p.symbol]}`);
                         // apply preset
diff --git a/src/verification/espece_params.ts b/src/verification/espece_params.ts
index 0e300ea2dff9b21d7f6dcacb020d8bef5f1d0bd1..5962a5f08c1f8848f5d2222810d1799463e2bafe 100644
--- a/src/verification/espece_params.ts
+++ b/src/verification/espece_params.ts
@@ -1,6 +1,6 @@
-import { ParamsEquation } from "../param/params-equation";
-import { ParamDefinition } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../internal_modules";
+import { ParamDefinition } from "../internal_modules";
+import { ParamDomainValue } from "../internal_modules";
 
 export class EspeceParams extends ParamsEquation {
 
diff --git a/src/verification/verificateur.ts b/src/verification/verificateur.ts
index 88bb47c14e1e1d92fcb9e816ba75aaec56f23ecd..c459b78b5eb628c410a65c9e178d6a4125505036 100644
--- a/src/verification/verificateur.ts
+++ b/src/verification/verificateur.ts
@@ -1,17 +1,16 @@
-import { Nub } from "../nub";
-import { Observer } from "../util/observer";
-import { CalculatorType } from "../compute-node";
-import { Session } from "../session";
-import { Result } from "../util/result";
-import { Espece } from "./espece";
-import { FishSpecies } from "./fish_species";
-import { EspeceParams } from "./espece_params";
-import { FishPass } from "../fish_pass";
-import { Message, MessageCode } from "../util/message";
-import { VerificateurParams } from "./verificateur_params";
-import { ParSimulation } from "../par/par_simulation";
-import { isGreaterThan } from "../base";
-import { ParType } from "../par/par";
+import { Nub } from "../internal_modules";
+import { CalculatorType } from "../internal_modules";
+import { Session } from "../internal_modules";
+import { Result } from "../internal_modules";
+import { Espece } from "../internal_modules";
+import { FishSpecies } from "../internal_modules";
+import { EspeceParams } from "../internal_modules";
+import { FishPass } from "../internal_modules";
+import { Message, MessageCode } from "../internal_modules";
+import { VerificateurParams } from "../internal_modules";
+import { ParSimulation } from "../internal_modules";
+import { isGreaterThan } from "../internal_modules";
+import { ParType } from "../internal_modules";
 
 export class Verificateur extends Nub {
 
@@ -21,9 +20,9 @@ export class Verificateur extends Nub {
     /** Index of the reseult element to verify, when the pass to verify is variating */
     protected _variatingIndex = 0;
 
-    constructor(dbg: boolean = false)  {
+    constructor(dbg: boolean = false) {
         super(new VerificateurParams(), dbg);
-        this._calcType = CalculatorType.Verificateur;
+        this.setCalculatorType(CalculatorType.Verificateur);
         // UID of Session Nub to verify
         this.nubToVerify = undefined;
         // List of fish species to check the pass against
@@ -46,7 +45,7 @@ export class Verificateur extends Nub {
     }
 
     public set speciesList(l: string[]) {
-        this.properties.setPropValue("speciesList", l);
+        this.setPropValue("speciesList", l);
         // (re)create Espece instances
         this.initSpecies();
     }
@@ -68,7 +67,7 @@ export class Verificateur extends Nub {
         if (n !== undefined) {
             uid = n.uid;
         }
-        this.properties.setPropValue("nubToVerify", uid);
+        this.setPropValue("nubToVerify", uid);
     }
 
     /**
@@ -100,7 +99,7 @@ export class Verificateur extends Nub {
         // calc pass systematically
         this.nubToVerify.CalcSerie();
         // check presence of valid result
-        if (! this.nubToVerify.result || ! this.nubToVerify.result.ok) {
+        if (!this.nubToVerify.result || !this.nubToVerify.result.ok) {
             this._result = new Result(undefined, this);
             this._result.addMessage(new Message(MessageCode.ERROR_VERIF_ERRORS_IN_PASS));
             return this._result;
@@ -116,7 +115,7 @@ export class Verificateur extends Nub {
 
         const passIsVarying = this.nubToVerify.resultHasMultipleValues();
 
-        if (! passIsVarying) { // pass to verify is not varying
+        if (!passIsVarying) { // pass to verify is not varying
             // prepare a new slot to store results
             this._variatingIndex = 0;
             this.initNewResultElement();
@@ -147,7 +146,7 @@ export class Verificateur extends Nub {
                 this.initNewResultElement();
 
                 // don't calculate if this iteration has errors
-                if (! this.nubToVerify.result.resultElements[this._variatingIndex].ok) {
+                if (!this.nubToVerify.result.resultElements[this._variatingIndex].ok) {
                     const m = new Message(MessageCode.ERROR_VERIF_VARYING_ERRORS_IN_PASS);
                     m.extraVar.i = String(l + 1);
                     this._result.resultElement.addMessage(m);
@@ -155,7 +154,7 @@ export class Verificateur extends Nub {
                 } else {
                     // calculate
                     this.doCalc(undefined); // résultat dans this.currentResult (resultElement le plus récent)
-                    if (! this._result.resultElement.ok) {
+                    if (!this._result.resultElement.ok) {
                         stageErrorsCount++;
                     }
                 }
@@ -181,7 +180,7 @@ export class Verificateur extends Nub {
     }
 
     public Calc(): Result {
-        this.currentResult = this.Equation();
+        this.currentResultElement = this.Equation();
         return this.result;
     }
 
@@ -195,7 +194,7 @@ export class Verificateur extends Nub {
         // species-independent check: PAR
         if (this.nubToVerify instanceof ParSimulation) {
             // 1. slope
-            const maxS = [ ParType.PLANE, ParType.FATOU ].includes(this.nubToVerify.parType) ? 0.2 : 0.16;
+            const maxS = [ParType.PLANE, ParType.FATOU].includes(this.nubToVerify.parType) ? 0.2 : 0.16;
             if (isGreaterThan(this.nubToVerify.prms.S.v, maxS)) {
                 const m = new Message(MessageCode.ERROR_VERIF_PAR_SLOPE);
                 m.extraVar.S = this.nubToVerify.prms.S.v;
@@ -223,13 +222,13 @@ export class Verificateur extends Nub {
             const subRes = speciesNub.Calc();
 
             let m: Message;
-            const isCustomSpecies = ! (this.speciesList[spIndex] in FishSpecies);
+            const isCustomSpecies = !(this.speciesList[spIndex] in FishSpecies);
             // if at least one error log in Espece nub, add one at Verificateur level, so that .ok is false
             // else add a success info message
             if (isCustomSpecies) {
                 if (subRes.resultElements[this._variatingIndex].hasErrorMessages()) {
                     m = new Message(MessageCode.ERROR_VERIF_SPECIES_NUB_KO);
-                } else if(subRes.resultElements[this._variatingIndex].hasWarningMessages()) {
+                } else if (subRes.resultElements[this._variatingIndex].hasWarningMessages()) {
                     m = new Message(MessageCode.WARNING_VERIF_SPECIES_NUB_OK_BUT);
                 } else {
                     m = new Message(MessageCode.INFO_VERIF_SPECIES_NUB_OK);
@@ -238,7 +237,7 @@ export class Verificateur extends Nub {
             } else {
                 if (subRes.resultElements[this._variatingIndex].hasErrorMessages()) {
                     m = new Message(MessageCode.ERROR_VERIF_SPECIES_GROUP_KO);
-                } else if(subRes.resultElements[this._variatingIndex].hasWarningMessages()) {
+                } else if (subRes.resultElements[this._variatingIndex].hasWarningMessages()) {
                     m = new Message(MessageCode.WARNING_VERIF_SPECIES_GROUP_OK_BUT);
                 } else {
                     m = new Message(MessageCode.INFO_VERIF_SPECIES_GROUP_OK);
@@ -252,7 +251,7 @@ export class Verificateur extends Nub {
                 v = 0;
             }
 
-            spIndex ++;
+            spIndex++;
         }
         r.vCalc = v;
 
diff --git a/src/verification/verificateur_params.ts b/src/verification/verificateur_params.ts
index cdca1cbf313981a85b8e527b8e678b8c839cd5ba..4a04db7631fd9b71fbae59cf276ed315d9afb4dd 100644
--- a/src/verification/verificateur_params.ts
+++ b/src/verification/verificateur_params.ts
@@ -1,4 +1,4 @@
-import { ParamsEquation } from "../param/params-equation";
+import { ParamsEquation } from "../internal_modules";
 
 export class VerificateurParams extends ParamsEquation {
 }