diff --git a/e2e/calculate-all-params.e2e-spec.ts b/e2e/calculate-all-params.e2e-spec.ts
index 39129ac615e92f804560d9bd3db5f34e8d14f98b..9003678bdf375829abd642fb6555a3d8ff243914 100644
--- a/e2e/calculate-all-params.e2e-spec.ts
+++ b/e2e/calculate-all-params.e2e-spec.ts
@@ -4,6 +4,7 @@ import { Navbar } from "./navbar.po";
 import { PreferencesPage } from "./preferences.po";
 import { browser, element, by } from "protractor";
 import { testedCalcTypes } from "./tested_calctypes";
+import { scrollPageToTop } from "./util.po";
 
 /**
  * For all calculators, try to calculate every parameter: check that only one parameter
@@ -65,7 +66,7 @@ describe("ngHyd − calculate all parameters of all calculators", async () => {
                         // that the calculable parameters are shown
                         if (ct === 30 && i > 0) {
                             // prevents "Element is not clickable at point"
-                            await browser.executeScript("window.scrollTo(0, 0);");
+                            await scrollPageToTop();
                             const inputLink = element(by.css("#pb-data-results-selector .drs-item a"));
                             await inputLink.click();
                         }
diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 400f4b0abbc88cf80c09be86d6a159f9362823ea..82d81213ae752de04d5fca0cb695ebe9d2e9fd11 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -1,4 +1,5 @@
-import { by, element, ElementFinder, browser } from "protractor";
+import { by, element, ElementFinder, browser, protractor, ElementArrayFinder } from "protractor";
+import { scrollPageToTop, scrollToElement } from "./util.po";
 
 export class CalculatorPage {
 
@@ -25,6 +26,66 @@ export class CalculatorPage {
         return element(by.css("h1"));
     }
 
+    /**
+     * return all selects in the calculator which id is in the form "select_*"
+     */
+    getAllCalculatorSelects(): ElementArrayFinder {
+        return element.all(by.css("mat-select[id^=select_]")); // all mat-select with id starting with "select_"
+    }
+
+    /**
+     * get the option count of a select
+     */
+    async getMatselectOptionCount(select: string | ElementFinder) {
+        const sel = select instanceof ElementFinder ? select : element(by.id(select));
+        await scrollToElement(sel);
+
+        if (await sel.isPresent() && await sel.isDisplayed()) {
+            await sel.click();
+            const options = element.all(by.css(".cdk-overlay-container mat-option"));
+            await sel.sendKeys(protractor.Key.ESCAPE); // close dropdown
+            return await options.count();
+        }
+    }
+
+    /**
+     * get the text of the all given select options
+     */
+    async getMatselectOptionsText(select: string | ElementFinder): Promise<string[]> {
+        const sel = select instanceof ElementFinder ? select : element(by.id(select));
+        await scrollToElement(sel);
+
+        if (await sel.isPresent() && await sel.isDisplayed()) {
+            await sel.click();
+            const options = element.all(by.css(".cdk-overlay-container mat-option span"));
+            let res = [];
+            const nopt = await options.count();
+            for (let o = 0; o < nopt; o++) {
+                const opt = options.get(o);
+                res.push(await opt.getText())
+            }
+            await sel.sendKeys(protractor.Key.ESCAPE); // close dropdown
+
+            return res;
+        }
+    }
+
+    /**
+     * get select current option
+     */
+    async getSelectCurrentOption(select: ElementFinder): Promise<ElementFinder> {
+        const id = await select.getAttribute("id");
+        return element(by.css("mat-select#" + id + " div[id^=mat-select-value-]"))
+    }
+
+    /**
+     * get text of select current option
+     */
+    async getMatselectCurrentOptionText(select: ElementFinder): Promise<string> {
+        const currentOption = await this.getSelectCurrentOption(select);
+        return await currentOption.element(by.css("span span")).getText();
+    }
+
     getSelectById(id: string) {
         return element(by.id(id));
     }
@@ -91,11 +152,11 @@ export class CalculatorPage {
         return element.all(by.css("fixedvar-results var-results table tbody tr"));
     }
 
-    scrollTo(elt: ElementFinder) {
-        browser.controlFlow().execute(function () {
-            browser.executeScript("arguments[0].scrollIntoView(true)", elt.getWebElement());
-        });
-    }
+    // scrollTo(elt: ElementFinder) {
+    //     browser.controlFlow().execute(function () {
+    //         browser.executeScript("arguments[0].scrollIntoView(true)", elt.getWebElement());
+    //     });
+    // }
 
     getFixedResultsTable() {
         return element(by.css(".fixed-results-inner-container table"));
@@ -246,6 +307,7 @@ export class CalculatorPage {
     }
 
     async clickSaveCalcButton() {
+        await scrollPageToTop();
         return await element(by.css("#save-calc")).click();
     }
 
@@ -287,7 +349,7 @@ export class CalculatorPage {
         const container = await this.findParentContainer(elt);
         // find radio buttons
         const button = container.element(by.css("mat-button-toggle.radio_" + mode + " > button"));
-        await browser.executeScript("window.scrollTo(0, 0);"); // sometimes button slides behind navbar and click() fails
+        await scrollPageToTop(); // sometimes button slides behind navbar and click() fails
         await button.click();
         // for "var" mode, close the modal
         if (mode === "var") {
diff --git a/e2e/clone-all-calc.e2e-spec.ts b/e2e/clone-all-calc.e2e-spec.ts
index e55c8b3f461791ffad1b8207ee81070e7c2b8879..ca352163c6d9e521ff65dd44fc3fc3160867356a 100644
--- a/e2e/clone-all-calc.e2e-spec.ts
+++ b/e2e/clone-all-calc.e2e-spec.ts
@@ -4,6 +4,7 @@ import { Navbar } from "./navbar.po";
 import { browser } from "protractor";
 import { PreferencesPage } from "./preferences.po";
 import { testedCalcTypes } from "./tested_calctypes";
+import { scrollPageToTop } from "./util.po";
 
 /**
  * Clone calculators
@@ -48,7 +49,7 @@ describe("ngHyd − clone all calculators with all possible <select> values", ()
                 const sourceValues = await calcPage.storeAllInputValues();
 
                 // clone calculator
-                await browser.executeScript("window.scrollTo(0, 0);");
+                await scrollPageToTop();
                 await calcPage.clickCloneCalcButton();
                 await browser.sleep(300);
 
diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts
index c09edd3c8681301af749ec21aeda27dc34e51a54..038a90e661a28a6526a9b143f407842f3bed4329 100644
--- a/e2e/clone-calc.e2e-spec.ts
+++ b/e2e/clone-calc.e2e-spec.ts
@@ -4,6 +4,7 @@ import { CalculatorPage } from "./calculator.po";
 import { Navbar } from "./navbar.po";
 import { browser } from "protractor";
 import { PreferencesPage } from "./preferences.po";
+import { scrollPageToTop } from "./util.po";
 
 /**
  * Clone calculators
@@ -66,7 +67,7 @@ describe("ngHyd − clone a calculator", () => {
         await browser.sleep(500);
 
         // otherwise clickCloneCalcButton() fails with "Element is not clickable at point"
-        await browser.executeScript("window.scrollTo(0, 0);");
+        await scrollPageToTop();
         await calcPage.clickCloneCalcButton();
         await browser.sleep(500);
 
diff --git a/e2e/lechapt-calmon.e2e-spec.ts b/e2e/lechapt-calmon.e2e-spec.ts
index 4dd2d834c83c4d07e3470c727e06950f8e366bb7..75732b7dd8a5e437f1e23277c9f650bea40d077f 100644
--- a/e2e/lechapt-calmon.e2e-spec.ts
+++ b/e2e/lechapt-calmon.e2e-spec.ts
@@ -40,7 +40,7 @@ describe("Lechapt&Calmon - ", () => {
         await browser.sleep(200);
     }
 
-    xit("when material is modified, results should change", async () => { // temporairement débranché, cf. jalhyd#334 / nghyd#585
+    it("when material is modified, results should change", async () => {
         await setup();
 
         // select last material type
diff --git a/e2e/load-save-session.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts
index 6535d326565c835c536cb993be69d7025922ca9d..31780b9fe2b1a741ca0798b33fe10baf18afb514 100644
--- a/e2e/load-save-session.e2e-spec.ts
+++ b/e2e/load-save-session.e2e-spec.ts
@@ -3,21 +3,84 @@ import { ListPage } from "./list.po";
 import { CalculatorPage } from "./calculator.po";
 import { Navbar } from "./navbar.po";
 import { SideNav } from "./sidenav.po";
-import { browser } from "protractor";
+import { browser, by, element } from "protractor";
 import { PreferencesPage } from "./preferences.po";
+import { expectNumber } from "./util.po";
+
+const fs = require("fs");
+const path = require("path");
+const os = require("os");
+
+let startPage: AppPage;
+let listPage: ListPage;
+let calcPage: CalculatorPage;
+let navbar: Navbar;
+let sidenav: SideNav;
+let prefPage: PreferencesPage;
+
+async function saveSession(): Promise<string> {
+    await calcPage.clickSaveCalcButton();
+    await browser.sleep(500);
+
+    // see: https://stackoverflow.com/questions/21935696/protractor-e2e-test-case-for-downloading-pdf-file
+    const filename = path.resolve(os.homedir(), "Téléchargements/session.json");
+    if (fs.existsSync(filename)) {
+        // Make sure the browser doesn't have to rename the download.
+        fs.unlinkSync(filename);
+    }
+
+    // Le code laissé en commentaire tente de corriger un bug :
+    // il s'écoule 40 secondes entre le clic sur le bouton menu (en haut à gauche) et l'ouverture du sidenav.
+    // Ceci ne se produit que lorsqu'on sauve effectivement la session : si on annule la sauvegarde, il n'y a pas de délai.
+    // https://stackoverflow.com/questions/75235558/delay-after-downloading-a-file-in-protractor-test
+
+    //browser.manage().timeouts().implicitlyWait(100);
+    //browser.ignoreSynchronization = true;
+    // await browser.waitForAngularEnabled(false);
+
+    if (true) {
+        await calcPage.getSaveSessionButton().click();
+    } else {
+        const cancel = element(by.css("dialog-save-session button.mat-primary"));
+        await cancel.click();
+    }
+    await browser.sleep(200);
+    // browser.ignoreSynchronization = false;
+    // await browser.waitForAngularEnabled(true);
+
+    // browser.executeScript('window.stop();');
+
+    // const wins = await browser.driver.getAllWindowHandles();
+    // await browser.switchTo().window(wins[0]);
+
+    // await browser.switchTo().activeElement();
+
+    // const bd = element(by.css("body"));
+    // await browser.actions().mouseMove(bd, { x: 0, y: 0 }).click().perform();
+
+    // await navbar.clickCalculatorTab(0);
+    // await browser.sleep(200);
+
+    // browser.actions().sendKeys(protractor.Key.ESCAPE).perform();
+
+    return filename;
+}
+
+async function loadSession(path: string) {
+    await navbar.clickMenuButton();
+    await browser.sleep(200);
+
+    await sidenav.clickLoadSessionButton();
+    await browser.sleep(200);
+
+    await sidenav.loadSessionFile(path);
+}
 
 /**
  * Save and load (serialise and unserialise) calculators to/from JSON files
  */
 describe("ngHyd − save and load sessions", () => {
-    let startPage: AppPage;
-    let listPage: ListPage;
-    let calcPage: CalculatorPage;
-    let navbar: Navbar;
-    let sidenav: SideNav;
-    let prefPage: PreferencesPage;
-
-    beforeEach(() => {
+    beforeAll(() => {
         startPage = new AppPage();
         listPage = new ListPage();
         calcPage = new CalculatorPage();
@@ -26,17 +89,16 @@ describe("ngHyd − save and load sessions", () => {
         prefPage = new PreferencesPage();
     });
 
+    beforeEach(() => {
+        jasmine.DEFAULT_TIMEOUT_INTERVAL = 45 * 60 * 1000; // 45 min
+        browser.manage().window().setPosition(2000, 30);
+    });
+
     it("when loading session-6-calc.test.json file from home page, 6 calculators should be loaded", async () => {
         await startPage.navigateTo();
 
-        await navbar.clickMenuButton();
-        await browser.sleep(200);
-
-        await sidenav.clickLoadSessionButton();
-        await browser.sleep(200);
-
-        await sidenav.loadSessionFile("./session/session-6-calc.test.json");
-        await browser.sleep(200);
+        await loadSession("./session/session-6-calc.test.json");
+        await browser.sleep(1000);
 
         expect(await navbar.getAllCalculatorTabs().count()).toBe(6);
     });
@@ -44,13 +106,7 @@ describe("ngHyd − save and load sessions", () => {
     it("when loading session-optional-params.test.json file from home page, the calculator should be loaded", async () => {
         await startPage.navigateTo();
 
-        await navbar.clickMenuButton();
-        await browser.sleep(200);
-
-        await sidenav.clickLoadSessionButton();
-        await browser.sleep(200);
-
-        await sidenav.loadSessionFile("./session/session-optional-params.test.json");
+        await loadSession("./session/session-optional-params.test.json");
         await browser.sleep(200);
 
         expect(await navbar.getAllCalculatorTabs().count()).toBe(1);
@@ -73,19 +129,7 @@ describe("ngHyd − save and load sessions", () => {
         await calcPage.getInputById("Ks").sendKeys("42");
         await browser.sleep(1000);
 
-        await calcPage.clickSaveCalcButton();
-
-        // see: https://stackoverflow.com/questions/21935696/protractor-e2e-test-case-for-downloading-pdf-file
-        const fs = require("fs");
-        const path = require("path");
-        const os = require("os");
-        const filename = path.resolve(os.homedir(), "Téléchargements/session.json");
-        if (fs.existsSync(filename)) {
-            // Make sure the browser doesn't have to rename the download.
-            fs.unlinkSync(filename);
-        }
-
-        await calcPage.getSaveSessionButton().click();
+        const filename = await saveSession();
         await browser.sleep(1000);
         const fileContent = fs.readFileSync(filename, { encoding: "utf8" });
 
@@ -93,4 +137,92 @@ describe("ngHyd − save and load sessions", () => {
         expect(fileContent).toContain(`{"symbol":"Ks","mode":"SINGLE","value":42}`);
     });
 
+    it("select value must be recovered when loading a session file", async () => {
+        // start page
+        await startPage.navigateTo();
+        await browser.sleep(200);
+
+        const calcTypes = await listPage.getAvailableCalcTypes();
+
+        const excludedCalculators = [
+            34, // vérificateur (nécessite d'ouvrir plusieurs calculettes)
+        ];
+
+        for (let i = 0; i < calcTypes.length; i++) {
+            const ct = calcTypes[i];
+            if (!excludedCalculators.includes(ct)) {
+                if (i == 0) {
+                    // enable evil option "empty fields on module creation"
+                    await prefPage.navigateTo();
+                    await prefPage.disableEvilEmptyFields();
+                    await browser.sleep(200);
+
+                    // start page
+                    await navbar.clickNewCalculatorButton();
+                    await browser.sleep(200);
+                }
+                else {
+                    // empty session
+                    await navbar.clickMenuButton();
+                    await browser.sleep(200);
+                    await sidenav.clickNewSessionButton();
+                    await browser.sleep(200);
+                }
+
+                // open calculator
+                await listPage.clickMenuEntryForCalcType(ct);
+                await browser.sleep(200);
+
+                // detect selects
+                const selects = calcPage.getAllCalculatorSelects();
+                const nsel = await selects.count();
+                for (let s = 0; s < nsel; s++) {  // /!\ ElementArrayFinder.each() is ASYNCHRONOUS !! https://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.each
+                    const sel = selects.get(s);
+                    const selId = await sel.getAttribute("id");
+
+                    const options = await calcPage.getMatselectOptionsText(sel);
+                    const optionCount = options.length;
+
+                    if (optionCount > 0) {
+                        // index of current selected option
+                        const optTxt = await calcPage.getMatselectCurrentOptionText(sel);
+                        const ind = options.indexOf(optTxt);
+
+                        // select next select option (optionally looping)
+                        const nextInd = (ind + 1) % optionCount;
+                        await calcPage.changeSelectValue(sel, nextInd);
+                        await browser.sleep(200);
+
+                        // save session
+                        const filename = await saveSession();
+                        await browser.sleep(200);
+
+                        // load session
+                        await loadSession(filename); // bug here : the click on the menu button (top left) takes 40s to take effect and open the side nav!)
+                        await browser.sleep(200);
+                        // the displayed calculator is now the loaded one
+
+                        // check the calculator has been loaded
+                        expectNumber("num calcs", await navbar.getCalculatorEntriesCount(), 2);
+
+                        // check the select in the loaded session points to the same option
+                        const sel2 = calcPage.getSelectById(selId);
+
+                        // check the same option is in the select
+                        const optTxt2 = await calcPage.getMatselectCurrentOptionText(sel2);
+                        await browser.sleep(100);
+                        const ind2 = options.indexOf(optTxt2);
+                        expectNumber("opt index", ind2, nextInd);
+
+                        // close last calculator (the loaded one)
+                        await navbar.middleClickCalculatorTab(1);
+                        await browser.sleep(200);
+
+                        // check last calculator has been closed
+                        expectNumber("num calcs(2)", await navbar.getCalculatorEntriesCount(), 1);
+                    }
+                }
+            }
+        }
+    });
 });
diff --git a/e2e/navbar.po.ts b/e2e/navbar.po.ts
index 4fd34062accddf803373854bdaa30e18aa968298..814da4e216a54d63cb9e2bc443e9786a746a8964 100644
--- a/e2e/navbar.po.ts
+++ b/e2e/navbar.po.ts
@@ -31,8 +31,11 @@ export class Navbar {
         const dropDown = element(by.css("mat-select#selectCalculator"));
         if (await dropDown.isPresent() && await dropDown.isDisplayed()) {
             await dropDown.click();
-            const optionId = ".cdk-overlay-container mat-option#mat-option-" + n;
-            const option = element(by.css(optionId));
+
+            // 1st option is not necessarly "mat-option-0"...
+            const options = element.all(by.css(".cdk-overlay-container mat-option"));
+            const option = options.get(n);
+
             await option.click();
         } else {
             const tabs = this.getAllCalculatorTabs();
diff --git a/e2e/pab.e2e-spec.ts b/e2e/pab.e2e-spec.ts
index 2f75f8df9d326d084d4302160a18b7ff431de7ac..866f67fb57da855a5c8ce10d407efd3da5616ffc 100644
--- a/e2e/pab.e2e-spec.ts
+++ b/e2e/pab.e2e-spec.ts
@@ -5,6 +5,7 @@ import { browser, by, element } from "protractor";
 import { AppPage } from "./app.po";
 import { SideNav } from "./sidenav.po";
 import { PreferencesPage } from "./preferences.po";
+import { scrollPageToTop } from "./util.po";
 
 /**
  * Clone calculators
@@ -124,7 +125,7 @@ describe("ngHyd − Passe à Bassins", () => {
             await calcButtonCl.click();
 
             // make sure "Generate PAB" button is visible (it might be hidden behind navbar)
-            await browser.executeScript("window.scrollTo(0, 0);");
+            await scrollPageToTop();
             // generate PAB
             const genButton = calcPage.getGeneratePabButton();
             await genButton.isPresent();
@@ -182,7 +183,7 @@ describe("ngHyd − Passe à Bassins", () => {
             await calcButtonCl.click();
 
             // make sure "Generate PAB" button is visible (it might be hidden behind navbar)
-            await browser.executeScript("window.scrollTo(0, 0);");
+            await scrollPageToTop();
             // create PAB from it, changing modal parameters
             const genButton = calcPage.getGeneratePabButton();
             await genButton.click();
diff --git a/e2e/solveur.e2e-spec.ts b/e2e/solveur.e2e-spec.ts
index a542f32ba20103af9ac8f1e42e886e1df209998e..89ca70d6ed4b357ddf9999ae61b08f9b4c4e5a9c 100644
--- a/e2e/solveur.e2e-spec.ts
+++ b/e2e/solveur.e2e-spec.ts
@@ -5,6 +5,7 @@ import { Navbar } from "./navbar.po";
 import { browser, by, element } from "protractor";
 import { SideNav } from "./sidenav.po";
 import { PreferencesPage } from "./preferences.po";
+import { scrollPageToTop } from "./util.po";
 
 /**
  * Clone calculators
@@ -124,8 +125,8 @@ describe("Solveur - ", () => {
         const hasResults = await calcPage.hasResults();
         expect(hasResults).toBe(true);
 
-        // otherwise clickCloneCalcButton() fails with "Element is not clickable at point"
-        await browser.executeScript("window.scrollTo(0, 0);");
+        await scrollPageToTop(); // otherwise clickCloneCalcButton() fails with "Element is not clickable at point"
+
         await calcPage.clickCloneCalcButton();
         await browser.sleep(500);
 
diff --git a/e2e/util.po.ts b/e2e/util.po.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e772a28ce9c01e0c54f85d0bce84a01df90e7ac5
--- /dev/null
+++ b/e2e/util.po.ts
@@ -0,0 +1,29 @@
+import { ElementFinder, browser } from "protractor";
+
+/**
+ * scroll page to make element visible
+ */
+export async function scrollToElement(elem: ElementFinder) {
+    await browser.executeScript("arguments[0].scrollIntoView({ block: 'center' });", elem.getWebElement());
+    await browser.sleep(50);
+}
+
+/**
+ * scroll page to top
+ */
+export async function scrollPageToTop() {
+    await browser.executeScript("window.scrollTo(0, 0);");
+}
+
+/**
+ * execute expect() on numbers and displays a failure message
+ * @param msg message in caase of failure
+ * @param val value to check
+ * @param expected expected value
+ */
+export function expectNumber(msg: string, val: number, expected: number) {
+    if (val !== expected) {
+        console.log(msg, "got", val, "expected", expected);
+    }
+    expect(val).toEqual(expected);
+}
diff --git a/jalhyd_branch b/jalhyd_branch
index 9e2dece83480eba1020a4a59afd1ed3e8eb63c31..0bd0de8433c44aa322701f9bf4b87ff6d54b525c 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-338-optimiser-l-affichage-des-unites
+334-restructurer-lechapt-et-calmon-pour-de-nouvelles-lois-de-pertes-de-charge
diff --git a/package-lock.json b/package-lock.json
index 9661a8c876a23a46f8118a8d679270b97149b3f7..87ddd2409a061f0e0cd71c99eeb5c547a9235478 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -84,6 +84,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": {
@@ -4138,6 +4139,11 @@
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "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/marked": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz",
@@ -23282,6 +23288,11 @@
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "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/marked": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz",
@@ -29813,6 +29824,7 @@
       "requires": {
         "@types/base-64": "^1.0.0",
         "@types/jasmine": "^4.0.3",
+        "@types/lodash": "^4.14.191",
         "@types/node": "^18.0.3",
         "@typescript-eslint/eslint-plugin": "^5.30.6",
         "@typescript-eslint/parser": "^5.30.6",
diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts
index f612f362aa0ac7e2475b785e0e2bbf76bbded771..042df751799ed61418e5b9a869e2277cb627110d 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.ts
+++ b/src/app/components/fieldset-container/fieldset-container.component.ts
@@ -89,8 +89,8 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit {
             const prms = after.backupParameters();
             // replace in-place to change properties (overkill)
             // @WTF why only those two ?
-            newFs.setNubPropValue("structureType", after.properties.getPropValue("structureType"));
-            newFs.setNubPropValue("loiDebit", after.properties.getPropValue("loiDebit"));
+            newFs.setPropValue("structureType", after.getPropValue("structureType"));
+            newFs.setPropValue("loiDebit", after.getPropValue("loiDebit"));
 
             // au cas où un des paramètres du fieldset source est en mode calcul,
             // on met le paramètre copié en mode fixé (nghyd#567)
diff --git a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
index 86eba4301034bb0bc758ebed7904cf1e4ae25f11..f388647dafbcf7d653fcffd263b87d3dfff40718 100644
--- a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
+++ b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
@@ -92,7 +92,7 @@ export class MacrorugoCompoundResultsComponent extends ResultsComponentDirective
             this.mrcResults
             && this.mrcResults.result
             && this.mrcResults.result.sourceNub
-            && this.mrcResults.result.sourceNub.properties.getPropValue("inclinedApron") === MRCInclination.INCLINED
+            && this.mrcResults.result.sourceNub.getPropValue("inclinedApron") === MRCInclination.INCLINED
         );
     }
 
diff --git a/src/app/components/modules-diagram/modules-diagram.component.ts b/src/app/components/modules-diagram/modules-diagram.component.ts
index 6f227edcbd98057673505915f06def23886df2b3..0b607e51e10e25cb2f5505c3e1bdf0993dfcffe5 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.ts
+++ b/src/app/components/modules-diagram/modules-diagram.component.ts
@@ -265,11 +265,11 @@ export class ModulesDiagramComponent implements AfterContentInit, AfterViewCheck
      */
     private describe(n: Nub) {
         let type = CalculatorType[n.calcType];
-        const nt = n.properties.getPropValue("nodeType");
+        const nt = n.getPropValue("nodeType");
         if (nt) {
             type = SectionType[nt];
         } else {
-            const ld = n.properties.getPropValue("loiDebit");
+            const ld = n.getPropValue("loiDebit");
             if (ld !== undefined) {
                 type = LoiDebit[ld];
             }
diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
index c8eff7ec5fbb007f2b11bf6f48ca87a94e3edab1..ee664e43ad59b3c77bd6e000921cbb11d8c32ea6 100644
--- a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
+++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
@@ -268,7 +268,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
                     ddSeries[sti] = [];
                 }
                 // orifices have no relevant ZDV
-                if (st.properties.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
+                if (st.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
                     // 2 points, to draw a segment
                     ddSeries[sti].push({
                         x: xs[i],
@@ -305,7 +305,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
             }
             // orifices have no relevant ZDV; lift gate will be drawn later for each series
             if (! [ LoiDebit.OrificeSubmerged, LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ]
-                .includes(st.properties.getPropValue("loiDebit"))
+                .includes(st.getPropValue("loiDebit"))
             ) {
                 // 2 points, to draw a segment
                 ddSeries[sti].push({
@@ -403,7 +403,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
                 // draw lift gate if any
                 if (isLastAbscissa) {
                     for (const st of dw.structures) {
-                        if ([ LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ].includes(st.properties.getPropValue("loiDebit"))) {
+                        if ([LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte].includes(st.getPropValue("loiDebit"))) {
                             // skip a point to disjoin line
                             dataN.push({
                                 x: x,
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 8ef4e14c146d960d5b7d726f0fbb1c824a1d3da1..ead6072f13b0af083cdf29b590ab1172de57f28a 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -594,7 +594,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     if (i === 0) { // 1st row
                         deviceParamRow.cells.push({
                             model: ouvrage,
-                            modelValue: ouvrage.properties.getPropValue("loiDebit"),
+                            modelValue: ouvrage.getPropValue("loiDebit"),
                             options: loisCloisons,
                             selectable: ouvrage
                         });
@@ -719,7 +719,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 if (i === 0) { // 1st row
                     deviceParamRowDW.cells.push({
                         model: ouvrage,
-                        modelValue: ouvrage.properties.getPropValue("loiDebit"),
+                        modelValue: ouvrage.getPropValue("loiDebit"),
                         options: loisAval
                     });
                 }
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
index 3762c846cb3fd3c5a11a21d850746f0a024c9074..62c8d3b3b20b6f9d962f626aa482b10cf27b1c2c 100644
--- a/src/app/formulaire/definition/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -31,7 +31,7 @@ export class FormulaireCourbeRemous extends FormulaireSection {
         this._remousResults.parameters = prmCR;
 
         // variable supplémentaire à calculer
-        this._remousResults.extraParamSymbol = this.currentNub.properties.getPropValue("varCalc");
+        this._remousResults.extraParamSymbol = this.currentNub.getPropValue("varCalc");
 
         // calcul
         this._remousResults.result = cr.CalcSerie();
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f2141323a49d79f1ff4fee955ce54213479efdf7..146d1746a8b74f4ffbaf36e2655da910816a9d1f 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -81,14 +81,18 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return this._calculateDisabled;
     }
 
+    private getPropValue(key: string): any {
+        if (this._currentNub === undefined)
+            return this.defaultProperties[key];
+        return this._currentNub.getPropValue(key);
+    }
+
     public get calculatorType(): CalculatorType {
-        const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
-        return props["calcType"];
+        return this.getPropValue("calcType")
     }
 
     public get nodeType(): SectionType {
-        const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
-        return props["nodeType"];
+        return this.getPropValue("nodeType")
     }
 
     public get calculatorName() {
@@ -113,6 +117,27 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return this._props;
     }
 
+    public parseConfigToProps(): Props {
+        const res: Props = new Props();
+
+        const jp = new ConfigParser(this._jsonConfig);
+        for (const fs of jp.forAll("fieldset")) {
+            const fsp = new ConfigParser(fs["fields"]);
+            for (const sel of fsp.forAll("select")) {
+                const p = sel["property"];
+                if (p !== undefined) { // if select has associated property
+                    const v = sel["default"];
+                    if (v !== undefined) { // if select has a default value for associated property
+                        const enumClass = Props.enumFromProperty[p];
+                        res.setPropValue(p, enumClass[v]);
+                    }
+                }
+            }
+        }
+
+        return res;
+    }
+
     /**
      * Creates a Nub from the given properties, and associates it to the current form
      */
@@ -127,7 +152,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     public set currentNub(n: Nub) {
-        const nubCalcType = (n.properties as Props).getPropValue("calcType");
+        const nubCalcType = n.getPropValue("calcType");
         if (this._props["calcType"] !== nubCalcType) {
             throw new Error(
                 `Nub ${n.properties["calcType"]} incompatible avec le formulaire ${this._calculatorName} (${this._props["calcType"]})`
diff --git a/src/app/formulaire/definition/form-espece.ts b/src/app/formulaire/definition/form-espece.ts
index 10ded3b83c1994fec8e6ff43cd5d5a684d13a79b..f0a36b93e1f5c9d4213438bd9095b25a7170292b 100644
--- a/src/app/formulaire/definition/form-espece.ts
+++ b/src/app/formulaire/definition/form-espece.ts
@@ -10,7 +10,7 @@ export class FormulaireEspece extends FormulaireFixedVar {
 
     protected completeParse(firstNotif: boolean = true) {
         super.completeParse(firstNotif);
-        this.updateDivingJetCriteriaInputs(this.currentNub.properties.getPropValue("divingJetSupported"));
+        this.updateDivingJetCriteriaInputs(this.currentNub.getPropValue("divingJetSupported"));
     }
 
     /**
diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
index 0a329f489308d59093da98d30da932a160e249fa..8eb6917e75496d210925a4bd8ab355c6ece3e107 100644
--- a/src/app/formulaire/definition/form-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -63,7 +63,7 @@ export class FormulaireFixedVar extends FormulaireDefinition {
 
     public afterParseFieldset(fs: FieldSet) {
         // observe all Select fields @see this.update()
-        fs.properties.addObserver(this);
+        fs.addPropertiesObserver(this);
     }
 
     protected completeParse(firstNotif: boolean = true) {
diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
index ec470e645ca81406ae5e353736467e77427508ba..306332cb56def101c15cd82afcb095fb06aa4fb3 100644
--- a/src/app/formulaire/definition/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -56,7 +56,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         super.completeParse(firstNotif);
         this.fieldsetContainer.addObserver(this);
         if (firstNotif) {
-            this.updateApronState(this.currentNub.properties.getPropValue("inclinedApron"));
+            this.updateApronState(this.currentNub.getPropValue("inclinedApron"));
         }
     }
 
diff --git a/src/app/formulaire/definition/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts
index b47c4808b021bba832df9c201b65ebc4aadb76f5..a5de99edd14ca3a699a0e1f3c502e49879046d80 100644
--- a/src/app/formulaire/definition/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-parallel-structures.ts
@@ -1,4 +1,4 @@
-import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition, Prop_NullParameters } from "jalhyd";
+import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition, Prop_NullParameters, IProperties } from "jalhyd";
 
 import { FieldsetContainer } from "../elements/fieldset-container";
 import { FieldSet } from "../elements/fieldset";
@@ -71,7 +71,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * and return it; does not store it in the Session (for Structures, not for Calculator Modules)
      * @param p properties for the new Nub
      */
-    protected createStructure(p: Props): Structure {
+    protected createStructure(p: IProperties): Structure {
         return Session.getInstance().createNub(p, this.currentNub as ParallelStructure) as Structure;
     }
 
@@ -81,9 +81,9 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * @param sn Structure to replace
      * @param params properties to build the new Nub (calcType, loiDebit...)
      */
-    protected replaceNub(sn: Structure, params: Props): Nub {
+    protected replaceNub(sn: Structure): Nub {
         const parent = (this.currentNub as ParallelStructure);
-        const newStructure = this.createStructure(params);
+        const newStructure = this.createStructure(sn);
         parent.replaceChildInplace(sn, newStructure);
         return newStructure;
     }
@@ -108,7 +108,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * @param name nom de la propriété qui vient de changer
      * @param val nouvelle valeur de la propriété
      */
-    protected adjustProperties(props: Props, name: string, val: any) {
+    protected adjustProperties(props: IProperties, name: string, val: any) {
         if (name === "structureType") {
             if (! StructureProperties.isCompatibleValues(
                 val, props.getPropValue("loiDebit"), this.currentNub as ParallelStructure
@@ -159,12 +159,12 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
         } else if (sender instanceof FieldSet && data.action === "propertyChange") {
             switch (sender.id) {
                 case "fs_ouvrage":
-                    const props = sender.properties;
                     // ensure loiDebit is set
-                    props.setPropValue("loiDebit", data.value);
-                    this.adjustProperties(props, data["name"], data["value"]);
+                    //props.setPropValue("loiDebit", data.value); // ?? et si la propriété modifiée n'est pas la loi de débit ?
+
+                    this.adjustProperties(sender, data["name"], data["value"]);
                     // replace Structure Nub
-                    const newNub = this.replaceNub((sender.nub as Structure), props);
+                    const newNub = this.replaceNub(sender.nub as Structure);
                     sender.setNub(newNub);
                     // treat the fieldset as new to re-subscribe to Nub properties change events
                     this.afterParseFieldset(sender);
diff --git a/src/app/formulaire/definition/form-pb-cloison.ts b/src/app/formulaire/definition/form-pb-cloison.ts
index 25910c87d6a1ed5681bd8d7af9e5a45092f876c0..145c03fe403d38338dc557da1f3cb41a2cf29c89 100644
--- a/src/app/formulaire/definition/form-pb-cloison.ts
+++ b/src/app/formulaire/definition/form-pb-cloison.ts
@@ -27,12 +27,12 @@ export class FormulairePbCloison extends FormulaireParallelStructure {
         } else if (sender instanceof FieldSet && data.action === "propertyChange") {
             switch (sender.id) {
                 case "fs_ouvrage":
-                    const props = sender.properties;
                     // ensure loiDebit is set
-                    props.setPropValue("loiDebit", data.value);
-                    this.adjustProperties(props, data["name"], data["value"]);
+                    //props.setPropValue("loiDebit", data.value); // ?? et si la propriété modifiée n'est pas la loi de débit ?
+
+                    this.adjustProperties(sender, data["name"], data["value"]);
                     // replace Structure Nub
-                    const newNub = this.replaceNub((sender.nub as Structure), props);
+                    const newNub = this.replaceNub(sender.nub as Structure);
                     sender.setNub(newNub);
                     // treat the fieldset as new to re-subscribe to Nub properties change events
                     this.afterParseFieldset(sender);
diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts
index 95e5f65498b3ad929c00730266a3fa0ccb33d221..c9a0d9e0db35efb7ff665b637520798032944bf6 100644
--- a/src/app/formulaire/definition/form-prebarrage.ts
+++ b/src/app/formulaire/definition/form-prebarrage.ts
@@ -367,7 +367,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
                     } catch (e) {
                         let res;
                         if (p.parentNub.calcType === CalculatorType.Structure) {
-                            res = p.parentNub.getParent().uid;
+                            res = p.parentNub.parent.uid;
                         } else {
                             res = p.parentNub.uid;
                         }
diff --git a/src/app/formulaire/definition/form-pressureloss.ts b/src/app/formulaire/definition/form-pressureloss.ts
index 60c98da99b692a86de8de20bc0025ff96d6327c6..4b1e7ceb4188e1d4cb2d4f4caf03b4da1f827b80 100644
--- a/src/app/formulaire/definition/form-pressureloss.ts
+++ b/src/app/formulaire/definition/form-pressureloss.ts
@@ -1,4 +1,4 @@
-import { PressureLoss, Props, PressureLossType } from "jalhyd";
+import { PressureLoss, Props, PressureLossType, Session, PressureLossLaw, CalculatorType } from "jalhyd";
 import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
@@ -17,8 +17,19 @@ export class FormulairePressureLoss extends FormulaireFixedVar {
         if (props === undefined) {
             props = new Props();
         }
+
+        // create pressure loss parent nub
+        const pll = this.defaultProperties["pressureLossType"];
         props.setPropValue("calcType", this.calculatorType);
-        props.setPropValue("pressureLossType", this.defaultProperties["pressureLossType"]);
+        props.setPropValue("pressureLossType", pll);
         super.initNub(props);
+
+        // create pressure loss law child nub
+        const propsLaw: Props = new Props();
+        const pressureLossCalc: CalculatorType = PressureLossLaw.calcTypeFromPressureLossLaw[pll];
+        propsLaw.setPropValue("calcType", pressureLossCalc);
+        const law = Session.getInstance().createNub(propsLaw) as PressureLossLaw;
+        const pl: PressureLoss = this.currentNub as PressureLoss;
+        pl.setLaw(law);
     }
 }
diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts
index 8f8be0af96d577110333fe270c861ec7297c621f..bf06c16b257e578889469d86dc696f6ea15249a0 100644
--- a/src/app/formulaire/definition/form-section.ts
+++ b/src/app/formulaire/definition/form-section.ts
@@ -7,16 +7,14 @@ import { SectionType } from "jalhyd";
 
 export class FormulaireSection extends FormulaireFixedVar {
 
-    /** for SectionNubs only */
-    protected _defaultSectionType;
-
     /**
      * determine default section type from select configuration
      */
     private parseDefaultSectionType() {
-        if (this._defaultSectionType === undefined) {
+        if (this.defaultProperties["nodeType"] === undefined) // still use "nodeType" for consistency, should be named "sectionType"
+        {
             const def = this.parseSelectDefaultValue(this._jsonConfig, "select_section");
-            this._defaultSectionType = SectionType[def];
+            this.defaultProperties["nodeType"] = SectionType[def];
         }
     }
 
@@ -31,7 +29,7 @@ export class FormulaireSection extends FormulaireFixedVar {
             // add new Section as first child, from given nodeType
             const propsSection = new Props();
             propsSection.setPropValue("calcType", CalculatorType.Section);
-            propsSection.setPropValue("nodeType", this._defaultSectionType);
+            propsSection.setPropValue("nodeType", this.defaultProperties["nodeType"]);
             propsSection.setPropValue(Prop_NullParameters, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
             const section = Session.getInstance().createNub(propsSection);
             this.currentNub.setSection(section as acSection);
diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts
index f658c98eefb762eece2bae95a7180273a8f307ae..0a3d446efac3a99a2fa2165f3b0916462fcfeb5a 100644
--- a/src/app/formulaire/definition/form-solveur.ts
+++ b/src/app/formulaire/definition/form-solveur.ts
@@ -58,7 +58,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                     // if searchedParam is set to a value that won't be available anymore
                     // once nubToCalculate is updated, setPropValue throws an error, but
                     // nubToCalculate is updated anyway; here, just inhibit the error
-                    this._currentNub.properties.setPropValue("nubToCalculate", data.value.value);
+                    this._currentNub.setPropValue("nubToCalculate", data.value.value);
                 } catch (e) { }
                 // refresh targetted result selector
                 const trSel = this.getFormulaireNodeById(this._targettedResultSelectId) as SelectField;
@@ -73,7 +73,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                 // update Solveur property: searched Parameter
                 try {
                     const p: ParamDefinition = data.value.value;
-                    this._currentNub.properties.setPropValue(
+                    this._currentNub.setPropValue(
                         "searchedParameter",
                         p.nubUid + "/" + p.symbol
                     );
diff --git a/src/app/formulaire/definition/form-verificateur.ts b/src/app/formulaire/definition/form-verificateur.ts
index 893754665a7cb997437bf7ab7aaa26b6643c9695..337bc789a44d1b06666e4133196d80f3aeb2736e 100644
--- a/src/app/formulaire/definition/form-verificateur.ts
+++ b/src/app/formulaire/definition/form-verificateur.ts
@@ -97,7 +97,7 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
             this.reset(); // reset results
             if (sender.id === "select_target_pass" && data.action === "select") {
                 // update Verificateur property: Pass to check
-                this._currentNub.properties.setPropValue("nubToVerify", data.value ? data.value.value : undefined);
+                this._currentNub.setPropValue("nubToVerify", data.value ? data.value.value : undefined);
 
             } else if (sender.id === "select_species_list" && data.action === "select") {
                 // update Verificateur property: Species list (string[])
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index d0229afe762326464684558389b299439dd7f7d0..3637d892d27725fe0d7a7d84ad805c3ee589f63b 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -1,7 +1,7 @@
 import {
     CalculatorType,
     ParamDefinition,
-    Props,
+    IProperties,
     Observer,
     Nub,
     enumValueFromString
@@ -16,7 +16,7 @@ import { SelectFieldFactory } from "./select/select-field-factory";
 import { FormulaireFixedVar } from "../definition/form-fixedvar";
 import { SelectEntry } from "./select/select-entry";
 
-export class FieldSet extends FormulaireElement implements Observer {
+export class FieldSet extends FormulaireElement implements IProperties {
 
     /** Nub associé */
     private _nub: Nub;
@@ -45,7 +45,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     private addField(f: Field) {
-        if (! f) {
+        if (!f) {
             throw new Error("FieldSet.addField() : argument incorrect (undefined)");
         }
         this.kids.push(f);
@@ -114,40 +114,8 @@ export class FieldSet extends FormulaireElement implements Observer {
         return res;
     }
 
-    public get properties(): Props {
-        return this.nub.properties;
-    }
-
-    private get sectionProperties(): Props {
-        const section = this.nub.getChildren()[0];
-        if (section) {
-            return section.properties;
-        } else {
-            return new Props();
-        }
-    }
-
-    /**
-     * get associated nub property value
-     * @param key property name
-     * @param inSection if true, will look for the required property in the Nub's section (children[0])
-     */
-    private getNubPropValue(key: string, inSection: boolean = false): any {
-        if (inSection) {
-            return this.sectionProperties.getPropValue(key);
-        } else {
-            return this.properties.getPropValue(key);
-        }
-    }
-
-    /**
-     * assign associated nub property
-     * @param key nub property name
-     * @param val value to assign with
-     * @returns true if property value has changed
-     */
-    public setNubPropValue(key: string, val: any): boolean {
-        return this.properties.setPropValue(key, val, this);
+    public addPropertiesObserver(o: Observer) {
+        this.nub.addPropertiesObserver(o);
     }
 
     private getNubParamFromSymbol(symbol: string): ParamDefinition {
@@ -250,7 +218,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     private setSelectValueFromProperty(selectId: string, inSection: boolean = false) {
         const selectField: SelectField = this.getFormulaireNodeById(selectId) as SelectField;
         if (selectField) {
-            let propVal: any = this.getNubPropValue(selectField.associatedProperty, inSection);
+            let propVal: any = this.getPropValue(selectField.associatedProperty, inSection);
             if (propVal === undefined) {
                 propVal = ""; // clodo bullet-proof loading
             }
@@ -277,9 +245,9 @@ export class FieldSet extends FormulaireElement implements Observer {
         this._helpLink = json["help"];
 
         const ct: string = json["calcType"];
-        const currentCt = this.properties.getPropValue("calcType");
+        const currentCt = this.getPropValue("calcType");
         const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : this.parentForm.calculatorType);
-        this.setNubPropValue("calcType", calc_type);
+        this.setPropValue("calcType", calc_type);
 
         // parse fields once, so that SelectField elements are present
         // when setting default properties below
@@ -293,9 +261,9 @@ export class FieldSet extends FormulaireElement implements Observer {
                     const prop = sel.associatedProperty;
                     const defaultValue = sel.configDefaultValue;
                     // Sets Nub default property, unless this property is already set
-                    const currentValue = this.properties.getPropValue(prop);
+                    const currentValue = this.getPropValue(prop);
                     if (defaultValue !== undefined && currentValue === undefined) {
-                        this.setNubPropValue(prop, enumValueFromString(prop, defaultValue));
+                        this.setPropValue(prop, enumValueFromString(prop, defaultValue));
                     }
                 }
             }
@@ -314,7 +282,7 @@ export class FieldSet extends FormulaireElement implements Observer {
 
     public getNodeParameterValue(symbol: string): number {
         const p = this.getNodeParameter(symbol);
-        if (! p) {
+        if (!p) {
             throw new Error(`FieldSet.getNodeParameterValue() : pas de paramètre ${symbol} trouvé`);
         }
 
@@ -336,7 +304,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     public getSelectedValue(selectFieldId: string): string | string[] {
         for (const p of this.kids) {
             if (p instanceof SelectField && p.isDisplayed && p.id === selectFieldId) {
-                if (! p.multiple) {
+                if (!p.multiple) {
                     const value: string = (p.getValue() as SelectEntry).value;
                     return FormulaireElement.removePrefix(value, selectFieldId + "_");
                 } else {
@@ -359,7 +327,7 @@ export class FieldSet extends FormulaireElement implements Observer {
                     if (senderId === "select_section") {
                         // sections paramétrées, courbes de remous, régimes uniformes
                         // "nodeType" is a property of the section child, not of the parent
-                        const oldNodeType = this.nub.getChildren()[0].properties.getPropValue("nodeType");
+                        const oldNodeType = this.nub.getChildren()[0].getPropValue("nodeType");
                         if (oldNodeType !== data.value.value) { // avoid infinite loops
                             // manually notify parent so that it replaces the child Nub @WARNING clodo trick
                             this.parentForm.update(this, {
@@ -380,9 +348,9 @@ export class FieldSet extends FormulaireElement implements Observer {
                                             const prop = sel.associatedProperty;
                                             // for multiple select
                                             if (Array.isArray(data.value)) {
-                                                this.setNubPropValue(prop, data.value.map((v: any) => v.value));
+                                                this.setPropValue(prop, data.value.map((v: any) => v.value));
                                             } else {
-                                                this.setNubPropValue(prop, data.value.value);
+                                                this.setPropValue(prop, data.value.value);
                                             }
                                         }
                                     }
@@ -394,4 +362,43 @@ export class FieldSet extends FormulaireElement implements Observer {
             }
         }
     }
+
+    // interface IProperties
+
+    public hasProperty(key: string): boolean {
+        return this._nub.hasProperty(key);
+    }
+
+    /**
+     * list of properties keys
+     */
+    public get keys(): string[] {
+        return this._nub.keys;
+    }
+
+    /**
+     * get associated nub property value
+     * @param key property name
+     * @param inSection if true, will look for the required property in the Nub's section (children[0])
+     */
+    public getPropValue(key: string, inSection: boolean = false): any {
+        if (inSection) {
+            const section = this.nub.getChildren()[0];
+            if (section) {
+                return section.getPropValue(key);
+            }
+            return undefined;
+        }
+        return this.nub.getPropValue(key);
+    }
+
+    /**
+     * assign associated nub property
+     * @param key nub property name
+     * @param val value to assign with
+     * @returns true if property value has changed
+     */
+    public setPropValue(key: string, val: any): boolean {
+        return this.nub.setPropValue(key, val, this);
+    }
 }
diff --git a/src/app/formulaire/elements/formulaire-element.ts b/src/app/formulaire/elements/formulaire-element.ts
index 579b62648b34a662d8edba307d86920a98ff32d3..25b5943fa846c1790b151d0aa5d01cfec1aae4da 100644
--- a/src/app/formulaire/elements/formulaire-element.ts
+++ b/src/app/formulaire/elements/formulaire-element.ts
@@ -56,6 +56,10 @@ export abstract class FormulaireElement extends FormulaireNode {
      */
     public get parentForm(): FormulaireDefinition {
         let res = this.parent;
+        if (res === undefined) {
+            return undefined;
+        }
+
         // while (!(res instanceof FormulaireDefinition))
         while (!("calculatorName" in res)) {
             // pour éviter de faire référence au type FormulaireDefinition, supprimer l'import correspondant et
diff --git a/src/app/formulaire/elements/select/select-field-device-loi-debit.ts b/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
index 07c1f555a52e05e8664209e9ec2ee510ed83ad01..683adebaefa22e1b2a35176cdb90bc19889f8377 100644
--- a/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
+++ b/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
@@ -34,7 +34,7 @@ export class SelectFieldDeviceLoiDebit extends SelectField {
      */
     private get loiDebit(): LoiDebit {
         const child = this.nub.getChildren()[this.parent.indexAsKid()];
-        return child.properties.getPropValue("loiDebit");
+        return child.getPropValue("loiDebit");
     }
 
     protected populate() {
diff --git a/src/app/formulaire/elements/select/select-field-device-structure-type.ts b/src/app/formulaire/elements/select/select-field-device-structure-type.ts
index 7b188d114de529c84e9c403274e689986f9d408a..0d1ce351d60caaf53c572e8f91f7bef415917c0d 100644
--- a/src/app/formulaire/elements/select/select-field-device-structure-type.ts
+++ b/src/app/formulaire/elements/select/select-field-device-structure-type.ts
@@ -21,6 +21,14 @@ export class SelectFieldDeviceStructureType extends SelectField {
         this._configDefaultValue = json["default"];
     }
 
+    /**
+    * get discharge law linked to this select's nub
+    */
+    private get structureType(): StructureType {
+        const child = this.nub.getChildren()[this.parent.indexAsKid()];
+        return child.getPropValue("structureType");
+    }
+
     protected populate() {
         // possible values depend on CalcType
         for (const st in (this.nub as ParallelStructure).getLoisAdmissibles()) {
@@ -30,6 +38,6 @@ export class SelectFieldDeviceStructureType extends SelectField {
     }
 
     protected initSelectedValue() {
-        this.findAndSetDefaultValue();
+        this.findAndSetDefaultValue(StructureType[this.structureType]);
     }
 }
diff --git a/src/app/formulaire/elements/select/select-field-nub-prop.ts b/src/app/formulaire/elements/select/select-field-nub-prop.ts
index 4fa8c4e862ff14dbbbde8b26d2a31ff49fcc50ac..233502db06a61c1133285507ce23046cf615f396 100644
--- a/src/app/formulaire/elements/select/select-field-nub-prop.ts
+++ b/src/app/formulaire/elements/select/select-field-nub-prop.ts
@@ -1,6 +1,5 @@
-import { Session } from "jalhyd";
+import { Props } from "jalhyd";
 import { FormulaireNode } from "../formulaire-node";
-import { SelectEntry } from "./select-entry";
 import { SelectField } from "./select-field";
 
 /*
@@ -27,7 +26,7 @@ export class SelectFieldNubProperty extends SelectField {
 
     protected populate() {
         // find enum associated to property
-        const enumClass = Session.enumFromProperty[this._associatedProperty];
+        const enumClass = Props.enumFromProperty[this._associatedProperty];
         if (enumClass !== undefined) {
             // add one select entry per enum entry, in the enum order
             for (let j = 0; j < Object.keys(enumClass).length / 2; j++) {
diff --git a/src/app/formulaire/elements/select/select-field.ts b/src/app/formulaire/elements/select/select-field.ts
index 86a9880048beb87da66730ef9ec3b69a45c770b3..2b9b65aa97fc770e1548718791597698decb7a09 100644
--- a/src/app/formulaire/elements/select/select-field.ts
+++ b/src/app/formulaire/elements/select/select-field.ts
@@ -50,6 +50,10 @@ export abstract class SelectField extends Field {
      * associated nub
      */
     protected get nub(): Nub {
+        const parent = this.parentForm;
+        if (parent === undefined) {
+            return undefined;
+        }
         return (this.parentForm as FormulaireDefinition).currentNub;
     }
 
@@ -128,22 +132,39 @@ export abstract class SelectField extends Field {
     }
 
     /**
-     * try to find a default value to select
+     * Try to find a default value to select.
+     * Priority order :
+     *   - passed parameter
+     *   - nub value for associated property
+     *   - default value from configuration file
+     *   - first select entry
      */
     protected findAndSetDefaultValue(value?: string) {
         // default to first available entry if any
         if (this._entries.length > 0) {
             let val: SelectEntry;
+
             if (value !== undefined) {
                 val = this.getEntryFromValue(enumValueFromString(this._associatedProperty, value));
-            } else if (this._configDefaultValue === undefined) {
-                val = this._entries[0];
+                if (val === undefined) {
+                    throw Error("invalid select default value " + value + " for " + this._associatedProperty + " property");
+                }
             } else {
-                val = this.getEntryFromValue(enumValueFromString(this._associatedProperty, this._configDefaultValue));
+                if (this.nub !== undefined) {
+                    val = this.getEntryFromValue(this.nub.getPropValue(this._associatedProperty));
+                    // nub may not have "this._associatedProperty" as a property
+                }
+                if (val === undefined && this._configDefaultValue !== undefined) {
+                    val = this.getEntryFromValue(enumValueFromString(this._associatedProperty, this._configDefaultValue));
+                    if (val === undefined) {
+                        throw Error("invalid select default value " + this._configDefaultValue + " for " + this._associatedProperty + " property");
+                    }
+                }
                 if (val === undefined) {
-                    throw Error("invalid select default value " + this._configDefaultValue + " for " + this._associatedProperty + " property");
+                    val = this._entries[0];
                 }
             }
+
             if (this._multiple) {
                 this.setValue([val]);
             } else {
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index 880741539bbb62d7a033a5dedc60ad76cc84eeaf..a32a1aec446448eb849d26fcddc3c5d77b81497f 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -371,7 +371,9 @@ export class FormulaireService extends Observable {
         if (nub) {
             f.currentNub = nub;
         } else {
-            f.initNub();
+            const confProps = f.parseConfigToProps();
+            confProps.setPropValue("calcType", ct);
+            f.initNub(confProps);
         }
 
         // Restaure le nom du module, sinon affecte le nom par défaut