diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index 342b4e970cae3ba5d011e6de6c2cea9484c086ca..306e7fcf319054e8e42c656cb6b89e13511493c9 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -13,7 +13,7 @@ Elle est déclinée à l'aide d'Electron et Cordova sous forme d'application hor
 
 Les tests unitaires sont réalisés avec Protractor.
 
-La documentation est générée avec Mkdocs.
+La documentation est générée avec Mkdocs, pandoc et LaTeX.
 
 ## Pile logicielle
 
@@ -24,6 +24,8 @@ La documentation est générée avec Mkdocs.
  * electron
  * cordova
  * mkdocs
+ * pandoc
+ * LaTeX
 
 ## Prérequis
 
@@ -34,6 +36,8 @@ La documentation est générée avec Mkdocs.
  * wine (pour Electron / windows)
  * java (pour cordova / Android)
  * SDK Android (pour cordova / Android)
+ * pandoc (pour la documentation PDF)
+ * une distribution LaTeX, par exemple texlive (pour la documentation PDF)
 
 ### pour l'exécution
 
@@ -60,9 +64,7 @@ Pour chaque module chargé en session, un arbre d'objets partant d'une instance
 
 #### formulaires
 
-Les formulaires dérivent de `FormulaireBase`. Lors de leur instanciation, ils se chargent de lire leur configuration (voir "configuration/modules" ci-dessous) et instancier les éléments enfants qui y sont déclarés : groupes de champs ("fieldset"), groupes de champs répétables ("fieldset_container"), paramètres d'entrée ("ngparam"), listes déroulantes ("select_field"). Ensuite le formulaire est lié au Nub de JaLHyd correspondant au module créé.
-
-Chaque formulaire est associé à une instance d'une classe `FormCompute*` et une instance d'une classe `FormResult*`. La première est chargée d'exécuter le Nub de JaLHYd associé au formulaire, et de transmettre les résultats de calcul à la seconde. La seconde est chargée d'organiser les résultats (par défaut les grouper en résultats fixes / résultats variés) afin de faciliter leur représentation par les composants graphiques.
+Les formulaires dérivent de `FormulaireDefinition`. Lors de leur instanciation, ils se chargent de lire leur configuration (voir "configuration/modules" ci-dessous) et instancier les éléments enfants qui y sont déclarés : groupes de champs ("fieldset"), groupes de champs répétables ("fieldset_container"), paramètres d'entrée ("ngparam"), listes déroulantes ("select_field"). Ensuite le formulaire est lié au Nub de JaLHyd correspondant au module créé.
 
 ### configuration
 
@@ -76,7 +78,7 @@ Dans `themes` on trouve l'organisation des modules en thèmes sur la page d'accu
 
 #### modules
 
-Chaque module de calcul JaLHyd doit être configuré dans `src/app/calculators`, dans un dossier portant le nom du module.
+Chaque module de calcul de JaLHyd doit être configuré dans `src/app/calculators`, dans un dossier portant le nom du module.
 
 Le fichier de configuration principal est `src/app/calculators/lemodule/config.json` (exemple pour le module "bief" : `src/app/calculators/bief/config.json`). Il contient la liste des composants graphiques à afficher à l'écran, de haut en bas (généralement des "fieldset"), la répartition des paramètres du module dans ces éléments, et un bloc de configuration à la fin.
 
@@ -92,7 +94,7 @@ Les chaînes de l'application sont traduites à l'aide du service `I18nService`,
 
 Les traductions doivent être placées dans les fichiers de langues du dossier `src/locale`.
 
-Lorsqu'un module de calcul a besoin d'une traduction contextualisée, par exemple dans le cas d'une variable ayant le même symbole que dans d'autres modules de calcul, les traductions doivent être placées dans `src/app/calculators/lemodule/lemodule.lalangue.json` (exemple pour le module "bief" en anglais : `src/app/calculators/bief/bief.en.json`).
+Lorsqu'un module de calcul a besoin d'une traduction contextualisée, par exemple dans le cas d'une variable ayant le même symbole que dans d'autres modules de calcul, les traductions doivent être placées dans `src/app/calculators/lemodule/lalangue.json` (exemple pour le module "bief" en anglais : `src/app/calculators/bief/en.json`).
 
 ### electron
 
@@ -112,19 +114,25 @@ Le déploiement de ngHyd sous forme d'application mobile se fait à l'aide de Co
 
 ### documentation
 
-La documentation est générée à l'aide de MkDocs.
+La documentation est générée à l'aide de MkDocs (`npm run mkdocs`).
 
 Les fichiers source pour une langue donnée se trouvent dans le dossier `docs/lang` (ex: `docs/fr`). Pour traduire la documentation dans une autre langue, il faut recopier l'intégralité des fichiers source puis les traduire. Afin de faciliter les liens de l'application vers la documentation, les noms des fichiers ne sont pas traduits et restent en français pour toutes les langues.
 
 L'organisation hiérarchique de la documentation est définie dans les fichiers `mkdocs-lang.yml` (ex: `mkdocs-fr.yml`).
 
+#### version PDF
+
+La documentation de chaque langue est compilée au format PDF via pandoc, qui convertit les sources markdown vers du LaTeX. Cette conversion est réalisée par le script python 3 `mkdocs2pdf.py`.
+
+Les préambules LaTeX pour chaque langue se trouvent dans `docs/latex`, par exemple `docs/latex/cassiopee_doc_fr.tex`. Les PDF générés sont placés dans `src/assets/docs/pdf`.
+
 ### tests unitaires
 
 Les tests unitaires dits "end-to-end" ou "e2e" sont réalisés avec Protractor, basé sur Selenium et fourni avec Angular. Les tests se trouvent dans le dossier `e2e` et sont configurés dans `protractor.conf.js`.
 
 Bien qu'elle soit supposée fonctionner avec d'autres navigateurs, l'exécution des tests n'est garantie qu'avec Chrome / Chromium. Le pilote Selenium pour Chrome ("chromedriver") posant parfois problème, `protractor.conf.js` contient une astuce qui recherche le pilote dans le système avant de le rechercher dans node_modules.
 
-Pour plus d'informations sur les problèmes liés à la version du pilote Selenium pour Chrome, consulter le chapitre "chromedriver version in e2e tests" dans la documentation développeurs (en anglais).
+Pour plus d'informations sur les problèmes liés à la version du pilote Selenium pour Chrome, consulter le chapitre "chromedriver version in e2e tests" dans la documentation utilisateurs (en anglais).
 
 ### scripts
 
@@ -170,9 +178,10 @@ Dans cet exemple, on définit un seul groupe de champs nommé arbitrairement "fs
 Le deuxième et dernier bloc contient les options pour ce module: le paramètre à calculer par défaut (`idCal`) qui peut être différent de celui choisi dans JaLHyd, et le lien vers la page de documentation pour ce module (`help`).
 
 Les options peuvent également contenir :
- * `defaultNodeType` : le type de noeud par défaut du module de calcul. Ce champ sert par exemple pour les sections paramétrées à déterminer le type de section à afficher lors de la création du module. Si ce champ est absent, sa valeur est `ComputeNodeType.None`.
+ * `defaultNodeType` : le type de section par défaut du module de calcul, pour les modules contenant une section
  * les valeurs par défaut des **propriétés** du module
  * les identifiants des listes déroulantes
+ * l'aide associée aux résultats (voir ci-dessous)
 
 #### aide contextuelle
 
@@ -230,36 +239,160 @@ Dans les fichiers `locale/messages.*.json` :
 
 ### classes de formulaire personnalisées
 
-En général la classe `FormulaireBase` est suffisante pour gérer un nouveau module, et est instanciée automatiquement par `FormulaireService` lors de la création d'un nouveau module. Elle agrège des instances de `FormComputeFixedVar` et `FormResultFixedVar`.
+En général la classe `FormulaireDefinition` est suffisante pour gérer un nouveau module, et est instanciée automatiquement par `FormulaireService` lors de la création d'un nouveau module.
 
 Mais dans des cas plus complexes, par exemple si le module contient des listes déroulantes ou des sous-modules, répétables ou non, il est nécessaire de créer de nouvelles classes de formulaires dérivées de celles-ci.
 
 Dans un tel cas, créer la classe du formulaire dans un nouveau fichier, dans le dossier `src/app/formulaire/definition` Par exemple `form-macrorugo-compound.ts`.
 
-Si les mécanismes de calcul ou de récupération des résultats doivent être modifiés, créer les classes nécessaires dans le dossier `src/app/formulaire/definition`, par exemple `form-compute-macrorugo-compound.ts` et `form-result-macrorugo-compound.ts`. Sinon, agréger des classes `FormCompute*` et `FormResult*` existantes.
-
 Si une nouvelle classe de formulaire a été créée, ajouter un `case` dans la méthode `newFormulaire()` de `FormulaireService`, dans `src/app/services/formulaire.service.ts`. Exemple :
 
 ```typescript
-case CalculatorType.Trigo:
-  f = new FormulaireTrigo();
+case CalculatorType.MacroRugoCompound:
+  f = new FormulaireMacrorugoCompound();
   break;
 ```
 
+### si le formulaire comprend des listes déroulantes
+
+Les listes déroulantes sont toujours associées à des **propriétés** du Nub.
+
+En général les valeurs autorisées sont tirées de l'**enum** correspondant, d'après le tableau `Session.enumFromProperty` de JaLHyd. Pour les autres cas, voir "si la liste n'est pas associée à un enum" ci-dessous.
+
+#### configuration
+
+Dans le fichier de configuration du module, ajouter la définition des listes déroulantes dans "fields", notamment la propriété associée et la valeur par défaut. Puis dans le bloc de configuration, déclarer les identifiants des listes dans "selectIds". Exemple dans `trigo/config.json`
+
+```json
+{
+    …
+    "fields": [
+        {
+            "id": "select_operation",
+            "type": "select",
+            "property": "trigoOperation",
+            "default": "COS"
+        },
+        {
+            "id": "select_unit",
+            "type": "select",
+            "property": "trigoUnit",
+            "default": "DEG"
+        },
+        …
+    ]
+},
+…
+{
+    "type": "options",
+    "selectIds": [ "select_operation", "select_unit" ],
+    …
+}
+```
+
+#### si la liste n'est pas associée à un enum
+ 
+Une liste déroulante peut être associée à une **source**, qui détermine quels sont les choix possibles.
+
+Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`.
+
+Exemple pour la source "remous_target" associée à la propriété "varCalc", dans le module CourbeRemous :
+
+```typescript
+switch (source) {
+    // driven by string[], not enum (easier for variable names)
+    case "remous_target":
+        this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
+        for (const at of CourbeRemous.availableTargets) {
+            const e: SelectEntry = new SelectEntry(this._entriesBaseId + at, at);
+            this.addEntry(e);
+        }
+        break;
+```
+
+Ici on ajoute des options de type `SelectEntry` à l'aide de la méthode `addEntry()` : une option vide au début, puis une pour chaque élément d'un tableau.
+
+Puis dans le fichier de configuration du module, déclarer la source :
+
+```json
+{
+    "id": "select_target",
+    "type": "select",
+    "property": "varCalc",
+    "source": "remous_target",
+    …
+```
+
+#### si l'affichage de certains champs dépend du choix dans la liste
+
+Les listes dont l'identifiant est déclaré dans le fichier de configuration du module déclencheront, lorsque leur valeur change, un effacement des résultats du module et une mise à jour de tous les "fieldset" du formulaire.
+
+Cette dernière opération permet de vérifier la visibilité de chaque champ du formulaire, et afficher / masquer ceux dont la visibilité a changé.
+
+Ainsi, pour rendre la visibilité d'un champ dépendante du choix dans la liste, il faut, **dans le code du Nub dans JaLHyd** :
+
+ * écouter le changement de propriété (méthode `update()`, action `propertyChange`)
+ * selon la nouvelle valeur, ajuster la propriété `.visible` des paramètres concernés
+ 
+ Il n'y a rien à faire de particulier dans ngHyd.
+
+### si le module agrège une section
+
+Il faut utiliser ou étendre `FormulaireSection`.
+
+Dans la configuration du module, ajouter un sélecteur de section, associé à la propriété "nodeType" :
+
+```json
+{
+    "id": "select_section",
+    "type": "select",
+    "property": "nodeType",
+    "help": {
+        "1": "hsl/types_sections.html#section-rectangulaire",
+        "0": "hsl/types_sections.html#section-circulaire",
+        "2": "hsl/types_sections.html#section-trapezoidale",
+        "3": "hsl/types_sections.html#section-parabolique"
+    }
+}
+```
+
+Puis dans les options, déclarer  ce sélecteur et ajouter "defaultNodeType" :
+
+```json
+{
+    "type": "options",
+    "defaultNodeType": "SectionRectangle",
+    "selectIds": [ "select_section" ],
+    …
+}
+```
+
 ### si le module agrège des modules enfants
 
 La traduction des variables des modules enfants doit aussi être ajoutée dans les fichiers de langues, dans le dossier de configuration du module.
 
 #### si ces modules enfants sont répétables ("fs_container")
 
-Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de `FormulaireMacrorugoCompound` par exemple. Notamment, implémenter ou surcharger les méthodes :
+Il faut utiliser ou étendre `FormulaireRepeatableFieldset`.
 
- * `createFieldset()`
- * `moveFieldsetUp()`
- * `moveFieldsetDown()`
- * `removeFieldset()`
- * `completeParse()`
- * `update()` (action "newFieldset")
+Dans la configuration du module, créer un "fieldset_template" en donnant le type des Nubs enfants dans la propriété "calcType", et créer un "template_container" associé à ce "fieldset_template" (exemple pour SPP) :
+
+```json
+{
+    "id": "fs_yaxn",
+        "type": "fieldset_template",
+        "calcType": "YAXN",
+        "fields": [
+        	…
+},
+{
+    "id": "yaxn_container",
+    "type": "template_container",
+    "templates": [
+        "fs_yaxn"
+    ]
+}
+```
 
 Dans la méthode `create()` de `CalculatorListComponent`, dans le fichier `src/app/components/calculator-list/calculator-list.component.ts`, ajouter la création d'un enfant par défaut. Exemple pour `MacrorugoCompound` :
 
@@ -297,93 +430,44 @@ Dans chaque fichier de langue du dossier `src/locale`, ajouter les traductions p
 "INFO_CHILD_TYPE_MACRORUGO_PLUR": "radiers",
 ```
 
-### si le formulaire comprend des listes déroulantes
-
-Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de FormulaireTrigo par exemple. Notamment, implémenter ou surcharger les méthodes :
+#### si ces enfants sont des structures avec des lois de débit
 
- * `afterParseFieldset()`
- * `parseOptions()`
- * `update()` (appeler `reset()` lors de l'action "propertyChange")
+Il faut utiliser ou étendre `FormulaireParallelStructure` (ex: Cloisons, Dever…).
 
-#### configuration
-
-Dans le fichier de configuration du module, ajouter la définition des listes déroulantes dans "fields" notamment leur **source** (voir "sources" plus bas), ainsi que leur valeur par défaut dans le "fieldset" parent. Exemple dans `trigo/config.json`
+Dans la configuration du module, dans le "fieldset_template", ajouter un sélecteur de structure associé à la propriété "structureType" et un sélecteur de loi de débit associé à la propriété  "loiDebit", noter les propriétés "calcType" (toujours "Structure" dans ce cas), "defaultStructType" et "defaultLoiDebit" :
 
 ```json
 {
-  "id": "fs_trigo",
-  "type": "fieldset",
-  "defaultOperation": "COS",
-  "defaultUnit": "DEG",
-  "fields": [
-    {
-      "id": "select_operation",
-      "type": "select",
-      "source": "trigo_operation"
-    },
-    {
-      "id": "select_unit",
-      "type": "select",
-      "source": "trigo_unit"
-    }
-  ]
-},
+    "id": "fs_ouvrage",
+    "type": "fieldset_template",
+    "calcType": "Structure",
+    "defaultStructType": "VanneRectangulaire",
+    "defaultLoiDebit": "GateCem88v",
+    "fields": [
+        {
+            "id": "select_structure",
+            "type": "select",
+            "property": "structureType",
+            "source": "device_structure_type"
+        },
+        {
+            "id": "select_loidebit",
+            "type": "select",
+            "property": "loiDebit",
+            "source": "device_loi_debit"
+        }
 ```
 
-Dans ce même fichier de configuration, dans le dernier élément "options", ajouter une entrée par liste déroulante :
+Dans les options, déclarer  les sélecteurs :
 
 ```json
-…
 {
-  "type": "options",
-  "operationSelectId": "select_operation",
-  "unitSelectId": "select_unit",
-  …
-```
- 
-#### sources
- 
-Chaque liste déroulante est associée à une **source** (voir "configuration" plus haut), qui détermine quels sont les choix possibles. Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`. Exemple pour "trigoOperation" :
-
-```typescript
-case "trigo_operation": // (cos, sin…)
-  for (let j = 0; j < Object.keys(TrigoOperation).length / 2; j++) {
-    this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
-  }
-  break;
-```
-
-#### lien avec les propriétés
-
-Les listes déroulantes doivent être liées à des **propriétés** du Nub. Pour ce faire, modifier la classe `FieldSet` dans le fichier `src/app/formulaire/elements/fieldset.ts` comme suit (exemple pour le module `Trigo`).
-
-Ajouter un `case` dans la fonction `updateFields()`
-
-```typescript
-case "fs_trigo": // Trigo
-  this.setSelectValueFromProperty("select_operation", "trigoOperation");
-  this.setSelectValueFromProperty("select_unit", "trigoUnit");
-  break;
-```
-
-Ajouter un `case` dans la fonction `update()`
-
-```typescript
-case "select_operation": // Trigo
-  this.setPropValue("trigoOperation", data.value.value);
-  break;
-case "select_unit": // Trigo
-  this.setPropValue("trigoUnit", data.value.value);
-  break;
+    "type": "options",
+    "selectIds": [ "select_structure", "select_loidebit" ],
+    …
+}
 ```
 
-Dans la fonction `parseConfig()`, ajouter un appel par à `setPropertyValueFromConfig()` pour chaque liste déroulante.
-
-```typescript
-  this.setPropertyValueFromConfig(json, "defaultOperation", "trigoOperation", TrigoOperation);
-  this.setPropertyValueFromConfig(json, "defaultUnit", "trigoUnit", TrigoUnit);
-```
- 
 ### documentation
 
 Pour chaque langue, ajouter un fichier .md dans les dossiers `docs/*/calculators`, puis placer ce nouveau fichier dans la hiérarchie de la documentation, en ajoutant son chemin dans les fichiers `mkdocs-*.yml`.
diff --git a/e2e/session/session-cascade-params.json b/e2e/session/session-cascade-params.json
index a17049558f011156e9733e88bf7a8b0c26270992..7c847730727ff68a4dab9e2b462cf9f55f32b7bd 100644
--- a/e2e/session/session-cascade-params.json
+++ b/e2e/session/session-cascade-params.json
@@ -4,7 +4,7 @@
             "uid": "ZTFxeW",
             "props": {
                 "calcType": 2,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "Sec. param."
@@ -14,7 +14,7 @@
                     "uid": "b21rNG",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -58,7 +58,7 @@
             "uid": "Z3EwY2",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme"
@@ -68,7 +68,7 @@
                     "uid": "ZnU0bn",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -112,7 +112,7 @@
             "uid": "Y2l2Y3",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme 1"
@@ -122,7 +122,7 @@
                     "uid": "MmV0dG",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
diff --git a/e2e/session/session-liens-spaghetti.json b/e2e/session/session-liens-spaghetti.json
index d33e60fd52a2b6608bb5d406432466c68af91d17..97852c2152baf06e2655890896d13afd3a4ee74f 100644
--- a/e2e/session/session-liens-spaghetti.json
+++ b/e2e/session/session-liens-spaghetti.json
@@ -9,7 +9,7 @@
             "uid": "ZHh1YW",
             "props": {
                 "calcType": 2,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "Sec. param."
@@ -19,7 +19,7 @@
                     "uid": "bXB1Y3",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -63,8 +63,7 @@
         {
             "uid": "eTgwMG",
             "props": {
-                "calcType": 11,
-                "nodeType": 0
+                "calcType": 11
             },
             "meta": {
                 "title": "Macro-rugo."
@@ -129,8 +128,7 @@
         {
             "uid": "dGx0em",
             "props": {
-                "calcType": 8,
-                "nodeType": 0
+                "calcType": 8
             },
             "meta": {
                 "title": "Ouvrages"
@@ -140,7 +138,7 @@
                     "uid": "ZmZ3bX",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -166,7 +164,7 @@
                     "uid": "aWo0M2",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -194,7 +192,7 @@
                     "uid": "YTBjcm",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -242,7 +240,7 @@
             "uid": "dzA1OX",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme"
@@ -252,7 +250,7 @@
                     "uid": "Ynlna2",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -297,8 +295,7 @@
         {
             "uid": "cXFraW",
             "props": {
-                "calcType": 9,
-                "nodeType": 0
+                "calcType": 9
             },
             "meta": {
                 "title": "Déver. dénoyés"
@@ -308,7 +305,7 @@
                     "uid": "Zzd1cH",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 0,
                         "loiDebit": 7
                     },
diff --git a/e2e/session/session-optional-params.test.json b/e2e/session/session-optional-params.test.json
index 7f4df3fcf3f8a44e564269f586d99a6f02109e5d..94d46a3d0ff08f9fd85396f5281f379cdd0b24fd 100644
--- a/e2e/session/session-optional-params.test.json
+++ b/e2e/session/session-optional-params.test.json
@@ -4,7 +4,7 @@
             "uid": "eHpub2",
             "props": {
                 "calcType": 2,
-                "nodeType": 4
+                "nodeType": 3
             },
             "meta": {
                 "title": "Sec. param."
@@ -14,7 +14,7 @@
                     "uid": "YXNoY2",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 4
+                        "nodeType": 3
                     },
                     "children": [],
                     "parameters": [
diff --git a/jalhyd_branch b/jalhyd_branch
index 1f7391f92b6a3792204e07e99f71f643cc35e7e1..47b2c5e06d000b4b0659972d55be7edcc4fb8ea9 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-master
+normalize-for-gui-forms
diff --git a/src/app/calculators/bief/config.json b/src/app/calculators/bief/config.json
index 12251aaaa1907ccec6c3b0a066d4a91dec12938f..5dec17342049cfa22abef0434e98f3544d53f313 100644
--- a/src/app/calculators/bief/config.json
+++ b/src/app/calculators/bief/config.json
@@ -6,7 +6,8 @@
             {
                 "id": "select_regime",
                 "type": "select",
-                "source": "bief_regime"
+                "property": "regime",
+                "default": "Fluvial"
             }
         ]
     },
@@ -17,13 +18,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -65,9 +66,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "defaultRegime": "Fluvial",
-        "sectionSourceId": "select_section",
-        "regimeSelectId": "select_regime",
+        "selectIds": [ "select_section", "select_regime" ],
         "help": "hsl/bief.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/bief/en.json b/src/app/calculators/bief/en.json
index 056d2873002dba19ea3ab322a185f7c413259a4c..772347ac1f48280ec7f13918b61819abcacc1835 100644
--- a/src/app/calculators/bief/en.json
+++ b/src/app/calculators/bief/en.json
@@ -8,10 +8,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/bief/fr.json b/src/app/calculators/bief/fr.json
index f22d1f0240caff2b34f64ce0d5b458624d6c6e5c..a8f1f5489da3ea14cd4348509ef742608b90787c 100644
--- a/src/app/calculators/bief/fr.json
+++ b/src/app/calculators/bief/fr.json
@@ -8,10 +8,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/cloisons/config.json b/src/app/calculators/cloisons/config.json
index 1356c2276ff9b587e99517bd605368b235c50058..fd387b8de6d37cb7f4fb7058c471ea1df5315ad3 100644
--- a/src/app/calculators/cloisons/config.json
+++ b/src/app/calculators/cloisons/config.json
@@ -22,19 +22,21 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "Orifice_OrificeSubmerged": "structures/orifice_noye.html",
                     "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html",
                     "SeuilRectangulaire_WeirSubmergedLarinier": "structures/fente_noyee.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "h1",
             "L",
@@ -57,7 +59,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "pab/cloisons.html"
     }
diff --git a/src/app/calculators/courberemous/config.json b/src/app/calculators/courberemous/config.json
index c6508c4a2acac496e4db666809db95fd00e601b6..710818fc395e03c0394ea70dd3977982d3c762b6 100644
--- a/src/app/calculators/courberemous/config.json
+++ b/src/app/calculators/courberemous/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -52,11 +52,12 @@
             {
                 "id": "select_resolution",
                 "type": "select",
-                "source": "remous_methode_resolution",
+                "property": "methodeResolution",
+                "default": "Trapezes",
                 "help": {
-                    "Trapezes": "../methodes_numeriques/integration_trapezes.html",
-                    "RungeKutta4": "../methodes_numeriques/rk4.html",
-                    "EulerExplicite": "../methodes_numeriques/euler_explicite.html"
+                    "0": "../methodes_numeriques/integration_trapezes.html",
+                    "1": "../methodes_numeriques/rk4.html",
+                    "2": "../methodes_numeriques/euler_explicite.html"
                 }
             }
         ]
@@ -68,6 +69,7 @@
             {
                 "id": "select_target",
                 "type": "select",
+                "property": "varCalc",
                 "source": "remous_target",
                 "help": {
                     "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
@@ -93,9 +95,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "sectionSourceId": "select_section",
-        "targetSelectId": "select_target",
-        "methodSelectId": "select_resolution",
+        "selectIds": [ "select_resolution", "select_section", "select_target" ],
         "help": "hsl/courbe_remous.html",
         "resultsHelp": {
             "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
diff --git a/src/app/calculators/courberemous/en.json b/src/app/calculators/courberemous/en.json
index 39ad2d88e3ff517beb05011e0e83d945a02042fe..cb5166fe0c34681d594ae8ce8f72eaa854b23064 100644
--- a/src/app/calculators/courberemous/en.json
+++ b/src/app/calculators/courberemous/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
@@ -43,9 +43,9 @@
     "UNIT_IMP": "N",
     "UNIT_TAU0": "Pa",
 
-    "select_resolution_Trapezes": "Integration by trapezoid",
-    "select_resolution_RungeKutta4": "Runge Kutta fourth order",
-    "select_resolution_EulerExplicite": "Explicit Euler",
+    "select_resolution_0": "Integration by trapezoid",
+    "select_resolution_1": "Runge Kutta fourth order",
+    "select_resolution_2": "Explicit Euler",
 
     "fs_target_data": "Data to compute",
     "select_target": "Choice of the data to compute",
diff --git a/src/app/calculators/courberemous/fr.json b/src/app/calculators/courberemous/fr.json
index 6c6d61121e0bf756d89b8dc2f5530fa3747d3e1e..3d9bfd7ee8898c11806a7e2b600ae6f96d8b033c 100644
--- a/src/app/calculators/courberemous/fr.json
+++ b/src/app/calculators/courberemous/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
@@ -42,9 +42,9 @@
     "UNIT_IMP": "N",
     "UNIT_TAU0": "Pa",
 
-    "select_resolution_Trapezes": "Intégration par trapèzes",
-    "select_resolution_RungeKutta4": "Runge Kutta d'ordre 4",
-    "select_resolution_EulerExplicite": "Euler explicite",
+    "select_resolution_0": "Intégration par trapèzes",
+    "select_resolution_1": "Runge Kutta d'ordre 4",
+    "select_resolution_2": "Euler explicite",
 
     "fs_target_data": "Donnée à calculer",
     "select_target": "Choix de la donnée à calculer",
diff --git a/src/app/calculators/dever/config.json b/src/app/calculators/dever/config.json
index b76d28c5512d23465568fef8abf256744f0eded6..dc68b2e264caff11ada702605f10f9c8dd67fdc8 100644
--- a/src/app/calculators/dever/config.json
+++ b/src/app/calculators/dever/config.json
@@ -20,17 +20,19 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "SeuilRectangulaire_WeirFree": "structures/kivi.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "ZDV",
             "L",
@@ -52,7 +54,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "structures/dever.html"
     }
diff --git a/src/app/calculators/grille/config.json b/src/app/calculators/grille/config.json
index ed3784d4b1e5e6eb3194df43a79609e358072dc3..5b074f9fd3f86ce2d83ae85a44b71d43c29b088e 100644
--- a/src/app/calculators/grille/config.json
+++ b/src/app/calculators/grille/config.json
@@ -17,12 +17,12 @@
     {
         "id": "fs_plan",
         "type": "fieldset",
-        "defaultGridType": "Conventional",
         "fields": [
             {
                 "id": "select_grid_type",
                 "type": "select",
-                "source": "grille_type",
+                "property": "gridType",
+                "default": "Conventional",
                 "help": {
                     "0": "devalaison/grille.html#grille-conventionnelle",
                     "1": "devalaison/grille.html#grille-orientee",
@@ -44,12 +44,12 @@
     {
         "id": "fs_grille",
         "type": "fieldset",
-        "defaultGridProfile": "Rectangular",
         "fields": [
             {
                 "id": "select_grid_profile",
                 "type": "select",
-                "source": "grille_profile",
+                "property": "gridProfile",
+                "default": "Rectangular",
                 "help": "devalaison/grille.html#profil-des-barreaux"
             },
             {
@@ -91,8 +91,7 @@
     },
     {
         "type": "options",
-        "gridTypeSelectId": "select_grid_type",
-        "gridProfileSelectId": "select_grid_profile",
+        "selectIds": [ "select_grid_type", "select_grid_profile" ],
         "help": "devalaison/grille.html",
         "resultsHelp": {
             "VAPDG": "devalaison/grille.html#vitesse-dapproche-moyenne-pour-le-debit-maximum-turbine-en-soustrayant-la-partie-superieure-eventuellement-obturee",
diff --git a/src/app/calculators/lechaptcalmon/config.json b/src/app/calculators/lechaptcalmon/config.json
index 87cf30bd5b204cb5bf2515ac0f3313f756593f53..663588dfffcffa21a19de9f9695d07c7c69d6341 100644
--- a/src/app/calculators/lechaptcalmon/config.json
+++ b/src/app/calculators/lechaptcalmon/config.json
@@ -7,7 +7,8 @@
             {
                 "id": "select_material",
                 "type": "select",
-                "source": "lechapt_calmon_material"
+                "property": "material",
+                "default": "UnlinedCastIronCoarseConcrete"
             },
             "L",
             "M",
@@ -28,7 +29,7 @@
     {
         "type": "options",
         "idCal": "J",
-        "lcMaterialSelectId": "select_material",
+        "selectIds": [ "select_material" ],
         "help": "hyd_en_charge/lechapt-calmon.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/macrorugocompound/config.json b/src/app/calculators/macrorugocompound/config.json
index 5ecdf13e079e870e4ead4fe937db89caec7e9ea6..db7b7d8fefc09357f2f66b8c2a19cfc92e66b64a 100644
--- a/src/app/calculators/macrorugocompound/config.json
+++ b/src/app/calculators/macrorugocompound/config.json
@@ -35,7 +35,7 @@
             {
                 "id": "select_pass_type",
                 "type": "select",
-                "source": "mrc_pass_type"
+                "property": "inclinedApron"
             },
             "ZRR",
             "ZRL",
@@ -61,7 +61,7 @@
     {
         "type": "options",
         "idCal": "Q",
-        "apronTypeSelectId": "select_pass_type",
+        "selectIds": [ "select_pass_type" ],
         "help": "pam/macrorugo_complexe.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/parallelstructure/config.json b/src/app/calculators/parallelstructure/config.json
index b469be78c2f4050f6e31d6d7aecad361a43d746b..d9fdec718be9d068b474cceda2165529e261094d 100644
--- a/src/app/calculators/parallelstructure/config.json
+++ b/src/app/calculators/parallelstructure/config.json
@@ -19,11 +19,14 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "SeuilRectangulaire_KIVI": "structures/kivi.html",
                     "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html",
@@ -38,8 +41,7 @@
                     "SeuilRectangulaire_WeirFree": "structures/kivi.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "S",
             "ZDV",
@@ -69,7 +71,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "structures/lois_ouvrages.html",
         "resultsHelp": {
diff --git a/src/app/calculators/regimeuniforme/config.json b/src/app/calculators/regimeuniforme/config.json
index 0961e0c643b2cf04f693acf2cb4a71364f8fc793..b78ebf54f0ae2420992a6b5a42a2d814dfc37477 100644
--- a/src/app/calculators/regimeuniforme/config.json
+++ b/src/app/calculators/regimeuniforme/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -44,8 +44,8 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
+        "selectIds": [ "select_section" ],
         "idCal": "Q",
-        "sectionSourceId": "fs_section",
         "help": "hsl/regime_uniforme.html",
         "resultsHelp": {
             "V": "hsl/var_hydrauliques.html#vitesse-moyenne-v"
diff --git a/src/app/calculators/regimeuniforme/en.json b/src/app/calculators/regimeuniforme/en.json
index 4e52b0ab8f8dc215a55cc383fbdb5c4b320232bf..e27ce7d4a4aee4efc5af8715bc9914cdbf427db3 100644
--- a/src/app/calculators/regimeuniforme/en.json
+++ b/src/app/calculators/regimeuniforme/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/regimeuniforme/fr.json b/src/app/calculators/regimeuniforme/fr.json
index c3c20571ce0f6bd8d7d86bd866723135c47d82bc..7d44f477523dd2f20762376dc1be112d33c0b952 100644
--- a/src/app/calculators/regimeuniforme/fr.json
+++ b/src/app/calculators/regimeuniforme/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/sectionparametree/config.json b/src/app/calculators/sectionparametree/config.json
index e4a901ed9d5ace6b68ece5b2031e0a04b78cd718..dc3d8f78c092c8c645237a0b6c45c5b3d034340b 100644
--- a/src/app/calculators/sectionparametree/config.json
+++ b/src/app/calculators/sectionparametree/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurBerge",
             "LargeurFond",
@@ -44,8 +44,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "sectionSourceId": "select_section",
-        "targetSelectId": "select_target",
+        "selectIds": [ "select_section" ],
         "help": "hsl/section_parametree.html",
         "resultsHelp": {
             "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
diff --git a/src/app/calculators/sectionparametree/en.json b/src/app/calculators/sectionparametree/en.json
index 915cdb5055cb5218113354b196c051f533179875..29699a3a182172df3639c08693104b739e84453d 100644
--- a/src/app/calculators/sectionparametree/en.json
+++ b/src/app/calculators/sectionparametree/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/sectionparametree/fr.json b/src/app/calculators/sectionparametree/fr.json
index c9065310f644a2ea11721e28bec94af8a7fac6dc..12e0163632b0951d44b779a185526a0979f2c4f3 100644
--- a/src/app/calculators/sectionparametree/fr.json
+++ b/src/app/calculators/sectionparametree/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/spp/config.json b/src/app/calculators/spp/config.json
index 0c3c2427242c7a15825837810866460d93f825a8..1a20f3cf15e242a781d2d3a06713eaf5cfa9937e 100644
--- a/src/app/calculators/spp/config.json
+++ b/src/app/calculators/spp/config.json
@@ -2,12 +2,12 @@
     {
         "id": "fs_spp",
         "type": "fieldset",
-        "defaultOperation": "SUM",
         "fields": [
             {
                 "id": "select_spp_operation",
                 "type": "select",
-                "source": "spp_operation"
+                "property": "sppOperation",
+                "default": "SUM"
             },
             "Y"
         ]
@@ -32,7 +32,7 @@
     {
         "type": "options",
         "idCal": "Y",
-        "operationSelectId": "select_spp_operation",
-        "_help": "util/trigo.html"
+        "selectIds": [ "select_spp_operation" ],
+        "_help": "util/spp.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/trigo/config.json b/src/app/calculators/trigo/config.json
index 6dbb51a8c4590022f6b10d9fc72652b9c7682b63..806076c83f82ead195bbd16b138eb6fec0ba90a6 100644
--- a/src/app/calculators/trigo/config.json
+++ b/src/app/calculators/trigo/config.json
@@ -2,18 +2,18 @@
     {
         "id": "fs_trigo",
         "type": "fieldset",
-        "defaultOperation": "COS",
-        "defaultUnit": "DEG",
         "fields": [
             {
                 "id": "select_operation",
                 "type": "select",
-                "source": "trigo_operation"
+                "property": "trigoOperation",
+                "default": "COS"
             },
             {
                 "id": "select_unit",
                 "type": "select",
-                "source": "trigo_unit"
+                "property": "trigoUnit",
+                "default": "DEG"
             }
         ]
     },
@@ -25,8 +25,7 @@
     {
         "type": "options",
         "idCal": "Y",
-        "operationSelectId": "select_operation",
-        "unitSelectId": "select_unit",
+        "selectIds": [ "select_operation", "select_unit" ],
         "_help": "util/trigo.html"
     }
 ]
\ No newline at end of file
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 948a63d4b08f6e6f9ccc9eb004753f2dd012fbd6..1d9a14069c2cb4d4a507467d66f6f0db32b1fcd5 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
@@ -1,6 +1,6 @@
 import { Component, ViewChild, DoCheck } from "@angular/core";
 
-import { Result, cLog, Message, MessageCode, MessageSeverity, MacrorugoCompound } from "jalhyd";
+import { Result, cLog, Message, MessageCode, MessageSeverity, MRCInclination } from "jalhyd";
 
 import { fv } from "../../../app/util";
 
@@ -321,7 +321,7 @@ export class MacrorugoCompoundResultsComponent implements DoCheck {
             this.mrcResults
             && this.mrcResults.result
             && this.mrcResults.result.sourceNub
-            && this.mrcResults.result.sourceNub.properties.getPropValue("inclinedApron")
+            && this.mrcResults.result.sourceNub.properties.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 093e5b332e74b15c9f0c23804bf1c558bc161578..a1081c57877dde4d74551b74c46b9b80cd98b1e5 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.ts
+++ b/src/app/components/modules-diagram/modules-diagram.component.ts
@@ -12,7 +12,7 @@ import {
     Session,
     ParamValueMode,
     CalculatorType,
-    ComputeNodeType,
+    SectionType,
     LoiDebit,
     Nub,
     MacrorugoCompound,
@@ -232,7 +232,7 @@ export class ModulesDiagramComponent implements AfterContentInit, AfterViewCheck
         let type = CalculatorType[n.calcType];
         const nt = n.properties.getPropValue("nodeType");
         if (nt) {
-            type = ComputeNodeType[nt];
+            type = SectionType[nt];
         } else {
             const ld = n.properties.getPropValue("loiDebit");
             if (ld !== undefined) {
diff --git a/src/app/formulaire/definition/form-bief.ts b/src/app/formulaire/definition/form-bief.ts
deleted file mode 100644
index 46b7ffad662ed47c7001e97e69ece33d4e2bae19..0000000000000000000000000000000000000000
--- a/src/app/formulaire/definition/form-bief.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { IObservable, SectionNub, Session, BiefRegime } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
-
-export class FormulaireBief extends FormulaireSection {
-
-    /** id du select configurant le régime */
-    private _regimeSelectId: string;
-
-    constructor() {
-        super();
-        // default properties
-        this._props["regime"] = BiefRegime.Fluvial;
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id du select configurant la méthode de résolution
-        this._regimeSelectId = this.getOption(json, "regimeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de méthode de résolution
-        if (this._regimeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._regimeSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-
-        super.update(sender, data);
-
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_water_line":
-                    this.reset();
-                    // Either Z1 or Z2 is calculable, depending on Regime
-                    this.getFieldsetById("fs_condlim").updateFields();
-                    break;
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
index 38d112690d6e76e60423815de2f2d437f8dfdaba..11c22edd0ec6b9f4d5de623234d5665a37d0d3f0 100644
--- a/src/app/formulaire/definition/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -1,9 +1,8 @@
-import { IObservable, MethodeResolution, SectionNub, Session, Result, CourbeRemous, CourbeRemousParams, acSection } from "jalhyd";
+import { Result, CourbeRemous, CourbeRemousParams, acSection } from "jalhyd";
 
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
 import { RemousResults } from "../../results/remous-results";
 import { CalculatorResults } from "../../results/calculator-results";
+import { FormulaireSection } from "./form-section";
 
 export class FormulaireCourbeRemous extends FormulaireSection {
 
@@ -14,36 +13,12 @@ export class FormulaireCourbeRemous extends FormulaireSection {
 
     private resultYc: Result;
 
-    /**
-     * id du select configurant la méthode de résolution
-     */
-    private _resolveMethSelectId: string;
-
     constructor() {
         super();
         this._remousResults = new RemousResults();
-        // default properties
-        this._props["methodeResolution"] = MethodeResolution.Trapezes;
         this._props["varCalc"] = ""; // important
     }
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id du select configurant la méthode de résolution
-        this._resolveMethSelectId = this.getOption(json, "methodSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de méthode de résolution
-        if (this._resolveMethSelectId) {
-            const sel = fs.getFormulaireNodeById(this._resolveMethSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     protected compute() {
         this.reaffectResultComponents();
     }
@@ -91,32 +66,4 @@ export class FormulaireCourbeRemous extends FormulaireSection {
         this._remousResults.helpLinks = this.helpLinks;
         return [ this._remousResults ];
     }
-
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-
-        super.update(sender, data);
-
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_param_calc":
-                case "fs_target_data":
-                    this.reset();
-                    break;
-            }
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f6cf46ffcceaca89dcf91f75e76208a5b5e20e9b..4c55719f1a82e22c8d56bb45eda119bf37d97ca5 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -1,4 +1,15 @@
-import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, SectionNub, acSection, ParamDefinition, Result } from "jalhyd";
+import {
+    CalculatorType,
+    SectionType,
+    Nub,
+    Props,
+    Observer,
+    Session,
+    SectionNub,
+    acSection,
+    ParamDefinition,
+    Result
+} from "jalhyd";
 
 import { FormulaireElement } from "../elements/formulaire-element";
 import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
@@ -73,7 +84,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return props["calcType"];
     }
 
-    public get nodeType(): ComputeNodeType {
+    public get nodeType(): SectionType {
         const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
         return props["nodeType"];
     }
@@ -145,7 +156,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     protected parseOptions(json: {}) {
         const dnt = json["defaultNodeType"];
         if (dnt !== undefined) {
-            this._defaultNodeType = ComputeNodeType[dnt];
+            this._defaultNodeType = SectionType[dnt];
         }
         this._helpLink = json["help"];
         this._resultsHelpLinks = json["resultsHelp"];
@@ -156,7 +167,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this.helpLinks = this._resultsHelpLinks;
     }
 
-    public getOption(json: {}, option: string): string {
+    public getOption(json: {}, option: string): any {
         if (json["type"] === "options") {
             return json[option];
         }
diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
index 9a5f38b9d69bbc269e8e90f456d1abf2afcfc42d..b2051ccbae7fc86927737f23bd6c53b0e411510b 100644
--- a/src/app/formulaire/definition/form-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -4,14 +4,18 @@ import { VarResults } from "../../results/var-results";
 import { ChartType } from "../../results/chart-type";
 import { CalculatorResults } from "../../results/calculator-results";
 import { ParamRadioConfig, NgParameter } from "../elements/ngparam";
+import { FieldSet } from "../elements/fieldset";
 
-import { Nub } from "jalhyd";
+import { Nub, IObservable } from "jalhyd";
 
 export class FormulaireFixedVar extends FormulaireDefinition {
 
     protected _fixedResults: FixedResults;
     protected _varResults: VarResults;
 
+    /** ids of select fields */
+    private _selectIds: string[] = [];
+
     constructor() {
         super();
         this._fixedResults = new FixedResults();
@@ -26,6 +30,10 @@ export class FormulaireFixedVar extends FormulaireDefinition {
         return this._varResults;
     }
 
+    public get selectids(): string[] {
+        return this._selectIds;
+    }
+
     public resetFormResults() {
         this._fixedResults.reset();
         this._varResults.reset();
@@ -61,6 +69,24 @@ export class FormulaireFixedVar extends FormulaireDefinition {
         return res;
     }
 
+    public afterParseFieldset(fs: FieldSet) {
+        // observe all select fields @see this.update()
+        if (this._selectIds.length > 0) {
+            for (const sId of this._selectIds) {
+                const sel = fs.getFormulaireNodeById(sId);
+                if (sel) {
+                    fs.properties.addObserver(this);
+                }
+            }
+        }
+    }
+
+    protected parseOptions(json: {}) {
+        super.parseOptions(json);
+        // get ids of all select fields
+        this._selectIds = this.getOption(json, "selectIds") || [];
+    }
+
     protected compute() {
         this.runNubCalc(this.currentNub);
         this.reaffectResultComponents();
@@ -90,4 +116,18 @@ export class FormulaireFixedVar extends FormulaireDefinition {
             this.varResults.update();
         }
     }
+
+    // interface Observer
+
+    public update(sender: IObservable, data: any) {
+        super.update(sender, data);
+        // whenever a select field is touched, reset results
+        if (data.action === "propertyChange") {
+            this.reset();
+            // reflect changes in GUI (who knows ?), for ex. show / hide dependent fields
+            for (const fs of this.allFieldsets) {
+                fs.updateFields();
+            }
+        }
+    }
 }
diff --git a/src/app/formulaire/definition/form-grille.ts b/src/app/formulaire/definition/form-grille.ts
index c66630c1af4dffb17aa583f4e982f0ddaf85834e..67aa6e692949dd5a54687c79428c134bbdd78e4b 100644
--- a/src/app/formulaire/definition/form-grille.ts
+++ b/src/app/formulaire/definition/form-grille.ts
@@ -1,6 +1,3 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
@@ -8,12 +5,6 @@ import { FormulaireFixedVar } from "./form-fixedvar";
  */
 export class FormulaireGrille extends FormulaireFixedVar {
 
-    /** id of select configuring grid profile */
-    private _gridProfileSelectId: string;
-
-    /** id of select configuring grid type */
-    private _gridTypeSelectId: string;
-
     constructor() {
         super();
         // custom variables order for results tables
@@ -25,44 +16,4 @@ export class FormulaireGrille extends FormulaireFixedVar {
         ];
     }
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._gridProfileSelectId = this.getOption(json, "gridProfileSelectId");
-        this._gridTypeSelectId = this.getOption(json, "gridTypeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._gridTypeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._gridTypeSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-        if (this._gridProfileSelectId) {
-            const sel = fs.getFormulaireNodeById(this._gridProfileSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            if (data.name === "gridType") {
-                this.reset();
-                // Inclined grids have more input fields (OEntH and cIncl)
-                this.getFieldsetById("fs_grille").updateFields();
-                // Alpha and Beta are not always shown
-                this.getFieldsetById("fs_plan").updateFields();
-            }
-            if (data.name === "gridProfile") {
-                this.reset();
-                // Shape coefficients a and c are not always shown
-                this.getFieldsetById("fs_grille").updateFields();
-            }
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-lechapt-calmon.ts b/src/app/formulaire/definition/form-lechapt-calmon.ts
deleted file mode 100644
index cedc683c5264b0bf45605bd4b99b8043b57d0150..0000000000000000000000000000000000000000
--- a/src/app/formulaire/definition/form-lechapt-calmon.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireFixedVar } from "./form-fixedvar";
-
-/**
- * Formulaire pour Lechapt et Calmon
- */
-export class FormulaireLechaptCalmon extends FormulaireFixedVar {
-
-    /** id of select configuring material */
-    private _lcMaterialSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._lcMaterialSelectId = this.getOption(json, "lcMaterialSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._lcMaterialSelectId) {
-            const sel = fs.getFormulaireNodeById(this._lcMaterialSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            if (data.name === "material") {
-                this.reset();
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
index 8c38f31ec341430f6579974449c85f0bc5b2127d..663da1f960e32217289a9c5d73c44f7b8b81d534 100644
--- a/src/app/formulaire/definition/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -1,4 +1,4 @@
-import { IObservable, Nub, MacrorugoCompound, Result } from "jalhyd";
+import { IObservable, Nub, MacrorugoCompound, Result, MRCInclination } from "jalhyd";
 
 import { FieldSet } from "../elements/fieldset";
 import { FieldsetContainer } from "../elements/fieldset-container";
@@ -13,32 +13,13 @@ import { CalculatorResults } from "../../results/calculator-results";
  */
 export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
 
-    /** id of select configuring apron type */
-    private _apronTypeSelectId: string;
-
     protected _mrcResults: MacrorugoCompoundResults;
 
     constructor() {
         super();
         this._mrcResults = new MacrorugoCompoundResults();
         // default properties
-        this._props["inclinedApron"] = false;
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._apronTypeSelectId = this.getOption(json, "apronTypeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // if Fieldset contains apron type selector
-        if (this._apronTypeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._apronTypeSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
+        this._props["inclinedApron"] = MRCInclination.NOT_INCLINED;
     }
 
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
@@ -105,7 +86,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
     /**
      * Reflect inclinedApron property state in GUI
      */
-    public updateApronState(inclined: boolean) {
+    public updateApronState(inclined: MRCInclination) {
         for (const fs of this.allFieldsets) {
             // show / hide dependent fields (read from model)
             fs.updateFields();
@@ -113,12 +94,12 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         // show / hide children list (GUI only)
         for (const elt of this.allFormElements) {
             if (elt instanceof FieldsetContainer) {
-                elt.isDisplayed = (! inclined);
+                elt.isDisplayed = (inclined === MRCInclination.NOT_INCLINED);
             }
         }
         // when switching to multiple aprons, remove all fieldset container
         // instances and reinstanciate for every MacroRugo child
-        if (! inclined) {
+        if (inclined === MRCInclination.NOT_INCLINED) {
             for (const elt of this.allFormElements) {
                 if (elt instanceof FieldsetContainer) {
                     elt.clearKids();
diff --git a/src/app/formulaire/definition/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts
index fa8a481f93fcbb0efb9933e7676ba8d9839b1205..6e238dd769a8342766cfb1360625324bfb305075 100644
--- a/src/app/formulaire/definition/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-parallel-structures.ts
@@ -10,29 +10,6 @@ import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset";
 
 export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
 
-    /**
-     * id du select configurant le type d'ouvrage
-     */
-    private __ouvrageSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-
-        // id du select configurant le type d'ouvrage
-        this.__ouvrageSelectId = this.getOption(json, "ouvrageSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de type d'ouvrage
-        if (this.__ouvrageSelectId) {
-            const sel = fs.getFormulaireNodeById(this.__ouvrageSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     /**
      * construit un identifiant de type { uid: "abcdef", symbol: "X" }
      * avec "abcdef" l'index de l'ouvrage et "X" son paramètre
diff --git a/src/app/formulaire/definition/form-regime-uniforme.ts b/src/app/formulaire/definition/form-regime-uniforme.ts
deleted file mode 100644
index f1630343a0ccaf89640002e4b440940c282a0e42..0000000000000000000000000000000000000000
--- a/src/app/formulaire/definition/form-regime-uniforme.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { IObservable, Observer, Session, SectionNub } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
-
-export class FormulaireRegimeUniforme extends FormulaireSection implements Observer {
-
-    update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        // changement de propriété du FieldSet contenant le select de choix du type de section
-        if (sender instanceof FieldSet && sender.id === "fs_section" && data.action === "propertyChange") {
-            // replace underlying section without replacing whole Nub
-            const newSect = Session.getInstance().createSection(data.value);
-            (this._currentNub as SectionNub).setSection(newSect);
-            // reflect changes in GUI
-            for (const fs of this.allFieldsets) {
-                // show / hide dependent fields
-                fs.updateFields();
-            }
-            this.reset();
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-section-parametree.ts b/src/app/formulaire/definition/form-section-parametree.ts
index a18349a53e998295a6e761ba3a1862d03c27bdb5..922edddb83604a7943abfd9e22973224d12ec059 100644
--- a/src/app/formulaire/definition/form-section-parametree.ts
+++ b/src/app/formulaire/definition/form-section-parametree.ts
@@ -1,9 +1,8 @@
-import { IObservable, Nub, Session, SectionNub, ParamDefinition, Result, SectionParametree, acSection } from "jalhyd";
+import { Nub, ParamDefinition, Result, SectionParametree, acSection } from "jalhyd";
 
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireSection } from "./form-section";
 import { SectionResults } from "../../results/section-results";
-import { ParamRadioConfig } from "../elements/ngparam";
+import { ParamRadioConfig, NgParameter } from "../elements/ngparam";
 import { CalculatorResults } from "../../results/calculator-results";
 
 export class FormulaireSectionParametree extends FormulaireSection {
@@ -78,30 +77,7 @@ export class FormulaireSectionParametree extends FormulaireSection {
         return res;
     }
 
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-        super.update(sender, data);
-
-        // changement de propriété du FieldSet contenant le select de choix du type de section
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_computed_var":
-                    this.reset();
-                    break;
-            }
-        }
+    public getSectionVariatedParameters(): NgParameter[] {
+        return this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
     }
 }
diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts
index e645b98aca767333ab40f809c5e86eae32925c38..bd1685b44c8920d423ede9930f811fd0255fe884 100644
--- a/src/app/formulaire/definition/form-section.ts
+++ b/src/app/formulaire/definition/form-section.ts
@@ -1,43 +1,24 @@
-import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireFixedVar } from "./form-fixedvar";
+import { FieldSet } from "../elements/fieldset";
 
-export abstract class FormulaireSection extends FormulaireFixedVar {
-
-    /** id de l'élément configurant le type de section */
-    private _sectionSourceId: string;
-
-    private get hasSectionNodeTypeSource(): boolean {
-        return this._sectionSourceId !== undefined;
-    }
-
-    public getSectionVariatedParameters(): NgParameter[] {
-        return this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
-    }
-
-    public getSectionComputedParam(): { symbol: string, label: string } {
-        const symbol = this.getSelectedValue("select_target");
-        const label = this.getSelectedLabel("select_target");
-        return { symbol, label };
-    }
+import { IObservable, Session, SectionNub } from "jalhyd";
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id de l'élément configurant le type de section
-        this._sectionSourceId = this.getOption(json, "sectionSourceId");
-    }
+export class FormulaireSection extends FormulaireFixedVar {
 
-    /**
-     * appelé après la création d'un FieldSet
-     * @param fs nouveau FieldSet
-     */
-    public afterParseFieldset(fs: FieldSet) {
-        if (this.hasSectionNodeTypeSource) { // s'il existe un menu de choix de section dans le module de calcul
-            const sel = fs.getFormulaireNodeById(this._sectionSourceId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet pour MAJ du nub, reset du formulaire, ...
-                fs.properties.addObserver(this);
+    update(sender: IObservable, data: any) {
+        super.update(sender, data);
+        // changement de propriété du FieldSet contenant le select de choix du type de section
+        if (sender instanceof FieldSet && sender.id === "fs_section" && data.action === "propertyChange") {
+            // replace underlying section without replacing whole Nub
+            const newSect = Session.getInstance().createSection(data.value);
+            (this._currentNub as SectionNub).setSection(newSect);
+            // reflect changes in GUI
+            for (const fs of this.allFieldsets) {
+                // show / hide dependent fields
+                fs.updateFields();
             }
+            this.reset();
         }
     }
+
 }
diff --git a/src/app/formulaire/definition/form-spp.ts b/src/app/formulaire/definition/form-spp.ts
index e7ddf4e1aeb3a964a7a50082230842970f8c06b0..6ca1be15e7d8aab5ab6350d96142797d32d15936 100644
--- a/src/app/formulaire/definition/form-spp.ts
+++ b/src/app/formulaire/definition/form-spp.ts
@@ -3,30 +3,13 @@ import { FieldSet } from "../elements/fieldset";
 import { FormulaireNode } from "../elements/formulaire-node";
 import { FieldsetContainer } from "../elements/fieldset-container";
 
-import { Nub, IObservable } from "jalhyd";
+import { Nub } from "jalhyd";
 
 /**
  * Formulaire pour "somme / produit de puissances"
  */
 export class FormulaireSPP extends FormulaireRepeatableFieldset {
 
-    /** id of select configuring operation */
-    private _operationSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._operationSelectId = this.getOption(json, "operationSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._operationSelectId) {
-            const sel = fs.getFormulaireNodeById(this._operationSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         if (json["calcType"] === "YAXN") {
             // indice après lequel insérer le nouveau FieldSet
@@ -63,13 +46,4 @@ export class FormulaireSPP extends FormulaireRepeatableFieldset {
         }
         return n as FieldsetContainer;
     }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            this.reset();
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-trigo.ts b/src/app/formulaire/definition/form-trigo.ts
deleted file mode 100644
index 332325710e2cd28720ae7b36bf1d0a05f7af945b..0000000000000000000000000000000000000000
--- a/src/app/formulaire/definition/form-trigo.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireFixedVar } from "./form-fixedvar";
-
-/**
- * Formulaire pour les fonctions trigonométriques
- */
-export class FormulaireTrigo extends FormulaireFixedVar {
-
-    /** id of select configuring operation */
-    private _operationSelectId: string;
-
-    /** id of select configuring unit */
-    private _unitSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._operationSelectId = this.getOption(json, "operationSelectId");
-        this._unitSelectId = this.getOption(json, "unitSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._operationSelectId) {
-            const sel = fs.getFormulaireNodeById(this._operationSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-        if (this._unitSelectId) {
-            const sel = fs.getFormulaireNodeById(this._unitSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            this.reset();
-        }
-    }
-}
diff --git a/src/app/formulaire/elements/fieldset-template.ts b/src/app/formulaire/elements/fieldset-template.ts
index de8c1e2d84ed973b8adf9c11de575143eb11eb03..3c9071131a974222b80bd5e26762f715de9e1864 100644
--- a/src/app/formulaire/elements/fieldset-template.ts
+++ b/src/app/formulaire/elements/fieldset-template.ts
@@ -1,5 +1,5 @@
 import { FieldSet } from "./fieldset";
-import { CalculatorType, ComputeNodeType, LoiDebit, Nub, StructureType } from "jalhyd";
+import { CalculatorType, LoiDebit, Nub, StructureType, SectionType } from "jalhyd";
 import { FormulaireDefinition } from "../definition/form-definition";
 import { FieldsetContainer } from "./fieldset-container";
 
@@ -19,9 +19,9 @@ export class FieldsetTemplate {
         return CalculatorType[ct];
     }
 
-    public get defaultNodeTypeFromConfig(): ComputeNodeType {
+    public get defaultNodeTypeFromConfig(): SectionType {
         const nt: string = this._jsonConfig["defaultNodeType"];
-        return ComputeNodeType[nt];
+        return SectionType[nt];
     }
 
     public get defaultStructTypeFromConfig(): StructureType {
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index 5e36142cc6c992e91d9edb77a6a332575cf59f3e..0472fdc5279f0f997a5222c057c566d3935a26c0 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -1,51 +1,33 @@
 import {
     CalculatorType,
     ParamDefinition,
-    LCMaterial,
-    LoiDebit,
     Props,
     Observer,
     Nub,
-    MethodeResolution,
-    GrilleType,
-    GrilleProfile,
-    BiefRegime,
-    TrigoOperation,
-    TrigoUnit,
-    SPPOperation,
+    Session,
 } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
 import { SelectField } from "./select-field";
 import { NgParameter, ParamRadioConfig } from "./ngparam";
-import { FormulaireDefinition } from "../definition/form-definition";
 import { StringMap } from "../../stringmap";
-import { FormulaireNode } from "./formulaire-node";
 import { FieldsetContainer } from "./fieldset-container";
 import { SelectFieldNub } from "./select-field-nub";
 import { SelectFieldParameter } from "./select-field-parameter";
+import { FormulaireFixedVar } from "../definition/form-fixedvar";
 
 export class FieldSet extends FormulaireElement implements Observer {
-    /**
-     * Nub associé
-     */
+
+    /** Nub associé */
     private _nub: Nub;
 
-    /**
-     * dictionnaire de traduction
-     */
+    /** dictionnaire de traduction */
     private _localisation: StringMap;
 
-    /**
-     * fichier de configuration
-     */
+    /** fichier de configuration */
     private _jsonConfig: {};
 
-    constructor(parent: FormulaireNode) {
-        super(parent);
-    }
-
     public get nub(): Nub {
         return this._nub;
     }
@@ -185,6 +167,9 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     private parseFields() {
+        // clear everything so that parseFields() is idempotent
+        this.clearFields();
+        // parse children fields from config
         const fields = this._jsonConfig["fields"];
         for (const field_index in fields) {
             let field = fields[field_index];
@@ -245,60 +230,16 @@ export class FieldSet extends FormulaireElement implements Observer {
      * Reflects all properties values in the interface, through the values of the <select> fields
      */
     public updateFields() {
-        this.clearFields();
         this.parseFields();
         this.updateLocalisation();
 
-        // MAJ des selects avec les valeurs actuelles des propriétés
-        // spécifique à chaque modul de calcul, à revoir
-        switch (this._confId) {
-
-            case "fs_ouvrage":
-                this.setSelectValueFromProperty("select_structure", "structureType");
-                this.setSelectValueFromProperty("select_loidebit", "loiDebit");
-                break;
-
-            case "fs_section":
-                // property nodeType is stored in the section, not in the parent Nub
-                this.setSelectValueFromProperty("select_section", "nodeType", true);
-                break;
-
-            case "fs_param_calc":
-                this.setSelectValueFromProperty("select_resolution", "methodeResolution");
-                break;
-
-            case "fs_materiau":
-                this.setSelectValueFromProperty("select_material", "material");
-                break;
-
-            case "fs_target_data": // courbe de remous
-                this.setSelectValueFromProperty("select_target", "varCalc");
-                break;
-
-            case "fs_pass_type": // macro-rugo complexe
-                this.setSelectValueFromProperty("select_pass_type", "inclinedApron");
-                break;
-
-            case "fs_plan": // Grille
-                this.setSelectValueFromProperty("select_grid_type", "gridType");
-                break;
-
-            case "fs_grille": // Grille
-                this.setSelectValueFromProperty("select_grid_profile", "gridProfile");
-                break;
-
-            case "fs_water_line": // Bief
-                this.setSelectValueFromProperty("select_regime", "regime");
-                break;
-
-            case "fs_trigo": // Trigo
-                this.setSelectValueFromProperty("select_operation", "trigoOperation");
-                this.setSelectValueFromProperty("select_unit", "trigoUnit");
-                break;
-
-            case "fs_spp": // SPP
-                this.setSelectValueFromProperty("select_spp_operation", "sppOperation");
-                break;
+        // for all select fields known by the form, set selected value
+        // from associated property
+        if (this.parentForm instanceof FormulaireFixedVar) {
+            const selectIds = this.parentForm.selectids;
+            for (const sId of selectIds) {
+                this.setSelectValueFromProperty(sId, (this._confId === "fs_section"));
+            }
         }
     }
 
@@ -306,10 +247,10 @@ export class FieldSet extends FormulaireElement implements Observer {
      * Reflects a property value in the interface, through the value of a <select> field, if this select exists
      * @param inSection if true, will look for the required property in the Nub's section (children[0])
      */
-    private setSelectValueFromProperty(selectId: string, propertyKey: string, inSection: boolean = false) {
+    private setSelectValueFromProperty(selectId: string, inSection: boolean = false) {
         const selectField: SelectField = this.getFormulaireNodeById(selectId) as SelectField;
         if (selectField) {
-            let propVal: any = this.getPropValue(propertyKey, inSection);
+            let propVal: any = this.getPropValue(selectField.associatedProperty, inSection);
             if (propVal === undefined) {
                 propVal = ""; // clodo bullet-proof loading
             }
@@ -317,26 +258,13 @@ export class FieldSet extends FormulaireElement implements Observer {
             try {
                 selectField.setValue(selectElement);
             } catch (e) {
-                console.error(`setSelectValueFromProperty: cannot set value ${propVal} on <select> ${selectId}`);
+                // silent fail, to avoid errors being thrown in Structure Nubs when
+                // trying to apply same LoiDebit on new StructureType
+                // console.error(`setSelectValueFromProperty: cannot set value ${propVal} on <select> ${selectId}`);
             }
         }
     }
 
-    /**
-     * Sets Nub default property from config file, unless this property is already set
-     */
-    private setPropertyValueFromConfig(json: {}, configKey: string, propertyKey: string, enumClass?) {
-        const configValue: string = json[configKey];
-        const currentValue = this.properties.getPropValue(propertyKey);
-        if (configValue && (currentValue === undefined)) {
-            let formalValue =  configValue;
-            if (enumClass) {
-                formalValue = enumClass[configValue];
-            }
-            this.setPropValue(propertyKey, formalValue);
-        }
-    }
-
     /**
      * Sets Nub default properties from config file, unless properties values are already set
      * (when deserialising an existing Nub)
@@ -348,23 +276,39 @@ export class FieldSet extends FormulaireElement implements Observer {
         this._confId = json["id"];
         this._helpLink = json["help"];
 
-        const parentForm = this.parentForm as FormulaireDefinition;
         const ct: string = json["calcType"];
         const currentCt = this.properties.getPropValue("calcType");
-        const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : parentForm.calculatorType);
+        const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : this.parentForm.calculatorType);
         this.setPropValue("calcType", calc_type);
 
-        this.setPropertyValueFromConfig(json, "defaultStructType", "structureType");
-        this.setPropertyValueFromConfig(json, "defaultLoiDebit", "loiDebit", LoiDebit);
-        this.setPropertyValueFromConfig(json, "methodeResolution", "methodeResolution", MethodeResolution);
-        this.setPropertyValueFromConfig(json, "defaultMaterial", "material", LCMaterial);
-        this.setPropertyValueFromConfig(json, "defaultGridProfile", "gridProfile", GrilleProfile);
-        this.setPropertyValueFromConfig(json, "defaultGridType", "gridType", GrilleType);
-        this.setPropertyValueFromConfig(json, "defaultRegime", "regime", BiefRegime);
-        this.setPropertyValueFromConfig(json, "varCalc", "varCalc");
-        this.setPropertyValueFromConfig(json, "defaultOperation", "trigoOperation", TrigoOperation);
-        this.setPropertyValueFromConfig(json, "defaultUnit", "trigoUnit", TrigoUnit);
-        this.setPropertyValueFromConfig(json, "defaultOperation", "sppOperation", SPPOperation);
+        // parse fields once, so that SelectField elements are present
+        // when setting default properties below
+        this.parseFields();
+
+        // for all select fields known by the form, apply default value
+        // to associated property, usually from associated enum
+        if (this.parentForm instanceof FormulaireFixedVar) {
+            const selectIds = this.parentForm.selectids;
+            for (const sId of selectIds) {
+                // find select element in parent form
+                const fe = this.getFormulaireNodeById(sId);
+                if (fe) {
+                    const prop = (fe as SelectField).associatedProperty;
+                    const defaultValue = (fe as SelectField).defaultValue;
+                    // Sets Nub default property, unless this property is already set
+                    const currentValue = this.properties.getPropValue(prop);
+                    if (defaultValue !== undefined && currentValue === undefined) {
+                        let formalValue = defaultValue;
+                        // !! property names must be unique throughout JaLHyd !!
+                        const enumClass = Session.enumFromProperty[prop];
+                        if (enumClass) {
+                            formalValue = enumClass[defaultValue];
+                        }
+                        this.setPropValue(prop, formalValue);
+                    }
+                }
+            }
+        }
 
         this.updateFields();
     }
@@ -416,57 +360,36 @@ export class FieldSet extends FormulaireElement implements Observer {
             switch (data.action) {
                 case "select":
                     const senderId: string = sender.id.replace(/\d+$/, "");
-                    switch (senderId) {
-                        case "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");
-                            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, {
-                                    action: "propertyChange",
-                                    name: "nodeType",
-                                    value: data.value.value
-                                });
+                    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");
+                        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, {
+                                action: "propertyChange",
+                                name: "nodeType",
+                                value: data.value.value
+                            });
+                        }
+                    } else {
+                        // for all select fields known by the form, apply received value
+                        // to associated property
+                        if (this.parentForm instanceof FormulaireFixedVar) {
+                            const selectIds = this.parentForm.selectids;
+                            for (const sId of selectIds) {
+                                if (senderId === sId) {
+                                    // find select element in parent form
+                                    const fe = this.parentForm.getFieldById(sId);
+                                    if (fe) {
+                                        const prop = (fe as SelectField).associatedProperty;
+                                        this.setPropValue(prop, data.value.value);
+                                    }
+                                }
                             }
-                            break;
-                        case "select_structure": // ouvrages parallèles
-                            this.setPropValue("structureType", data.value.value);
-                            break;
-                        case "select_loidebit": // ouvrages parallèles et dérivés
-                            this.setPropValue("loiDebit", data.value.value);
-                            break;
-                        case "select_resolution": // courbes de remous, méthode de résolution
-                            this.setPropValue("methodeResolution", data.value.value);
-                            break;
-                        case "select_target": // courbes de remous, variable à calculer
-                            this.setPropValue("varCalc", data.value.value);
-                            break;
-                        case "select_material": // Lechapt-Calmon, matériau
-                            this.setPropValue("material", data.value.value);
-                            break;
-                        case "select_pass_type": // macro-rugo complexe
-                            this.setPropValue("inclinedApron", data.value.value);
-                            break;
-                        case "select_grid_type": // Grille
-                            this.setPropValue("gridType", data.value.value);
-                            break;
-                        case "select_grid_profile": // Grille
-                            this.setPropValue("gridProfile", data.value.value);
-                            break;
-                        case "select_regime": // Bief
-                            this.setPropValue("regime", data.value.value);
-                            break;
-                        case "select_operation": // Trigo
-                            this.setPropValue("trigoOperation", data.value.value);
-                            break;
-                        case "select_unit": // Trigo
-                            this.setPropValue("trigoUnit", data.value.value);
-                            break;
-                        case "select_spp_operation": // SPP
-                            this.setPropValue("sppOperation", data.value.value);
-                            break;
+                        }
                     }
-                    break;
+                    break; // switch (data.action)
             }
         }
     }
diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts
index 0d98274bb9d0a81f8891e02e80bcf0d3a5696cde..cfd54a582adbfafdd6b8d21962df848178b30210 100644
--- a/src/app/formulaire/elements/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -1,17 +1,11 @@
 import {
-    BiefRegime,
-    LechaptCalmon,
     acSection,
     CourbeRemous,
     Nub,
     ParallelStructure,
     StructureType,
     LoiDebit,
-    GrilleType,
-    GrilleProfile,
-    TrigoUnit,
-    TrigoOperation,
-    SPPOperation
+    Session
  } from "jalhyd";
 
 import { Field } from "./field";
@@ -29,6 +23,12 @@ export class SelectField extends Field {
 
     protected _selectedEntry: SelectEntry;
 
+    /** name of the Nub property associated to this field, if any */
+    protected _associatedProperty: string;
+
+    /** default value for this field */
+    protected _defaultValue: string;
+
     constructor(parent: FormulaireNode) {
         super(parent);
         this.clearEntries();
@@ -42,6 +42,14 @@ export class SelectField extends Field {
         return this._entries;
     }
 
+    public get associatedProperty(): string {
+        return this._associatedProperty;
+    }
+
+    public get defaultValue(): string {
+        return this._defaultValue;
+    }
+
     public clearEntries() {
         this._entries = [];
     }
@@ -123,34 +131,14 @@ export class SelectField extends Field {
         this._confId = field["id"];
         this._entriesBaseId = this._confId + "_";
         this._helpLink = field["help"];
+        this._associatedProperty = field["property"];
+        this._defaultValue = field["default"];
         const source = field["source"];
+
         const nub: Nub = (this.parentForm as FormulaireDefinition).currentNub;
         // ad-hoc cases
         switch (source) {
-
-            case "lechapt_calmon_material":
-                let i = 0;
-                for (const mat of LechaptCalmon.materials) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + (i + 1), i);
-                    this.addEntry(e);
-                    i++;
-                }
-                break;
-
-            case "acsection_section":
-                for (const sec of acSection.availableSectionTypes) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + sec.id, sec.value);
-                    this.addEntry(e);
-                }
-                break;
-
-            case "remous_methode_resolution":
-                for (const mr of CourbeRemous.availableMethodeResolution) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + mr.id, mr.value);
-                    this.addEntry(e);
-                }
-                break;
-
+            // driven by string[], not enum (easier for variable names)
             case "remous_target":
                 this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
                 for (const at of CourbeRemous.availableTargets) {
@@ -159,6 +147,7 @@ export class SelectField extends Field {
                 }
                 break;
 
+            // possible values depend on CalcType
             case "device_structure_type":
                 for (const st in (nub as ParallelStructure).getLoisAdmissibles()) {
                     const e: SelectEntry = new SelectEntry(this._entriesBaseId + st, StructureType[st]);
@@ -166,6 +155,7 @@ export class SelectField extends Field {
                 }
                 break;
 
+            // possible values depend on CalcType
             case "device_loi_debit":
                 // get current structure type from appropriate Nub child
                 const child = nub.getChildren()[this.parent.indexAsKid()];
@@ -178,43 +168,16 @@ export class SelectField extends Field {
                 }
                 break;
 
-            case "mrc_pass_type": // macrorugo complexe: type de radier
-                this.addEntry(new SelectEntry(this._entriesBaseId + "0", false));
-                this.addEntry(new SelectEntry(this._entriesBaseId + "1", true));
-                break;
-
-            case "grille_type": // Grille: type de grille
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Conventional, GrilleType.Conventional));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Oriented, GrilleType.Oriented));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Inclined, GrilleType.Inclined));
-                break;
-
-            case "grille_profile": // Grille: profil des barreaux
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Rectangular, GrilleProfile.Rectangular));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Hydrodynamic, GrilleProfile.Hydrodynamic));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Custom, GrilleProfile.Custom));
-                break;
-
-            case "bief_regime": // Bief: type de régime
-                this.addEntry(new SelectEntry(this._entriesBaseId + BiefRegime.Fluvial, BiefRegime.Fluvial));
-                this.addEntry(new SelectEntry(this._entriesBaseId + BiefRegime.Torrentiel, BiefRegime.Torrentiel));
-                break;
-
-            case "trigo_operation": // Trigo: opération (cos, sin…)
-                for (let j = 0; j < Object.keys(TrigoOperation).length / 2; j++) {
-                    this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
+            // general case : property values taken from an enum
+            default:
+                // find enum associated to property
+                const enumClass = Session.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++) {
+                        this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
+                    }
                 }
-                break;
-
-            case "trigo_unit": // Trigo: unité (degrés, radians)
-                this.addEntry(new SelectEntry(this._entriesBaseId + TrigoUnit.DEG, TrigoUnit.DEG));
-                this.addEntry(new SelectEntry(this._entriesBaseId + TrigoUnit.RAD, TrigoUnit.RAD));
-                break;
-
-            case "spp_operation": // SPP: opération (somme, produit)
-                this.addEntry(new SelectEntry(this._entriesBaseId + SPPOperation.SUM, SPPOperation.SUM));
-                this.addEntry(new SelectEntry(this._entriesBaseId + SPPOperation.PRODUCT, SPPOperation.PRODUCT));
-                break;
         }
 
         this.afterParseConfig();
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index c4dc4ab45ee6325c8e3b03551c82f5f42602a3c6..101572ca12f6d88a4cc3658d284cf375357e3f4b 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -29,20 +29,17 @@ import { SelectField } from "../formulaire/elements/select-field";
 import { StringMap } from "../stringmap";
 import { FormulaireSectionParametree } from "../formulaire/definition/form-section-parametree";
 import { FormulaireCourbeRemous } from "../formulaire/definition/form-courbe-remous";
-import { FormulaireRegimeUniforme } from "../formulaire/definition/form-regime-uniforme";
 import { FormulaireParallelStructure } from "../formulaire/definition/form-parallel-structures";
 import { NgParameter } from "../formulaire/elements/ngparam";
 import { FieldsetContainer } from "../formulaire/elements/fieldset-container";
 import { FormulairePab } from "../formulaire/definition/form-pab";
 import { FormulaireMacrorugoCompound } from "../formulaire/definition/form-macrorugo-compound";
-import { FormulaireLechaptCalmon } from "../formulaire/definition/form-lechapt-calmon";
 import { FormulaireGrille } from "../formulaire/definition/form-grille";
-import { FormulaireBief } from "../formulaire/definition/form-bief";
 import { FormulaireSolveur } from "../formulaire/definition/form-solveur";
 import { AppComponent } from "../app.component";
 import { FormulaireSPP } from "../formulaire/definition/form-spp";
-import { FormulaireTrigo } from "../formulaire/definition/form-trigo";
 import { FormulaireFixedVar } from "../formulaire/definition/form-fixedvar";
+import { FormulaireSection } from "../formulaire/definition/form-section";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -275,22 +272,15 @@ export class FormulaireService extends Observable {
                 f = new FormulaireSectionParametree();
                 break;
 
+            case CalculatorType.Bief:
             case CalculatorType.RegimeUniforme:
-                f = new FormulaireRegimeUniforme();
+                f = new FormulaireSection();
                 break;
 
             case CalculatorType.CourbeRemous:
                 f = new FormulaireCourbeRemous();
                 break;
 
-            case CalculatorType.Bief:
-                f = new FormulaireBief();
-                break;
-
-            case CalculatorType.LechaptCalmon:
-                f = new FormulaireLechaptCalmon();
-                break;
-
             case CalculatorType.ParallelStructure:
             case CalculatorType.Dever:
             case CalculatorType.Cloisons:
@@ -317,10 +307,6 @@ export class FormulaireService extends Observable {
                 f = new FormulaireSPP();
                 break;
 
-            case CalculatorType.Trigo:
-                f = new FormulaireTrigo();
-                break;
-
             default:
                 f = new FormulaireFixedVar();
         }