From 847dc9455860c8b8b0e3ba08e297b3390f479cdc Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 13 Jan 2020 15:43:24 +0100
Subject: [PATCH] Fix #353 - merge Formulaire classes

---
 DEVELOPERS.md                                 |   8 +-
 README.md                                     |   8 +
 src/app/app.component.ts                      |   8 +
 .../base-param-input.component.ts             |   2 +-
 .../calculator-list.component.ts              |  10 +-
 .../dialog-edit-param-computed.component.ts   |   2 +-
 .../dialog-edit-param-values.component.ts     |   2 +-
 .../field-set/field-set.component.ts          |  14 +-
 .../fieldset-container.component.ts           |   4 +-
 .../fixed-results.component.ts                |   2 +-
 .../fixedvar-results.component.ts             |   2 +-
 .../fixedvar-results/results.component.ts     |   2 +-
 .../calculator.component.ts                   |   8 +-
 .../generic-input/generic-input.component.ts  |   2 +-
 .../macrorugo-compound-results.component.ts   |   2 +-
 .../ngparam-input/ngparam-input.component.ts  |   2 +-
 .../pab-results/pab-results.component.ts      |   2 +-
 .../pab-table/pab-table.component.ts          |   2 +-
 .../param-computed.component.ts               |   2 +-
 .../param-field-line.component.ts             |   2 +-
 .../param-link/param-link.component.ts        |   2 +-
 .../param-values/param-values.component.ts    |   2 +-
 .../select-field-line.component.ts            |   6 +-
 .../select-model-field-line.component.ts      |   6 +-
 .../jalhyd-model-validation.directive.ts      |   2 +-
 .../definition/concrete/form-base.ts          |  54 -------
 .../definition/concrete/form-courbe-remous.ts |  79 ----------
 .../definition/concrete/form-pab.ts           |  25 ----
 .../concrete/form-section-parametree.ts       |  69 ---------
 .../definition/{concrete => }/form-bief.ts    |  14 +-
 .../definition/form-compute-courbe-remous.ts  |  52 -------
 .../definition/form-compute-fixedvar.ts       |  46 ------
 .../form-compute-macrorugo-compound.ts        |  46 ------
 .../form-compute-parallel-structures.ts       |  22 ---
 .../form-compute-section-parametree.ts        |  57 -------
 src/app/formulaire/definition/form-compute.ts |  93 ------------
 .../definition/form-courbe-remous.ts          | 122 +++++++++++++++
 .../formulaire/definition/form-definition.ts  | 139 +++++++++++++-----
 ...rm-result-fixedvar.ts => form-fixedvar.ts} |  53 +++++--
 .../definition/{concrete => }/form-grille.ts  |   9 +-
 .../{concrete => }/form-lechapt-calmon.ts     |   6 +-
 .../{concrete => }/form-macrorugo-compound.ts |  74 ++++++++--
 .../{form-compute-pab.ts => form-pab.ts}      |  53 +++++--
 .../form-parallel-structures.ts               |  45 +++---
 .../{concrete => }/form-regime-uniforme.ts    |  29 +---
 .../form-repeatable-fieldset.ts               |  10 +-
 .../form-result-macrorugo-compound.ts         |  35 -----
 .../formulaire/definition/form-result-pab.ts  |  35 -----
 .../definition/form-result-remous.ts          |  35 -----
 .../definition/form-result-section.ts         |  72 ---------
 src/app/formulaire/definition/form-result.ts  |  13 --
 .../definition/form-section-parametree.ts     | 107 ++++++++++++++
 .../{form-def-section.ts => form-section.ts}  |  32 ++--
 .../definition/{concrete => }/form-solveur.ts |  12 +-
 .../definition/{concrete => }/form-spp.ts     |   6 +-
 .../definition/{concrete => }/form-trigo.ts   |   6 +-
 src/app/formulaire/{ => elements}/field.ts    |   0
 .../{ => elements}/fieldset-container.ts      |   2 +-
 .../{ => elements}/fieldset-template.ts       |   2 +-
 src/app/formulaire/{ => elements}/fieldset.ts |   4 +-
 .../{ => elements}/formulaire-element.ts      |   9 +-
 .../{ => elements}/formulaire-node.ts         |   3 +-
 .../formulaire/{ => elements}/input-field.ts  |   0
 src/app/formulaire/{ => elements}/ngparam.ts  |   4 +-
 .../formulaire/{ => elements}/pab-table.ts    |   2 +-
 .../formulaire/{ => elements}/select-entry.ts |   0
 .../{ => elements}/select-field-model.ts      |   0
 .../{ => elements}/select-field-nub.ts        |   4 +-
 .../{ => elements}/select-field-parameter.ts  |   4 +-
 .../{ => elements}/select-field-reference.ts  |   0
 .../formulaire/{ => elements}/select-field.ts |   4 +-
 .../form-iterator/abstract-node-iterator.ts   |   2 +-
 .../form-iterator/deep-element-iterator.ts    |   2 +-
 .../form-iterator/deep-fieldset-iterator.ts   |   4 +-
 .../form-iterator/top-element-iterator.ts     |   2 +-
 src/app/results/calculator-results.ts         |   2 +-
 src/app/results/fixed-results.ts              |   2 +-
 src/app/results/multidimension-results.ts     |   2 +-
 src/app/results/param-calc-results.ts         |   2 +-
 src/app/results/remous-results.ts             |   2 +-
 src/app/results/var-results.ts                |   2 +-
 src/app/services/formulaire.service.ts        |  48 +++---
 src/app/util.ts                               |   2 +-
 83 files changed, 657 insertions(+), 1007 deletions(-)
 delete mode 100644 src/app/formulaire/definition/concrete/form-base.ts
 delete mode 100644 src/app/formulaire/definition/concrete/form-courbe-remous.ts
 delete mode 100644 src/app/formulaire/definition/concrete/form-pab.ts
 delete mode 100644 src/app/formulaire/definition/concrete/form-section-parametree.ts
 rename src/app/formulaire/definition/{concrete => }/form-bief.ts (83%)
 delete mode 100644 src/app/formulaire/definition/form-compute-courbe-remous.ts
 delete mode 100644 src/app/formulaire/definition/form-compute-fixedvar.ts
 delete mode 100644 src/app/formulaire/definition/form-compute-macrorugo-compound.ts
 delete mode 100644 src/app/formulaire/definition/form-compute-parallel-structures.ts
 delete mode 100644 src/app/formulaire/definition/form-compute-section-parametree.ts
 delete mode 100644 src/app/formulaire/definition/form-compute.ts
 create mode 100644 src/app/formulaire/definition/form-courbe-remous.ts
 rename src/app/formulaire/definition/{form-result-fixedvar.ts => form-fixedvar.ts} (50%)
 rename src/app/formulaire/definition/{concrete => }/form-grille.ts (88%)
 rename src/app/formulaire/definition/{concrete => }/form-lechapt-calmon.ts (83%)
 rename src/app/formulaire/definition/{concrete => }/form-macrorugo-compound.ts (69%)
 rename src/app/formulaire/definition/{form-compute-pab.ts => form-pab.ts} (59%)
 rename src/app/formulaire/definition/{concrete => }/form-parallel-structures.ts (88%)
 rename src/app/formulaire/definition/{concrete => }/form-regime-uniforme.ts (51%)
 rename src/app/formulaire/definition/{concrete => }/form-repeatable-fieldset.ts (84%)
 delete mode 100644 src/app/formulaire/definition/form-result-macrorugo-compound.ts
 delete mode 100644 src/app/formulaire/definition/form-result-pab.ts
 delete mode 100644 src/app/formulaire/definition/form-result-remous.ts
 delete mode 100644 src/app/formulaire/definition/form-result-section.ts
 delete mode 100644 src/app/formulaire/definition/form-result.ts
 create mode 100644 src/app/formulaire/definition/form-section-parametree.ts
 rename src/app/formulaire/definition/{form-def-section.ts => form-section.ts} (53%)
 rename src/app/formulaire/definition/{concrete => }/form-solveur.ts (89%)
 rename src/app/formulaire/definition/{concrete => }/form-spp.ts (92%)
 rename src/app/formulaire/definition/{concrete => }/form-trigo.ts (87%)
 rename src/app/formulaire/{ => elements}/field.ts (100%)
 rename src/app/formulaire/{ => elements}/fieldset-container.ts (98%)
 rename src/app/formulaire/{ => elements}/fieldset-template.ts (96%)
 rename src/app/formulaire/{ => elements}/fieldset.ts (99%)
 rename src/app/formulaire/{ => elements}/formulaire-element.ts (88%)
 rename src/app/formulaire/{ => elements}/formulaire-node.ts (97%)
 rename src/app/formulaire/{ => elements}/input-field.ts (100%)
 rename src/app/formulaire/{ => elements}/ngparam.ts (99%)
 rename src/app/formulaire/{ => elements}/pab-table.ts (93%)
 rename src/app/formulaire/{ => elements}/select-entry.ts (100%)
 rename src/app/formulaire/{ => elements}/select-field-model.ts (100%)
 rename src/app/formulaire/{ => elements}/select-field-nub.ts (93%)
 rename src/app/formulaire/{ => elements}/select-field-parameter.ts (94%)
 rename src/app/formulaire/{ => elements}/select-field-reference.ts (100%)
 rename src/app/formulaire/{ => elements}/select-field.ts (98%)

diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index 6c7ea22aa..05022eb49 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -124,6 +124,8 @@ Les tests unitaires dits "end-to-end" ou "e2e" sont réalisés avec Protractor,
 
 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).
+
 ### scripts
 
 Le dossier `scripts` contient des scripts d'aide à la compilation, utilisés par les commandes `npm` déclarées dans `package.json`.
@@ -238,7 +240,7 @@ En général la classe `FormulaireBase` est suffisante pour gérer un nouveau mo
 
 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/concrete` Par exemple `form-macrorugo-compound.ts`.
+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.
 
@@ -347,7 +349,7 @@ Dans ce même fichier de configuration, dans le dernier élément "options", ajo
  
 #### 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/select-field.ts`. Exemple pour "trigoOperation" :
+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…)
@@ -359,7 +361,7 @@ case "trigo_operation": // (cos, sin…)
 
 #### 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/fieldset.ts` comme suit (exemple pour le module `Trigo`).
+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()`
 
diff --git a/README.md b/README.md
index a3bcbdc41..6c2ae0811 100644
--- a/README.md
+++ b/README.md
@@ -225,6 +225,14 @@ npm run viz
 
 Custom Material SVG Icons will only show up when the application is deployed on the domain root (no subfolders), see [this feature request](https://github.com/angular/material2/issues/4263)
 
+### chromedriver version in e2e tests
+
+It is possible that Chrome / Chromium version installed on your system evolves faster than the Chrome Selenium driver (`chromedriver`) installed by "protractor" dependency of Angular, which makes e2e tests fail with an error message about versions compatibility. In this case, it's possible to install an updated system-wide version of the pilot:
+```bash
+sudo npm install -g protractor
+sudo webdriver-manager update
+sudo find /usr/lib/node_modules/protractor -regextype sed -regex "^.*/chromedriver.*[0-9]$" -exec ln -s '{}' /usr/bin/chromedriver ';'
+```
 
 ## Release policy
 
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 6f2375744..55812e840 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -747,6 +747,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
    */
   public scrollToQuicknav(itemId: string, behavior: ScrollBehavior = "smooth") {
     const idx = this.getCalculatorIndexFromId(this.currentFormId);
+    let succeeded = false;
     if (idx > -1) {
       const id = QuicknavComponent.prefix + itemId;
       // Scroll https://stackoverflow.com/a/56391657/5986614
@@ -757,10 +758,17 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
               top: yCoordinate - 60, // substract a little more than navbar height
               behavior: behavior
           });
+          succeeded = true;
           // Save position
           this._calculators[idx].latestAnchor = itemId;
       }
     }
+    if (! succeeded) {
+      // throw an error so that caller CalculatorComponent.scrollToResults()
+      // switches to plan B, in case we're trying to scroll to results pane
+      // after a module is calculated
+      throw Error("unable to scroll to quicknav anchor");
+    }
   }
 
   /**
diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts
index 49d20f3ef..44ea91b9b 100644
--- a/src/app/components/base-param-input/base-param-input.component.ts
+++ b/src/app/components/base-param-input/base-param-input.component.ts
@@ -7,7 +7,7 @@ import { Message, ParamDefinition, ParamDomain, ParamDomainValue, Observable } f
 import { I18nService } from "../../services/internationalisation.service";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
 import { ServiceFactory } from "../../services/service-factory";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 
 export class NgBaseParam extends Observable {
diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts
index d9047b66f..f64758d72 100644
--- a/src/app/components/calculator-list/calculator-list.component.ts
+++ b/src/app/components/calculator-list/calculator-list.component.ts
@@ -6,13 +6,13 @@ import { CalculatorType, EnumEx, Session } from "jalhyd";
 import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 import { ServiceFactory } from "../../services/service-factory";
 import { I18nService } from "../../services/internationalisation.service";
-import { FormulaireParallelStructure } from "../../formulaire/definition/concrete/form-parallel-structures";
-import { FieldsetContainer } from "../../formulaire/fieldset-container";
-import { FormulairePab } from "../../formulaire/definition/concrete/form-pab";
+import { FormulaireParallelStructure } from "../../formulaire/definition/form-parallel-structures";
+import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
+import { FormulairePab } from "../../formulaire/definition/form-pab";
 import { HttpService } from "../../services/http.service";
 import { AppComponent } from "../../app.component";
-import { FormulaireMacrorugoCompound } from "../../formulaire/definition/concrete/form-macrorugo-compound";
-import { FormulaireSPP } from "../../formulaire/definition/concrete/form-spp";
+import { FormulaireMacrorugoCompound } from "../../formulaire/definition/form-macrorugo-compound";
+import { FormulaireSPP } from "../../formulaire/definition/form-spp";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 
 
diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
index eeaa8ccd1..ca943003a 100644
--- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
+++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
@@ -1,7 +1,7 @@
 import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material";
 import { Inject, Component, ViewChild, OnInit } from "@angular/core";
 import { I18nService } from "../../services/internationalisation.service";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { NgParamInputComponent } from "../ngparam-input/ngparam-input.component";
 
 @Component({
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
index 5032b6eca..80bd1baff 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
@@ -3,7 +3,7 @@ import { Inject, Component, OnInit } from "@angular/core";
 import { FormBuilder, FormGroup, Validators } from "@angular/forms";
 
 import { I18nService } from "../../services/internationalisation.service";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { ResultsComponent } from "../fixedvar-results/results.component";
 
 import { sprintf } from "sprintf-js";
diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts
index ef2cc6885..c8201280b 100644
--- a/src/app/components/field-set/field-set.component.ts
+++ b/src/app/components/field-set/field-set.component.ts
@@ -1,14 +1,14 @@
 import { Component, Input, Output, EventEmitter, ViewChildren, QueryList, DoCheck } from "@angular/core";
 
-import { ParamRadioConfig } from "../../formulaire/ngparam";
-import { FieldSet } from "../../formulaire/fieldset";
+import { ParamRadioConfig } from "../../formulaire/elements/ngparam";
+import { FieldSet } from "../../formulaire/elements/fieldset";
 import { ParamFieldLineComponent } from "../param-field-line/param-field-line.component";
-import { Field } from "../../formulaire/field";
-import { InputField } from "../../formulaire/input-field";
-import { SelectField } from "../../formulaire/select-field";
-import { FormulairePab } from "../../formulaire/definition/concrete/form-pab";
+import { Field } from "../../formulaire/elements/field";
+import { InputField } from "../../formulaire/elements/input-field";
+import { SelectField } from "../../formulaire/elements/select-field";
+import { FormulairePab } from "../../formulaire/definition/form-pab";
 import { SelectFieldLineComponent } from "../select-field-line/select-field-line.component";
-import { FieldsetContainer } from "../../formulaire/fieldset-container";
+import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
 import { NotificationsService } from "../../services/notifications.service";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 import { I18nService } from "../../services/internationalisation.service";
diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts
index 2d206a133..dbc3a5a22 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.ts
+++ b/src/app/components/fieldset-container/fieldset-container.component.ts
@@ -1,8 +1,8 @@
 import { Component, Input, Output, EventEmitter, QueryList, ViewChildren, DoCheck, AfterViewInit } from "@angular/core";
 
-import { FieldsetContainer } from "../../formulaire/fieldset-container";
+import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
 import { FieldSetComponent } from "../field-set/field-set.component";
-import { FieldSet } from "../../formulaire/fieldset";
+import { FieldSet } from "../../formulaire/elements/fieldset";
 import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 import { I18nService } from "../../services/internationalisation.service";
 import { ApplicationSetupService } from "../../services/app-setup.service";
diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index ab00d2350..9681fa15d 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -1,7 +1,7 @@
 import { Component, ViewChild, ElementRef } from "@angular/core";
 
 import { FixedResults } from "../../results/fixed-results";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { CalculatorResults } from "../../results/calculator-results";
 import { I18nService } from "../../services/internationalisation.service";
 import { FormulaireService } from "../../services/formulaire.service";
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index 58bbbf90c..6aa179c30 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -6,7 +6,7 @@ import { VarResults } from "../../results/var-results";
 import { ResultsChartComponent } from "../results-chart/results-chart.component";
 import { CalculatorResults } from "../../results/calculator-results";
 import { Result, cLog } from "jalhyd";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { FixedResultsComponent } from "./fixed-results.component";
 import { VarResultsComponent } from "./var-results.component";
 import { ResultsComponent } from "./results.component";
diff --git a/src/app/components/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts
index 355a28b31..296ba3edf 100644
--- a/src/app/components/fixedvar-results/results.component.ts
+++ b/src/app/components/fixedvar-results/results.component.ts
@@ -1,7 +1,7 @@
 import * as screenfull from "screenfull";
 import { Screenfull } from "screenfull"; // @see https://github.com/sindresorhus/screenfull.js/issues/126#issuecomment-488796645
 
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { ServiceFactory } from "../../services/service-factory";
 import { fv } from "../../util";
 
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 8e256b367..44f7e7e26 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -8,20 +8,20 @@ import { AppComponent } from "../../app.component";
 import { FormulaireService } from "../../services/formulaire.service";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 import { I18nService } from "../../services/internationalisation.service";
-import { FieldSet } from "../../formulaire/fieldset";
+import { FieldSet } from "../../formulaire/elements/fieldset";
 import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 import { CalculatorResultsComponent } from "../../components/calculator-results/calculator-results.component";
 import { Subscription } from "rxjs";
 import { FieldSetComponent } from "../field-set/field-set.component";
 import { CalculatorNameComponent } from "./calc-name.component";
-import { FormulaireElement } from "../../formulaire/formulaire-element";
-import { FieldsetContainer } from "../../formulaire/fieldset-container";
+import { FormulaireElement } from "../../formulaire/elements/formulaire-element";
+import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
 import { FieldsetContainerComponent } from "../fieldset-container/fieldset-container.component";
 import { PabTableComponent } from "../pab-table/pab-table.component";
 import { MatDialog } from "@angular/material";
 import { DialogConfirmCloseCalcComponent } from "../dialog-confirm-close-calc/dialog-confirm-close-calc.component";
 import { DialogGeneratePABComponent } from "../dialog-generate-pab/dialog-generate-pab.component";
-import { PabTable } from "../../formulaire/pab-table";
+import { PabTable } from "../../formulaire/elements/pab-table";
 
 import { HotkeysService, Hotkey } from "angular2-hotkeys";
 
diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts
index bbc0476d9..3339ae54d 100644
--- a/src/app/components/generic-input/generic-input.component.ts
+++ b/src/app/components/generic-input/generic-input.component.ts
@@ -2,7 +2,7 @@ import { Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, ViewChild }
 import { NgModel } from "@angular/forms";
 import { isNumeric } from "jalhyd";
 import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { I18nService } from "../../services/internationalisation.service";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 
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 a969d0cce..948a63d4b 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
@@ -6,7 +6,7 @@ import { fv } from "../../../app/util";
 
 import { LogComponent } from "../../components/log/log.component";
 import { CalculatorResults } from "../../results/calculator-results";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 import { PlottableData } from "../../results/plottable-data";
 import { ResultsChartComponent } from "../results-chart/results-chart.component";
diff --git a/src/app/components/ngparam-input/ngparam-input.component.ts b/src/app/components/ngparam-input/ngparam-input.component.ts
index 1a06a691d..a9608f9cd 100644
--- a/src/app/components/ngparam-input/ngparam-input.component.ts
+++ b/src/app/components/ngparam-input/ngparam-input.component.ts
@@ -5,7 +5,7 @@ import { Component, ChangeDetectorRef, OnDestroy } from "@angular/core";
 import { Message, Observer } from "jalhyd";
 
 import { I18nService } from "../../services/internationalisation.service";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 
diff --git a/src/app/components/pab-results/pab-results.component.ts b/src/app/components/pab-results/pab-results.component.ts
index 137d6c1b6..25127b986 100644
--- a/src/app/components/pab-results/pab-results.component.ts
+++ b/src/app/components/pab-results/pab-results.component.ts
@@ -4,7 +4,7 @@ import { Result, cLog, Message, MessageCode, MessageSeverity } from "jalhyd";
 
 import { LogComponent } from "../../components/log/log.component";
 import { CalculatorResults } from "../../results/calculator-results";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { PabResultsTableComponent } from "./pab-results-table.component";
 import { PabResults } from "../../results/pab-results";
 import { VariableResultsSelectorComponent } from "../variable-results-selector/variable-results-selector.component";
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 3c965c103..e3308fc84 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -22,7 +22,7 @@ import { I18nService } from "../../services/internationalisation.service";
 import { FormulaireService } from "../../services/formulaire.service";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 import { NotificationsService } from "../../services/notifications.service";
-import { PabTable } from "../../formulaire/pab-table";
+import { PabTable } from "../../formulaire/elements/pab-table";
 import { DialogEditPabComponent } from "../dialog-edit-pab/dialog-edit-pab.component";
 import { AppComponent } from "../../app.component";
 
diff --git a/src/app/components/param-computed/param-computed.component.ts b/src/app/components/param-computed/param-computed.component.ts
index 54bbe75fb..ac7e7c2e7 100644
--- a/src/app/components/param-computed/param-computed.component.ts
+++ b/src/app/components/param-computed/param-computed.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input } from "@angular/core";
 import { MatDialog } from "@angular/material";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { ParamCalculability, Structure } from "jalhyd";
 import { DialogEditParamComputedComponent } from "../dialog-edit-param-computed/dialog-edit-param-computed.component";
 import { I18nService } from "../../services/internationalisation.service";
diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts
index 58d0b5d62..cf0570d2d 100644
--- a/src/app/components/param-field-line/param-field-line.component.ts
+++ b/src/app/components/param-field-line/param-field-line.component.ts
@@ -1,7 +1,7 @@
 import { Component, ViewChild, Input, Output, EventEmitter, OnChanges } from "@angular/core";
 
 import { I18nService } from "../../services/internationalisation.service";
-import { NgParameter, ParamRadioConfig } from "../../formulaire/ngparam";
+import { NgParameter, ParamRadioConfig } from "../../formulaire/elements/ngparam";
 import { NgParamInputComponent } from "../ngparam-input/ngparam-input.component";
 import { ServiceFactory } from "../../services/service-factory";
 import { ParamValueMode, ParallelStructure } from "jalhyd";
diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index 0db7fb037..c2463904a 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input, Output, EventEmitter, OnChanges, OnDestroy } from "@angular/core";
 
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { LinkedValue, ParamValueMode, Observer, Structure, acSection, ParamDefinition, ChildNub } from "jalhyd";
 import { FormulaireService } from "../../services/formulaire.service";
 import { I18nService } from "../../services/internationalisation.service";
diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts
index 6246b6825..9279c976b 100644
--- a/src/app/components/param-values/param-values.component.ts
+++ b/src/app/components/param-values/param-values.component.ts
@@ -1,5 +1,5 @@
 import { Component, Input, AfterViewInit, Output, EventEmitter } from "@angular/core";
-import { NgParameter } from "../../formulaire/ngparam";
+import { NgParameter } from "../../formulaire/elements/ngparam";
 import { DialogEditParamValuesComponent } from "../dialog-edit-param-values/dialog-edit-param-values.component";
 import { MatDialog } from "@angular/material";
 import { ParamValueMode, Observer, Structure } from "jalhyd";
diff --git a/src/app/components/select-field-line/select-field-line.component.ts b/src/app/components/select-field-line/select-field-line.component.ts
index 6b863acda..2cdeca62c 100644
--- a/src/app/components/select-field-line/select-field-line.component.ts
+++ b/src/app/components/select-field-line/select-field-line.component.ts
@@ -1,9 +1,9 @@
 import { Component, Input, OnInit } from "@angular/core";
 
-import { SelectField } from "../../formulaire/select-field";
-import { SelectEntry } from "../../formulaire/select-entry";
+import { SelectField } from "../../formulaire/elements/select-field";
+import { SelectEntry } from "../../formulaire/elements/select-entry";
 import { I18nService } from "../../services/internationalisation.service";
-import { SelectFieldReference } from "../../formulaire/select-field-reference";
+import { SelectFieldReference } from "../../formulaire/elements/select-field-reference";
 import { ApplicationSetupService } from "../../services/app-setup.service";
 
 @Component({
diff --git a/src/app/components/select-model-field-line/select-model-field-line.component.ts b/src/app/components/select-model-field-line/select-model-field-line.component.ts
index 853d0077a..592e3032e 100644
--- a/src/app/components/select-model-field-line/select-model-field-line.component.ts
+++ b/src/app/components/select-model-field-line/select-model-field-line.component.ts
@@ -1,10 +1,10 @@
 import { Component, Input, OnInit } from "@angular/core";
 import { Router } from "@angular/router";
 
-import { SelectEntry } from "../../formulaire/select-entry";
+import { SelectEntry } from "../../formulaire/elements/select-entry";
 import { FormulaireService } from "../../services/formulaire.service";
-import { FieldsetContainer } from "../../formulaire/fieldset-container";
-import { SelectFieldModel } from "../../formulaire/select-field-model";
+import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
+import { SelectFieldModel } from "../../formulaire/elements/select-field-model";
 
 @Component({
     selector: "select-model-field-line",
diff --git a/src/app/directives/jalhyd-model-validation.directive.ts b/src/app/directives/jalhyd-model-validation.directive.ts
index 8d7d52771..41d4bbe9c 100644
--- a/src/app/directives/jalhyd-model-validation.directive.ts
+++ b/src/app/directives/jalhyd-model-validation.directive.ts
@@ -1,7 +1,7 @@
 import { NG_VALIDATORS, Validator, AbstractControl, ValidatorFn } from "@angular/forms";
 import { Directive, Input } from "@angular/core";
 import { NgBaseParam } from "../components/base-param-input/base-param-input.component";
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { sprintf } from "sprintf-js";
 import { ServiceFactory } from "../services/service-factory";
 
diff --git a/src/app/formulaire/definition/concrete/form-base.ts b/src/app/formulaire/definition/concrete/form-base.ts
deleted file mode 100644
index 35f9b9cc8..000000000
--- a/src/app/formulaire/definition/concrete/form-base.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { FormulaireDefinition } from "../form-definition";
-import { CalculatorResults } from "../../../results/calculator-results";
-import { FormResult } from "../form-result";
-import { FormCompute } from "../form-compute";
-import { FormResultFixedVar } from "../form-result-fixedvar";
-import { FormComputeFixedVar } from "../form-compute-fixedvar";
-import { ServiceFactory } from "../../../services/service-factory";
-
-export class FormulaireBase extends FormulaireDefinition {
-
-    protected _formCompute: FormCompute;
-
-    protected _formResult: FormResult;
-
-    constructor() {
-        super();
-        this._formResult = new FormResultFixedVar(this);
-        this._formCompute = new FormComputeFixedVar(this, (this._formResult as FormResultFixedVar));
-    }
-
-    protected completeParse(json: {}) {
-        super.completeParse(json);
-        this._formResult.helpLinks = this._resultsHelpLinks;
-    }
-
-    /**
-     * Resets the form results, the results panel on screen, the model
-     * results, and does the same for all depending modules
-     * @param symbol symbol of the parameter whose value change triggered this method
-     * @param forceResetAllDependencies if true, even non-calculated non-modified parameters
-     *      links will be considered as dependencies @see jalhyd#98
-     */
-    public resetResults(visited: string[] = [], symbol?: string, forceResetAllDependencies: boolean = false) {
-        visited.push(this.currentNub.uid);
-        // reset GUI results
-        this._formResult.resetResults();
-        // reset model results
-        this.currentNub.resetResult();
-        // reset the result panels of all forms depending on this one
-        ServiceFactory.instance.formulaireService.resetAllDependingFormsResults(this, visited, symbol, forceResetAllDependencies);
-    }
-
-    public doCompute() {
-        this._formCompute.doCompute();
-    }
-
-    public get hasResults(): boolean {
-        return this._formResult.hasResults;
-    }
-
-    public get results(): CalculatorResults[] {
-        return this._formResult.results;
-    }
-}
diff --git a/src/app/formulaire/definition/concrete/form-courbe-remous.ts b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
deleted file mode 100644
index ce98814c1..000000000
--- a/src/app/formulaire/definition/concrete/form-courbe-remous.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { IObservable, MethodeResolution, SectionNub, Session } from "jalhyd";
-
-import { FormResultRemous } from "../form-result-remous";
-import { FormDefSection } from "../form-def-section";
-import { FormComputeCourbeRemous } from "../form-compute-courbe-remous";
-import { FieldSet } from "../../fieldset";
-import { FormulaireBase } from "./form-base";
-
-export class FormulaireCourbeRemous extends FormulaireBase {
-
-    private _formSection: FormDefSection;
-
-    /**
-     * id du select configurant la méthode de résolution
-     */
-    private _resolveMethSelectId: string;
-
-    constructor() {
-        super();
-        this._formSection = new FormDefSection(this);
-        this._formResult = new FormResultRemous(this);
-
-        // remove obsolete observer set by super()
-        this.removeObserver(this._formCompute);
-        this._formCompute = new FormComputeCourbeRemous(this, (this._formResult as FormResultRemous));
-        // default properties
-        this._props["methodeResolution"] = MethodeResolution.Trapezes;
-        this._props["varCalc"] = ""; // important
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._formSection.parseOptions(json);
-
-        // id du select configurant la méthode de résolution
-        this._resolveMethSelectId = this.getOption(json, "methodSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        this._formSection.afterParseFieldset(fs);
-
-        // 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);
-            }
-        }
-    }
-
-    // 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/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts
deleted file mode 100644
index ca5311fa1..000000000
--- a/src/app/formulaire/definition/concrete/form-pab.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Pab } from "jalhyd";
-
-import { FormulaireBase } from "./form-base";
-import { FormComputePab } from "../form-compute-pab";
-import { FormResultPab } from "../form-result-pab";
-
-/**
- * Formulaire pour les passes à bassins, inspiré du formulaire
- * pour les structures en parallèle
- */
-export class FormulairePab extends FormulaireBase {
-
-    constructor() {
-        super();
-        this._formResult = new FormResultPab(this);
-
-        // remove obsolete observer set by super()
-        this.removeObserver(this._formCompute);
-        this._formCompute = new FormComputePab(this, (this._formResult as FormResultPab));
-    }
-
-    public get pabNub(): Pab {
-        return this.currentNub as Pab;
-    }
-}
diff --git a/src/app/formulaire/definition/concrete/form-section-parametree.ts b/src/app/formulaire/definition/concrete/form-section-parametree.ts
deleted file mode 100644
index 3bb8a56c7..000000000
--- a/src/app/formulaire/definition/concrete/form-section-parametree.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { IObservable, Nub, Session, SectionNub } from "jalhyd";
-
-import { FormResultSection } from "../form-result-section";
-import { FormDefSection } from "../form-def-section";
-import { FormComputeSectionParametree } from "../form-compute-section-parametree";
-import { FieldSet } from "../../fieldset";
-import { FormulaireBase } from "./form-base";
-
-export class FormulaireSectionParametree extends FormulaireBase {
-
-    private _formSection: FormDefSection;
-
-    constructor() {
-        super();
-        this._formSection = new FormDefSection(this);
-        this._formResult = new FormResultSection(this);
-
-        // remove obsolete observer set by super()
-        this.removeObserver(this._formCompute);
-        this._formCompute = new FormComputeSectionParametree(
-            this, this._formSection, (this._formResult as FormResultSection)
-        );
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._formSection.parseOptions(json);
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        this._formSection.afterParseFieldset(fs);
-    }
-
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-        // super.update(sender, data);
-
-        if (sender instanceof Nub) {
-            switch (data.action) {
-                case "resultUpdated":
-                    // forward Nub results update notification to FormCompute objects
-                    this.notifyNubResultUpdated(sender);
-                    break;
-            }
-        }
-
-        // 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;
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/concrete/form-bief.ts b/src/app/formulaire/definition/form-bief.ts
similarity index 83%
rename from src/app/formulaire/definition/concrete/form-bief.ts
rename to src/app/formulaire/definition/form-bief.ts
index 90edbe135..46b7ffad6 100644
--- a/src/app/formulaire/definition/concrete/form-bief.ts
+++ b/src/app/formulaire/definition/form-bief.ts
@@ -1,34 +1,26 @@
 import { IObservable, SectionNub, Session, BiefRegime } from "jalhyd";
 
-import { FormDefSection } from "../form-def-section";
-import { FieldSet } from "../../fieldset";
-import { FormulaireBase } from "./form-base";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireSection } from "./form-section";
 
-export class FormulaireBief extends FormulaireBase {
-
-    private _formSection: FormDefSection;
+export class FormulaireBief extends FormulaireSection {
 
     /** id du select configurant le régime */
     private _regimeSelectId: string;
 
     constructor() {
         super();
-        this._formSection = new FormDefSection(this);
         // default properties
         this._props["regime"] = BiefRegime.Fluvial;
     }
 
     protected parseOptions(json: {}) {
         super.parseOptions(json);
-        this._formSection.parseOptions(json);
-
         // id du select configurant la méthode de résolution
         this._regimeSelectId = this.getOption(json, "regimeSelectId");
     }
 
     public afterParseFieldset(fs: FieldSet) {
-        this._formSection.afterParseFieldset(fs);
-
         // si le FieldSet contient le select de méthode de résolution
         if (this._regimeSelectId) {
             const sel = fs.getFormulaireNodeById(this._regimeSelectId);
diff --git a/src/app/formulaire/definition/form-compute-courbe-remous.ts b/src/app/formulaire/definition/form-compute-courbe-remous.ts
deleted file mode 100644
index a4cff1cbd..000000000
--- a/src/app/formulaire/definition/form-compute-courbe-remous.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { acSection, Result, CourbeRemousParams, CourbeRemous } from "jalhyd";
-
-import { RemousResults } from "../../results/remous-results";
-import { FormulaireDefinition } from "./form-definition";
-import { FormCompute } from "./form-compute";
-import { FormResultRemous } from "./form-result-remous";
-
-export class FormComputeCourbeRemous extends FormCompute {
-
-    private resultYn: Result;
-
-    private resultYc: Result;
-
-    constructor(formBase: FormulaireDefinition, formResult: FormResultRemous) {
-        super(formBase, formResult);
-    }
-
-    private get remousResults(): RemousResults {
-        const f = this._formResult as FormResultRemous;
-        return f.remousResults;
-    }
-
-    protected compute() {
-        this.reaffectResultComponents();
-    }
-
-    protected reaffectResultComponents() {
-        const cr: CourbeRemous = this._formBase.currentNub as CourbeRemous;
-        const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams;
-
-        this.remousResults.parameters = prmCR;
-
-        // variable supplémentaire à calculer
-        this.remousResults.extraParamSymbol = this._formBase.currentNub.properties.getPropValue("varCalc");
-
-        // calcul
-        this.remousResults.result = cr.CalcSerie();
-
-        const sect: acSection = cr.Sn;
-        this.resultYn = sect.CalcSection("Yn"); // hauteur normale
-        this.resultYc = sect.CalcSection("Yc"); // hauteur critique
-
-        // données du graphe
-        this.remousResults.hauteurNormale = this.resultYn.resultElement;
-        this.remousResults.hauteurCritique = this.resultYc.resultElement;
-        if (this.remousResults.extraParamSymbol) {
-            this.remousResults.extraChart = ! ["Hs", "Hsc", "Ycor", "Ycon"].includes(this.remousResults.extraParamSymbol);
-        } else {
-            this.remousResults.extraChart = false;
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
deleted file mode 100644
index 9a9bf1d91..000000000
--- a/src/app/formulaire/definition/form-compute-fixedvar.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Nub } from "jalhyd";
-
-import { FormCompute } from "./form-compute";
-import { NgParameter } from "../ngparam";
-import { FormResultFixedVar } from "./form-result-fixedvar";
-import { FormulaireDefinition } from "./form-definition";
-
-export class FormComputeFixedVar extends FormCompute {
-    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
-        super(formBase, formResult);
-    }
-
-    protected get formResult(): FormResultFixedVar {
-        return this._formResult as FormResultFixedVar;
-    }
-
-    protected compute() {
-        this.runNubCalc(this._formBase.currentNub);
-        this.reaffectResultComponents();
-    }
-
-    protected reaffectResultComponents() {
-        const nub: Nub = this._formBase.currentNub;
-        const computedParam: NgParameter = this.getComputedParameter();
-        this.formResult.resetResults(); // to avoid adding fixed parameters more than once (see below)
-        this.formResult.addFixedParameters();
-        const varParams: NgParameter[] = this.getVariatedParameters();
-
-        if (varParams.length === 0) {
-            // pas de paramètre à varier
-            this.formResult.fixedResults.result = nub.result;
-            if (computedParam !== undefined) {
-                this.formResult.fixedResults.calculatedParameter = computedParam;
-            }
-        } else {
-            // il y a un paramètre à varier
-            this.formResult.varResults.variatedParameters = varParams;
-            if (computedParam !== undefined) {
-                this.formResult.varResults.calculatedParameter = computedParam;
-            }
-
-            this.formResult.varResults.result = nub.result;
-            this.formResult.varResults.update();
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-compute-macrorugo-compound.ts b/src/app/formulaire/definition/form-compute-macrorugo-compound.ts
deleted file mode 100644
index 6f2b4c303..000000000
--- a/src/app/formulaire/definition/form-compute-macrorugo-compound.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Result, MacrorugoCompound } from "jalhyd";
-
-import { FormulaireDefinition } from "./form-definition";
-import { FormCompute } from "./form-compute";
-import { FormResultMacrorugoCompound } from "./form-result-macrorugo-compound";
-import { NgParameter } from "../ngparam";
-
-export class FormComputeMacrorugoCompound extends FormCompute {
-
-    constructor(formBase: FormulaireDefinition, formResult: FormResultMacrorugoCompound) {
-        super(formBase, formResult);
-    }
-
-    protected get formResult(): FormResultMacrorugoCompound {
-        return this._formResult as FormResultMacrorugoCompound;
-    }
-
-    protected compute() {
-        this.runNubCalc(this._formBase.currentNub);
-        // reset variable index to avoid trying to access an index > 0 when nothing varies
-        const mrcr = this.formResult.mrcResults;
-        mrcr.variableIndex = 0;
-
-        this.reaffectResultComponents();
-    }
-
-    protected reaffectResultComponents() {
-        const mrc: MacrorugoCompound = (this._formBase.currentNub as MacrorugoCompound);
-        const computedParam: NgParameter = this.getComputedParameter();
-        const varParams: NgParameter[] = this.getVariatedParameters();
-
-        // résultat de calcul de la passe à macrorugo complexe
-        const mrcr = this.formResult.mrcResults;
-        mrcr.calculatedParameter = computedParam;
-        mrcr.result = mrc.result;
-        if (varParams) {
-            mrcr.variatedParameters = varParams;
-        }
-        // résultat de chaque enfant
-        const cr: Result[] = [];
-        for (const c of mrc.children) {
-            cr.push(c.result);
-        }
-        mrcr.childrenResults = cr;
-    }
-}
diff --git a/src/app/formulaire/definition/form-compute-parallel-structures.ts b/src/app/formulaire/definition/form-compute-parallel-structures.ts
deleted file mode 100644
index c673ab46d..000000000
--- a/src/app/formulaire/definition/form-compute-parallel-structures.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Structure, ParamDefinition } from "jalhyd";
-
-import { FormComputeFixedVar } from "./form-compute-fixedvar";
-
-export class FormComputeParallelStructures extends FormComputeFixedVar {
-
-    /**
-     * construit un identifiant de type { uid: "abcdef", symbol: "X" }
-     * avec "abcdef" l'index de l'ouvrage et "X" son paramètre
-     */
-    protected getParameterRefid(p: ParamDefinition): any {
-        const nub = p.parentComputeNode;
-        if (nub instanceof Structure) {
-            return {
-                uid: nub.uid,
-                symbol: p.symbol
-            };
-        } else {
-            return super.getParameterRefid(p);
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
deleted file mode 100644
index 0a47bd11f..000000000
--- a/src/app/formulaire/definition/form-compute-section-parametree.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { SectionParametree, acSection, Result, ParamDefinition, Nub } from "jalhyd";
-
-import { FormCompute } from "./form-compute";
-import { FormDefSection } from "./form-def-section";
-import { FormResultSection } from "./form-result-section";
-import { VarResults } from "../../results/var-results";
-import { SectionResults } from "../../results/section-results";
-import { FormulaireDefinition } from "./form-definition";
-
-export class FormComputeSectionParametree extends FormCompute {
-
-    constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResultSection) {
-        super(formBase, formResult);
-    }
-
-    private get _formSectionResult(): FormResultSection {
-        return this._formResult as FormResultSection;
-    }
-
-    private get _varResults(): VarResults {
-        return this._formSectionResult.varResults;
-    }
-
-    private get _sectionResults(): SectionResults {
-        return this._formSectionResult.sectionResults;
-    }
-
-    protected compute() {
-        this.runNubCalc(this._formBase.currentNub);
-        this.reaffectResultComponents();
-    }
-
-    protected runNubCalc(nub: Nub, computedParam?: ParamDefinition): Result {
-        return nub.CalcSerie();
-    }
-
-    protected reaffectResultComponents() {
-        const sectNub: SectionParametree = this._formBase.currentNub as SectionParametree;
-        const sect: acSection = sectNub.section;
-        this._sectionResults.section = sect;
-
-        const varParams = this._formSection.getSectionVariatedParameters();
-        if (varParams.length > 0) {
-            // résultats variés avec tous les résultats complémentaires
-            this._varResults.variatedParameters = varParams;
-            this._varResults.result = sectNub.result;
-            this._varResults.update();
-        } else {
-            // résultats de section (avec le graphique de section)
-            this._sectionResults.result = sectNub.result;
-            // résultats complémentaires des paramètres fixés
-            this._formSectionResult.addSectionFixedParameters();
-            this._formSectionResult.fixedResults.result = sectNub.result;
-        }
-
-    }
-}
diff --git a/src/app/formulaire/definition/form-compute.ts b/src/app/formulaire/definition/form-compute.ts
deleted file mode 100644
index 3e4c20fa6..000000000
--- a/src/app/formulaire/definition/form-compute.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { Nub, Result, ParamDomainValue, Observer, ParamDefinition } from "jalhyd";
-
-import { FormResult } from "./form-result";
-import { FormulaireDefinition } from "./form-definition";
-import { NgParameter, ParamRadioConfig } from "../ngparam";
-
-export abstract class FormCompute implements Observer {
-
-    constructor(protected _formBase: FormulaireDefinition, protected _formResult: FormResult) {
-        // indirectly subscribe to Nub result updates
-        this._formBase.addObserver(this);
-    }
-
-    protected abstract compute();
-
-    protected get formResult(): FormResult {
-        return this._formResult;
-    }
-
-    /**
-     * retourne un identifiant du paramètre dans le formulaire
-     * surchargé dans le cas des ouvrages //
-     */
-    protected getParameterRefid(p: ParamDefinition) {
-        return p.symbol;
-    }
-
-    /**
-     * Copies current Nub result into result components for display on page.
-     * Should be called every time the Nub result changes.
-     * Must be idempotent.
-     */
-    protected abstract reaffectResultComponents();
-
-    /**
-     * Lance le calcul d'un paramètre en déterminant une valeur initiale.
-     * Si nécessaire déclenche un calcul en chaîne des modules en amont.
-     */
-    protected runNubCalc(nub: Nub): Result {
-        return nub.CalcSerie();
-    }
-
-    protected getComputedParameter(): NgParameter {
-        const cpd = this._formBase.currentNub.calculatedParam;
-        let ngparam: NgParameter;
-        if (cpd !== undefined) {
-            ngparam = this._formBase.getParamFromSymbol(cpd.symbol);
-            if (ngparam === undefined) { // calculated parameter is not displayed on screen
-                ngparam = new NgParameter(cpd, this._formBase);
-            }
-        }
-        return ngparam;
-    }
-
-    protected getVariatedParameters(): NgParameter[] {
-        let res: NgParameter[] = [];
-        // find variated local parameters
-        res = this._formBase.getDisplayedParamListFromState(ParamRadioConfig.VAR);
-        // add variated linked parameters
-        const pms = this._formBase.getDisplayedParamListFromState(ParamRadioConfig.LINK);
-        for (const p of pms) {
-            if (p.paramDefinition.hasMultipleValues) {
-                res.push(p);
-            }
-        }
-        return res;
-    }
-
-    /**
-     * Triggers computation of the Nub, updates form results
-     */
-    public doCompute() {
-        // calculate module
-        this.compute();
-        // refresh results
-        this._formBase.notifyObservers({
-            "action": "resultsUpdated",
-        }, this._formBase);
-    }
-
-    // interface Observer
-
-    public update(sender: any, data: any): void {
-        if (sender instanceof Nub) {
-            switch (data.action) {
-                case "nubResultUpdated":
-                    // forward Nub results update notification to FormCompute objects
-                    this.reaffectResultComponents();
-                    break;
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
new file mode 100644
index 000000000..38d112690
--- /dev/null
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -0,0 +1,122 @@
+import { IObservable, MethodeResolution, SectionNub, Session, 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";
+
+export class FormulaireCourbeRemous extends FormulaireSection {
+
+    /** résultats de courbes de remous */
+    private _remousResults: RemousResults;
+
+    private resultYn: Result;
+
+    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();
+    }
+
+    protected reaffectResultComponents() {
+        const cr: CourbeRemous = this.currentNub as CourbeRemous;
+        const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams;
+
+        this.remousResults.parameters = prmCR;
+
+        // variable supplémentaire à calculer
+        this.remousResults.extraParamSymbol = this.currentNub.properties.getPropValue("varCalc");
+
+        // calcul
+        this.remousResults.result = cr.CalcSerie();
+
+        const sect: acSection = cr.Sn;
+        this.resultYn = sect.CalcSection("Yn"); // hauteur normale
+        this.resultYc = sect.CalcSection("Yc"); // hauteur critique
+
+        // données du graphe
+        this.remousResults.hauteurNormale = this.resultYn.resultElement;
+        this.remousResults.hauteurCritique = this.resultYc.resultElement;
+        if (this.remousResults.extraParamSymbol) {
+            this.remousResults.extraChart = ! ["Hs", "Hsc", "Ycor", "Ycon"].includes(this.remousResults.extraParamSymbol);
+        } else {
+            this.remousResults.extraChart = false;
+        }
+    }
+
+    public get remousResults() {
+        return this._remousResults;
+    }
+
+    public resetFormResults() {
+        this._remousResults.reset();
+    }
+
+    public get hasResults(): boolean {
+        return this._remousResults.hasResults;
+    }
+
+    public get results(): CalculatorResults[] {
+        // ensure help links are propagated
+        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 908c91caf..f6cf46ffc 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -1,18 +1,18 @@
-import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, SectionNub, acSection, ParamValueMode } from "jalhyd";
+import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, SectionNub, acSection, ParamDefinition, Result } from "jalhyd";
 
-import { FormulaireElement } from "../formulaire-element";
-import { NgParameter, ParamRadioConfig } from "../ngparam";
-import { Field } from "../field";
+import { FormulaireElement } from "../elements/formulaire-element";
+import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
+import { Field } from "../elements/field";
 import { StringMap } from "../../stringmap";
-import { FormulaireNode } from "../formulaire-node";
-import { FieldSet } from "../fieldset";
-import { FieldsetContainer } from "../fieldset-container";
-import { SelectField } from "../select-field";
+import { FormulaireNode } from "../elements/formulaire-node";
+import { FieldSet } from "../elements/fieldset";
+import { FieldsetContainer } from "../elements/fieldset-container";
+import { SelectField } from "../elements/select-field";
 import { DeepFieldsetIterator } from "../form-iterator/deep-fieldset-iterator";
 import { TopFormulaireElementIterator } from "../form-iterator/top-element-iterator";
 import { CalculatorResults } from "../../results/calculator-results";
 import { ServiceFactory } from "../../services/service-factory";
-import { PabTable } from "../pab-table";
+import { PabTable } from "../elements/pab-table";
 
 /**
  * classe de base pour tous les formulaires
@@ -43,6 +43,9 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     /** ISO 639-1 language code of the current language (to avoid unnecessary localisation reload) */
     private _currentLanguage: string;
 
+    /** copy of options.resultsHelp read by FormDefinition.parseOptions() */
+    public helpLinks: { [key: string]: string };
+
     constructor() {
         super(undefined);
     }
@@ -106,9 +109,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
 
         if (this.currentNub instanceof SectionNub) {
             // add new Section as first child, from given nodeType
-            p.setPropValue("calcType", CalculatorType.Section);
-            p.setPropValue("nodeType", this._defaultNodeType);
-            const section = Session.getInstance().createNub(p);
+            const propsSection = new Props();
+            propsSection.setPropValue("calcType", CalculatorType.Section);
+            propsSection.setPropValue("nodeType", this._defaultNodeType);
+            const section = Session.getInstance().createNub(propsSection);
             this.currentNub.setSection(section as acSection);
         }
     }
@@ -149,6 +153,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
 
     /** called at the end of parseConfig() */
     protected completeParse(json: {}) {
+        this.helpLinks = this._resultsHelpLinks;
     }
 
     public getOption(json: {}, option: string): string {
@@ -157,8 +162,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }
     }
 
-    public afterParseFieldset(fs: FieldSet) {
-    }
+    public afterParseFieldset(fs: FieldSet) { }
 
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         const res: FieldSet = new FieldSet(parent);
@@ -216,7 +220,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         // il est utile de le faire avant le reste pour les modules de calcul utilisant
         // des sections (id des selects type de section/variable à calculer)
 
-        // tslint:disable-next-line:forin
         for (const conf_index in json) {
             const conf = json[conf_index];
             const type: string = conf["type"];
@@ -239,7 +242,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         // analyse des éléments du formulaire
         const templates: any[] = [];
 
-        // tslint:disable-next-line:forin
         for (const conf_index in this._jsonConfig) {
             const conf = this._jsonConfig[conf_index];
             const type: string = conf["type"];
@@ -352,16 +354,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }, this);
     }
 
-    /**
-     * Forwards Nub's result updated notification.
-     * Used by FormCompute to update results display
-     */
-    protected notifyNubResultUpdated(sender) {
-        this.notifyObservers({
-            action: "nubResultUpdated"
-        }, sender);
-    }
-
     /**
      * Forwards Nub's progress updated notification.
      * Used by CalculatorComponent to update progress bar
@@ -400,11 +392,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return select.getValue().label;
     }
 
-    public abstract resetResults(visited: string[], symbol?: string, forceResetAllDependencies?: boolean);
-    public abstract doCompute();
-    public abstract get hasResults(): boolean;
-    public abstract get results(): CalculatorResults[];
-
     public updateLocalisation(localisation: StringMap, lang: string) {
         this._specificLocalisation = localisation;
         this._currentLanguage = lang;
@@ -442,7 +429,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     /**
-     * Appelé par CalculatorComponent lrosque le Formulaire est chargé dans la vue,
+     * Appelé par CalculatorComponent lorsque le Formulaire est chargé dans la vue,
      * c'est à dire lorsqu'on affiche un module de calcul à l'écran
      */
     public onCalculatorInit() {}
@@ -454,9 +441,95 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
             switch (data.action) {
                 case "resultUpdated":
                     // forward Nub results update notification to FormCompute objects
-                    this.notifyNubResultUpdated(sender);
+                    this.reaffectResultComponents();
                     break;
             }
         }
     }
+
+    /**
+     * Resets the form results, the results panel on screen, the model
+     * results, and does the same for all depending modules
+     * @param symbol symbol of the parameter whose value change triggered this method
+     * @param forceResetAllDependencies if true, even non-calculated non-modified parameters
+     *      links will be considered as dependencies @see jalhyd#98
+     */
+    public resetResults(visited: string[] = [], symbol?: string, forceResetAllDependencies: boolean = false) {
+        visited.push(this.currentNub.uid);
+        // reset GUI results
+        this.resetFormResults();
+        // reset model results
+        this.currentNub.resetResult();
+        // reset the result panels of all forms depending on this one
+        ServiceFactory.instance.formulaireService.resetAllDependingFormsResults(this, visited, symbol, forceResetAllDependencies);
+    }
+
+    protected abstract compute();
+
+    public abstract get hasResults(): boolean;
+
+    public abstract get results(): CalculatorResults[];
+
+    /**
+     * Copies current Nub result into result components for display on page.
+     * Should be called every time the Nub result changes.
+     * Must be idempotent.
+     */
+    protected abstract reaffectResultComponents();
+
+    /**
+     * retourne un identifiant du paramètre dans le formulaire
+     * surchargé dans le cas des ouvrages //
+     */
+    protected getParameterRefid(p: ParamDefinition) {
+        return p.symbol;
+    }
+
+    /**
+     * Lance le calcul d'un paramètre en déterminant une valeur initiale.
+     * Si nécessaire déclenche un calcul en chaîne des modules en amont.
+     */
+    protected runNubCalc(nub: Nub): Result {
+        return nub.CalcSerie();
+    }
+
+    protected getComputedParameter(): NgParameter {
+        const cpd = this.currentNub.calculatedParam;
+        let ngparam: NgParameter;
+        if (cpd !== undefined) {
+            ngparam = this.getParamFromSymbol(cpd.symbol);
+            if (ngparam === undefined) { // calculated parameter is not displayed on screen
+                ngparam = new NgParameter(cpd, this);
+            }
+        }
+        return ngparam;
+    }
+
+    protected getVariatedParameters(): NgParameter[] {
+        let res: NgParameter[] = [];
+        // find variated local parameters
+        res = this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
+        // add variated linked parameters
+        const pms = this.getDisplayedParamListFromState(ParamRadioConfig.LINK);
+        for (const p of pms) {
+            if (p.paramDefinition.hasMultipleValues) {
+                res.push(p);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Triggers computation of the Nub, updates form results
+     */
+    public doCompute() {
+        // calculate module
+        this.compute();
+        // refresh results
+        this.notifyObservers({
+            "action": "resultsUpdated",
+        }, this);
+    }
+
+    public resetFormResults() {}
 }
diff --git a/src/app/formulaire/definition/form-result-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
similarity index 50%
rename from src/app/formulaire/definition/form-result-fixedvar.ts
rename to src/app/formulaire/definition/form-fixedvar.ts
index 512a6342d..9a5f38b9d 100644
--- a/src/app/formulaire/definition/form-result-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -1,22 +1,19 @@
+import { FormulaireDefinition } from "./form-definition";
 import { FixedResults } from "../../results/fixed-results";
 import { VarResults } from "../../results/var-results";
-import { ParamRadioConfig } from "../ngparam";
-import { FormResult } from "./form-result";
-import { FormulaireDefinition } from "./form-definition";
-import { CalculatorResults } from "../../results/calculator-results";
 import { ChartType } from "../../results/chart-type";
+import { CalculatorResults } from "../../results/calculator-results";
+import { ParamRadioConfig, NgParameter } from "../elements/ngparam";
 
-export class FormResultFixedVar extends FormResult {
+import { Nub } from "jalhyd";
+
+export class FormulaireFixedVar extends FormulaireDefinition {
 
-    /** résultats fixes/variables */
     protected _fixedResults: FixedResults;
     protected _varResults: VarResults;
 
-    protected _formBase: FormulaireDefinition;
-
-    constructor(base: FormulaireDefinition) {
+    constructor() {
         super();
-        this._formBase = base;
         this._fixedResults = new FixedResults();
         this._varResults = new VarResults();
     }
@@ -29,17 +26,17 @@ export class FormResultFixedVar extends FormResult {
         return this._varResults;
     }
 
-    public resetResults() {
+    public resetFormResults() {
         this._fixedResults.reset();
         this._varResults.reset();
     }
 
     public addFixedParameters() {
-        for (const p of this._formBase.getDisplayedParamListFromState(ParamRadioConfig.FIX)) {
+        for (const p of this.getDisplayedParamListFromState(ParamRadioConfig.FIX)) {
             this._fixedResults.addFixedParameter(p);
         }
 
-        for (const p of this._formBase.getDisplayedParamListFromState(ParamRadioConfig.LINK)) {
+        for (const p of this.getDisplayedParamListFromState(ParamRadioConfig.LINK)) {
             if (!p.paramDefinition.hasMultipleValues) {
                 this._fixedResults.addFixedParameter(p);
             }
@@ -63,4 +60,34 @@ export class FormResultFixedVar extends FormResult {
         res.push(this._varResults);
         return res;
     }
+
+    protected compute() {
+        this.runNubCalc(this.currentNub);
+        this.reaffectResultComponents();
+    }
+
+    protected reaffectResultComponents() {
+        const nub: Nub = this.currentNub;
+        const computedParam: NgParameter = this.getComputedParameter();
+        this.resetFormResults(); // to avoid adding fixed parameters more than once (see below)
+        this.addFixedParameters();
+        const varParams: NgParameter[] = this.getVariatedParameters();
+
+        if (varParams.length === 0) {
+            // pas de paramètre à varier
+            this.fixedResults.result = nub.result;
+            if (computedParam !== undefined) {
+                this.fixedResults.calculatedParameter = computedParam;
+            }
+        } else {
+            // il y a un paramètre à varier
+            this.varResults.variatedParameters = varParams;
+            if (computedParam !== undefined) {
+                this.varResults.calculatedParameter = computedParam;
+            }
+
+            this.varResults.result = nub.result;
+            this.varResults.update();
+        }
+    }
 }
diff --git a/src/app/formulaire/definition/concrete/form-grille.ts b/src/app/formulaire/definition/form-grille.ts
similarity index 88%
rename from src/app/formulaire/definition/concrete/form-grille.ts
rename to src/app/formulaire/definition/form-grille.ts
index b8b9760de..c66630c1a 100644
--- a/src/app/formulaire/definition/concrete/form-grille.ts
+++ b/src/app/formulaire/definition/form-grille.ts
@@ -1,13 +1,12 @@
 import { IObservable } from "jalhyd";
 
-import { FormulaireBase } from "./form-base";
-import { FieldSet } from "../../fieldset";
-import { FormResultFixedVar } from "../form-result-fixedvar";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
  * Formulaire pour les Grilles (perte de charge)
  */
-export class FormulaireGrille extends FormulaireBase {
+export class FormulaireGrille extends FormulaireFixedVar {
 
     /** id of select configuring grid profile */
     private _gridProfileSelectId: string;
@@ -18,7 +17,7 @@ export class FormulaireGrille extends FormulaireBase {
     constructor() {
         super();
         // custom variables order for results tables
-        (this._formResult as FormResultFixedVar).fixedResults.variablesOrder = [
+        this.fixedResults.variablesOrder = [
             "QMax", "CRad", "CEau", "H", "CSomGrille", "HG", "B", "S", "SPDG", "VA", "VAPDG",
             "Beta", "Alpha", "LG", "D", "DG", "SG", "VN",
             "b", "p", "e", "a", "c", "RFB", "REEB", "OB", "O", "OEntH", "cIncl",
diff --git a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts b/src/app/formulaire/definition/form-lechapt-calmon.ts
similarity index 83%
rename from src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
rename to src/app/formulaire/definition/form-lechapt-calmon.ts
index 0bdda676d..cedc683c5 100644
--- a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
+++ b/src/app/formulaire/definition/form-lechapt-calmon.ts
@@ -1,12 +1,12 @@
 import { IObservable } from "jalhyd";
 
-import { FormulaireBase } from "./form-base";
-import { FieldSet } from "../../fieldset";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
  * Formulaire pour Lechapt et Calmon
  */
-export class FormulaireLechaptCalmon extends FormulaireBase {
+export class FormulaireLechaptCalmon extends FormulaireFixedVar {
 
     /** id of select configuring material */
     private _lcMaterialSelectId: string;
diff --git a/src/app/formulaire/definition/concrete/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
similarity index 69%
rename from src/app/formulaire/definition/concrete/form-macrorugo-compound.ts
rename to src/app/formulaire/definition/form-macrorugo-compound.ts
index cd4810da7..8c38f31ec 100644
--- a/src/app/formulaire/definition/concrete/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -1,12 +1,12 @@
-import { IObservable, Nub } from "jalhyd";
-
-import { FieldSet } from "../../fieldset";
-import { FieldsetContainer } from "../../fieldset-container";
-import { FormulaireNode } from "../../formulaire-node";
-import { NgParameter } from "../../ngparam";
-import { FormResultMacrorugoCompound } from "../form-result-macrorugo-compound";
-import { FormComputeMacrorugoCompound } from "../form-compute-macrorugo-compound";
+import { IObservable, Nub, MacrorugoCompound, Result } from "jalhyd";
+
+import { FieldSet } from "../elements/fieldset";
+import { FieldsetContainer } from "../elements/fieldset-container";
+import { FormulaireNode } from "../elements/formulaire-node";
+import { NgParameter } from "../elements/ngparam";
 import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset";
+import { MacrorugoCompoundResults } from "../../results/macrorugo-compound-results";
+import { CalculatorResults } from "../../results/calculator-results";
 
 /**
  * Formulaire pour les passes à macrorugosités complexes
@@ -16,16 +16,13 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
     /** id of select configuring apron type */
     private _apronTypeSelectId: string;
 
+    protected _mrcResults: MacrorugoCompoundResults;
+
     constructor() {
         super();
-        this._formResult = new FormResultMacrorugoCompound(this);
-
+        this._mrcResults = new MacrorugoCompoundResults();
         // default properties
         this._props["inclinedApron"] = false;
-
-        // remove obsolete observer set by super()
-        this.removeObserver(this._formCompute);
-        this._formCompute = new FormComputeMacrorugoCompound(this, (this._formResult as FormResultMacrorugoCompound));
     }
 
     protected parseOptions(json: {}) {
@@ -76,7 +73,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
     protected completeParse(json: {}) {
         this.subscribeFieldsetContainer();
         this.updateApronState(this.currentNub.properties.getPropValue("inclinedApron"));
-        this._formResult.helpLinks = this._resultsHelpLinks;
+        this.helpLinks = this._resultsHelpLinks;
     }
 
     protected get fieldsetContainer(): FieldsetContainer {
@@ -133,6 +130,53 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         }
     }
 
+    protected compute() {
+        this.runNubCalc(this.currentNub);
+        // reset variable index to avoid trying to access an index > 0 when nothing varies
+        const mrcr = this.mrcResults;
+        mrcr.variableIndex = 0;
+
+        this.reaffectResultComponents();
+    }
+
+    protected reaffectResultComponents() {
+        const mrc: MacrorugoCompound = (this.currentNub as MacrorugoCompound);
+        const computedParam: NgParameter = this.getComputedParameter();
+        const varParams: NgParameter[] = this.getVariatedParameters();
+
+        // résultat de calcul de la passe à macrorugo complexe
+        const mrcr = this.mrcResults;
+        mrcr.calculatedParameter = computedParam;
+        mrcr.result = mrc.result;
+        if (varParams) {
+            mrcr.variatedParameters = varParams;
+        }
+        // résultat de chaque enfant
+        const cr: Result[] = [];
+        for (const c of mrc.children) {
+            cr.push(c.result);
+        }
+        mrcr.childrenResults = cr;
+    }
+
+    public get mrcResults() {
+        return this._mrcResults;
+    }
+
+    public resetFormResults() {
+        this._mrcResults.reset();
+    }
+
+    public get results(): CalculatorResults[] {
+        // ensure help links are propagated
+        this._mrcResults.helpLinks = this.helpLinks;
+        return [ this._mrcResults ];
+    }
+
+    public get hasResults(): boolean {
+        return this._mrcResults.hasResults;
+    }
+
     // interface Observer
 
     public update(sender: IObservable, data: any) {
diff --git a/src/app/formulaire/definition/form-compute-pab.ts b/src/app/formulaire/definition/form-pab.ts
similarity index 59%
rename from src/app/formulaire/definition/form-compute-pab.ts
rename to src/app/formulaire/definition/form-pab.ts
index a0ebc6f32..f4ba51958 100644
--- a/src/app/formulaire/definition/form-compute-pab.ts
+++ b/src/app/formulaire/definition/form-pab.ts
@@ -1,37 +1,44 @@
-import { Result, Pab } from "jalhyd";
+import { Pab, Result } from "jalhyd";
 
 import { FormulaireDefinition } from "./form-definition";
-import { FormResultPab } from "./form-result-pab";
-import { FormCompute } from "./form-compute";
-import { NgParameter } from "../ngparam";
-import { longestVarParam } from "../../../app/util";
+import { PabResults } from "../../results/pab-results";
+import { NgParameter } from "../elements/ngparam";
+import { longestVarParam } from "../../util";
+import { CalculatorResults } from "../../results/calculator-results";
 
-export class FormComputePab extends FormCompute {
+/**
+ * Formulaire pour les passes à bassins, inspiré du formulaire
+ * pour les structures en parallèle
+ */
+export class FormulairePab extends FormulaireDefinition {
 
-    constructor(formBase: FormulaireDefinition, formResult: FormResultPab) {
-        super(formBase, formResult);
+    protected _pabResults: PabResults;
+
+    constructor() {
+        super();
+        this._pabResults = new PabResults();
     }
 
-    protected get formResult(): FormResultPab {
-        return this._formResult as FormResultPab;
+    public get pabNub(): Pab {
+        return this.currentNub as Pab;
     }
 
     protected compute() {
-        this.runNubCalc(this._formBase.currentNub);
+        this.runNubCalc(this.currentNub);
         // reset variable index to avoid trying to access an index > 0 when nothing varies
-        const pabr = this.formResult.pabResults;
+        const pabr = this.pabResults;
         pabr.variableIndex = 0;
 
         this.reaffectResultComponents();
     }
 
     protected reaffectResultComponents() {
-        const pab: Pab = (this._formBase.currentNub as Pab);
+        const pab: Pab = (this.currentNub as Pab);
         const computedParam: NgParameter = this.getComputedParameter();
         const varParams: NgParameter[] = this.getVariatedParameters();
 
         // résultat de calcul de la passe à bassins
-        const pabr = this.formResult.pabResults;
+        const pabr = this.pabResults;
         pabr.calculatedParameter = computedParam;
         pabr.result = pab.result;
 
@@ -70,4 +77,22 @@ export class FormComputePab extends FormCompute {
             pabr.variatedParameters = varParams;
         }
     }
+
+    public get pabResults() {
+        return this._pabResults;
+    }
+
+    public resetResults() {
+        this._pabResults.reset();
+    }
+
+    public get results(): CalculatorResults[] {
+        // ensure help links are propagated
+        this._pabResults.helpLinks = this.helpLinks;
+        return [ this._pabResults ];
+    }
+
+    public get hasResults(): boolean {
+        return this._pabResults.hasResults;
+    }
 }
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts
similarity index 88%
rename from src/app/formulaire/definition/concrete/form-parallel-structures.ts
rename to src/app/formulaire/definition/form-parallel-structures.ts
index 2ed380c04..fa8a481f9 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-parallel-structures.ts
@@ -1,13 +1,11 @@
-import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session } from "jalhyd";
-
-import { FormComputeParallelStructures } from "../form-compute-parallel-structures";
-import { FormResultFixedVar } from "../form-result-fixedvar";
-import { FieldsetContainer } from "../../fieldset-container";
-import { FieldSet } from "../../fieldset";
-import { SelectField } from "../../select-field";
-import { NgParameter } from "../../ngparam";
-import { FieldsetTemplate } from "../../fieldset-template";
-import { FormulaireNode } from "../../formulaire-node";
+import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition } from "jalhyd";
+
+import { FieldsetContainer } from "../elements/fieldset-container";
+import { FieldSet } from "../elements/fieldset";
+import { SelectField } from "../elements/select-field";
+import { NgParameter } from "../elements/ngparam";
+import { FieldsetTemplate } from "../elements/fieldset-template";
+import { FormulaireNode } from "../elements/formulaire-node";
 import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset";
 
 export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
@@ -17,15 +15,6 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      */
     private __ouvrageSelectId: string;
 
-    constructor() {
-        super();
-        this._formResult = new FormResultFixedVar(this);
-
-        // remove obsolete observer set by super()
-        this.removeObserver(this._formCompute);
-        this._formCompute = new FormComputeParallelStructures(this, (this._formResult as FormResultFixedVar));
-    }
-
     protected parseOptions(json: {}) {
         super.parseOptions(json);
 
@@ -44,6 +33,22 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
         }
     }
 
+    /**
+     * construit un identifiant de type { uid: "abcdef", symbol: "X" }
+     * avec "abcdef" l'index de l'ouvrage et "X" son paramètre
+     */
+    protected getParameterRefid(p: ParamDefinition): any {
+        const nub = p.parentComputeNode;
+        if (nub instanceof Structure) {
+            return {
+                uid: nub.uid,
+                symbol: p.symbol
+            };
+        } else {
+            return super.getParameterRefid(p);
+        }
+    }
+
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         if (json["calcType"] === "Structure") {
             // indice après lequel insérer le nouveau FieldSet
@@ -112,7 +117,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
 
     protected completeParse(json: {}) {
         this.subscribeFieldsetContainer();
-        this._formResult.helpLinks = this._resultsHelpLinks;
+        this.helpLinks = this._resultsHelpLinks;
     }
 
     protected get fieldsetContainer(): FieldsetContainer {
diff --git a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts b/src/app/formulaire/definition/form-regime-uniforme.ts
similarity index 51%
rename from src/app/formulaire/definition/concrete/form-regime-uniforme.ts
rename to src/app/formulaire/definition/form-regime-uniforme.ts
index 791fd322c..f1630343a 100644
--- a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
+++ b/src/app/formulaire/definition/form-regime-uniforme.ts
@@ -1,32 +1,9 @@
 import { IObservable, Observer, Session, SectionNub } from "jalhyd";
-import { FormDefSection } from "../form-def-section";
-import { FieldSet } from "../../fieldset";
-import { FormulaireBase } from "./form-base";
 
-export class FormulaireRegimeUniforme extends FormulaireBase implements Observer {
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireSection } from "./form-section";
 
-    private _formSection: FormDefSection;
-
-    constructor() {
-        super();
-        this._formSection = new FormDefSection(this);
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._formSection.parseOptions(json);
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        this._formSection.afterParseFieldset(fs);
-    }
-
-    protected completeParse(json: {}) {
-        super.completeParse(json);
-        this._formResult.helpLinks = this._resultsHelpLinks;
-    }
-
-    // interface Observer
+export class FormulaireRegimeUniforme extends FormulaireSection implements Observer {
 
     update(sender: IObservable, data: any) {
         super.update(sender, data);
diff --git a/src/app/formulaire/definition/concrete/form-repeatable-fieldset.ts b/src/app/formulaire/definition/form-repeatable-fieldset.ts
similarity index 84%
rename from src/app/formulaire/definition/concrete/form-repeatable-fieldset.ts
rename to src/app/formulaire/definition/form-repeatable-fieldset.ts
index 6cec8f90a..68ca2692d 100644
--- a/src/app/formulaire/definition/concrete/form-repeatable-fieldset.ts
+++ b/src/app/formulaire/definition/form-repeatable-fieldset.ts
@@ -1,11 +1,11 @@
-import { FieldSet } from "../../fieldset";
-import { FieldsetContainer } from "../../fieldset-container";
-import { FormulaireBase } from "./form-base";
-import { FieldsetTemplate } from "../../fieldset-template";
+import { FieldSet } from "../elements/fieldset";
+import { FieldsetContainer } from "../elements/fieldset-container";
+import { FormulaireFixedVar } from "./form-fixedvar";
+import { FieldsetTemplate } from "../elements/fieldset-template";
 
 import { Props, Session, Nub } from "jalhyd";
 
-export abstract class FormulaireRepeatableFieldset extends FormulaireBase {
+export abstract class FormulaireRepeatableFieldset extends FormulaireFixedVar {
 
     protected abstract get fieldsetContainer(): FieldsetContainer;
 
diff --git a/src/app/formulaire/definition/form-result-macrorugo-compound.ts b/src/app/formulaire/definition/form-result-macrorugo-compound.ts
deleted file mode 100644
index d73ec051c..000000000
--- a/src/app/formulaire/definition/form-result-macrorugo-compound.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { FormulaireDefinition } from "./form-definition";
-import { FormResult } from "./form-result";
-import { CalculatorResults } from "../../results/calculator-results";
-import { MacrorugoCompoundResults } from "../../results/macrorugo-compound-results";
-
-export class FormResultMacrorugoCompound extends FormResult {
-
-    protected _formBase: FormulaireDefinition;
-
-    protected _mrcResults: MacrorugoCompoundResults;
-
-    constructor(base: FormulaireDefinition) {
-        super();
-        this._formBase = base;
-        this._mrcResults = new MacrorugoCompoundResults();
-    }
-
-    public get mrcResults() {
-        return this._mrcResults;
-    }
-
-    public resetResults() {
-        this._mrcResults.reset();
-    }
-
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._mrcResults.helpLinks = this.helpLinks;
-        return [ this._mrcResults ];
-    }
-
-    public get hasResults(): boolean {
-        return this._mrcResults.hasResults;
-    }
-}
diff --git a/src/app/formulaire/definition/form-result-pab.ts b/src/app/formulaire/definition/form-result-pab.ts
deleted file mode 100644
index 6a4cd34fd..000000000
--- a/src/app/formulaire/definition/form-result-pab.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { FormulaireDefinition } from "./form-definition";
-import { FormResult } from "./form-result";
-import { CalculatorResults } from "../../results/calculator-results";
-import { PabResults } from "../../results/pab-results";
-
-export class FormResultPab extends FormResult {
-
-    protected _formBase: FormulaireDefinition;
-
-    protected _pabResults: PabResults;
-
-    constructor(base: FormulaireDefinition) {
-        super();
-        this._formBase = base;
-        this._pabResults = new PabResults();
-    }
-
-    public get pabResults() {
-        return this._pabResults;
-    }
-
-    public resetResults() {
-        this._pabResults.reset();
-    }
-
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._pabResults.helpLinks = this.helpLinks;
-        return [ this._pabResults ];
-    }
-
-    public get hasResults(): boolean {
-        return this._pabResults.hasResults;
-    }
-}
diff --git a/src/app/formulaire/definition/form-result-remous.ts b/src/app/formulaire/definition/form-result-remous.ts
deleted file mode 100644
index 4ae14b792..000000000
--- a/src/app/formulaire/definition/form-result-remous.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { RemousResults } from "../../results/remous-results";
-import { FormResult } from "./form-result";
-import { FormulaireDefinition } from "./form-definition";
-import { CalculatorResults } from "../../results/calculator-results";
-
-export class FormResultRemous extends FormResult {
-
-    /**
-     * résultats de courbes de remous
-     */
-    private _remousResults: RemousResults;
-
-    constructor(base: FormulaireDefinition) {
-        super();
-        this._remousResults = new RemousResults();
-    }
-
-    public get remousResults() {
-        return this._remousResults;
-    }
-
-    public resetResults() {
-        this._remousResults.reset();
-    }
-
-    public get hasResults(): boolean {
-        return this._remousResults.hasResults;
-    }
-
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._remousResults.helpLinks = this.helpLinks;
-        return [ this._remousResults ];
-    }
-}
diff --git a/src/app/formulaire/definition/form-result-section.ts b/src/app/formulaire/definition/form-result-section.ts
deleted file mode 100644
index e4acf4a41..000000000
--- a/src/app/formulaire/definition/form-result-section.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { SectionResults } from "../../results/section-results";
-import { ParamRadioConfig } from "../ngparam";
-import { FixedResults } from "../../results/fixed-results";
-import { VarResults } from "../../results/var-results";
-import { FormResult } from "./form-result";
-import { FormulaireDefinition } from "./form-definition";
-import { CalculatorResults } from "../../results/calculator-results";
-
-export class FormResultSection extends FormResult {
-    private _formBase: FormulaireDefinition;
-
-    /**
-     * résultats fixes/variables
-     */
-    private _fixedResults: FixedResults;
-    private _varResults: VarResults;
-
-    /**
-     * résultats de section paramétrée
-     */
-    private _sectionResults: SectionResults;
-
-    constructor(base: FormulaireDefinition) {
-        super();
-        this._formBase = base;
-        this._fixedResults = new FixedResults();
-        this._varResults = new VarResults();
-        this._sectionResults = new SectionResults();
-    }
-
-    public get fixedResults() {
-        return this._fixedResults;
-    }
-
-    public get varResults() {
-        return this._varResults;
-    }
-
-    public get sectionResults() {
-        return this._sectionResults;
-    }
-
-    public resetResults() {
-        this._fixedResults.reset();
-        this._varResults.reset();
-        this._sectionResults.reset();
-    }
-
-    public addSectionFixedParameters() {
-        for (const p of this._formBase.getDisplayedParamListFromState(ParamRadioConfig.FIX)) {
-            this._fixedResults.addFixedParameter(p);
-        }
-    }
-
-    public get hasResults(): boolean {
-        return (this._fixedResults !== undefined && this._fixedResults.hasResults)
-            || (this._varResults !== undefined && this._varResults.hasResults)
-            || (this._sectionResults !== undefined && this._sectionResults.hasResults);
-    }
-
-    public get results(): CalculatorResults[] {
-        const res: CalculatorResults[] = [];
-        // ensure help links are propagated
-        this._fixedResults.helpLinks = this.helpLinks;
-        this._varResults.helpLinks = this.helpLinks;
-        this._sectionResults.helpLinks = this.helpLinks;
-        res.push(this._fixedResults);
-        res.push(this._varResults);
-        res.push(this._sectionResults);
-        return res;
-    }
-}
diff --git a/src/app/formulaire/definition/form-result.ts b/src/app/formulaire/definition/form-result.ts
deleted file mode 100644
index 5e5fa62eb..000000000
--- a/src/app/formulaire/definition/form-result.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { CalculatorResults } from "../../results/calculator-results";
-
-export abstract class FormResult {
-
-    /** copy of options.resultsHelp read by FormDefinition.parseOptions() */
-    public helpLinks: { [key: string]: string };
-
-    public abstract resetResults();
-
-    public abstract get hasResults(): boolean;
-
-    public abstract get results(): CalculatorResults[];
-}
diff --git a/src/app/formulaire/definition/form-section-parametree.ts b/src/app/formulaire/definition/form-section-parametree.ts
new file mode 100644
index 000000000..a18349a53
--- /dev/null
+++ b/src/app/formulaire/definition/form-section-parametree.ts
@@ -0,0 +1,107 @@
+import { IObservable, Nub, Session, SectionNub, 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 { CalculatorResults } from "../../results/calculator-results";
+
+export class FormulaireSectionParametree extends FormulaireSection {
+
+    /**
+     * résultats de section paramétrée
+     */
+    private _sectionResults: SectionResults;
+
+    public constructor() {
+        super();
+        this._sectionResults = new SectionResults();
+    }
+
+    protected compute() {
+        this.runNubCalc(this.currentNub);
+        this.reaffectResultComponents();
+    }
+
+    protected runNubCalc(nub: Nub, computedParam?: ParamDefinition): Result {
+        return nub.CalcSerie();
+    }
+
+    protected reaffectResultComponents() {
+        const sectNub: SectionParametree = this.currentNub as SectionParametree;
+        const sect: acSection = sectNub.section;
+        this._sectionResults.section = sect;
+
+        const varParams = this.getSectionVariatedParameters();
+        if (varParams.length > 0) {
+            // résultats variés avec tous les résultats complémentaires
+            this._varResults.variatedParameters = varParams;
+            this._varResults.result = sectNub.result;
+            this._varResults.update();
+        } else {
+            // résultats de section (avec le graphique de section)
+            this._sectionResults.result = sectNub.result;
+            // résultats complémentaires des paramètres fixés
+            this.addSectionFixedParameters();
+            this.fixedResults.result = sectNub.result;
+        }
+
+    }
+
+    public resetFormResults() {
+        this._fixedResults.reset();
+        this._varResults.reset();
+        this._sectionResults.reset();
+    }
+
+    public addSectionFixedParameters() {
+        for (const p of this.getDisplayedParamListFromState(ParamRadioConfig.FIX)) {
+            this._fixedResults.addFixedParameter(p);
+        }
+    }
+
+    public get hasResults(): boolean {
+        return (this._fixedResults !== undefined && this._fixedResults.hasResults)
+            || (this._varResults !== undefined && this._varResults.hasResults)
+            || (this._sectionResults !== undefined && this._sectionResults.hasResults);
+    }
+
+    public get results(): CalculatorResults[] {
+        const res: CalculatorResults[] = [];
+        // ensure help links are propagated
+        this._fixedResults.helpLinks = this.helpLinks;
+        this._varResults.helpLinks = this.helpLinks;
+        this._sectionResults.helpLinks = this.helpLinks;
+        res.push(this._fixedResults);
+        res.push(this._varResults);
+        res.push(this._sectionResults);
+        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;
+            }
+        }
+    }
+}
diff --git a/src/app/formulaire/definition/form-def-section.ts b/src/app/formulaire/definition/form-section.ts
similarity index 53%
rename from src/app/formulaire/definition/form-def-section.ts
rename to src/app/formulaire/definition/form-section.ts
index a2c011e8d..e645b98ac 100644
--- a/src/app/formulaire/definition/form-def-section.ts
+++ b/src/app/formulaire/definition/form-section.ts
@@ -1,36 +1,30 @@
-import { NgParameter, ParamRadioConfig } from "../ngparam";
-import { FormulaireDefinition } from "./form-definition";
-import { FieldSet } from "../fieldset";
+import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireFixedVar } from "./form-fixedvar";
 
-export class FormDefSection {
-    /**
-     * id de l'élément configurant le type de section
-     */
-    private _sectionSourceId: string;
+export abstract class FormulaireSection extends FormulaireFixedVar {
 
-    private _formBase: FormulaireDefinition;
-
-    constructor(base: FormulaireDefinition) {
-        this._formBase = base;
-    }
+    /** 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._formBase.getDisplayedParamListFromState(ParamRadioConfig.VAR);
+        return this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
     }
 
     public getSectionComputedParam(): { symbol: string, label: string } {
-        const symbol = this._formBase.getSelectedValue("select_target");
-        const label = this._formBase.getSelectedLabel("select_target");
+        const symbol = this.getSelectedValue("select_target");
+        const label = this.getSelectedLabel("select_target");
         return { symbol, label };
     }
 
-    public parseOptions(json: {}) {
+    protected parseOptions(json: {}) {
+        super.parseOptions(json);
         // id de l'élément configurant le type de section
-        this._sectionSourceId = this._formBase.getOption(json, "sectionSourceId");
+        this._sectionSourceId = this.getOption(json, "sectionSourceId");
     }
 
     /**
@@ -42,7 +36,7 @@ export class FormDefSection {
             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._formBase);
+                fs.properties.addObserver(this);
             }
         }
     }
diff --git a/src/app/formulaire/definition/concrete/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts
similarity index 89%
rename from src/app/formulaire/definition/concrete/form-solveur.ts
rename to src/app/formulaire/definition/form-solveur.ts
index 2856388e6..2057ce084 100644
--- a/src/app/formulaire/definition/concrete/form-solveur.ts
+++ b/src/app/formulaire/definition/form-solveur.ts
@@ -1,14 +1,14 @@
-import { IObservable, ParamDefinition, Solveur } from "jalhyd";
+import { IObservable, ParamDefinition } from "jalhyd";
 
-import { FormulaireBase } from "./form-base";
-import { SelectFieldNub } from "../../select-field-nub";
-import { SelectFieldParameter } from "../../select-field-parameter";
-import { NgParameter } from "../../ngparam";
+import { SelectFieldNub } from "../elements/select-field-nub";
+import { SelectFieldParameter } from "../elements/select-field-parameter";
+import { NgParameter } from "../elements/ngparam";
+import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
  * Formulaire pour les Solveurs
  */
-export class FormulaireSolveur extends FormulaireBase {
+export class FormulaireSolveur extends FormulaireFixedVar {
 
     /** id of select configuring target Nub */
     private _targetNubSelectId: string;
diff --git a/src/app/formulaire/definition/concrete/form-spp.ts b/src/app/formulaire/definition/form-spp.ts
similarity index 92%
rename from src/app/formulaire/definition/concrete/form-spp.ts
rename to src/app/formulaire/definition/form-spp.ts
index e5430273c..e7ddf4e1a 100644
--- a/src/app/formulaire/definition/concrete/form-spp.ts
+++ b/src/app/formulaire/definition/form-spp.ts
@@ -1,7 +1,7 @@
 import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset";
-import { FieldSet } from "../../fieldset";
-import { FormulaireNode } from "../../formulaire-node";
-import { FieldsetContainer } from "../../fieldset-container";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireNode } from "../elements/formulaire-node";
+import { FieldsetContainer } from "../elements/fieldset-container";
 
 import { Nub, IObservable } from "jalhyd";
 
diff --git a/src/app/formulaire/definition/concrete/form-trigo.ts b/src/app/formulaire/definition/form-trigo.ts
similarity index 87%
rename from src/app/formulaire/definition/concrete/form-trigo.ts
rename to src/app/formulaire/definition/form-trigo.ts
index 499d6e03a..332325710 100644
--- a/src/app/formulaire/definition/concrete/form-trigo.ts
+++ b/src/app/formulaire/definition/form-trigo.ts
@@ -1,12 +1,12 @@
 import { IObservable } from "jalhyd";
 
-import { FormulaireBase } from "./form-base";
-import { FieldSet } from "../../fieldset";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
  * Formulaire pour les fonctions trigonométriques
  */
-export class FormulaireTrigo extends FormulaireBase {
+export class FormulaireTrigo extends FormulaireFixedVar {
 
     /** id of select configuring operation */
     private _operationSelectId: string;
diff --git a/src/app/formulaire/field.ts b/src/app/formulaire/elements/field.ts
similarity index 100%
rename from src/app/formulaire/field.ts
rename to src/app/formulaire/elements/field.ts
diff --git a/src/app/formulaire/fieldset-container.ts b/src/app/formulaire/elements/fieldset-container.ts
similarity index 98%
rename from src/app/formulaire/fieldset-container.ts
rename to src/app/formulaire/elements/fieldset-container.ts
index 3e2c3d3b7..1c31212da 100644
--- a/src/app/formulaire/fieldset-container.ts
+++ b/src/app/formulaire/elements/fieldset-container.ts
@@ -1,7 +1,7 @@
 import { FormulaireElement } from "./formulaire-element";
 import { FieldSet } from "./fieldset";
 import { FieldsetTemplate } from "./fieldset-template";
-import { StringMap } from "../stringmap";
+import { StringMap } from "../../stringmap";
 import { FormulaireNode } from "./formulaire-node";
 import { Nub } from "jalhyd";
 
diff --git a/src/app/formulaire/fieldset-template.ts b/src/app/formulaire/elements/fieldset-template.ts
similarity index 96%
rename from src/app/formulaire/fieldset-template.ts
rename to src/app/formulaire/elements/fieldset-template.ts
index 97b0a9d46..de8c1e2d8 100644
--- a/src/app/formulaire/fieldset-template.ts
+++ b/src/app/formulaire/elements/fieldset-template.ts
@@ -1,6 +1,6 @@
 import { FieldSet } from "./fieldset";
 import { CalculatorType, ComputeNodeType, LoiDebit, Nub, StructureType } from "jalhyd";
-import { FormulaireDefinition } from "./definition/form-definition";
+import { FormulaireDefinition } from "../definition/form-definition";
 import { FieldsetContainer } from "./fieldset-container";
 
 export class FieldsetTemplate {
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
similarity index 99%
rename from src/app/formulaire/fieldset.ts
rename to src/app/formulaire/elements/fieldset.ts
index 03cfa6701..5e36142cc 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -19,8 +19,8 @@ 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 { 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";
diff --git a/src/app/formulaire/formulaire-element.ts b/src/app/formulaire/elements/formulaire-element.ts
similarity index 88%
rename from src/app/formulaire/formulaire-element.ts
rename to src/app/formulaire/elements/formulaire-element.ts
index 96153bcc4..19b0d5827 100644
--- a/src/app/formulaire/formulaire-element.ts
+++ b/src/app/formulaire/elements/formulaire-element.ts
@@ -1,9 +1,8 @@
 import { FormulaireNode } from "./formulaire-node";
-import { StringMap } from "../stringmap";
-import { DeepFormulaireElementIterator } from "./form-iterator/deep-element-iterator";
-import { I18nService } from "../services/internationalisation.service";
-import { ServiceFactory } from "../services/service-factory";
-import { FormulaireDefinition } from "./definition/form-definition";
+import { StringMap } from "../../stringmap";
+import { I18nService } from "../../services/internationalisation.service";
+import { ServiceFactory } from "../../services/service-factory";
+import { FormulaireDefinition } from "../definition/form-definition";
 
 /**
  * élément (enfant) du formulaire : fieldset, input, container, ...
diff --git a/src/app/formulaire/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts
similarity index 97%
rename from src/app/formulaire/formulaire-node.ts
rename to src/app/formulaire/elements/formulaire-node.ts
index 8f3ccf188..cffa97d86 100644
--- a/src/app/formulaire/formulaire-node.ts
+++ b/src/app/formulaire/elements/formulaire-node.ts
@@ -1,6 +1,7 @@
 import { JalhydObject, IObservable, Observer, Observable, ParamValueMode } from "jalhyd";
+
 import { FormulaireElement } from "./formulaire-element";
-import { DeepFormulaireElementIterator } from "./form-iterator/deep-element-iterator";
+import { DeepFormulaireElementIterator } from "../form-iterator/deep-element-iterator";
 import { NgParameter } from "./ngparam";
 
 /**
diff --git a/src/app/formulaire/input-field.ts b/src/app/formulaire/elements/input-field.ts
similarity index 100%
rename from src/app/formulaire/input-field.ts
rename to src/app/formulaire/elements/input-field.ts
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/elements/ngparam.ts
similarity index 99%
rename from src/app/formulaire/ngparam.ts
rename to src/app/formulaire/elements/ngparam.ts
index c4ab16b6b..f09c9081b 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/elements/ngparam.ts
@@ -4,9 +4,9 @@ import { Interval, ParamDefinition, ParamDomain, ParamValueMode, INumberIterator
 import { sprintf } from "sprintf-js";
 
 import { InputField } from "./input-field";
-import { ServiceFactory } from "../services/service-factory";
+import { ServiceFactory } from "../../services/service-factory";
 import { FormulaireNode } from "./formulaire-node";
-import { fv } from "../util";
+import { fv } from "../../util";
 
 export enum ParamRadioConfig {
     /** pas de radio, paramètre modifiable à la main uniquement */
diff --git a/src/app/formulaire/pab-table.ts b/src/app/formulaire/elements/pab-table.ts
similarity index 93%
rename from src/app/formulaire/pab-table.ts
rename to src/app/formulaire/elements/pab-table.ts
index a31529bc5..aea39c56e 100644
--- a/src/app/formulaire/pab-table.ts
+++ b/src/app/formulaire/elements/pab-table.ts
@@ -2,7 +2,7 @@ import { Pab } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { FormulaireNode } from "./formulaire-node";
-import { FormulairePab } from "./definition/concrete/form-pab";
+import { FormulairePab } from "../definition/form-pab";
 
 /**
  * The big editable data grid for calculator type "Pab" (form element).
diff --git a/src/app/formulaire/select-entry.ts b/src/app/formulaire/elements/select-entry.ts
similarity index 100%
rename from src/app/formulaire/select-entry.ts
rename to src/app/formulaire/elements/select-entry.ts
diff --git a/src/app/formulaire/select-field-model.ts b/src/app/formulaire/elements/select-field-model.ts
similarity index 100%
rename from src/app/formulaire/select-field-model.ts
rename to src/app/formulaire/elements/select-field-model.ts
diff --git a/src/app/formulaire/select-field-nub.ts b/src/app/formulaire/elements/select-field-nub.ts
similarity index 93%
rename from src/app/formulaire/select-field-nub.ts
rename to src/app/formulaire/elements/select-field-nub.ts
index b19492cc0..52053385b 100644
--- a/src/app/formulaire/select-field-nub.ts
+++ b/src/app/formulaire/elements/select-field-nub.ts
@@ -1,7 +1,7 @@
 import { SelectFieldReference } from "./select-field-reference";
 import { SelectEntry } from "./select-entry";
-import { ServiceFactory } from "../services/service-factory";
-import { decodeHtml } from "../util";
+import { ServiceFactory } from "../../services/service-factory";
+import { decodeHtml } from "../../util";
 
 import { Session, Solveur } from "jalhyd";
 
diff --git a/src/app/formulaire/select-field-parameter.ts b/src/app/formulaire/elements/select-field-parameter.ts
similarity index 94%
rename from src/app/formulaire/select-field-parameter.ts
rename to src/app/formulaire/elements/select-field-parameter.ts
index c0ddf2b6e..c643edd71 100644
--- a/src/app/formulaire/select-field-parameter.ts
+++ b/src/app/formulaire/elements/select-field-parameter.ts
@@ -1,7 +1,7 @@
 import { SelectFieldReference } from "./select-field-reference";
 import { SelectEntry } from "./select-entry";
-import { decodeHtml } from "../util";
-import { ServiceFactory } from "../services/service-factory";
+import { decodeHtml } from "../../util";
+import { ServiceFactory } from "../../services/service-factory";
 
 import { Nub, Solveur } from "jalhyd";
 
diff --git a/src/app/formulaire/select-field-reference.ts b/src/app/formulaire/elements/select-field-reference.ts
similarity index 100%
rename from src/app/formulaire/select-field-reference.ts
rename to src/app/formulaire/elements/select-field-reference.ts
diff --git a/src/app/formulaire/select-field.ts b/src/app/formulaire/elements/select-field.ts
similarity index 98%
rename from src/app/formulaire/select-field.ts
rename to src/app/formulaire/elements/select-field.ts
index c67f117d1..0d98274bb 100644
--- a/src/app/formulaire/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -16,9 +16,9 @@ import {
 
 import { Field } from "./field";
 import { SelectEntry } from "./select-entry";
-import { StringMap } from "../stringmap";
+import { StringMap } from "../../stringmap";
 import { FormulaireNode } from "./formulaire-node";
-import { FormulaireDefinition } from "./definition/form-definition";
+import { FormulaireDefinition } from "../definition/form-definition";
 
 export class SelectField extends Field {
 
diff --git a/src/app/formulaire/form-iterator/abstract-node-iterator.ts b/src/app/formulaire/form-iterator/abstract-node-iterator.ts
index f08987006..a57b7fbc9 100644
--- a/src/app/formulaire/form-iterator/abstract-node-iterator.ts
+++ b/src/app/formulaire/form-iterator/abstract-node-iterator.ts
@@ -1,4 +1,4 @@
-import { FormulaireNode } from "../formulaire-node";
+import { FormulaireNode } from "../elements/formulaire-node";
 
 /**
  * classe de construction d'itérateurs qui parcourent un arbre de FormulaireNode
diff --git a/src/app/formulaire/form-iterator/deep-element-iterator.ts b/src/app/formulaire/form-iterator/deep-element-iterator.ts
index 8834c2847..336ac5e72 100644
--- a/src/app/formulaire/form-iterator/deep-element-iterator.ts
+++ b/src/app/formulaire/form-iterator/deep-element-iterator.ts
@@ -1,5 +1,5 @@
 import { AbstractFormulaireNodeIterator } from "./abstract-node-iterator";
-import { FormulaireElement } from "../formulaire-element";
+import { FormulaireElement } from "../elements/formulaire-element";
 
 /**
  * itérateur qui extrait récursivement les FormulaireElement dans un tableau de FormulaireElement
diff --git a/src/app/formulaire/form-iterator/deep-fieldset-iterator.ts b/src/app/formulaire/form-iterator/deep-fieldset-iterator.ts
index 7bc362468..b87c598e6 100644
--- a/src/app/formulaire/form-iterator/deep-fieldset-iterator.ts
+++ b/src/app/formulaire/form-iterator/deep-fieldset-iterator.ts
@@ -1,6 +1,6 @@
 import { AbstractFormulaireNodeIterator } from "./abstract-node-iterator";
-import { FieldSet } from "../fieldset";
-import { FormulaireNode } from "../formulaire-node";
+import { FieldSet } from "../elements/fieldset";
+import { FormulaireNode } from "../elements/formulaire-node";
 
 /**
  * itérateur qui extrait récursivement les FieldSet dans un tableau de FormulaireElement
diff --git a/src/app/formulaire/form-iterator/top-element-iterator.ts b/src/app/formulaire/form-iterator/top-element-iterator.ts
index 32f9e63e9..ef0bdbace 100644
--- a/src/app/formulaire/form-iterator/top-element-iterator.ts
+++ b/src/app/formulaire/form-iterator/top-element-iterator.ts
@@ -1,5 +1,5 @@
 import { AbstractFormulaireNodeIterator } from "./abstract-node-iterator";
-import { FormulaireElement } from "../formulaire-element";
+import { FormulaireElement } from "../elements/formulaire-element";
 
 /**
  * itérateur qui extrait les FormulaireElement de 1er niveau dans un tableau de FormulaireElement
diff --git a/src/app/results/calculator-results.ts b/src/app/results/calculator-results.ts
index 53e7a58b0..344364bbb 100644
--- a/src/app/results/calculator-results.ts
+++ b/src/app/results/calculator-results.ts
@@ -1,6 +1,6 @@
 import { Nub, capitalize } from "jalhyd";
 
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { ServiceFactory } from "../services/service-factory";
 
 import { sprintf } from "sprintf-js";
diff --git a/src/app/results/fixed-results.ts b/src/app/results/fixed-results.ts
index 1c02b1e04..3aa8a407a 100644
--- a/src/app/results/fixed-results.ts
+++ b/src/app/results/fixed-results.ts
@@ -1,4 +1,4 @@
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { CalculatedParamResults } from "./param-calc-results";
 
 export class FixedResults extends CalculatedParamResults {
diff --git a/src/app/results/multidimension-results.ts b/src/app/results/multidimension-results.ts
index b0ecbca0e..4b2aee2ed 100644
--- a/src/app/results/multidimension-results.ts
+++ b/src/app/results/multidimension-results.ts
@@ -1,5 +1,5 @@
 import { CalculatedParamResults } from "./param-calc-results";
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 
 
 export class MultiDimensionResults extends CalculatedParamResults {
diff --git a/src/app/results/param-calc-results.ts b/src/app/results/param-calc-results.ts
index 3f5c8c4b0..62cd26f84 100644
--- a/src/app/results/param-calc-results.ts
+++ b/src/app/results/param-calc-results.ts
@@ -1,5 +1,5 @@
 import { CalculatorResults } from "./calculator-results";
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { Result, cLog } from "jalhyd";
 
 /**
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index 7b31ad6e5..a499c8355 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -2,7 +2,7 @@ import { cLog, CourbeRemousParams, Result, ResultElement, ParamDefinition, Param
 
 import { CalculatorResults } from "./calculator-results";
 import { VarResults } from "./var-results";
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { ServiceFactory } from "../services/service-factory";
 
 export class RemousResults extends CalculatorResults {
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index 72664aea5..79dbca9fd 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -1,6 +1,6 @@
 import { CalculatorResults } from "./calculator-results";
 import { CalculatedParamResults } from "./param-calc-results";
-import { NgParameter } from "../formulaire/ngparam";
+import { NgParameter } from "../formulaire/elements/ngparam";
 import { ResultElement, ParamFamily, capitalize, Nub } from "jalhyd";
 import { ServiceFactory } from "../services/service-factory";
 import { PlottableData } from "./plottable-data";
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index 6db648c1b..4f506cb11 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -23,26 +23,26 @@ import { I18nService } from "./internationalisation.service";
 import { NotificationsService } from "./notifications.service";
 
 import { FormulaireDefinition } from "../formulaire/definition/form-definition";
-import { FormulaireElement } from "../formulaire/formulaire-element";
-import { InputField } from "../formulaire/input-field";
-import { SelectField } from "../formulaire/select-field";
+import { FormulaireElement } from "../formulaire/elements/formulaire-element";
+import { InputField } from "../formulaire/elements/input-field";
+import { SelectField } from "../formulaire/elements/select-field";
 import { StringMap } from "../stringmap";
-import { FormulaireBase } from "../formulaire/definition/concrete/form-base";
-import { FormulaireSectionParametree } from "../formulaire/definition/concrete/form-section-parametree";
-import { FormulaireCourbeRemous } from "../formulaire/definition/concrete/form-courbe-remous";
-import { FormulaireRegimeUniforme } from "../formulaire/definition/concrete/form-regime-uniforme";
-import { FormulaireParallelStructure } from "../formulaire/definition/concrete/form-parallel-structures";
-import { NgParameter } from "../formulaire/ngparam";
-import { FieldsetContainer } from "../formulaire/fieldset-container";
-import { FormulairePab } from "../formulaire/definition/concrete/form-pab";
-import { FormulaireMacrorugoCompound } from "../formulaire/definition/concrete/form-macrorugo-compound";
-import { FormulaireLechaptCalmon } from "../formulaire/definition/concrete/form-lechapt-calmon";
-import { FormulaireGrille } from "../formulaire/definition/concrete/form-grille";
-import { FormulaireBief } from "../formulaire/definition/concrete/form-bief";
-import { FormulaireSolveur } from "../formulaire/definition/concrete/form-solveur";
+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/concrete/form-spp";
-import { FormulaireTrigo } from "../formulaire/definition/concrete/form-trigo";
+import { FormulaireSPP } from "../formulaire/definition/form-spp";
+import { FormulaireTrigo } from "../formulaire/definition/form-trigo";
+import { FormulaireFixedVar } from "../formulaire/definition/form-fixedvar";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -297,7 +297,7 @@ export class FormulaireService extends Observable {
         return this._httpService.httpGetRequestPromise(f);
     }
 
-    private newFormulaire(ct: CalculatorType, jsonState?: {}): FormulaireDefinition {
+    private newFormulaire(ct: CalculatorType): FormulaireDefinition {
         let f: FormulaireDefinition;
         switch (ct) {
 
@@ -313,6 +313,10 @@ export class FormulaireService extends Observable {
                 f = new FormulaireCourbeRemous();
                 break;
 
+            case CalculatorType.Bief:
+                f = new FormulaireBief();
+                break;
+
             case CalculatorType.LechaptCalmon:
                 f = new FormulaireLechaptCalmon();
                 break;
@@ -335,10 +339,6 @@ export class FormulaireService extends Observable {
                 f = new FormulaireGrille();
                 break;
 
-            case CalculatorType.Bief:
-                f = new FormulaireBief();
-                break;
-
             case CalculatorType.Solveur:
                 f = new FormulaireSolveur();
                 break;
@@ -352,7 +352,7 @@ export class FormulaireService extends Observable {
                 break;
 
             default:
-                f = new FormulaireBase();
+                f = new FormulaireFixedVar();
         }
 
         f.defaultProperties["calcType"] = ct;
diff --git a/src/app/util.ts b/src/app/util.ts
index 73ca8da3a..a8fbfd572 100644
--- a/src/app/util.ts
+++ b/src/app/util.ts
@@ -1,4 +1,4 @@
-import { NgParameter } from "./formulaire/ngparam";
+import { NgParameter } from "./formulaire/elements/ngparam";
 import { ServiceFactory } from "./services/service-factory";
 
 import { formattedValue } from "jalhyd";
-- 
GitLab