From 746e5c02c09b4ef4462a376e5d28575d6c89c47e Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Wed, 7 Mar 2018 16:22:13 +0100
Subject: [PATCH] =?UTF-8?q?=20#27=20:=20d=C3=A9coupage=20de=20classe=20For?=
 =?UTF-8?q?mulaireDefinition=20en=20classes=20g=C3=A9rant=20diff=C3=A9rent?=
 =?UTF-8?q?s=20aspects=20-=20d=C3=A9finition=20du=20formulaire=20:=20=20?=
 =?UTF-8?q?=20-=20FormDefFixedVar=20(formulaires=20avec=20un=20param=C3=A8?=
 =?UTF-8?q?tre=20fix=C3=A9=20ou=20=C3=A0=20varier)=20=20=20-=20FormDefPara?=
 =?UTF-8?q?mToCalculate=20(formulaires=20avec=20un=20param=C3=A8tre=20?=
 =?UTF-8?q?=C3=A0=20calculer)=20=20=20-=20FormDefSection=20(formulaires=20?=
 =?UTF-8?q?avec=20une=20section=20:=20section=20param=C3=A9tr=C3=A9e,=20r?=
 =?UTF-8?q?=C3=A9gime=20uniforme,=20remous)=20-=20calcul=20:=20classes=20F?=
 =?UTF-8?q?ormComputeXXX=20-=20r=C3=A9sultats=20:=20classes=20FormResultXX?=
 =?UTF-8?q?X=20-=20formulaire/definition/concrete=20:=20classes=20des=20ca?=
 =?UTF-8?q?lculettes=20r=C3=A9alis=C3=A9es=20par=20assemblage=20des=20clas?=
 =?UTF-8?q?ses=20ci=20dessus?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.component.ts                      |    2 +-
 .../calculator-list.component.ts              |    2 +-
 .../calculator-results.component.html         |    6 +-
 .../calculator-results.component.ts           |   20 +-
 .../fixedvar-results.component.html           |   74 +-
 .../fixedvar-results.component.ts             |   45 +-
 .../generic-calculator/calc-name.component.ts |    2 +-
 .../calculator.component.ts                   |   12 +-
 .../remous-results.component.html             |   98 +-
 .../remous-results.component.ts               |   42 +-
 .../section-canvas.component.ts               |    2 +-
 .../section-results.component.html            |   36 +-
 .../section-results.component.ts              |   50 +-
 src/app/formulaire/check-field.ts             |    8 +-
 .../definition/concrete/form-cond-distri.ts   |   61 +
 .../definition/concrete/form-courbe-remous.ts |   52 +
 .../concrete/form-lechapt-calmon.ts           |   67 ++
 .../concrete/form-passe-bassin-dim.ts         |   62 +
 .../concrete/form-passe-bassin-puissance.ts   |   61 +
 .../concrete/form-regime-uniforme.ts          |   68 ++
 .../concrete/form-section-parametree.ts       |   70 ++
 .../definition/form-compute-cond-distri.ts    |   22 +
 .../definition/form-compute-courbe-remous.ts  |   81 ++
 .../definition/form-compute-fixedvar.ts       |  126 ++
 .../definition/form-compute-lechapt-calmon.ts |   24 +
 .../definition/form-compute-pab-bassin-dim.ts |   21 +
 .../form-compute-pab-bassin-puissance.ts      |   21 +
 .../form-compute-regime-uniforme.ts           |   17 +
 .../form-compute-section-parametree.ts        |  164 +++
 src/app/formulaire/definition/form-compute.ts |   33 +
 .../definition/form-def-fixedvar.ts           |   96 ++
 .../definition/form-def-paramcalc.ts          |   69 ++
 .../formulaire/definition/form-def-section.ts |  176 +++
 .../formulaire/definition/form-definition.ts  |  353 ++++++
 .../definition/form-result-fixedvar.ts        |   73 ++
 .../definition/form-result-remous.ts          |   40 +
 .../definition/form-result-section.ts         |   66 ++
 src/app/formulaire/definition/form-result.ts  |    9 +
 src/app/formulaire/field.ts                   |   16 +-
 src/app/formulaire/fieldset-container.ts      |   12 +-
 src/app/formulaire/fieldset.ts                |   21 +-
 src/app/formulaire/formulaire-definition.ts   | 1038 -----------------
 src/app/formulaire/formulaire-element.ts      |   34 +-
 src/app/formulaire/formulaire-node.ts         |    4 +-
 src/app/formulaire/input-field.ts             |    6 +-
 src/app/formulaire/ngparam.ts                 |    8 +-
 src/app/formulaire/select-field.ts            |    8 +-
 .../services/formulaire/formulaire.service.ts |   49 +-
 src/app/services/param/param.service.ts       |    6 +-
 49 files changed, 2155 insertions(+), 1278 deletions(-)
 create mode 100644 src/app/formulaire/definition/concrete/form-cond-distri.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-courbe-remous.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-passe-bassin-dim.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-passe-bassin-puissance.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-regime-uniforme.ts
 create mode 100644 src/app/formulaire/definition/concrete/form-section-parametree.ts
 create mode 100644 src/app/formulaire/definition/form-compute-cond-distri.ts
 create mode 100644 src/app/formulaire/definition/form-compute-courbe-remous.ts
 create mode 100644 src/app/formulaire/definition/form-compute-fixedvar.ts
 create mode 100644 src/app/formulaire/definition/form-compute-lechapt-calmon.ts
 create mode 100644 src/app/formulaire/definition/form-compute-pab-bassin-dim.ts
 create mode 100644 src/app/formulaire/definition/form-compute-pab-bassin-puissance.ts
 create mode 100644 src/app/formulaire/definition/form-compute-regime-uniforme.ts
 create mode 100644 src/app/formulaire/definition/form-compute-section-parametree.ts
 create mode 100644 src/app/formulaire/definition/form-compute.ts
 create mode 100644 src/app/formulaire/definition/form-def-fixedvar.ts
 create mode 100644 src/app/formulaire/definition/form-def-paramcalc.ts
 create mode 100644 src/app/formulaire/definition/form-def-section.ts
 create mode 100644 src/app/formulaire/definition/form-definition.ts
 create mode 100644 src/app/formulaire/definition/form-result-fixedvar.ts
 create mode 100644 src/app/formulaire/definition/form-result-remous.ts
 create mode 100644 src/app/formulaire/definition/form-result-section.ts
 create mode 100644 src/app/formulaire/definition/form-result.ts
 delete mode 100644 src/app/formulaire/formulaire-definition.ts

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 30278fe95..f78f761a4 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -8,7 +8,7 @@ import { Observer } from './services/observer';
 import { ErrorService } from './services/error/error.service';
 // import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
 import { FormulaireService } from './services/formulaire/formulaire.service';
-import { FormulaireDefinition } from './formulaire/formulaire-definition';
+import { FormulaireDefinition } from './formulaire/definition/form-definition';
 
 
 @Component({
diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts
index 7a46f4293..0d674c2e1 100644
--- a/src/app/components/calculator-list/calculator-list.component.ts
+++ b/src/app/components/calculator-list/calculator-list.component.ts
@@ -3,7 +3,7 @@ import { Router } from '@angular/router';
 
 import { CalculatorType, EnumEx } from "jalhyd";
 
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 import { InternationalisationService } from '../../services/internationalisation/internationalisation.service';
 
diff --git a/src/app/components/calculator-results/calculator-results.component.html b/src/app/components/calculator-results/calculator-results.component.html
index b91503534..21cb31f87 100644
--- a/src/app/components/calculator-results/calculator-results.component.html
+++ b/src/app/components/calculator-results/calculator-results.component.html
@@ -1,5 +1,5 @@
 <div class="container-fluid">
-    <fixedvar-results [style.display]="getFixedVarResultsStyleDisplay()"> </fixedvar-results>
-    <section-results [style.display]="getSectionResultsStyleDisplay()"></section-results>
-    <remous-results [style.display]="getRemousResultsStyleDisplay()"></remous-results>
+    <fixedvar-results> </fixedvar-results>
+    <section-results></section-results>
+    <remous-results></remous-results>
 </div>
diff --git a/src/app/components/calculator-results/calculator-results.component.ts b/src/app/components/calculator-results/calculator-results.component.ts
index 15546ce01..76eb9842a 100644
--- a/src/app/components/calculator-results/calculator-results.component.ts
+++ b/src/app/components/calculator-results/calculator-results.component.ts
@@ -3,7 +3,7 @@ import { Component, ViewChild, Output, EventEmitter, AfterViewChecked } from "@a
 import { FixedVarResultsComponent } from "../../components/fixedvar-results/fixedvar-results.component";
 import { SectionResultsComponent } from "../../components/section-results/section-results.component";
 import { RemousResultsComponent } from "../../components/remous-results/remous-results.component";
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 
 @Component({
     selector: "calc-results",
@@ -44,9 +44,9 @@ export class CalculatorResultsComponent implements AfterViewChecked {
             this.remousResultsComponent.results = undefined;
         }
         else {
-            this.fixedVarResultsComponent.results = f.fixVarResults;
-            this.sectionResultsComponent.results = f.sectionResults;
-            this.remousResultsComponent.results = f.remousResults;
+            this.fixedVarResultsComponent.results = f.results;
+            this.sectionResultsComponent.results = f.results;
+            this.remousResultsComponent.results = f.results;
         }
     }
 
@@ -59,16 +59,4 @@ export class CalculatorResultsComponent implements AfterViewChecked {
     public ngAfterViewChecked() {
         this.afterViewChecked.emit();
     }
-
-    private getFixedVarResultsStyleDisplay() {
-        return this._formulaire != undefined && this._formulaire.hasFixVarResults ? "block" : "none";
-    }
-
-    private getSectionResultsStyleDisplay() {
-        return this._formulaire != undefined && this._formulaire.hasSectionResults ? "block" : "none";
-    }
-
-    private getRemousResultsStyleDisplay() {
-        return this._formulaire != undefined && this._formulaire.hasRemousResults ? "block" : "none";
-    }
 }
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.html b/src/app/components/fixedvar-results/fixedvar-results.component.html
index 05555d931..b47085875 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.html
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.html
@@ -1,45 +1,47 @@
-<!-- journal -->
-<log></log>
+<div class="container-fluid" [style.display]="hasResults">
+    <!-- journal -->
+    <log></log>
 
-<results-graph *ngIf="showVarResults"></results-graph>
+    <results-graph *ngIf="showVarResults"></results-graph>
 
-<!-- 
+    <!-- 
     classe conditionnelle :
     [ngClass]="(condition) ? 'classe-si-vrai' : 'classe-si-faux'"
  -->
 
-<div class="row">
-    <!-- table des résultats fixés -->
-    <div class="col mx-auto" *ngIf="showFixedResults">
-        <table class="table" style="border: 1px solid rgb(230,230,230);">
-            <tr>
-                <th class="result_center">{{uitextParamFixes}}</th>
-                <th class="result_center">{{uitextValeurs}}</th>
-            </tr>
-            <tr *ngFor="let r of fixedResults; let i=index">
-                <td class="result_right {{getFixedResultClass(i)}}">{{r.label}}</td>
-                <td class="result_center {{getFixedResultClass(i)}}">
-                    <single-result [result]=r.value> </single-result>
-                </td>
-            </tr>
-        </table>
-    </div>
+    <div class="row">
+        <!-- table des résultats fixés -->
+        <div class="col mx-auto" *ngIf="showFixedResults">
+            <table class="table" style="border: 1px solid rgb(230,230,230);">
+                <tr>
+                    <th class="result_center">{{uitextParamFixes}}</th>
+                    <th class="result_center">{{uitextValeurs}}</th>
+                </tr>
+                <tr *ngFor="let r of fixedResults; let i=index">
+                    <td class="result_right {{getFixedResultClass(i)}}">{{r.label}}</td>
+                    <td class="result_center {{getFixedResultClass(i)}}">
+                        <single-result [result]=r.value> </single-result>
+                    </td>
+                </tr>
+            </table>
+        </div>
 
-    <!-- table des résultats variés -->
-    <div class="col" *ngIf="showVarResults">
-        <table class="table table-striped" style="border: 1px solid rgb(230,230,230);">
-            <tr>
-                <th class="result_center">{{_results.variableParamHeader}}</th>
-                <th class="result_center">{{_results.variableResultHeader}}</th>
-            </tr>
-            <tr *ngFor="let r of varResults; let i=index">
-                <td class="result_center">
-                    <single-result [result]=r.param></single-result>
-                </td>
-                <td class="result_center">
-                    <single-result [result]=r.result></single-result>
-                </td>
-            </tr>
-        </table>
+        <!-- table des résultats variés -->
+        <div class="col" *ngIf="showVarResults">
+            <table class="table table-striped" style="border: 1px solid rgb(230,230,230);">
+                <tr>
+                    <th class="result_center">{{_results.variableParamHeader}}</th>
+                    <th class="result_center">{{_results.variableResultHeader}}</th>
+                </tr>
+                <tr *ngFor="let r of varResults; let i=index">
+                    <td class="result_center">
+                        <single-result [result]=r.param></single-result>
+                    </td>
+                    <td class="result_center">
+                        <single-result [result]=r.result></single-result>
+                    </td>
+                </tr>
+            </table>
+        </div>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index f55c8cd54..f391529fb 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -4,6 +4,7 @@ import { InternationalisationService } from "../../services/internationalisation
 import { LogComponent } from '../../components/log/log.component';
 import { FixedVarResults } from "../../results/fixed-var-results";
 import { ResultsGraphComponent } from "../results-graph/results-graph.component";
+import { CalculatorResults } from "../../results/calculator-results";
 
 @Component({
     selector: "fixedvar-results",
@@ -37,7 +38,7 @@ export class FixedVarResultsComponent implements DoCheck {
     /**
      * true si le graphe des résultats doit être remis à jour
      */
-    private _updateResultsGraph: boolean;
+    private _doUpdate: boolean = false;
 
     /**
      * composant journal
@@ -52,31 +53,41 @@ export class FixedVarResultsComponent implements DoCheck {
         private intlService: InternationalisationService
     ) { }
 
-    public set results(r: FixedVarResults) {
-        this._results = r;
-        this._updateResultsGraph = true;
+    public set results(rs: CalculatorResults[]) {
+        this._results = undefined;
+        if (rs != undefined)
+            for (const r of rs) {
+                if (r instanceof FixedVarResults)
+                    this._results = r;
+                break;
+            }
+        this.updateView();
     }
 
     public updateView() {
         this.logComponent.log = undefined;
-        this.generateResults();
-        this._updateResultsGraph = true;
+
+        if (this._results != undefined)
+            this._doUpdate = this._results.hasResults;
     }
 
     public ngDoCheck() {
-        if (this._updateResultsGraph) {
-            if (this.resultsGraphComponent != undefined) {
-                this.resultsGraphComponent.results = this._results;
-                this.resultsGraphComponent.updateView();
-                this._updateResultsGraph = false;
-            }
-        }
+        if (this._doUpdate)
+            this._doUpdate = !this.updateResults();
     }
 
-    private generateResults() {
-        if (this._results != undefined) {
+    /** 
+     * met à jour l'affichage des résultats
+     * @returns true si les résultats ont pu être mis à jour
+     */
+    private updateResults() {
+        if (this._results != undefined && this.resultsGraphComponent != undefined && this.logComponent != undefined) {
+            this.resultsGraphComponent.results = this._results;
+            this.resultsGraphComponent.updateView();
             this.logComponent.log = this._results.log;
+            return true;
         }
+        return false;
     }
 
     /**
@@ -114,4 +125,8 @@ export class FixedVarResultsComponent implements DoCheck {
     private get varResults() {
         return this._results.varResults;
     }
+
+    private get hasResults(): boolean {
+        return this.results != undefined && this._results.hasResults;
+    }
 }
diff --git a/src/app/components/generic-calculator/calc-name.component.ts b/src/app/components/generic-calculator/calc-name.component.ts
index f20cb215d..4c37b10e8 100644
--- a/src/app/components/generic-calculator/calc-name.component.ts
+++ b/src/app/components/generic-calculator/calc-name.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input } from "@angular/core";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 
 @Component({
     selector: 'calc-name',
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 2076dfa17..97903ce03 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router';
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { FieldSet } from "../../formulaire/fieldset";
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 import { CalculatorResultsComponent } from "../../components/calculator-results/calculator-results.component";
 import { Observer } from "../../services/observer";
 import { Subscription } from "rxjs/Subscription";
@@ -174,16 +174,10 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
     }
 
     /*
-     * gestion des événements clic sur les radios :
-     * envoi d'un message au composant parent
-     * cf. https://angular.io/guide/component-interaction#parent-listens-for-child-event
+     * gestion des événements clic sur les radios
      */
     private onRadioClick(info: string) {
-        let tmp: string[] = info.split("_");
-        let symbol: string = tmp[0]; // symbole du paramètre dont vient l'événement radio
-        let option: string = tmp[1]; // nouvel état (radio)
-
-        this._formulaire.resetRadiosAndResults(symbol, option);
+        this._formulaire.onRadioClick(info);
     }
 
     private onCloseForm() {
diff --git a/src/app/components/remous-results/remous-results.component.html b/src/app/components/remous-results/remous-results.component.html
index a2eecd6ce..bf217e669 100644
--- a/src/app/components/remous-results/remous-results.component.html
+++ b/src/app/components/remous-results/remous-results.component.html
@@ -1,54 +1,56 @@
-<div class="row">
-    <div class="col">
-        <chart [type]="graph1_type" [data]="graph1_data" [options]="graph1_options"></chart>
+<div class="container-fluid" *ngIf="hasResults">
+    <div class="row">
+        <div class="col">
+            <chart [type]="graph1_type" [data]="graph1_data" [options]="graph1_options"></chart>
+        </div>
     </div>
-</div>
-<div class="row">
-    <div class="col">
-        <chart *ngIf="extraGraph" [type]="graph2_type" [data]="graph2_data" [options]="graph2_options"></chart>
+    <div class="row">
+        <div class="col">
+            <chart *ngIf="extraGraph" [type]="graph2_type" [data]="graph2_data" [options]="graph2_options"></chart>
+        </div>
     </div>
-</div>
 
-<!-- journal -->
-<log></log>
+    <!-- journal -->
+    <log></log>
 
-<div *ngIf="hasSeries" class="row">
-    <!-- résultats numériques -->
-    <table class="table">
-        <thead>
-            <tr>
-                <th></th>
-                <th>{{uitextLigneFluviale}}</th>
-                <th></th>
-                <th>{{uitextLigneTorrentielle}}</th>
-                <th></th>
+    <div *ngIf="hasSeries" class="row">
+        <!-- résultats numériques -->
+        <table class="table">
+            <thead>
+                <tr>
+                    <th></th>
+                    <th>{{uitextLigneFluviale}}</th>
+                    <th></th>
+                    <th>{{uitextLigneTorrentielle}}</th>
+                    <th></th>
+                </tr>
+                <tr>
+                    <th>{{uitextAbscisse}}</th>
+                    <th>{{uitextTirant}}</th>
+                    <th>{{extraParamLabel}}</th>
+                    <th>{{uitextTirant}}</th>
+                    <th>{{extraParamLabel}}</th>
+                </tr>
+            </thead>
+            <tr *ngFor="let r of values; let i=index" [class]="getResultClass(i)">
+                <td>{{r.abs}}</td>
+                <!-- <td>{{r.flu}}</td> -->
+                <td>
+                    <single-result [result]=r.flu></single-result>
+                </td>
+                <!-- <td>{{r.extraFlu}}</td> -->
+                <td>
+                    <single-result [result]=r.extraFlu></single-result>
+                </td>
+                <!-- <td>{{r.tor}}</td> -->
+                <td>
+                    <single-result [result]=r.tor></single-result>
+                </td>
+                <!-- <td>{{r.extraTor}}</td> -->
+                <td>
+                    <single-result [result]=r.extraTor></single-result>
+                </td>
             </tr>
-            <tr>
-                <th>{{uitextAbscisse}}</th>
-                <th>{{uitextTirant}}</th>
-                <th>{{extraParamLabel}}</th>
-                <th>{{uitextTirant}}</th>
-                <th>{{extraParamLabel}}</th>
-            </tr>
-        </thead>
-        <tr *ngFor="let r of values; let i=index" [class]="getResultClass(i)">
-            <td>{{r.abs}}</td>
-            <!-- <td>{{r.flu}}</td> -->
-            <td>
-                <single-result [result]=r.flu></single-result>
-            </td>
-            <!-- <td>{{r.extraFlu}}</td> -->
-            <td>
-                <single-result [result]=r.extraFlu></single-result>
-            </td>
-            <!-- <td>{{r.tor}}</td> -->
-            <td>
-                <single-result [result]=r.tor></single-result>
-            </td>
-            <!-- <td>{{r.extraTor}}</td> -->
-            <td>
-                <single-result [result]=r.extraTor></single-result>
-            </td>
-        </tr>
-    </table>
+        </table>
+    </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
index c72b5b10c..e414ced11 100644
--- a/src/app/components/remous-results/remous-results.component.ts
+++ b/src/app/components/remous-results/remous-results.component.ts
@@ -5,6 +5,7 @@ import { Result, ArrayReverseIterator, ResultElement } from "jalhyd";
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { LogComponent } from "../../components/log/log.component";
 import { RemousResults } from "../../results/remous-results";
+import { CalculatorResults } from "../../results/calculator-results";
 
 @Component({
     selector: "remous-results",
@@ -52,6 +53,11 @@ export class RemousResultsComponent {
      */
     private _values: Object[];
 
+    /**
+     * true si les résultats doivent être mis à jour
+     */
+    private _doUpdate: boolean = false;
+
     /**
      * composant journal
      */
@@ -109,8 +115,15 @@ export class RemousResultsComponent {
         return this._results == undefined ? undefined : this._results.extraParamLabel;
     }
 
-    public set results(r: RemousResults) {
-        this._results = r;
+    public set results(rs: CalculatorResults[]) {
+        this._results = undefined;
+        if (rs != undefined)
+            for (const r of rs) {
+                if (r instanceof RemousResults) {
+                    this._results = r;
+                    break;
+                }
+            }
         this.updateView();
     }
 
@@ -119,12 +132,29 @@ export class RemousResultsComponent {
         this.graph1_options = {};
         this.graph2_data = {};
         this.graph2_options = {};
-        this.logComponent.log = undefined;
+        if (this.logComponent != undefined)
+            this.logComponent.log = undefined;
         this._values = [];
-        if (this._results != undefined) {
+
+        if (this._results != undefined)
+            this._doUpdate = this._results.hasResults;
+    }
+
+    /** 
+     * appelé pour gérer les changements non détectés par Angular
+     */
+    public ngDoCheck() {
+        if (this._doUpdate)
+            this._doUpdate = !this.updateResults();
+    }
+
+    private updateResults() {
+        if (this.logComponent != undefined && this._results != undefined) {
             this.logComponent.log = this._results.log;
             this.generateGraph();
+            return true;
         }
+        return false;
     }
 
     private connectRessaut(lineFlu: LineData, lineTor: LineData) {
@@ -327,6 +357,10 @@ export class RemousResultsComponent {
     private getResultClass(i: number) {
         return "result_id_" + String(i & 1);
     }
+
+    private get hasResults(): boolean {
+        return this._results != undefined && this._results.hasResults;
+    }
 }
 
 /**
diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index fcac05278..ce5d8ef7c 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -40,7 +40,7 @@ export class SectionCanvasComponent {
     private _section: acSection;
 
     // tirants
-    private _levels: Object[];
+    private _levels: Object[] = [];
 
     @ViewChild("calcCanvas")
     private _calcCanvas: CalcCanvasComponent;
diff --git a/src/app/components/section-results/section-results.component.html b/src/app/components/section-results/section-results.component.html
index c9143041f..02e93f988 100644
--- a/src/app/components/section-results/section-results.component.html
+++ b/src/app/components/section-results/section-results.component.html
@@ -1,20 +1,22 @@
-<!-- graphique -->
-<div class="row">
-    <div class="col" style="text-align: center">
-        <section-canvas></section-canvas>
+<div class="container-fluid" *ngIf="hasResults">
+    <!-- graphique -->
+    <div class="row">
+        <div class="col" style="text-align: center">
+            <section-canvas></section-canvas>
+        </div>
     </div>
-</div>
 
-<!-- tableau de valeurs -->
-<div *ngIf="hasResults" class="row">
-    <div class="col mx-auto">
-        <table style="width: 100%">
-            <tr *ngFor="let r of sectionResults; let i=index" [class]="getResultClass(i)">
-                <td class="result_label">{{r.label}}</td>
-                <td class="result_value">
-                    <single-result [result]=r.value></single-result>
-                </td>
-            </tr>
-        </table>
+    <!-- tableau de valeurs -->
+    <div class="row">
+        <div class="col mx-auto">
+            <table style="width: 100%">
+                <tr *ngFor="let r of sectionResults; let i=index" [class]="getResultClass(i)">
+                    <td class="result_label">{{r.label}}</td>
+                    <td class="result_value">
+                        <single-result [result]=r.value></single-result>
+                    </td>
+                </tr>
+            </table>
+        </div>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/src/app/components/section-results/section-results.component.ts b/src/app/components/section-results/section-results.component.ts
index 528e3ef84..ea6daaae4 100644
--- a/src/app/components/section-results/section-results.component.ts
+++ b/src/app/components/section-results/section-results.component.ts
@@ -1,10 +1,11 @@
-import { Component, ViewChild } from '@angular/core';
+import { Component, ViewChild, DoCheck } from '@angular/core';
 
 import { acSection, Result } from 'jalhyd';
 
 import { SectionCanvasComponent } from '../section-canvas/section-canvas.component';
 import { SectionResults } from '../../results/section-results';
 import { ApplicationSetupService } from '../../services/app-setup/app-setup.service';
+import { CalculatorResults } from '../../results/calculator-results';
 
 @Component({
     selector: 'section-results',
@@ -30,11 +31,11 @@ import { ApplicationSetupService } from '../../services/app-setup/app-setup.serv
     `
     ]
 })
-export class SectionResultsComponent {
+export class SectionResultsComponent implements DoCheck {
     /**
     * résultats non mis en forme
     */
-    private _sectionResults: SectionResults;
+    private _results: SectionResults;
 
     constructor(private appSetupService: ApplicationSetupService) { }
 
@@ -48,25 +49,44 @@ export class SectionResultsComponent {
         "Yco": { r: 255, g: 0, b: 255 },
     };
 
+    private _doUpdate: boolean = false;
+
     @ViewChild(SectionCanvasComponent)
     private _sectionCanvas: SectionCanvasComponent;
 
-    public set results(r: SectionResults) {
-        this._sectionResults = r;
+    public set results(rs: CalculatorResults[]) {
+        this._results = undefined;
+        if (rs != undefined)
+            for (const r of rs) {
+                if (r instanceof SectionResults) {
+                    this._results = r;
+                    break;
+                }
+            }
         this.updateView();
     }
 
     public updateView() {
-        this._sectionCanvas.reset();
-        if (this._sectionResults != undefined)
-            this.formatResults();
+        if (this._sectionCanvas != undefined)
+            this._sectionCanvas.reset();
+
+        if (this._results != undefined)
+            this._doUpdate = this._results.hasResults;
+    }
+
+    /** 
+     * appelé pour gérer les changements non détectés par Angular
+     */
+    public ngDoCheck() {
+        if (this._doUpdate)
+            this._doUpdate = !this.updateResults();
     }
 
-    private formatResults() {
-        if (this._sectionResults.results.length > 0) {
+    private updateResults() {
+        if (this._results != undefined && this._sectionCanvas != undefined) {
             const nDigits = this.appSetupService.displayDigits;
 
-            for (let r of this._sectionResults.results) {
+            for (let r of this._results.results) {
                 const v: Result = r["value"];
                 const l = r["label"];
 
@@ -74,16 +94,18 @@ export class SectionResultsComponent {
                 if (drawLabel != undefined && v.vCalc != undefined)
                     this._sectionCanvas.addLevel(v.vCalc, drawLabel + " = " + v.vCalc.toFixed(nDigits), SectionResultsComponent.labelColors[drawLabel]);
             }
-            this._sectionCanvas.section = this._sectionResults.section;
+            this._sectionCanvas.section = this._results.section;
+            return true;
         }
+        return false;
     }
 
     private get hasResults(): boolean {
-        return this._sectionResults != undefined;
+        return this._results != undefined && this._results.hasResults;
     }
 
     private get sectionResults() {
-        return this._sectionResults.results;
+        return this._results.results;
     }
 
     private getResultClass(i: number) {
diff --git a/src/app/formulaire/check-field.ts b/src/app/formulaire/check-field.ts
index adf584eda..90328325a 100644
--- a/src/app/formulaire/check-field.ts
+++ b/src/app/formulaire/check-field.ts
@@ -3,13 +3,13 @@ import { ComputeNodeType } from "jalhyd";
 import { Field } from "./field";
 import { Dependency } from "./dependency/dependency";
 import { DependencyConditionType } from "./dependency/dependency-condition";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 
 export class CheckField extends Field {
     private _value: boolean;
 
-    constructor(nodeType: ComputeNodeType, parentForm: FormulaireDefinition, isTmpl: boolean = false) {
-        super(nodeType, parentForm, isTmpl);
+    constructor(nodeType: ComputeNodeType, isTmpl: boolean = false) {
+        super(nodeType, isTmpl);
         this._value = false;
     }
 
@@ -41,7 +41,7 @@ export class CheckField extends Field {
      * crée une nouvelle instance
      */
     protected clone(): CheckField {
-        return new CheckField(this.computeNodeType, this.parentForm);
+        return new CheckField(this.computeNodeType);
     }
 
     public parseConfig(json: {}, data?: {}) {
diff --git a/src/app/formulaire/definition/concrete/form-cond-distri.ts b/src/app/formulaire/definition/concrete/form-cond-distri.ts
new file mode 100644
index 000000000..9c11da38b
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-cond-distri.ts
@@ -0,0 +1,61 @@
+import { FormDefFixedVar } from "../form-def-fixedvar";
+import { CalculatorType } from "jalhyd";
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { FormResultFixedVar } from "../form-result-fixedvar";
+import { FormComputeConduiteDistributrice } from "../form-compute-cond-distri";
+import { FormulaireDefinition } from "../form-definition";
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormDefParamToCalculate } from "../form-def-paramcalc";
+
+export class FormulaireConduiteDistributrice extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formParamCalc: FormDefParamToCalculate;
+
+    private _formCompute: FormComputeConduiteDistributrice;
+
+    private _formResult: FormResultFixedVar;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.ConduiteDistributrice, paramService, appSetupService);
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formParamCalc = new FormDefParamToCalculate(this);
+        this._formResult = new FormResultFixedVar(this, false);
+        this._formCompute = new FormComputeConduiteDistributrice(this, this._formResult);
+    }
+
+    protected initParse() {
+        this._formParamCalc.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formParamCalc.parseOptions(json);
+    }
+
+    protected completeParse() {
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"
+     */
+    public onRadioClick(info: string) {
+        this._formParamCalc.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    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
new file mode 100644
index 000000000..88bd5a352
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
@@ -0,0 +1,52 @@
+import { CalculatorType } from "jalhyd";
+
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { FormResultRemous } from "../form-result-remous";
+import { FormDefSection } from "../form-def-section";
+import { FormComputeCourbeRemous } from "../form-compute-courbe-remous";
+import { FormulaireDefinition } from "../form-definition";
+import { CalculatorResults } from "../../../results/calculator-results";
+
+export class FormulaireCourbeRemous extends FormulaireDefinition {
+    private _formSection: FormDefSection;
+
+    private _formCompute: FormComputeCourbeRemous;
+
+    private _formResult: FormResultRemous;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.CourbeRemous, paramService, appSetupService)
+        this._formSection = new FormDefSection(this, appSetupService);
+        this._formResult = new FormResultRemous(this);
+        this._formCompute = new FormComputeCourbeRemous(this, this._formSection, this._formResult);
+    }
+
+    protected initParse() {
+        this._formSection.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formSection.parseOptions(json);
+    }
+
+    protected completeParse() {
+        this._formSection.completeParse();
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    public doCompute() {
+        this._formCompute.doCompute();
+    }
+
+    public get hasResults(): boolean {
+        return this._formResult.hasResults;
+    }
+
+    public get results(): CalculatorResults[] {
+        return this._formResult.results;
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
new file mode 100644
index 000000000..8a7070d00
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
@@ -0,0 +1,67 @@
+import { CalculatorType } from "jalhyd";
+
+import { FormResultFixedVar } from "../form-result-fixedvar";
+import { FormResultSection } from "../form-result-section";
+import { FormulaireElement } from "../../formulaire-element";
+import { NgParameter, ParamRadioConfig } from "../../ngparam";
+import { Field } from "../../field";
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { FormDefSection } from "../form-def-section";
+import { FormDefFixedVar } from "../form-def-fixedvar";
+import { FormComputeLechaptCalmon } from "../form-compute-lechapt-calmon";
+import { FormulaireDefinition } from "../form-definition";
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormDefParamToCalculate } from "../form-def-paramcalc";
+
+export class FormulaireLechaptCalmon extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formParamCalc: FormDefParamToCalculate;
+
+    private _formCompute: FormComputeLechaptCalmon;
+
+    private _formResult: FormResultFixedVar;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.LechaptCalmon, paramService, appSetupService)
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formParamCalc = new FormDefParamToCalculate(this);
+        this._formResult = new FormResultFixedVar(this, false);
+        this._formCompute = new FormComputeLechaptCalmon(this, this._formResult);
+    }
+
+    protected initParse() {
+        this._formParamCalc.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formParamCalc.parseOptions(json);
+    }
+
+    protected completeParse() {
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"    
+     */
+    public onRadioClick(info: string) {
+        this._formParamCalc.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    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-passe-bassin-dim.ts b/src/app/formulaire/definition/concrete/form-passe-bassin-dim.ts
new file mode 100644
index 000000000..6a7041919
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-passe-bassin-dim.ts
@@ -0,0 +1,62 @@
+import { CalculatorType } from "jalhyd";
+
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormulaireDefinition } from "../form-definition";
+import { FormDefFixedVar } from "../form-def-fixedvar";
+import { FormDefParamToCalculate } from "../form-def-paramcalc";
+import { FormComputePasseBassinDimensions } from "../form-compute-pab-bassin-dim";
+import { FormResultFixedVar } from "../form-result-fixedvar";
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+
+export class FormulairePasseBassinDimensions extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formParamCalc: FormDefParamToCalculate;
+
+    private _formCompute: FormComputePasseBassinDimensions;
+
+    private _formResult: FormResultFixedVar;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.PabDimensions, paramService, appSetupService);
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formParamCalc = new FormDefParamToCalculate(this);
+        this._formResult = new FormResultFixedVar(this, false);
+        this._formCompute = new FormComputePasseBassinDimensions(this, this._formResult);
+    }
+
+    protected initParse() {
+        this._formParamCalc.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formParamCalc.parseOptions(json);
+    }
+
+    protected completeParse() {
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"    
+     */
+    public onRadioClick(info: string) {
+        this._formParamCalc.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    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-passe-bassin-puissance.ts b/src/app/formulaire/definition/concrete/form-passe-bassin-puissance.ts
new file mode 100644
index 000000000..7ade60201
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-passe-bassin-puissance.ts
@@ -0,0 +1,61 @@
+import { FormDefFixedVar } from "../form-def-fixedvar";
+import { FormResultFixedVar } from "../form-result-fixedvar";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { ParamService } from "../../../services/param/param.service";
+import { CalculatorType } from "jalhyd";
+import { FormulaireDefinition } from "../form-definition";
+import { FormComputePasseBassinPuissance } from "../form-compute-pab-bassin-puissance";
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormDefParamToCalculate } from "../form-def-paramcalc";
+
+export class FormulairePasseBassinPuissance extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formParamCalc: FormDefParamToCalculate;
+
+    private _formCompute: FormComputePasseBassinPuissance;
+
+    private _formResult: FormResultFixedVar;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.PabPuissance, paramService, appSetupService);
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formParamCalc = new FormDefParamToCalculate(this);
+        this._formResult = new FormResultFixedVar(this, false);
+        this._formCompute = new FormComputePasseBassinPuissance(this, this._formResult);
+    }
+
+    protected initParse() {
+        this._formParamCalc.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formParamCalc.parseOptions(json);
+    }
+
+    protected completeParse() {
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"    
+     */
+    public onRadioClick(info: string) {
+        this._formParamCalc.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    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-regime-uniforme.ts b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
new file mode 100644
index 000000000..48207f7bb
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
@@ -0,0 +1,68 @@
+import { FormDefFixedVar } from "../form-def-fixedvar";
+import { CalculatorType } from "jalhyd";
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { FormResultFixedVar } from "../form-result-fixedvar";
+import { FormulaireDefinition } from "../form-definition";
+import { FormComputeRegimeUniforme } from "../form-compute-regime-uniforme";
+import { FormDefSection } from "../form-def-section";
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormDefParamToCalculate } from "../form-def-paramcalc";
+
+export class FormulaireRegimeUniforme extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formParamCalc: FormDefParamToCalculate;
+
+    private _formSection: FormDefSection;
+
+    private _formCompute: FormComputeRegimeUniforme;
+
+    private _formResult: FormResultFixedVar;
+
+    constructor(paramService: ParamService, appSetupService: ApplicationSetupService) {
+        super(CalculatorType.RegimeUniforme, paramService, appSetupService)
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formParamCalc = new FormDefParamToCalculate(this);
+        this._formSection = new FormDefSection(this, appSetupService);
+        this._formResult = new FormResultFixedVar(this, true);
+        this._formCompute = new FormComputeRegimeUniforme(this, this._formSection, this._formResult);
+    }
+
+    protected initParse() {
+        this._formSection.initParse();
+        this._formParamCalc.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formSection.parseOptions(json);
+        this._formParamCalc.parseOptions(json);
+    }
+
+    protected completeParse() {
+        this._formSection.completeParse();
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"    
+     */
+    public onRadioClick(info: string) {
+        this._formParamCalc.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formResult.resetResults();
+    }
+
+    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-section-parametree.ts b/src/app/formulaire/definition/concrete/form-section-parametree.ts
new file mode 100644
index 000000000..a599f05d8
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-section-parametree.ts
@@ -0,0 +1,70 @@
+import { CalculatorType, acSection, ParamsEquation } from "jalhyd";
+
+import { FormResultSection } from "../form-result-section";
+import { ParamService } from "../../../services/param/param.service";
+import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
+import { FormDefSection } from "../form-def-section";
+import { NgParameter } from "../../ngparam";
+import { InputField } from "../../input-field";
+import { FormComputeSectionParametree } from "../form-compute-section-parametree";
+import { FormulaireDefinition } from "../form-definition";
+import { InternationalisationService } from "../../../services/internationalisation/internationalisation.service";
+import { CalculatorResults } from "../../../results/calculator-results";
+import { FormDefFixedVar } from "../form-def-fixedvar";
+
+export class FormulaireSectionParametree extends FormulaireDefinition {
+    private _formFixedVar: FormDefFixedVar;
+
+    private _formSection: FormDefSection;
+
+    private _formCompute: FormComputeSectionParametree;
+
+    private _formSectionResult: FormResultSection;
+
+    constructor(
+        paramService: ParamService,
+        appSetupService: ApplicationSetupService,
+        intlService: InternationalisationService
+    ) {
+        super(CalculatorType.SectionParametree, paramService, appSetupService);
+        this._formFixedVar = new FormDefFixedVar(this);
+        this._formSection = new FormDefSection(this, appSetupService);
+        this._formSectionResult = new FormResultSection(this, this._formSection);
+        this._formCompute = new FormComputeSectionParametree(this, this._formSection, this._formSectionResult, intlService);
+    }
+
+    protected initParse() {
+        this._formSection.initParse();
+    }
+
+    protected parseOptions(json: {}) {
+        this._formSection.parseOptions(json);
+    }
+
+    protected completeParse() {
+        this._formSection.completeParse();
+    }
+
+    /**
+     * gestion du clic sur les radios "paramètre fixé, à varier, à calculer"    
+     */
+    public onRadioClick(info: string) {
+        this._formFixedVar.onRadioClick(info);
+    }
+
+    public resetResults() {
+        this._formSectionResult.resetResults();
+    }
+
+    public doCompute() {
+        this._formCompute.doCompute();
+    }
+
+    public get hasResults(): boolean {
+        return this._formSectionResult.hasResults;
+    }
+
+    public get results(): CalculatorResults[] {
+        return this._formSectionResult.results;
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute-cond-distri.ts b/src/app/formulaire/definition/form-compute-cond-distri.ts
new file mode 100644
index 000000000..62099c01b
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-cond-distri.ts
@@ -0,0 +1,22 @@
+import { ComputeNode, ParamsEquation, ConduiteDistribParams, ConduiteDistrib } from "jalhyd";
+
+import { FormComputeFixedVar } from "./form-compute-fixedvar";
+import { FormulaireDefinition } from "./form-definition";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+
+export class FormComputeConduiteDistributrice extends FormComputeFixedVar {
+    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    public getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        let Q: number = this._formBase.getParameterValue("Q"); // débit Q
+        let D: number = this._formBase.getParameterValue("D"); // diamètre D
+        let J: number = this._formBase.getParameterValue("J"); // perte de charge J
+        let Lg: number = this._formBase.getParameterValue("Lg"); // Longueur de la conduite Lg
+        let Nu: number = this._formBase.getParameterValue("Nu"); // viscosité dynamique 
+        let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
+        let nub = new ConduiteDistrib(prms);
+        return [nub, prms];
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute-courbe-remous.ts b/src/app/formulaire/definition/form-compute-courbe-remous.ts
new file mode 100644
index 000000000..2b4542c3d
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-courbe-remous.ts
@@ -0,0 +1,81 @@
+import { acSection, ParamsEquation, Nub, ComputeNode, Result, MethodeResolution, CourbeRemousParams, CourbeRemous, ResultElement } from "jalhyd";
+
+import { SelectField } from "../select-field";
+import { RemousResults } from "../../results/remous-results";
+import { FormulaireDefinition } from "./form-definition";
+import { FormDefSection } from "./form-def-section";
+import { FormCompute } from "./form-compute";
+import { FormResultRemous } from "./form-result-remous";
+
+export class FormComputeCourbeRemous extends FormCompute {
+    constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResultRemous) {
+        super(formBase, formResult);
+    }
+
+    protected getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        return this._formSection.getSectionNubAndParameters(false);
+    }
+
+    private get remousResults(): RemousResults {
+        const f = this._formResult as FormResultRemous;
+        return f.remousResults;
+    }
+
+    protected compute() {
+        var np: [ComputeNode, ParamsEquation] = this.getNubAndParameters();
+
+        let sect: acSection = np[0] as acSection;
+        let prmSect: ParamsEquation = np[1];
+
+        let Yamont: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "Yamont"); // tirant amont
+        let Yaval: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "Yaval"); // tirant aval
+        let Dx: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "Dx"); // pas de discrétisation
+        let Long: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "Long"); // longueur du bief
+        let If: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "If"); // pente du fond
+        let YB: number = this._formBase.getNodeParameterValue(this._formSection.sectionNodeType, "YB"); // hauteur de berge
+        let Yn: Result = sect.Calc("Yn"); // hauteur normale
+        let Yc: Result = sect.Calc("Yc"); // hauteur critique
+
+        this.remousResults.penteFond = If;
+
+        // méthode de résolution
+
+        let msf: SelectField = <SelectField>this._formBase.getFormulaireNodeById("select_resolution");
+        let smeth: string = msf.getValue().value;
+        let methRes: MethodeResolution;
+        if (smeth == "select_resolution_trap")
+            methRes = MethodeResolution.Trapezes;
+        else if (smeth == "select_resolution_rk4")
+            methRes = MethodeResolution.RungeKutta4;
+        else if (smeth == "select_resolution_euler")
+            methRes = MethodeResolution.EulerExplicite;
+        else
+            throw "GenericCalculatorComponent.doComputeRemous() : type de méthode de résolution '" + smeth + "' inconnu";
+
+        // paramètre supplémentaire à calculer
+
+        const extraSymbol: string = this._formBase.getSelectedValue("select_target");
+
+        // calcul
+
+        let prmCR: CourbeRemousParams = new CourbeRemousParams(sect, Yamont, Yaval, Long, Dx, methRes);
+        let cr = new CourbeRemous(prmCR);
+        let res: Result = cr.calculRemous(extraSymbol == "none" ? undefined : extraSymbol);
+
+        // affichage du graphe
+
+        this.remousResults.hauteurBerge = new ResultElement(YB);
+        this.remousResults.hauteurNormale = Yn.result;
+        this.remousResults.hauteurCritique = Yc.result;
+        if (extraSymbol != "none") {
+            this.remousResults.extraParamLabel = this._formBase.getSelectedLabel("select_target");
+            this.remousResults.extraGraph = ["Hs", "Hsc", "Yf", "Yt", "Yco"].indexOf(extraSymbol) == -1;
+        }
+        else
+            this.remousResults.extraGraph = false;
+
+        // résultats numériques
+
+        this.remousResults.addResult(res);
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
new file mode 100644
index 000000000..33cd93150
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-fixedvar.ts
@@ -0,0 +1,126 @@
+import { Nub, ParamsEquation, Result, ParamDomainValue, ComputeNode } from "jalhyd";
+
+import { FormCompute } from "./form-compute";
+import { NgParameter, ParamValueMode, ParamRadioConfig } from "../ngparam";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
+import { FormulaireDefinition } from "./form-definition";
+
+export abstract class FormComputeFixedVar extends FormCompute {
+    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    protected get formResult(): FormResultFixedVar {
+        return this._formResult as FormResultFixedVar;
+    }
+
+    private getVariatedParameter(): NgParameter {
+        return this._formBase.getParamFromState(ParamRadioConfig.VAR);
+    }
+
+    private getComputedParameter(): NgParameter {
+        return this._formBase.getParamFromState(ParamRadioConfig.CAL);
+    }
+
+    /**
+     * lance le calcul d'un paramètre en déterminant une valeur initiale
+     */
+    private runNubCalc(nub: Nub, p: NgParameter, prec: number): Result {
+        let init: number;
+        switch (p.domain.domain) {
+            case ParamDomainValue.ANY:
+            case ParamDomainValue.POS_NULL:
+                init = 0;
+                break;
+
+            case ParamDomainValue.INTERVAL:
+                init = p.domain.minValue;
+                break;
+
+            case ParamDomainValue.NOT_NULL:
+            case ParamDomainValue.POS:
+                init = 1e-8;
+                break;
+        }
+        if (prec == undefined)
+            return nub.Calc(p.symbol, init);
+
+        return nub.Calc(p.symbol, init, prec);
+    }
+
+    protected compute() {
+        let nub: Nub;
+        let prms: ParamsEquation;
+        let np: [ComputeNode, ParamsEquation] = this.getNubAndParameters();
+        nub = np[0] as Nub;
+        prms = np[1];
+
+        if (this._formBase.hasParameter("Pr"))
+            var computePrec: number = this._formBase.getParameterValue("Pr"); // précision de calcul
+
+        let computedParam: NgParameter = this.getComputedParameter();
+
+        let varParam: NgParameter = this.getVariatedParameter();
+        if (varParam == undefined) {
+            // pas de paramètre à varier
+
+            let res: Result = this.runNubCalc(nub, computedParam, computePrec);
+            if (res.ok) {
+                this.formResult.addFixedResults();
+                this.formResult.addFixedResultElement(computedParam, res.result);
+            }
+            else {
+                this.formResult.addLogMessages(res.log);
+            }
+        }
+        else {
+            // il y a un paramètre à varier
+
+            this.formResult.addFixedResults();
+            this.formResult.setVariableParamHeaderFromParameter(varParam);
+            this.formResult.setVariableResultHeaderFromParameter(computedParam);
+
+            switch (varParam.valueMode) {
+                case ParamValueMode.MINMAX:
+                    this.formResult.graphType = GraphType.Scatter;
+
+                    let min: number = +varParam.minValue;
+                    let max: number = +varParam.maxValue;
+                    let step: number = +varParam.stepValue;
+
+                    for (let val = min; val <= max; val += step) {
+                        prms[varParam.symbol].v = val;
+
+                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
+                        if (res.ok) {
+                            this.formResult.addVarResultElement(val, res.result);
+                        }
+                        else {
+                            this.formResult.addLogMessages(res.log);
+                        }
+                    }
+                    break;
+
+                case ParamValueMode.LISTE:
+                    this.formResult.graphType = GraphType.Histogram;
+
+                    for (let val of varParam.valueList) {
+                        prms[varParam.symbol].v = val;
+
+                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
+                        if (res.ok) {
+                            this.formResult.addVarResultElement(val, res.result);
+                        }
+                        else {
+                            this.formResult.addLogMessages(res.log);
+                        }
+                    }
+
+                    break;
+            }
+
+            this.formResult.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
+        }
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute-lechapt-calmon.ts b/src/app/formulaire/definition/form-compute-lechapt-calmon.ts
new file mode 100644
index 000000000..21f1e8b38
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-lechapt-calmon.ts
@@ -0,0 +1,24 @@
+import { ComputeNode, ParamsEquation, LechaptCalmonParams, LechaptCalmon } from "jalhyd";
+
+import { FormComputeFixedVar } from "./form-compute-fixedvar";
+import { FormulaireDefinition } from "./form-definition";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+
+export class FormComputeLechaptCalmon extends FormComputeFixedVar {
+    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    public getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        let Q: number = this._formBase.getParameterValue("Q"); // débit Q
+        let D: number = this._formBase.getParameterValue("D"); // diamètre D
+        let J: number = this._formBase.getParameterValue("J"); // perte de charge J
+        let Lg: number = this._formBase.getParameterValue("Lg"); // Longueur de la conduite Lg
+        let L: number = this._formBase.getParameterValue("L"); // paramètre de matériau 1
+        let M: number = this._formBase.getParameterValue("M"); // paramètre de matériau 2
+        let N: number = this._formBase.getParameterValue("N"); // paramètre de matériau 3
+        let prms = new LechaptCalmonParams(Q, D, J, Lg, L, M, N);
+        let nub = new LechaptCalmon(prms);
+        return [nub, prms];
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute-pab-bassin-dim.ts b/src/app/formulaire/definition/form-compute-pab-bassin-dim.ts
new file mode 100644
index 000000000..266812988
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-pab-bassin-dim.ts
@@ -0,0 +1,21 @@
+import { ComputeNode, ParamsEquation, PabDimensionParams, PabDimension } from "jalhyd";
+
+import { FormComputeFixedVar } from "./form-compute-fixedvar";
+import { FormulaireDefinition } from "./form-definition";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+
+export class FormComputePasseBassinDimensions extends FormComputeFixedVar {
+    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    public getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        let L: number = this._formBase.getParameterValue("L"); // longueur L
+        let W: number = this._formBase.getParameterValue("W"); // largeur W
+        let Y: number = this._formBase.getParameterValue("Y"); // tirant d'eau Y
+        let V: number = this._formBase.getParameterValue("V"); // volume V
+        let prms = new PabDimensionParams(L, W, Y, V);
+        let nub = new PabDimension(prms); // pour initialiser la calculabilité des paramètres
+        return [nub, prms];
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-compute-pab-bassin-puissance.ts b/src/app/formulaire/definition/form-compute-pab-bassin-puissance.ts
new file mode 100644
index 000000000..829300d29
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-pab-bassin-puissance.ts
@@ -0,0 +1,21 @@
+import { ComputeNode, ParamsEquation, PabPuissanceParams, PabPuissance } from "jalhyd";
+
+import { FormComputeFixedVar } from "./form-compute-fixedvar";
+import { FormulaireDefinition } from "./form-definition";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+
+export class FormComputePasseBassinPuissance extends FormComputeFixedVar {
+    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    public getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        let DH: number = this._formBase.getParameterValue("DH");  // Chute entre bassins
+        let Q: number = this._formBase.getParameterValue("Q"); // Débit 
+        let V: number = this._formBase.getParameterValue("V"); // volume V
+        let Pv: number = this._formBase.getParameterValue("Pv"); // puissance dissipée
+        let prms = new PabPuissanceParams(DH, Q, V, Pv);
+        let nub = new PabPuissance(prms); // pour initialiser la calculabilité des paramètres
+        return [nub, prms];
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-compute-regime-uniforme.ts b/src/app/formulaire/definition/form-compute-regime-uniforme.ts
new file mode 100644
index 000000000..2f004b303
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-regime-uniforme.ts
@@ -0,0 +1,17 @@
+import { ComputeNode, ParamsEquation, RegimeUniforme, acSection } from "jalhyd";
+
+import { FormComputeFixedVar } from "./form-compute-fixedvar";
+import { FormulaireDefinition } from "./form-definition";
+import { FormResultFixedVar } from "./form-result-fixedvar";
+import { FormDefSection } from "./form-def-section";
+
+export class FormComputeRegimeUniforme extends FormComputeFixedVar {
+    constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+    }
+
+    protected getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        const snp: [acSection, ParamsEquation] = this._formSection.getSectionNubAndParameters();
+        return [new RegimeUniforme(snp[0]), snp[1]];
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
new file mode 100644
index 000000000..9df9ba2ea
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute-section-parametree.ts
@@ -0,0 +1,164 @@
+import { FormCompute } from "./form-compute";
+import { NgParameter } from "../ngparam";
+import { acSection, ParamsEquation, ComputeNodeType, ComputeNode } from "jalhyd";
+import { FormResult } from "./form-result";
+import { Form } from "@angular/forms";
+import { FormDefSection } from "./form-def-section";
+import { FormResultSection } from "./form-result-section";
+import { InputField } from "../input-field";
+import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
+import { FixedVarResults } from "../../results/fixed-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: FormResult,
+        private intlService: InternationalisationService) {
+        super(formBase, formResult);
+    }
+
+    private get _formSectionResult(): FormResultSection {
+        return this._formResult as FormResultSection;
+    }
+
+    private get _fixVarResults(): FixedVarResults {
+        return this._formSectionResult.fixedVarResults;
+    }
+
+    private get _sectionResults(): SectionResults {
+        return this._formSectionResult.sectionResults;
+    }
+
+    protected getNubAndParameters(): [ComputeNode, ParamsEquation] {
+        return this._formSection.getSectionNubAndParameters();
+    }
+
+    /**
+     * calcul de la section paramétrée dans le cas d'un paramètre à varier
+     * @param varParam paramètre à varier
+     */
+    private doComputeSectionVar(varParam: NgParameter) {
+        let computePrec: number = this._formBase.getParameterValue("Pr"); // précision de calcul
+        let nDigits = -Math.log10(computePrec);
+
+        this._formSectionResult.addSectionFixedResults(false);
+
+        // paramètre à calculer en fonction du paramètre à varier
+        let computedParam = this._formSection.getSectionComputedParam();
+
+        this._fixVarResults.setVariableParamHeaderFromParameter(varParam, false);
+        this._fixVarResults.setVariableResultHeader(computedParam["label"]);
+
+        var np: [ComputeNode, ParamsEquation] = this.getNubAndParameters();
+        let sect: acSection = np[0] as acSection;
+        let prms: ParamsEquation = np[1];
+
+        this._sectionResults.section = sect;
+
+        let min: number = +varParam.minValue;
+        let max: number = +varParam.maxValue;
+        let step: number = +varParam.stepValue;
+
+        let yField: InputField = <InputField>this._formBase.getFormulaireNodeById("Y");
+        let Y: number = yField.getValue();
+
+        let compSymbol = computedParam["symbol"];
+        for (let val = min; val <= max; val += step) {
+            prms[varParam.symbol].v = val;
+
+            sect.Reset(true);
+            let res = sect.Calc(compSymbol, Y);
+            this._fixVarResults.addVarResultElement(val, res.result);
+        }
+
+        this._fixVarResults.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
+    }
+
+    protected compute() {
+        let varParam = this._formSection.getSectionVariatedParameter();
+        if (varParam != undefined) {
+            this.doComputeSectionVar(varParam);
+            return;
+        }
+
+        var np: [ComputeNode, ParamsEquation] = this.getNubAndParameters();
+
+        let sect: acSection = np[0] as acSection;
+        let prms: ParamsEquation = np[1];
+
+        this._sectionResults.section = sect;
+
+        let computePrec: number = this._formBase.getNodeParameterValue(ComputeNodeType.None, "Pr"); // précision de calcul
+        let nDigits = -Math.log10(computePrec);
+
+        let Y = prms.map.Y.v; // tirant d'eau original (doit être fourni à acSection.Calc() sous peine d'être modifié par les appels successifs car c'est en même temps un paramètre et une variable temporaire)
+
+        // charge spécifique
+        let Hs = sect.Calc("Hs", Y);
+        this._formSectionResult.addSectionFixedResult(Hs.result, this.intlService.localizeText("INFO_GRANDEUR_HS"), "Hs");
+
+        // charge critique
+        let Hsc = sect.Calc("Hsc", Y);
+        this._formSectionResult.addSectionFixedResult(Hsc.result, this.intlService.localizeText("INFO_GRANDEUR_HSC"), "Hsc");
+
+        // largeur au miroir
+        let B = sect.Calc("B", Y);
+        this._formSectionResult.addSectionFixedResult(B.result, this.intlService.localizeText("INFO_GRANDEUR_B"));
+
+        // périmètre hydraulique
+        let P = sect.Calc("P", Y);
+        this._formSectionResult.addSectionFixedResult(P.result, this.intlService.localizeText("INFO_GRANDEUR_P"));
+
+        // surface hydraulique
+        let S = sect.Calc("S", Y);
+        this._formSectionResult.addSectionFixedResult(S.result, this.intlService.localizeText("INFO_GRANDEUR_S"));
+
+        // rayon hydraulique
+        let R = sect.Calc("R", Y);
+        this._formSectionResult.addSectionFixedResult(R.result, this.intlService.localizeText("INFO_GRANDEUR_R"));
+
+        // vitesse moyenne
+        let V = sect.Calc("V", Y);
+        this._formSectionResult.addSectionFixedResult(V.result, this.intlService.localizeText("INFO_GRANDEUR_V"));
+
+        // nombre de Froude
+        let Fr = sect.Calc("Fr", Y);
+        this._formSectionResult.addSectionFixedResult(Fr.result, this.intlService.localizeText("INFO_GRANDEUR_FR"), );
+
+        // tirant d'eau critique
+        let Yc = sect.Calc("Yc", Y);
+        this._formSectionResult.addSectionFixedResult(Yc.result, this.intlService.localizeText("INFO_GRANDEUR_YC"), "Yc");
+
+        // tirant d'eau normal
+        let Yn = sect.Calc("Yn", Y);
+        this._formSectionResult.addSectionFixedResult(Yn.result, this.intlService.localizeText("INFO_GRANDEUR_YN"), "Yn");
+
+        // tirant d'eau fluvial
+        let Yf = sect.Calc("Yf", Y);
+        this._formSectionResult.addSectionFixedResult(Yf.result, this.intlService.localizeText("INFO_GRANDEUR_YF"), "Yf");
+
+        // tirant d'eau torrentiel
+        let Yt = sect.Calc("Yt", Y);
+        this._formSectionResult.addSectionFixedResult(Yt.result, this.intlService.localizeText("INFO_GRANDEUR_YT"), "Yt");
+
+        // tirant d'eau conjugué
+        let Yco = sect.Calc("Yco", Y);
+        this._formSectionResult.addSectionFixedResult(Yco.result, this.intlService.localizeText("INFO_GRANDEUR_YCO"), "Yco");
+
+        // perte de charge
+        let J = sect.Calc("J", Y);
+        this._formSectionResult.addSectionFixedResult(J.result, this.intlService.localizeText("INFO_GRANDEUR_J"));
+
+        // Variation linéaire de l'énergie spécifique
+        let IJ = sect.Calc("I-J", Y);
+        this._formSectionResult.addSectionFixedResult(IJ.result, this.intlService.localizeText("INFO_GRANDEUR_I-J"));
+
+        // impulsion hydraulique
+        let Imp = sect.Calc("Imp", Y);
+        this._formSectionResult.addSectionFixedResult(Imp.result, this.intlService.localizeText("INFO_GRANDEUR_IMP"));
+
+        // contrainte de cisaillement
+        let Tau0 = sect.Calc("Tau0", Y);
+        this._formSectionResult.addSectionFixedResult(Tau0.result, this.intlService.localizeText("INFO_GRANDEUR_TAU0"));
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute.ts b/src/app/formulaire/definition/form-compute.ts
new file mode 100644
index 000000000..33b9eb2db
--- /dev/null
+++ b/src/app/formulaire/definition/form-compute.ts
@@ -0,0 +1,33 @@
+import { IObservable, Observable, Observer } from "../../services/observer";
+import { FormResult } from "./form-result";
+import { ParamsEquation, ComputeNode } from "jalhyd";
+import { FormulaireDefinition } from "./form-definition";
+
+export abstract class FormCompute {
+    /**
+     * implémentation par délégation de IObservable
+     */
+    private _observable: Observable;
+
+    constructor(protected _formBase: FormulaireDefinition, protected _formResult: FormResult) {
+        this._observable = new Observable;
+    }
+
+    protected abstract getNubAndParameters(): [ComputeNode, ParamsEquation];
+
+    protected abstract compute();
+
+    protected get formResult(): FormResult {
+        return this._formResult;
+    }
+
+    public doCompute() {
+        this._formResult.resetResults();
+
+        this.compute();
+
+        this._formBase.notifyObservers({
+            "action": "resultsUpdated",
+        });
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-def-fixedvar.ts b/src/app/formulaire/definition/form-def-fixedvar.ts
new file mode 100644
index 000000000..8c27523d4
--- /dev/null
+++ b/src/app/formulaire/definition/form-def-fixedvar.ts
@@ -0,0 +1,96 @@
+import { ParamRadioConfig, NgParameter } from "../ngparam";
+import { FormulaireDefinition } from "./form-definition";
+
+/**
+ * gestion des formulaires avec "paramètre fixé" et "paramètre à varier"
+ */
+export class FormDefFixedVar {
+    protected _formBase: FormulaireDefinition;
+
+    constructor(base: FormulaireDefinition) {
+        this._formBase = base;
+    }
+
+    /**
+     * remet les radios de tous les paramètres à FIX sauf "me" et ceux (celui) à l'état "except"
+     */
+    protected resetOtherRadio(me: NgParameter, except: ParamRadioConfig) {
+        for (const p of this._formBase.allFormElements) {
+            if (p instanceof NgParameter)
+                if (p != me && p.radioState != except && p.radioConfig != ParamRadioConfig.FIX)
+                    p.radioState = ParamRadioConfig.FIX;
+        }
+    }
+
+    protected processRadioStateChange(sourceParam: NgParameter, oldState: ParamRadioConfig, newState: ParamRadioConfig) {
+        switch (oldState) {
+            case ParamRadioConfig.FIX:
+                switch (newState) {
+                    case ParamRadioConfig.VAR:
+                        this.resetOtherRadio(sourceParam, ParamRadioConfig.CAL);
+                        break;
+
+                    case ParamRadioConfig.CAL:
+                        this.resetOtherRadio(sourceParam, ParamRadioConfig.VAR);
+                        break;
+                }
+                break;
+
+            case ParamRadioConfig.VAR:
+                switch (newState) {
+                    case ParamRadioConfig.CAL:
+                        this.resetOtherRadio(sourceParam, ParamRadioConfig.VAR);
+                        break;
+                }
+                break;
+        }
+    }
+
+    /**
+     * modifie les boutons radio "fix", "var", "cal" de tous les paramètres
+     * en fonction de la modification de l'état d'un des paramètres
+     * @param symbol symbole du paramètre source
+     * @param option nouvel état "fix", "var" ou "cal" du paramètre source
+     */
+    protected resetRadiosAndResults(symbol: string, option: string) {
+        let sourceParam: NgParameter = this._formBase.getParamFromSymbol(symbol);
+        let oldState: ParamRadioConfig = sourceParam.radioState;
+        let newState: ParamRadioConfig = ParamRadioConfig[option.toUpperCase()];
+
+        this.processRadioStateChange(sourceParam, oldState, newState);
+
+        sourceParam.radioState = newState;
+
+        // on vérifie qu'il y a au moins un paramètre "à calculer" et sinon, on prend le 1er qui est à "fixé"
+        if (this._formBase.getParamFromState(ParamRadioConfig.CAL) == undefined) {
+            let newCal: NgParameter = undefined;
+
+            for (const p of this._formBase.allFormElements) {
+                if (p instanceof NgParameter)
+                    if (p.radioConfig == ParamRadioConfig.CAL && p.radioState == ParamRadioConfig.FIX && p != sourceParam) {
+                        newCal = p;
+                        break;
+                    }
+                if (newCal != undefined)
+                    break;
+            }
+
+            if (newCal != undefined)
+                newCal.radioState = ParamRadioConfig.CAL;
+        }
+
+        this._formBase.resetResults();
+        this._formBase.applyDependencies();
+    }
+
+    /**
+     * gestion des événements clic sur les radios
+     */
+    public onRadioClick(info: string) {
+        let tmp: string[] = info.split("_");
+        let symbol: string = tmp[0]; // symbole du paramètre dont vient l'événement radio
+        let option: string = tmp[1]; // nouvel état (radio)
+
+        this.resetRadiosAndResults(symbol, option);
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-def-paramcalc.ts b/src/app/formulaire/definition/form-def-paramcalc.ts
new file mode 100644
index 000000000..9cf2f1cc0
--- /dev/null
+++ b/src/app/formulaire/definition/form-def-paramcalc.ts
@@ -0,0 +1,69 @@
+import { ParamRadioConfig, NgParameter } from "../ngparam";
+import { FormulaireDefinition } from "./form-definition";
+import { FormDefFixedVar } from "./form-def-fixedvar";
+
+/** 
+ * gestion des formulaires avec "paramètre à calculer" (conduite distributrice, Lechapt-Calmon, régime uniforme, passes à bassin)
+ */
+export class FormDefParamToCalculate extends FormDefFixedVar {
+    /**
+     * symbole du paramètre à calculer par défaut (cf config "idCal")
+     */
+    private _defaultCalculatedParam: string;
+
+    constructor(base: FormulaireDefinition) {
+        super(base);
+    }
+
+    public initParse() {
+        this._defaultCalculatedParam = undefined;
+    }
+
+    public parseOptions(json: {}) {
+        // id du paramètre à calculer par défaut
+
+        this._defaultCalculatedParam = json["idCal"];
+        if (this._defaultCalculatedParam != undefined) {
+            let p = this._formBase.getParamFromSymbol(this._defaultCalculatedParam);
+            p.isDefault = true;
+            p.radioState = ParamRadioConfig.CAL;
+        }
+    }
+
+    /**
+     * met le paramètre par défaut à CAL
+     */
+    private setDefault() {
+        let defaultParamCal = this._formBase.getParamFromSymbol(this._defaultCalculatedParam);
+        defaultParamCal.radioState = ParamRadioConfig.CAL;
+    }
+
+    protected processRadioStateChange(sourceParam: NgParameter, oldState: ParamRadioConfig, newState: ParamRadioConfig) {
+        super.processRadioStateChange(sourceParam, oldState, newState);
+
+        switch (oldState) {
+            case ParamRadioConfig.CAL:
+                switch (newState) {
+                    case ParamRadioConfig.FIX:
+                        this.setDefault();
+                        break;
+
+                    case ParamRadioConfig.VAR:
+                        super.resetOtherRadio(sourceParam, ParamRadioConfig.CAL);
+                        this.setDefault();
+                        break;
+                }
+        }
+    }
+
+    /**
+     * gestion des événements clic sur les radios
+     */
+    public onRadioClick(info: string) {
+        let tmp: string[] = info.split("_");
+        let symbol: string = tmp[0]; // symbole du paramètre dont vient l'événement radio
+        let option: string = tmp[1]; // nouvel état (radio)
+
+        this.resetRadiosAndResults(symbol, option);
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-def-section.ts b/src/app/formulaire/definition/form-def-section.ts
new file mode 100644
index 000000000..5e23b3755
--- /dev/null
+++ b/src/app/formulaire/definition/form-def-section.ts
@@ -0,0 +1,176 @@
+import {
+    ComputeNodeType, CalculatorType, ParamsSectionTrapez, cSnTrapez, ParamsSectionRectang, cSnRectang,
+    ParamsSectionCirc, cSnCirc, ParamsSectionPuiss, cSnPuiss, acSection, ParamsEquation
+} from "jalhyd";
+
+import { SelectField } from "../select-field";
+import { Field } from "../field";
+import { IObservable, Observer } from "../../services/observer";
+import { NgParameter, ParamRadioConfig } from "../ngparam";
+import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
+import { FormulaireDefinition } from "./form-definition";
+
+export class FormDefSection implements Observer {
+    /**
+     * id du SelectField configurant le type de section
+     */
+    private _sectionSelectFieldId: string;
+
+    /**
+     * Type de noeud de calcul actuel de la section (si la calculette est basée sur une section et qu'un menu permet 
+     * de sélectionner le type de section)
+     */
+    private _sectionNodeType: ComputeNodeType = undefined;
+
+    private _formBase: FormulaireDefinition;
+
+    constructor(base: FormulaireDefinition, private appSetupService: ApplicationSetupService) {
+        this._formBase = base;
+    }
+
+    private get hasSectionNodeTypeSelect(): boolean {
+        return this._sectionSelectFieldId != undefined;
+    }
+
+    private updateSectionNodeType() {
+        this._sectionNodeType = this.getNodeTypeFromSelectField();
+    }
+
+    public get sectionNodeType(): ComputeNodeType {
+        return this._sectionNodeType;
+    }
+
+    public isMySectionType(nodeType: ComputeNodeType, strict: boolean) {
+        let res: boolean = nodeType == this._sectionNodeType;
+        if (strict)
+            return res;
+
+        return res || this._formBase.calculatorType == CalculatorType.SectionParametree
+    }
+
+    public getSectionVariatedParameter(): NgParameter {
+        let res: NgParameter = this._formBase.getParamFromState(ParamRadioConfig.VAR);
+        if (res != undefined && this.isMySectionType(res.computeNodeType, false))
+            return res;
+        return undefined;
+    }
+
+    public getSectionNubAndParameters(getY: boolean = true): [acSection, ParamsEquation] {
+        // bief
+        let Ks = this._formBase.getParameterValue("Ks"); // Strickler
+        let If: number = this._formBase.getParameterValue("If"); // Pente du fond
+        let YB: number = this._formBase.getParameterValue("YB"); // Hauteur de berge
+
+        // caractéristiques hydro
+        let Q: number = this._formBase.getParameterValue("Q"); // débit Q
+        if (getY)
+            var Y: number = this._formBase.getParameterValue("Y"); // tirant d'eau
+        else
+            Y = undefined;
+
+        let Prec = this._formBase.getParameterValue("Pr"); // précision calcul/affichage
+
+        // ??
+        // let YCL: number = f.getParameterValue("YCL"); // Condition limite en cote à l'amont ou à l'aval
+        // let Dx: number = f.getParameterValue("Dx"); // Pas d'espace (positif en partant de l'aval, négatif en partant de l'amont)
+        // let Long: number = f.getParameterValue("Long"); // Longueur du bief
+
+        const nt = this._sectionNodeType;
+        switch (nt) {
+            case ComputeNodeType.SectionTrapeze:
+                {
+                    let LargeurFond = this._formBase.getNodeParameterValue(nt, "LargeurFond"); // Largeur au fond
+                    let Fruit = this._formBase.getNodeParameterValue(nt, "Fruit"); // Fruit des berges
+                    let prms = new ParamsSectionTrapez(LargeurFond, Fruit, Y, Ks, Q, If, Prec, YB);
+                    let cn = new cSnTrapez(prms);
+                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
+                    return [cn, prms];
+                }
+
+            case ComputeNodeType.SectionRectangle:
+                {
+                    let LargeurFond = this._formBase.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au fond
+                    let prms = new ParamsSectionRectang(Y, LargeurFond, Ks, Q, If, Prec, YB);
+                    let cn = new cSnRectang(prms);
+                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
+                    return [cn, prms];
+                }
+
+            case ComputeNodeType.SectionCercle:
+                {
+                    let D = this._formBase.getNodeParameterValue(nt, "D"); // Largeur au fond
+                    let prms = new ParamsSectionCirc(D, Y, Ks, Q, If, Prec, YB);
+                    let cn = new cSnCirc(prms);
+                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
+                    return [cn, prms];
+                }
+
+            case ComputeNodeType.SectionPuissance:
+                {
+                    let k = this._formBase.getNodeParameterValue(nt, "k"); // coefficient
+                    let LargeurBerge = this._formBase.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au niveau des berges
+                    let prms = new ParamsSectionPuiss(k, Y, LargeurBerge, Ks, Q, If, Prec, YB);
+                    let cn = new cSnPuiss(prms);
+                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
+                    return [cn, prms];
+                }
+
+            default:
+                throw new Error(`FormWithSection.getSectionNubAndParameters() : valeur de ComputeNodeType ${nt} non implémentée`);
+        }
+    }
+
+    public getSectionComputedParam(): { symbol: string, label: string } {
+        const symbol = this._formBase.getSelectedValue("select_target");
+        const label = this._formBase.getSelectedLabel("select_target");
+        return { symbol, label };
+    }
+
+    private getNodeTypeFromSelectField(): ComputeNodeType {
+        const sect = this._formBase.getSelectedValue(this._sectionSelectFieldId);
+        switch (sect) {
+            case "trapez":
+                return ComputeNodeType.SectionTrapeze;
+
+            case "rect":
+                return ComputeNodeType.SectionRectangle;
+
+            case "circ":
+                return ComputeNodeType.SectionCercle;
+
+            case "puiss":
+                return ComputeNodeType.SectionPuissance;
+
+            default:
+                throw new Error(`getComputeNodeTypeFromSection() : section ${sect} non pris en charge`);
+        }
+    }
+
+    public initParse() {
+    }
+
+    public parseOptions(json: {}) {
+        // id du SelectField configurant le type de section
+        this._sectionSelectFieldId = this._formBase.getOption(json, "sectionSelectId");
+    }
+
+    public completeParse() {
+        // si le formulaire a un menu pour le type de section, on s'abonne à la valeur du champ correspondant
+        if (this.hasSectionNodeTypeSelect) {
+            const f: Field = this._formBase.getFieldById(this._sectionSelectFieldId);
+            if (f == undefined || !(f instanceof SelectField))
+                throw new Error(`le champ ${this._sectionSelectFieldId} n'est pas du type SelectField`);
+            const sectTypeField: SelectField = f as SelectField;
+            sectTypeField.addObserver(this);
+            this.updateSectionNodeType()
+        }
+    }
+
+    // interface Observer 
+
+    update(sender: IObservable, data: any): void {
+        if (sender instanceof SelectField) {
+            this.updateSectionNodeType();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
new file mode 100644
index 000000000..5be3538e6
--- /dev/null
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -0,0 +1,353 @@
+import { CalculatorType, ComputeNodeType } from "jalhyd";
+import { FormulaireElement } from "../formulaire-element";
+import { NgParameter, ParamRadioConfig } from "../ngparam";
+import { Field } from "../field";
+import { IObservable, Observer, Observable } from "../../services/observer";
+import { StringMap } from "../../stringmap";
+import { FormulaireNode } from "../formulaire-node";
+import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
+import { ParamService } from "../../services/param/param.service";
+import { FieldSet } from "../fieldset";
+import { FieldsetContainer } from "../fieldset-container";
+import { SelectField } from "../select-field";
+import { DeepFieldsetIterator } from "../form-iterator/deep-fieldset-iterator";
+import { DeepFormulaireElementIterator } from "../form-iterator/deep-element-iterator";
+import { TopFormulaireElementIterator } from "../form-iterator/top-element-iterator";
+import { CalculatorResults } from "../../results/calculator-results";
+
+/**
+ * classe de base pour tous les formulaires
+ */
+export abstract class FormulaireDefinition extends FormulaireNode { //implements IFormulaireDefinition {
+    /**
+     * implémentation par délégation de IObservable
+     */
+    private _observable: Observable;
+
+    /**
+     * type de calculette
+     */
+    private _calcType: CalculatorType;
+
+    /**
+     * nom de la calculette
+     */
+    private _calculatorName: string;
+
+    constructor(calcType: CalculatorType,
+        private paramService: ParamService,
+        private appSetupService: ApplicationSetupService
+    ) {
+        super();
+        this._calcType = calcType;
+        this._observable = new Observable();
+    }
+
+    public get calculatorType(): CalculatorType {
+        return this._calcType;
+    }
+
+    public get calculatorName() {
+        return this._calculatorName;
+    }
+
+    public set calculatorName(name: string) {
+        this._calculatorName = name;
+    }
+
+    protected abstract initParse();
+    protected abstract parseOptions(json: {});
+    protected abstract completeParse();
+
+    public getOption(json: {}, option: string): string {
+        if (json["type"] === "options")
+            return json[option];
+
+        return undefined;
+    }
+
+    private parse_fieldset(json: {}): FieldSet {
+        const nt: string = json["nodeType"];
+        let node_type: ComputeNodeType = nt == undefined ? ComputeNodeType.None : ComputeNodeType[nt];
+
+        const res: FieldSet = new FieldSet(node_type, json["type"] === "fieldset_template");
+        res.parseConfig(json,
+            {
+                "paramService": this.paramService,
+                "appSetupService": this.appSetupService,
+                "calcType": this.calculatorType
+            });
+        return res;
+    }
+
+    private parse_template_container(json: {}, templates: { [key: string]: FieldSet }) {
+        const fsc: FieldsetContainer = new FieldsetContainer(this);
+        fsc.parseConfig(json, templates);
+        this.formElements.push(fsc);
+    }
+
+    public parseDependencies(json: {}) {
+        for (let conf_index in json) {
+            const conf = json[conf_index];
+            const type: string = conf["type"];
+
+            switch (type) {
+                // field set
+                case "fieldset":
+                case "template_container":
+                    for (const k of this.kids)
+                        if (k.id == conf["id"]) {
+                            k.parseDependencies(conf, this);
+                            break;
+                        }
+                    break;
+
+                case "fieldset_template":
+                    for (const k of this.kids)
+                        if (k instanceof FieldsetContainer)
+                            k.parseDependencies(conf);
+                    break;
+            }
+        }
+    }
+
+    public parseConfig(json: {}) {
+        this.initParse();
+
+        const templates: { [key: string]: FieldSet } = {};
+
+        for (let conf_index in json) {
+            const conf = json[conf_index];
+            const type: string = conf["type"];
+
+            switch (type) {
+                // field set
+                case "fieldset":
+                case "fieldset_template":
+                    const fs: FieldSet = this.parse_fieldset(conf);
+                    if (fs.isTemplate)
+                        templates[fs.id] = fs;
+                    else
+                        this.kids.push(fs);
+                    break;
+
+                // options globales
+                case "options":
+                    this.parseOptions(conf);
+                    break;
+
+                case "template_container":
+                    this.parse_template_container(conf, templates);
+                    break;
+
+                default:
+                    throw new Error(`type d'objet de calculette ${type} non pris en charge`);
+            }
+        }
+
+        this.completeParse();
+
+        // logObject(this._fieldSets, "fieldsets");
+        // logObject(this._dependencies, "dependences");
+
+        this.parseDependencies(json);
+    }
+
+    public getDisplayedInputParameters(): NgParameter[] {
+        let res = [];
+        for (let fs of this.allFieldsets)
+            if (fs.isDisplayed)
+                for (let p of fs.fields)
+                    if (p instanceof NgParameter && p.isDisplayed)
+                        res.push(p);
+        return res;
+    }
+
+    public hasParameter(symbol: string): boolean {
+        for (const p of this.allFormElements) {
+            if (p instanceof NgParameter)
+                if (p.symbol === symbol)
+                    return true;
+        }
+        return false;
+    }
+
+    public getParamFromSymbol(symbol: string): NgParameter {
+        for (const p of this.allFormElements) {
+            if (p instanceof NgParameter)
+                if (p.symbol === symbol)
+                    return p;
+        }
+        return undefined;
+    }
+
+    public getParamFromState(st: ParamRadioConfig): NgParameter {
+        for (const p of this.allFormElements) {
+            if (p instanceof NgParameter)
+                if (p.radioState == st)
+                    return p;
+        }
+        return undefined;
+    }
+
+    public getFieldById(id: string): Field {
+        let res = this.getFormulaireNodeById(id);
+        if (res instanceof Field)
+            return res;
+        return undefined;
+    }
+
+    public getNodeParameterValue(nodeType: ComputeNodeType, symbol: string): number {
+        for (let fs of this.allFieldsets) {
+            for (let p of fs.fields) {
+                if (p instanceof NgParameter)
+                    // if (p.computeNodeType == nodeType && (p.symbol === symbol || p.alias == symbol)) {
+                    if (p.computeNodeType == nodeType && p.symbol === symbol) {
+                        switch (p.radioState) {
+                            case ParamRadioConfig.FIX:
+                                return p.getValue();
+
+                            case ParamRadioConfig.VAR:
+                            case ParamRadioConfig.CAL:
+                                return undefined;
+                        }
+                    }
+            }
+        }
+
+        if (nodeType != ComputeNodeType.None)
+            return this.getNodeParameterValue(ComputeNodeType.None, symbol);
+
+        throw "Formulaire.getNodeParameterValue() : pas de paramètre " + symbol + " trouvé pour le noeud " + ComputeNodeType[nodeType] + "(" + nodeType + ")";
+    }
+
+    public getParameterValue(symbol: string): number {
+        return this.getNodeParameterValue(ComputeNodeType.None, symbol);
+    }
+
+    private removePrefix(s: string, prefix: string): string {
+        if (s.startsWith(prefix)) {
+            let l = prefix.length;
+            return s.substr(l, s.length - l);
+        }
+        return undefined;
+    }
+
+    /**
+     * retourne la valeur actuellement sélectionnée d'un SelectField
+     * @param selectFieldId id du SelectField
+     * @returns valeur courante du select sans le préfixe
+     */
+    public getSelectedValue(selectFieldId: string): string {
+        let select: SelectField = <SelectField>this.getFieldById(selectFieldId);
+        let value: string = select.getValue().value;
+        return this.removePrefix(value, selectFieldId + "_");
+    }
+
+    /**
+     * retourne le label actuellement sélectionnée d'un SelectField
+     * @param selectFieldId id du SelectField
+     * @returns label courant du select
+     */
+    public getSelectedLabel(selectFieldId: string): string {
+        let select: SelectField = <SelectField>this.getFieldById(selectFieldId);
+        return select.getValue().label;
+    }
+
+    public get formElements(): FormulaireElement[] {
+        return this.kids as FormulaireElement[];
+    }
+
+    public applyDependencies() {
+        for (const fe of this.allFormElements)
+            fe.applyDependencies(this);
+    }
+
+    public abstract resetResults();
+    public abstract doCompute();
+    public abstract get hasResults(): boolean;
+    public abstract get results(): CalculatorResults[];
+
+    public updateLocalisation(localisation: StringMap) {
+        for (let fe of this.topFormElements)
+            fe.updateLocalisation(localisation);
+
+        if (this.hasResults)
+            this.doCompute(); // pour mettre à jour la langue
+    }
+
+    public isDisplayed(id: string) {
+        return (<FormulaireElement>this.getFormulaireNodeById(id)).isDisplayed;
+    }
+
+    public get isValid(): boolean {
+        let res: boolean = true;
+        for (let fs of this.allFieldsets)
+            res = res && fs.isValid;
+        return res;
+    }
+
+    /**
+     * gestion d'un clic sur les radios
+     */
+    public onRadioClick(info: any) {
+    }
+
+    /**
+     * itère sur tous les FieldSet
+     */
+    private get allFieldsets(): IterableIterator<FieldSet> {
+        return new DeepFieldsetIterator(this);
+    }
+
+    /**
+     * itère sur tous les FormulaireElement
+     */
+    public get allFormElements(): IterableIterator<FormulaireElement> {
+        return new DeepFormulaireElementIterator(this);
+    }
+
+    /**
+     * itère sur tous les FormulaireElement de 1er niveau
+    */
+    private get topFormElements(): IterableIterator<FormulaireElement> {
+        return new TopFormulaireElementIterator(this);
+    }
+
+    /**
+     * copie des membres
+     */
+    protected copyMembers(n: FormulaireNode) {
+        throw new Error("FormulaireDefinition.copyMembers() non implémenté");
+    }
+
+    /**
+     * crée une nouvelle instance
+     */
+    protected clone(): FormulaireNode {
+        throw new Error("FormulaireDefinition.clone() non implémenté");
+    }
+
+    // interface IObservable
+
+    /**
+     * ajoute un observateur à la liste
+     */
+    public addObserver(o: Observer) {
+        this._observable.addObserver(o);
+    }
+
+    /**
+     * supprime un observateur de la liste
+     */
+    public removeObserver(o: Observer) {
+        this._observable.removeObserver(o);
+    }
+
+    /**
+     * notifie un événement aux observateurs
+     */
+    public notifyObservers(data: any) {
+        this._observable.notifyObservers(data, this);
+    }
+}
diff --git a/src/app/formulaire/definition/form-result-fixedvar.ts b/src/app/formulaire/definition/form-result-fixedvar.ts
new file mode 100644
index 000000000..a18bc3aa7
--- /dev/null
+++ b/src/app/formulaire/definition/form-result-fixedvar.ts
@@ -0,0 +1,73 @@
+import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
+import { ParamRadioConfig, NgParameter, ParamValueMode } from "../ngparam";
+import { Nub, ParamsEquation, CalculatorType, Result, ResultElement, cLog } from "jalhyd";
+import { FormResult } from "./form-result";
+import { FormulaireDefinition } from "./form-definition";
+import { CalculatorResults } from "../../results/calculator-results";
+
+export class FormResultFixedVar extends FormResult {
+    /**
+     * résultats fixes/variables
+     */
+    private _fixVarResults: FixedVarResults;
+
+    private _formBase: FormulaireDefinition;
+
+    constructor(base: FormulaireDefinition, private displaySymbol: boolean) {
+        super();
+        this._formBase = base;
+        this._fixVarResults = new FixedVarResults();
+    }
+
+    public get fixVarResults() {
+        return this._fixVarResults;
+    }
+
+    public resetResults() {
+        this._fixVarResults.reset();
+    }
+
+    public addFixedResults() {
+        for (const p of this._formBase.getDisplayedInputParameters())
+            if (p.radioState == ParamRadioConfig.FIX && p.symbol !== "Pr")
+                this._fixVarResults.addFixedResultElement(p, p.getValue(), this.displaySymbol);
+    }
+
+    public addFixedResultElement(p: NgParameter, v: ResultElement | number) {
+        this._fixVarResults.addFixedResultElement(p, v, this.displaySymbol);
+    }
+
+    public addVarResultElement(paramVal: number, resVal: ResultElement) {
+        this._fixVarResults.addVarResultElement(paramVal, resVal);
+    }
+
+    public setVariableParamHeaderFromParameter(p: NgParameter) {
+        this.fixVarResults.setVariableParamHeaderFromParameter(p, this.displaySymbol);
+    }
+
+    public setVariableResultHeaderFromParameter(p: NgParameter) {
+        this.fixVarResults.setVariableResultHeaderFromParameter(p);
+    }
+
+    public addLogMessages(l: cLog) {
+        this._fixVarResults.addLogMessages(l);
+    }
+
+    public set graphType(t: GraphType) {
+        this._fixVarResults.graphType = t;
+    }
+
+    public set graphTitle(t: string) {
+        this._fixVarResults.graphTitle = t;
+    }
+
+    public get hasResults(): boolean {
+        return this._fixVarResults.hasResults;
+    }
+
+    public get results(): CalculatorResults[] {
+        const res: CalculatorResults[] = [];
+        res.push(this._fixVarResults)
+        return res;
+    }
+}
diff --git a/src/app/formulaire/definition/form-result-remous.ts b/src/app/formulaire/definition/form-result-remous.ts
new file mode 100644
index 000000000..9709b6deb
--- /dev/null
+++ b/src/app/formulaire/definition/form-result-remous.ts
@@ -0,0 +1,40 @@
+import { acSection, ParamsEquation, Result, MethodeResolution, CourbeRemousParams, CourbeRemous, ResultElement } from "jalhyd";
+
+import { RemousResults } from "../../results/remous-results";
+import { SelectField } from "../select-field";
+import { FormResult } from "./form-result";
+import { FormulaireDefinition } from "./form-definition";
+import { CalculatorResults } from "../../results/calculator-results";
+
+export class FormResultRemous extends FormResult {
+    private _formBase: FormulaireDefinition;
+
+    /**
+     * résultats de courbes de remous
+     */
+    private _remousResults: RemousResults;
+
+    constructor(base: FormulaireDefinition) {
+        super();
+        this._formBase = base;
+        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[] {
+        const res: CalculatorResults[] = [];
+        res.push(this._remousResults)
+        return res;
+    }
+}
\ No newline at end of file
diff --git a/src/app/formulaire/definition/form-result-section.ts b/src/app/formulaire/definition/form-result-section.ts
new file mode 100644
index 000000000..a307c77c9
--- /dev/null
+++ b/src/app/formulaire/definition/form-result-section.ts
@@ -0,0 +1,66 @@
+import { SectionResults } from "../../results/section-results";
+import { ResultElement, ParamsEquation } from "jalhyd";
+import { ParamRadioConfig, NgParameter } from "../ngparam";
+import { FormDefSection } from "./form-def-section";
+import { FixedVarResults } from "../../results/fixed-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;
+
+    private _formSection: FormDefSection;
+
+    /**
+     * résultats fixes/variables
+     */
+    private _fixedVarResults: FixedVarResults;
+
+    /**
+     * résultats de section paramétrée
+     */
+    private _sectionResults: SectionResults;
+
+    constructor(base: FormulaireDefinition, formSection: FormDefSection) {
+        super();
+        this._formBase = base;
+        this._fixedVarResults = new FixedVarResults();
+        this._sectionResults = new SectionResults();
+        this._formSection = formSection;
+    }
+
+    public get fixedVarResults() {
+        return this._fixedVarResults;
+    }
+
+    public get sectionResults() {
+        return this._sectionResults;
+    }
+
+    public resetResults() {
+        this._fixedVarResults.reset();
+        this._sectionResults.reset();
+    }
+
+    public addSectionFixedResult(val: ResultElement, label: string, drawLabel: string = undefined) {
+        this._sectionResults.addResult(val, label, drawLabel);
+    }
+
+    public addSectionFixedResults(displaySymbol: boolean) {
+        for (let p of this._formBase.getDisplayedInputParameters())
+            if (p.radioState == ParamRadioConfig.FIX && this._formSection.isMySectionType(p.computeNodeType, false) && p.symbol !== "Pr")
+                this._fixedVarResults.addFixedResultElement(p, p.getValue(), displaySymbol);
+    }
+
+    public get hasResults(): boolean {
+        return (this._fixedVarResults != undefined && this._fixedVarResults.hasResults) || (this._sectionResults != undefined && this._sectionResults.hasResults);
+    }
+
+    public get results(): CalculatorResults[] {
+        const res: CalculatorResults[] = [];
+        res.push(this._fixedVarResults)
+        res.push(this._sectionResults)
+        return res;
+    }
+}
diff --git a/src/app/formulaire/definition/form-result.ts b/src/app/formulaire/definition/form-result.ts
new file mode 100644
index 000000000..07a3c55a0
--- /dev/null
+++ b/src/app/formulaire/definition/form-result.ts
@@ -0,0 +1,9 @@
+import { CalculatorResults } from "../../results/calculator-results";
+
+export abstract class FormResult {
+    public abstract resetResults();
+
+    public abstract get hasResults(): boolean;
+
+    public abstract get results(): CalculatorResults[];
+}
diff --git a/src/app/formulaire/field.ts b/src/app/formulaire/field.ts
index a10059c65..84961567f 100644
--- a/src/app/formulaire/field.ts
+++ b/src/app/formulaire/field.ts
@@ -1,12 +1,12 @@
 import { ComputeNodeType } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 import { ValueDependency } from "./dependency/value-dependency";
 
 export abstract class Field extends FormulaireElement {
-    constructor(nodeType: ComputeNodeType, parentForm: FormulaireDefinition, isTmpl: boolean = false) {
-        super(nodeType, parentForm, isTmpl);
+    constructor(nodeType: ComputeNodeType, isTmpl: boolean = false) {
+        super(nodeType, isTmpl);
     }
 
     public abstract get isValid();
@@ -14,10 +14,10 @@ export abstract class Field extends FormulaireElement {
     public abstract getValue(): any;
     public abstract setValue(val: any): void;
 
-    private parse_value_dependencies(json: {}) {
+    private parse_value_dependencies(json: {}, parentForm: FormulaireDefinition) {
         for (let di in json) {
             let d = json[di];
-            let masterField: FormulaireElement = this.parentForm.getFormulaireElementById(d["refid"]);
+            let masterField: FormulaireElement = parentForm.getFormulaireNodeById(d["refid"]) as FormulaireElement;
             if (masterField != undefined) {
                 let masterValue = d["refvalue"];
                 let dep = new ValueDependency(masterField, masterValue);
@@ -29,11 +29,11 @@ export abstract class Field extends FormulaireElement {
         }
     }
 
-    public parseDependencies(json: {}) {
-        super.parseDependencies(json);
+    public parseDependencies(json: {}, parentForm: FormulaireDefinition) {
+        super.parseDependencies(json, parentForm);
 
         const dep = json["dep_value"];
         if (dep != undefined)
-            this.parse_value_dependencies(dep);
+            this.parse_value_dependencies(dep, parentForm);
     }
 }
diff --git a/src/app/formulaire/fieldset-container.ts b/src/app/formulaire/fieldset-container.ts
index 778613ba7..8738d8fdb 100644
--- a/src/app/formulaire/fieldset-container.ts
+++ b/src/app/formulaire/fieldset-container.ts
@@ -4,7 +4,7 @@ import { FormulaireElement } from "./formulaire-element";
 import { FieldSet } from "./fieldset";
 import { Dependency } from "./dependency/dependency";
 import { StringMap } from "../stringmap";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 import { FormulaireNode } from "./formulaire-node";
 
 export class FieldsetContainer extends FormulaireElement {
@@ -14,8 +14,8 @@ export class FieldsetContainer extends FormulaireElement {
 
     public title: string
 
-    constructor(parentForm: FormulaireDefinition) {
-        super(ComputeNodeType.None, parentForm);
+    constructor(private parentForm: FormulaireDefinition) {
+        super(ComputeNodeType.None);
         this._templates = [];
     }
 
@@ -68,7 +68,7 @@ export class FieldsetContainer extends FormulaireElement {
         const templ: FieldSet = this.getTemplate(templId);
         const inst = templ.instanciateTemplate();
         this.fieldsets.push(inst);
-        inst.applyDependencies();
+        inst.applyDependencies(this.parentForm);
         this.updateLocalisation()
     }
 
@@ -90,10 +90,10 @@ export class FieldsetContainer extends FormulaireElement {
     }
 
     public parseDependencies(json: {}) {
-        super.parseDependencies(json);
+        super.parseDependencies(json, this.parentForm);
 
         for (const t of this._templates)
-            t.parseDependencies(json);
+            t.parseDependencies(json, this.parentForm);
     }
 
     protected verifyDependency(d: Dependency): boolean {
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 1e8dff614..c2b8be765 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -9,6 +9,7 @@ import { SelectField } from "./select-field";
 import { NgParameter } from "./ngparam";
 import { ParamService } from "../services/param/param.service";
 import { ApplicationSetupService } from "../services/app-setup/app-setup.service";
+import { FormulaireDefinition } from "./definition/form-definition";
 
 export class FieldSet extends FormulaireElement {
     public get fields(): Field[] {
@@ -19,7 +20,7 @@ export class FieldSet extends FormulaireElement {
      * crée une nouvelle instance
      */
     protected clone(): FieldSet {
-        return new FieldSet(this.computeNodeType, this.parentForm);
+        return new FieldSet(this.computeNodeType);
     }
 
     public instanciateTemplate(): FieldSet {
@@ -66,7 +67,7 @@ export class FieldSet extends FormulaireElement {
         const nt: string = json["nodeType"];
         let node_type: ComputeNodeType = nt == undefined ? default_node_type : ComputeNodeType[nt];
 
-        let res: CheckField = new CheckField(node_type, this.parentForm, this.isTemplate);
+        let res: CheckField = new CheckField(node_type, this.isTemplate);
         res.parseConfig(json)
         return res;
     }
@@ -75,7 +76,7 @@ export class FieldSet extends FormulaireElement {
         const nt: string = json["nodeType"];
         let node_type: ComputeNodeType = nt == undefined ? default_node_type : ComputeNodeType[nt];
 
-        let res: SelectField = new SelectField(node_type, this.parentForm, this.isTemplate);
+        let res: SelectField = new SelectField(node_type, this.isTemplate);
         res.parseConfig(json);
         return res;
     }
@@ -84,13 +85,10 @@ export class FieldSet extends FormulaireElement {
         paramService: ParamService, appSetupService: ApplicationSetupService): NgParameter {
         let input_id: string = json["id"];
 
-        const ct: string = json["calcType"];
-        let calc_type: CalculatorType = ct == undefined ? default_calc_type : CalculatorType[ct];
-
         const nt: string = json["nodeType"];
         let node_type: ComputeNodeType = nt == undefined ? default_node_type : ComputeNodeType[nt];
 
-        let res: NgParameter = paramService.createParameter(calc_type, node_type, input_id, this.parentForm, this.isTemplate);
+        let res: NgParameter = paramService.createParameter(default_calc_type, node_type, input_id, this.isTemplate);
         if (res == undefined)
             throw new Error(`pas de paramètre '${input_id}' trouvé dans le noeud ${ComputeNodeType[node_type]} (${node_type}) ou ComputeNodeType.None`);
 
@@ -102,11 +100,12 @@ export class FieldSet extends FormulaireElement {
     public parseConfig(json: {}, data?: {}) {
         const paramService: ParamService = data["paramService"];
         const appSetupService: ApplicationSetupService = data["appSetupService"];
+        const defaultCalcType: CalculatorType = data["calcType"];
 
         this._confId = json["id"];
 
         const ct: string = json["calcType"];
-        let calc_type: CalculatorType = ct == undefined ? this.parentForm.calculatorType : CalculatorType[ct];
+        let calc_type: CalculatorType = ct == undefined ? defaultCalcType : CalculatorType[ct];
 
         const fields = json["fields"];
         for (const field_index in fields) {
@@ -126,8 +125,8 @@ export class FieldSet extends FormulaireElement {
         }
     }
 
-    public parseDependencies(json: {}) {
-        super.parseDependencies(json);
+    public parseDependencies(json: {}, parentForm: FormulaireDefinition) {
+        super.parseDependencies(json, parentForm);
 
         for (const k1 in json) {
             if (k1 === "fields") {
@@ -140,7 +139,7 @@ export class FieldSet extends FormulaireElement {
                         case "check":
                             for (const k of this.kids)
                                 if (k.id == field["id"]) {
-                                    k.parseDependencies(field);
+                                    k.parseDependencies(field, parentForm);
                                     break;
                                 }
                             break;
diff --git a/src/app/formulaire/formulaire-definition.ts b/src/app/formulaire/formulaire-definition.ts
deleted file mode 100644
index befa48d58..000000000
--- a/src/app/formulaire/formulaire-definition.ts
+++ /dev/null
@@ -1,1038 +0,0 @@
-import { CalculatorType, ComputeNodeType, ParamsEquation, Nub, acSection, RegimeUniforme, MethodeResolution } from "jalhyd";
-import { CourbeRemous, CourbeRemousParams, ParamDomainValue, Result, ResultElement } from "jalhyd";
-import { ParamsSectionRectang, cSnRectang, ParamsSectionCirc, cSnCirc, ParamsSectionPuiss, cSnPuiss } from "jalhyd";
-import { ConduiteDistrib, ConduiteDistribParams, LechaptCalmon, LechaptCalmonParams, ParamsSectionTrapez, cSnTrapez } from "jalhyd";
-import { PabDimension, PabDimensionParams, PabPuissance, PabPuissanceParams } from "jalhyd";
-
-import { ParamService } from "../services/param/param.service";
-import { InternationalisationService } from "../services/internationalisation/internationalisation.service";
-import { ApplicationSetupService } from "../services/app-setup/app-setup.service";
-import { Field } from "./field";
-import { NgParameter, ParamRadioConfig, ParamValueMode } from "./ngparam";
-import { InputField } from "./input-field";
-import { SelectField } from "./select-field";
-import { FieldSet } from "./fieldset";
-import { FieldsetContainer } from "./fieldset-container";
-import { FormulaireElement } from "./formulaire-element";
-import { FixedVarResults, GraphType } from "../results/fixed-var-results";
-import { SectionResults } from "../results/section-results";
-import { RemousResults } from "../results/remous-results";
-import { StringMap } from "../stringmap";
-import { Observable, Observer, IObservable } from "../services/observer";
-import { TopFormulaireElementIterator } from "./form-iterator/top-element-iterator";
-import { DeepFieldsetIterator } from "./form-iterator/deep-fieldset-iterator";
-import { DeepFormulaireElementIterator } from "./form-iterator/deep-element-iterator";
-import { FormulaireNode } from "./formulaire-node";
-
-export class FormulaireDefinition extends FormulaireNode implements IObservable, Observer {
-    /**
-     * implémentation par délégation de IObservable
-     */
-    private _observable: Observable;
-
-    /**
-     * symbole du paramètre à calculer par défaut (cf config "idCal")
-     */
-    private _defaultCalculatedParam: string;
-
-    /**
-     * id du SelectField configurant le type de section
-     */
-    private _sectionSelectFieldId: string;
-
-    /**
-     * Type de noeud de calcul actuel de la section (si la calculette est basée sur une section et qu'un menu permet 
-     * de sélectionner le type de section)
-     */
-    private _sectionNodeType: ComputeNodeType = undefined;
-
-    /**
-     * résultats fixes/variables
-     */
-    private _fixVarResults: FixedVarResults;
-
-    /**
-     * résultats de section paramétrée
-     */
-    private _sectionResults: SectionResults;
-
-    /**
-     * résultats de courbes de remous
-     */
-    private _remousResults: RemousResults;
-
-    /**
-     * nom de de la calculette
-     */
-    private _calculatorName: string;
-
-    constructor(
-        private _calcType: CalculatorType,
-        private paramService: ParamService,
-        private intlService: InternationalisationService,
-        private appSetupService: ApplicationSetupService
-    ) {
-        super();
-        this._observable = new Observable;
-        this._fixVarResults = new FixedVarResults();
-        this._sectionResults = new SectionResults();
-        this._remousResults = new RemousResults();
-    }
-
-    public get calculatorType(): CalculatorType {
-        return this._calcType;
-    }
-
-    public get fixVarResults() {
-        return this._fixVarResults;
-    }
-
-    public get sectionResults() {
-        return this._sectionResults;
-    }
-
-    public get remousResults() {
-        return this._remousResults;
-    }
-
-    public get formElements(): FormulaireElement[] {
-        return this.kids as FormulaireElement[];
-    }
-
-    private getFieldSet(id: string): FieldSet {
-        for (let fs of this.allFieldsets) {
-            if (fs.id == id)
-                return fs;
-        }
-        return undefined;
-    }
-
-    private hasParameter(symbol: string): boolean {
-        for (const p of this.allFormElements) {
-            if (p instanceof NgParameter)
-                if (p.symbol === symbol)
-                    return true;
-        }
-        return false;
-    }
-
-    public getParamFromSymbol(symbol: string): NgParameter {
-        for (const p of this.allFormElements) {
-            if (p instanceof NgParameter)
-                if (p.symbol === symbol)
-                    return p;
-        }
-        return undefined;
-    }
-
-    public getParamFromState(st: ParamRadioConfig): NgParameter {
-        for (const p of this.allFormElements) {
-            if (p instanceof NgParameter)
-                if (p.radioState == st)
-                    return p;
-        }
-        return undefined;
-    }
-
-    private removePrefix(s: string, prefix: string): string {
-        if (s.startsWith(prefix)) {
-            let l = prefix.length;
-            return s.substr(l, s.length - l);
-        }
-        return undefined;
-    }
-
-    private get hasSectionNodeTypeSelect(): boolean {
-        return this._sectionSelectFieldId != undefined;
-    }
-
-    private updateSectionNodeType() {
-        this._sectionNodeType = this.getNodeTypeFromSelectField();
-    }
-
-    private getNodeTypeFromSelectField(): ComputeNodeType {
-        if (this.hasSectionNodeTypeSelect) {
-            let ssf: SelectField = <SelectField>this.getFormulaireElementById(this._sectionSelectFieldId);
-            return this.getNodeTypeFromSelectValue(ssf.getValue().value);
-        }
-
-        return undefined;
-    }
-
-    private getNodeTypeFromSelectValue(select_val: string): ComputeNodeType {
-        let sect: string = this.removePrefix(select_val, this._sectionSelectFieldId + "_");
-        switch (sect) {
-            case "trapez":
-                return ComputeNodeType.SectionTrapeze;
-
-            case "rect":
-                return ComputeNodeType.SectionRectangle;
-
-            case "circ":
-                return ComputeNodeType.SectionCercle;
-
-            case "puiss":
-                return ComputeNodeType.SectionPuissance;
-
-            default:
-                throw new Error(`getComputeNodeTypeFromSection() : section ${sect} non pris en charge`);
-        }
-    }
-
-    /**
-     * remet les radios de tous les paramètres à FIX sauf "me" et ceux (celui) à l'état "except"
-     */
-    private resetOtherRadio(me: NgParameter, except: ParamRadioConfig) {
-        for (const p of this.allFormElements) {
-            if (p instanceof NgParameter)
-                if (p != me && p.radioState != except && p.radioConfig != ParamRadioConfig.FIX)
-                    p.radioState = ParamRadioConfig.FIX;
-        }
-    }
-
-    /**
-     * modifie les boutons radio "fix", "var", "cal" de tous les paramètres
-     * en fonction de la modification de l'état d'un des paramètres
-     * @param symbol symbole du paramètre source
-     * @param option nouvel état "fix", "var" ou "cal" du paramètre source
-     */
-    public resetRadiosAndResults(symbol: string, option: string) {
-        let sourceParam = this.getParamFromSymbol(symbol);
-        let oldState: ParamRadioConfig = sourceParam.radioState;
-        let newState: ParamRadioConfig = ParamRadioConfig[option.toUpperCase()];
-
-        switch (oldState) {
-            case ParamRadioConfig.FIX:
-                switch (newState) {
-                    case ParamRadioConfig.VAR:
-                        this.resetOtherRadio(sourceParam, ParamRadioConfig.CAL);
-                        break;
-
-                    case ParamRadioConfig.CAL:
-                        this.resetOtherRadio(sourceParam, ParamRadioConfig.VAR);
-                        break;
-                }
-                break;
-
-            case ParamRadioConfig.VAR:
-                switch (newState) {
-                    case ParamRadioConfig.CAL:
-                        this.resetOtherRadio(sourceParam, ParamRadioConfig.VAR);
-                        break;
-                }
-                break;
-
-            case ParamRadioConfig.CAL:
-                switch (newState) {
-                    case ParamRadioConfig.FIX:
-                        this.setDefault();
-                        break;
-
-                    case ParamRadioConfig.VAR:
-                        this.resetOtherRadio(sourceParam, ParamRadioConfig.CAL);
-                        this.setDefault();
-                        break;
-                }
-        }
-
-        sourceParam.radioState = newState;
-
-        // on vérifie qu'il y a au moins un paramètre "à calculer" et sinon, on prend le 1er qui est à "fixé"
-        if (this.getParamFromState(ParamRadioConfig.CAL) == undefined) {
-            let newCal: NgParameter = undefined;
-
-            for (const p of this.allFormElements) {
-                if (p instanceof NgParameter)
-                    if (p.radioConfig == ParamRadioConfig.CAL && p.radioState == ParamRadioConfig.FIX && p != sourceParam) {
-                        newCal = p;
-                        break;
-                    }
-                if (newCal != undefined)
-                    break;
-            }
-
-            if (newCal != undefined)
-                newCal.radioState = ParamRadioConfig.CAL;
-        }
-
-        this.resetResults();
-        this.applyDependencies();
-    }
-
-
-    public applyDependencies() {
-        for (const fe of this.allFormElements)
-            fe.applyDependencies();
-    }
-
-    public resetResults() {
-        this._fixVarResults.reset();
-        this._sectionResults.reset();
-        this._remousResults.reset();
-    }
-
-    /**
-     * met le paramètre par défaut à CAL
-     */
-    private setDefault() {
-        let defaultParamCal = this.getParamFromSymbol(this._defaultCalculatedParam);
-        defaultParamCal.radioState = ParamRadioConfig.CAL;
-    }
-
-    private getDisplayedInputParameters(): NgParameter[] {
-        let res = [];
-        for (let fs of this.allFieldsets)
-            if (fs.isDisplayed)
-                for (let p of fs.fields)
-                    if (p instanceof NgParameter && p.isDisplayed)
-                        res.push(p);
-        return res;
-    }
-
-    private getNodeParameterValue(nodeType: ComputeNodeType, symbol: string): number {
-        for (let fs of this.allFieldsets) {
-            for (let p of fs.fields) {
-                if (p instanceof NgParameter)
-                    // if (p.computeNodeType == nodeType && (p.symbol === symbol || p.alias == symbol)) {
-                    if (p.computeNodeType == nodeType && p.symbol === symbol) {
-                        switch (p.radioState) {
-                            case ParamRadioConfig.FIX:
-                                return p.getValue();
-
-                            case ParamRadioConfig.VAR:
-                            case ParamRadioConfig.CAL:
-                                return undefined;
-                        }
-                    }
-            }
-        }
-
-        if (nodeType != ComputeNodeType.None)
-            return this.getNodeParameterValue(ComputeNodeType.None, symbol);
-
-        throw "Formulaire.getNodeParameterValue() : pas de paramètre " + symbol + " trouvé pour le noeud " + ComputeNodeType[nodeType] + "(" + nodeType + ")";
-    }
-
-    private getParameterValue(symbol: string): number {
-        return this.getNodeParameterValue(ComputeNodeType.None, symbol);
-    }
-
-    private getSectionComputedParam(): { symbol: string, label: string } {
-        let targetSelect: SelectField = <SelectField>this.getFieldById("select_target");
-        let targetValue: string = targetSelect.getValue().value;
-
-        let symbol: string = this.removePrefix(targetValue, "select_target_");
-
-        let label = targetSelect.getLabel();
-        return { symbol, label };
-    }
-
-    public getFormulaireElementById(id: string): FormulaireElement {
-        const res = this.getFormulaireNodeById(id);
-        if (res instanceof FormulaireElement)
-            return res;
-        return undefined;
-    }
-
-    public getFieldById(id: string): Field {
-        let res = this.getFormulaireElementById(id);
-        if (res instanceof Field)
-            return res;
-        return undefined;
-    }
-
-    private parse_fieldset(json: {}): FieldSet {
-        const nt: string = json["nodeType"];
-        let node_type: ComputeNodeType = nt == undefined ? ComputeNodeType.None : ComputeNodeType[nt];
-
-        const res: FieldSet = new FieldSet(node_type, this, json["type"] === "fieldset_template");
-        res.parseConfig(json, { "paramService": this.paramService, "appSetupService": this.appSetupService });
-        return res;
-    }
-
-    private parse_template_container(json: {}, templates: { [key: string]: FieldSet }) {
-        const fsc: FieldsetContainer = new FieldsetContainer(this);
-        fsc.parseConfig(json, templates);
-        this.formElements.push(fsc);
-    }
-
-    private getOption(json: {}, option: string): string {
-        for (let conf_index in json) {
-            let conf = json[conf_index];
-            if (conf["type"] === "options")
-                return conf[option];
-        }
-
-        return undefined;
-    }
-
-    public parseConfig(json: {}) {
-        this._defaultCalculatedParam = undefined;
-        const templates: { [key: string]: FieldSet } = {};
-
-        for (let conf_index in json) {
-            const conf = json[conf_index];
-            const type: string = conf["type"];
-
-            switch (type) {
-                // field set
-                case "fieldset":
-                case "fieldset_template":
-                    const fs: FieldSet = this.parse_fieldset(conf);
-                    if (fs.isTemplate)
-                        templates[fs.id] = fs;
-                    else
-                        this.kids.push(fs);
-                    break;
-
-                // options globales
-                case "options":
-                    // id du paramètre à calculer par défaut
-
-                    this._defaultCalculatedParam = conf["idCal"];
-                    if (this._defaultCalculatedParam != undefined) {
-                        let p = this.getParamFromSymbol(this._defaultCalculatedParam);
-                        p.isDefault = true;
-                        p.radioState = ParamRadioConfig.CAL;
-                    }
-
-                    // id du SelectField configurant le type de section
-                    this._sectionSelectFieldId = this.getOption(json, "sectionSelectId");
-                    break;
-
-                case "template_container":
-                    this.parse_template_container(conf, templates);
-                    break;
-
-                default:
-                    throw new Error(`type d'objet de calculette ${type} non pris en charge`);
-            }
-        }
-
-        // si le formulaire a un menu pour le type de section, on s'abonne à la valeur du champ correspondant
-        if (this.hasSectionNodeTypeSelect) {
-            const f: Field = this.getFieldById(this._sectionSelectFieldId);
-            if (f == undefined || !(f instanceof SelectField))
-                throw new Error(`le champ ${this._sectionSelectFieldId} n'est pas du type SelectField`);
-            const sectTypeField: SelectField = f as SelectField;
-            sectTypeField.addObserver(this);
-            this.updateSectionNodeType()
-        }
-
-        // logObject(this._fieldSets, "fieldsets");
-        // logObject(this._dependencies, "dependences");
-
-        this.parseDependencies(json);
-    }
-
-    public parseDependencies(json: {}) {
-        for (let conf_index in json) {
-            const conf = json[conf_index];
-            const type: string = conf["type"];
-
-            switch (type) {
-                // field set
-                case "fieldset":
-                case "template_container":
-                    for (const k of this.kids)
-                        if (k.id == conf["id"]) {
-                            k.parseDependencies(conf);
-                            break;
-                        }
-                    break;
-
-                case "fieldset_template":
-                    for (const k of this.kids)
-                        if (k instanceof FieldsetContainer)
-                            k.parseDependencies(conf);
-                    break;
-            }
-        }
-    }
-
-    private isMySectionType(nodeType: ComputeNodeType, strict: boolean) {
-        let res: boolean = nodeType == this._sectionNodeType;
-        if (strict)
-            return res;
-
-        return res || this._calcType == CalculatorType.SectionParametree
-    }
-
-    private addFixedResults(displaySymbol: boolean) {
-        for (const p of this.getDisplayedInputParameters())
-            if (p.radioState == ParamRadioConfig.FIX && p.symbol !== "Pr")
-                this._fixVarResults.addFixedResultElement(p, p.getValue(), displaySymbol);
-    }
-
-    private addSectionFixedResult(val: ResultElement, label: string, drawLabel: string = undefined) {
-        this._sectionResults.addResult(val, label, drawLabel);
-    }
-
-    private addSectionFixedResults(displaySymbol: boolean) {
-        for (let p of this.getDisplayedInputParameters())
-            if (p.radioState == ParamRadioConfig.FIX && this.isMySectionType(p.computeNodeType, false) && p.symbol !== "Pr")
-                this._fixVarResults.addFixedResultElement(p, p.getValue(), displaySymbol);
-    }
-
-    private getSectionVariatedParameter(): NgParameter {
-        let res: NgParameter = this.getParamFromState(ParamRadioConfig.VAR);
-        if (res != undefined && this.isMySectionType(res.computeNodeType, false))
-            return res;
-        return undefined;
-    }
-
-    private doComputeSectionVar(varParam: NgParameter) {
-        let computePrec: number = this.getParameterValue("Pr"); // précision de calcul
-        let nDigits = -Math.log10(computePrec);
-
-        this.addSectionFixedResults(false);
-
-        let computedParam = this.getSectionComputedParam();
-
-        this._fixVarResults.setVariableParamHeaderFromParameter(varParam, false);
-        this._fixVarResults.setVariableResultHeader(computedParam["label"]);
-
-        var np: [acSection, ParamsEquation] = this.getSectionNubAndParameters(this._sectionNodeType);
-        let sect: acSection = np[0];
-        let prms: ParamsEquation = np[1];
-
-        this._sectionResults.section = sect;
-
-        let min: number = +varParam.minValue;
-        let max: number = +varParam.maxValue;
-        let step: number = +varParam.stepValue;
-
-        let yField: InputField = <InputField>this.getFormulaireElementById("Y");
-        let Y: number = yField.getValue();
-
-        let compSymbol = computedParam["symbol"];
-        for (let val = min; val <= max; val += step) {
-            prms[varParam.symbol].v = val;
-
-            sect.Reset(true);
-            let res = sect.Calc(compSymbol, Y);
-            this._fixVarResults.addVarResultElement(val, res.result);
-        }
-
-        this._fixVarResults.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
-    }
-
-    private doComputeSection() {
-        let varParam = this.getSectionVariatedParameter();
-        if (varParam != undefined) {
-            this.doComputeSectionVar(varParam);
-            return;
-        }
-
-        var np: [acSection, ParamsEquation] = this.getSectionNubAndParameters(this._sectionNodeType);
-
-        let sect: acSection = np[0];
-        let prms: ParamsEquation = np[1];
-
-        this._sectionResults.section = sect;
-
-        let computePrec: number = this.getNodeParameterValue(ComputeNodeType.None, "Pr"); // précision de calcul
-        let nDigits = -Math.log10(computePrec);
-
-        let Y = prms.map.Y.v; // tirant d'eau original (doit être fourni à acSection.Calc() sous peine d'être modifié par les appels successifs car c'est en même temps un paramètre et une variable temporaire)
-
-        // charge spécifique
-        let Hs = sect.Calc("Hs", Y);
-        this.addSectionFixedResult(Hs.result, this.intlService.localizeText("INFO_GRANDEUR_HS"), "Hs");
-
-        // charge critique
-        let Hsc = sect.Calc("Hsc", Y);
-        this.addSectionFixedResult(Hsc.result, this.intlService.localizeText("INFO_GRANDEUR_HSC"), "Hsc");
-
-        // largeur au miroir
-        let B = sect.Calc("B", Y);
-        this.addSectionFixedResult(B.result, this.intlService.localizeText("INFO_GRANDEUR_B"));
-
-        // périmètre hydraulique
-        let P = sect.Calc("P", Y);
-        this.addSectionFixedResult(P.result, this.intlService.localizeText("INFO_GRANDEUR_P"));
-
-        // surface hydraulique
-        let S = sect.Calc("S", Y);
-        this.addSectionFixedResult(S.result, this.intlService.localizeText("INFO_GRANDEUR_S"));
-
-        // rayon hydraulique
-        let R = sect.Calc("R", Y);
-        this.addSectionFixedResult(R.result, this.intlService.localizeText("INFO_GRANDEUR_R"));
-
-        // vitesse moyenne
-        let V = sect.Calc("V", Y);
-        this.addSectionFixedResult(V.result, this.intlService.localizeText("INFO_GRANDEUR_V"));
-
-        // nombre de Froude
-        let Fr = sect.Calc("Fr", Y);
-        this.addSectionFixedResult(Fr.result, this.intlService.localizeText("INFO_GRANDEUR_FR"), );
-
-        // tirant d'eau critique
-        let Yc = sect.Calc("Yc", Y);
-        this.addSectionFixedResult(Yc.result, this.intlService.localizeText("INFO_GRANDEUR_YC"), "Yc");
-
-        // tirant d'eau normal
-        let Yn = sect.Calc("Yn", Y);
-        this.addSectionFixedResult(Yn.result, this.intlService.localizeText("INFO_GRANDEUR_YN"), "Yn");
-
-        // tirant d'eau fluvial
-        let Yf = sect.Calc("Yf", Y);
-        this.addSectionFixedResult(Yf.result, this.intlService.localizeText("INFO_GRANDEUR_YF"), "Yf");
-
-        // tirant d'eau torrentiel
-        let Yt = sect.Calc("Yt", Y);
-        this.addSectionFixedResult(Yt.result, this.intlService.localizeText("INFO_GRANDEUR_YT"), "Yt");
-
-        // tirant d'eau conjugué
-        let Yco = sect.Calc("Yco", Y);
-        this.addSectionFixedResult(Yco.result, this.intlService.localizeText("INFO_GRANDEUR_YCO"), "Yco");
-
-        // perte de charge
-        let J = sect.Calc("J", Y);
-        this.addSectionFixedResult(J.result, this.intlService.localizeText("INFO_GRANDEUR_J"));
-
-        // Variation linéaire de l'énergie spécifique
-        let IJ = sect.Calc("I-J", Y);
-        this.addSectionFixedResult(IJ.result, this.intlService.localizeText("INFO_GRANDEUR_I-J"));
-
-        // impulsion hydraulique
-        let Imp = sect.Calc("Imp", Y);
-        this.addSectionFixedResult(Imp.result, this.intlService.localizeText("INFO_GRANDEUR_IMP"));
-
-        // contrainte de cisaillement
-        let Tau0 = sect.Calc("Tau0", Y);
-        this.addSectionFixedResult(Tau0.result, this.intlService.localizeText("INFO_GRANDEUR_TAU0"));
-    }
-
-    private doComputeRemous() {
-        var np: [acSection, ParamsEquation] = this.getSectionNubAndParameters(this._sectionNodeType, false);
-
-        let sect: acSection = np[0];
-        let prmSect: ParamsEquation = np[1];
-
-        let Yamont: number = this.getNodeParameterValue(this._sectionNodeType, "Yamont"); // tirant amont
-        let Yaval: number = this.getNodeParameterValue(this._sectionNodeType, "Yaval"); // tirant aval
-        let Dx: number = this.getNodeParameterValue(this._sectionNodeType, "Dx"); // pas de discrétisation
-        let Long: number = this.getNodeParameterValue(this._sectionNodeType, "Long"); // longueur du bief
-        let If: number = this.getNodeParameterValue(this._sectionNodeType, "If"); // pente du fond
-        let YB: number = this.getNodeParameterValue(this._sectionNodeType, "YB"); // hauteur de berge
-        let Yn: Result = sect.Calc("Yn"); // hauteur normale
-        let Yc: Result = sect.Calc("Yc"); // hauteur critique
-
-        this._remousResults.penteFond = If;
-
-        // méthode de résolution
-
-        let msf: SelectField = <SelectField>this.getFormulaireElementById("select_resolution");
-        let smeth: string = msf.getValue().value;
-        let methRes: MethodeResolution;
-        if (smeth == "select_resolution_trap")
-            methRes = MethodeResolution.Trapezes;
-        else if (smeth == "select_resolution_rk4")
-            methRes = MethodeResolution.RungeKutta4;
-        else if (smeth == "select_resolution_euler")
-            methRes = MethodeResolution.EulerExplicite;
-        else
-            throw "GenericCalculatorComponent.doComputeRemous() : type de méthode de résolution '" + smeth + "' inconnu";
-
-        // paramètre supplémentaire à calculer
-
-        let dsf: SelectField = <SelectField>this.getFormulaireElementById("select_target");
-        let extraSymbol: string = this.removePrefix(dsf.getValue().value, "select_target_");
-
-        // calcul
-
-        let prmCR: CourbeRemousParams = new CourbeRemousParams(sect, Yamont, Yaval, Long, Dx, methRes);
-        let cr = new CourbeRemous(prmCR);
-        let res: Result = cr.calculRemous(extraSymbol == "none" ? undefined : extraSymbol);
-
-        // affichage du graphe
-
-        this._remousResults.hauteurBerge = new ResultElement(YB);
-        this._remousResults.hauteurNormale = Yn.result;
-        this._remousResults.hauteurCritique = Yc.result;
-        if (extraSymbol != "none") {
-            this._remousResults.extraParamLabel = dsf.getValue().label;
-            this._remousResults.extraGraph = ["Hs", "Hsc", "Yf", "Yt", "Yco"].indexOf(extraSymbol) == -1;
-        }
-        else
-            this._remousResults.extraGraph = false;
-
-        // résultats numériques
-
-        this._remousResults.addResult(res);
-    }
-
-    private getVariatedParameter(): NgParameter {
-        return this.getParamFromState(ParamRadioConfig.VAR);
-    }
-
-    private getComputedParameter(): NgParameter {
-        return this.getParamFromState(ParamRadioConfig.CAL);
-    }
-
-    private getNubAndParameters(): [Nub, ParamsEquation] {
-        switch (this.calculatorType) {
-            case CalculatorType.ConduiteDistributrice:
-                {
-                    let Q: number = this.getParameterValue("Q"); // débit Q
-                    let D: number = this.getParameterValue("D"); // diamètre D
-                    let J: number = this.getParameterValue("J"); // perte de charge J
-                    let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-                    let Nu: number = this.getParameterValue("Nu"); // viscosité dynamique 
-                    let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
-                    let nub = new ConduiteDistrib(prms);
-                    return [nub, prms];
-                }
-
-            case CalculatorType.LechaptCalmon:
-                {
-                    let Q: number = this.getParameterValue("Q"); // débit Q
-                    let D: number = this.getParameterValue("D"); // diamètre D
-                    let J: number = this.getParameterValue("J"); // perte de charge J
-                    let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-                    let L: number = this.getParameterValue("L"); // paramètre de matériau 1
-                    let M: number = this.getParameterValue("M"); // paramètre de matériau 2
-                    let N: number = this.getParameterValue("N"); // paramètre de matériau 3
-                    let prms = new LechaptCalmonParams(Q, D, J, Lg, L, M, N);
-                    let nub = new LechaptCalmon(prms);
-                    return [nub, prms];
-                }
-
-            case CalculatorType.PabDimensions:
-                {
-                    let L: number = this.getParameterValue("L"); // longueur L
-                    let W: number = this.getParameterValue("W"); // largeur W
-                    let Y: number = this.getParameterValue("Y"); // tirant d'eau Y
-                    let V: number = this.getParameterValue("V"); // volume V
-                    let prms = new PabDimensionParams(L, W, Y, V);
-                    let nub = new PabDimension(prms); // pour initialiser la calculabilité des paramètres
-                    return [nub, prms];
-                }
-
-            case CalculatorType.PabPuissance:
-                {
-                    let DH: number = this.getParameterValue("DH");  // Chute entre bassins
-                    let Q: number = this.getParameterValue("Q"); // Débit 
-                    let V: number = this.getParameterValue("V"); // volume V
-                    let Pv: number = this.getParameterValue("Pv"); // puissance dissipée
-                    let prms = new PabPuissanceParams(DH, Q, V, Pv);
-                    let nub = new PabPuissance(prms); // pour initialiser la calculabilité des paramètres
-                    return [nub, prms];
-                }
-
-            default:
-                throw "FormulaireDefinition.getNubAndParameters() : valeur de CalculatorType " + this.calculatorType + " non implémentée"
-        }
-    }
-
-    private getSectionNubAndParameters(nt: ComputeNodeType, getY: boolean = true): [acSection, ParamsEquation] {
-        // bief
-        let Ks = this.getParameterValue("Ks"); // Strickler
-        let If: number = this.getParameterValue("If"); // Pente du fond
-        let YB: number = this.getParameterValue("YB"); // Hauteur de berge
-
-        // caractéristiques hydro
-        let Q: number = this.getParameterValue("Q"); // débit Q
-        if (getY)
-            var Y: number = this.getParameterValue("Y"); // tirant d'eau
-        else
-            Y = undefined;
-
-        let Prec = this.getParameterValue("Pr"); // précision calcul/affichage
-
-        // ??
-        // let YCL: number = f.getParameterValue("YCL"); // Condition limite en cote à l'amont ou à l'aval
-        // let Dx: number = f.getParameterValue("Dx"); // Pas d'espace (positif en partant de l'aval, négatif en partant de l'amont)
-        // let Long: number = f.getParameterValue("Long"); // Longueur du bief
-
-        switch (nt) {
-            case ComputeNodeType.SectionTrapeze:
-                {
-                    let LargeurFond = this.getNodeParameterValue(nt, "LargeurFond"); // Largeur au fond
-                    let Fruit = this.getNodeParameterValue(nt, "Fruit"); // Fruit des berges
-                    let prms = new ParamsSectionTrapez(LargeurFond, Fruit, Y, Ks, Q, If, Prec, YB);
-                    let cn = new cSnTrapez(prms);
-                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
-                    return [cn, prms];
-                }
-
-            case ComputeNodeType.SectionRectangle:
-                {
-                    let LargeurFond = this.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au fond
-                    let prms = new ParamsSectionRectang(Y, LargeurFond, Ks, Q, If, Prec, YB);
-                    let cn = new cSnRectang(prms);
-                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
-                    return [cn, prms];
-                }
-
-            case ComputeNodeType.SectionCercle:
-                {
-                    let D = this.getNodeParameterValue(nt, "D"); // Largeur au fond
-                    let prms = new ParamsSectionCirc(D, Y, Ks, Q, If, Prec, YB);
-                    let cn = new cSnCirc(prms);
-                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
-                    return [cn, prms];
-                }
-
-            case ComputeNodeType.SectionPuissance:
-                {
-                    let k = this.getNodeParameterValue(nt, "k"); // coefficient
-                    let LargeurBerge = this.getNodeParameterValue(nt, "LargeurBerge"); // Largeur au niveau des berges
-                    let prms = new ParamsSectionPuiss(k, Y, LargeurBerge, Ks, Q, If, Prec, YB);
-                    let cn = new cSnPuiss(prms);
-                    cn.newtonMaxIter = this.appSetupService.newtonMaxIter;
-                    return [cn, prms];
-                }
-
-            default:
-                throw "FormulaireDefinition.getSectionNubAndParameters() : valeur de ComputeNodeType " + nt + " non implémentée"
-        }
-    }
-
-    /**
-     * lance le calcul d'un paramètre en déterminant une valeur initiale
-     */
-    private runNubCalc(nub: Nub, p: NgParameter, prec: number): Result {
-        let init: number;
-        switch (p.domain.domain) {
-            case ParamDomainValue.ANY:
-            case ParamDomainValue.POS_NULL:
-                init = 0;
-                break;
-
-            case ParamDomainValue.INTERVAL:
-                init = p.domain.minValue;
-                break;
-
-            case ParamDomainValue.NOT_NULL:
-            case ParamDomainValue.POS:
-                init = 1e-8;
-                break;
-        }
-        if (prec == undefined)
-            return nub.Calc(p.symbol, init);
-
-        return nub.Calc(p.symbol, init, prec);
-    }
-
-    private doComputeFixedVar() {
-        let np: [Nub, ParamsEquation];
-        let nub: Nub;
-        let prms: ParamsEquation;
-        let rg: boolean = this.calculatorType == CalculatorType.RegimeUniforme;
-        if (rg) {
-            let snp: [acSection, ParamsEquation] = this.getSectionNubAndParameters(this._sectionNodeType);
-            nub = new RegimeUniforme(snp[0]);
-            prms = snp[1];
-        }
-        else {
-            np = this.getNubAndParameters();
-            nub = np[0];
-            prms = np[1];
-        }
-
-        if (this.hasParameter("Pr"))
-            var computePrec: number = this.getParameterValue("Pr"); // précision de calcul
-
-        let computedParam: NgParameter = this.getComputedParameter();
-
-        let varParam: NgParameter = this.getVariatedParameter();
-        if (varParam == undefined) {
-            // pas de paramètre à varier
-
-            let res: Result = this.runNubCalc(nub, computedParam, computePrec);
-            if (res.ok) {
-                this.addFixedResults(!rg);
-                this._fixVarResults.addFixedResultElement(computedParam, res.result, !rg);
-            }
-            else {
-                this._fixVarResults.addLogMessages(res.log);
-            }
-        }
-        else {
-            // il y a un paramètre à varier
-
-            this.addFixedResults(!rg);
-            this._fixVarResults.setVariableParamHeaderFromParameter(varParam, !rg);
-            this._fixVarResults.setVariableResultHeaderFromParameter(computedParam);
-
-            switch (varParam.valueMode) {
-                case ParamValueMode.MINMAX:
-                    this._fixVarResults.graphType = GraphType.Scatter;
-
-                    let min: number = +varParam.minValue;
-                    let max: number = +varParam.maxValue;
-                    let step: number = +varParam.stepValue;
-
-                    for (let val = min; val <= max; val += step) {
-                        prms[varParam.symbol].v = val;
-
-                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
-                        if (res.ok) {
-                            this._fixVarResults.addVarResultElement(val, res.result);
-                        }
-                        else {
-                            this._fixVarResults.addLogMessages(res.log);
-                        }
-                    }
-                    break;
-
-                case ParamValueMode.LISTE:
-                    this._fixVarResults.graphType = GraphType.Histogram;
-
-                    for (let val of varParam.valueList) {
-                        prms[varParam.symbol].v = val;
-
-                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
-                        if (res.ok) {
-                            this._fixVarResults.addVarResultElement(val, res.result);
-                        }
-                        else {
-                            this._fixVarResults.addLogMessages(res.log);
-                        }
-                    }
-
-                    break;
-            }
-
-            this._fixVarResults.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
-        }
-    }
-
-    public doCompute() {
-        this.resetResults();
-
-        switch (this.calculatorType) {
-            case CalculatorType.SectionParametree:
-                this.doComputeSection();
-                break;
-
-            case CalculatorType.CourbeRemous:
-                this.doComputeRemous();
-                break;
-
-            default:
-                this.doComputeFixedVar();
-                break;
-        }
-
-        this.notifyObservers({
-            "action": "resultsUpdated",
-        });
-    }
-
-    public isDisplayed(id: string) {
-        return this.getFormulaireElementById(id).isDisplayed;
-    }
-
-    public get hasFixVarResults(): boolean {
-        return this._fixVarResults.hasResults;
-    }
-
-    public get hasSectionResults(): boolean {
-        return this._sectionResults.hasResults;
-    }
-
-    public get hasRemousResults(): boolean {
-        return this._remousResults.hasResults;
-    }
-
-    public get hasResults(): boolean {
-        return this.hasFixVarResults || this.hasSectionResults || this.hasRemousResults;
-    }
-
-    public updateLocalisation(localisation: StringMap) {
-        for (let fe of this.topFormElements)
-            fe.updateLocalisation(localisation);
-
-        if (this.hasResults)
-            this.doCompute(); // pour mettre à jour la langue
-    }
-
-    public get isValid(): boolean {
-        let res: boolean = true;
-        for (let fs of this.allFieldsets)
-            res = res && fs.isValid;
-        return res;
-    }
-
-    public get calculatorName() {
-        return this._calculatorName;
-    }
-
-    public set calculatorName(n: string) {
-        this._calculatorName = n;
-        this.notifyObservers({
-            "action": "nameChanged",
-            "name": n
-        });
-    }
-
-    /**
-     * itère sur tous les FieldSet
-     */
-    private get allFieldsets(): IterableIterator<FieldSet> {
-        return new DeepFieldsetIterator(this);
-    }
-
-    /**
-     * itère sur tous les FormulaireElement de 1er niveau
-     */
-    private get topFormElements(): IterableIterator<FormulaireElement> {
-        return new TopFormulaireElementIterator(this);
-    }
-
-    /**
-     * itère sur tous les FormulaireElement
-     */
-    private get allFormElements(): IterableIterator<FormulaireElement> {
-        return new DeepFormulaireElementIterator(this);
-    }
-
-    /**
-     * copie des membres
-     */
-    protected copyMembers(n: FormulaireNode) {
-        throw new Error("FormulaireDefinition.copyMembers() non implémenté");
-    }
-
-    /**
-     * crée une nouvelle instance
-     */
-    protected clone(): FormulaireNode {
-        throw new Error("FormulaireDefinition.clone() non implémenté");
-    }
-
-    // interface Observer 
-
-    update(sender: IObservable, data: any): void {
-        if (sender instanceof SelectField) {
-            this.updateSectionNodeType();
-        }
-    }
-
-    // interface IObservable
-
-    /**
-     * ajoute un observateur à la liste
-     */
-    public addObserver(o: Observer) {
-        this._observable.addObserver(o);
-    }
-
-    /**
-     * supprime un observateur de la liste
-     */
-    public removeObserver(o: Observer) {
-        this._observable.removeObserver(o);
-    }
-
-    /**
-     * notifie un événement aux observateurs
-     */
-    public notifyObservers(data: any) {
-        this._observable.notifyObservers(data, this);
-    }
-}
diff --git a/src/app/formulaire/formulaire-element.ts b/src/app/formulaire/formulaire-element.ts
index d2557e7c9..21ab9a9d1 100644
--- a/src/app/formulaire/formulaire-element.ts
+++ b/src/app/formulaire/formulaire-element.ts
@@ -7,7 +7,7 @@ import { DependencyCondition, DependencyConditionType } from "./dependency/depen
 import { ValueDependency } from "./dependency/value-dependency";
 import { ValueDependencyCondition } from "./dependency/value-dependency-condition";
 import { ExistenceDependency } from "./dependency/existence-dependency";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 
 /** 
  * élément (enfant) du formulaire : fieldset, input, container, ...
@@ -18,11 +18,6 @@ export abstract class FormulaireElement extends FormulaireNode {
      */
     private _nodeType: ComputeNodeType;
 
-    /**
-     * formulaire parent
-     */
-    private _parentForm: FormulaireDefinition;
-
     /**
      * affiché ?
      */
@@ -35,21 +30,16 @@ export abstract class FormulaireElement extends FormulaireNode {
 
     protected _dependencies: Dependency[] = [];
 
-    constructor(nodeType: ComputeNodeType, parentForm: FormulaireDefinition, isTmpl: boolean = false) {
+    constructor(nodeType: ComputeNodeType, isTmpl: boolean = false) {
         super(isTmpl);
         this._nodeType = nodeType;
         this._isDisplayed = true;
-        this._parentForm = parentForm;
     }
 
     get computeNodeType(): ComputeNodeType {
         return this._nodeType;
     }
 
-    get parentForm(): FormulaireDefinition {
-        return this._parentForm;
-    }
-
     get isDisplayed(): boolean {
         return this._isDisplayed;
     }
@@ -66,10 +56,10 @@ export abstract class FormulaireElement extends FormulaireNode {
         return Number(s) != NaN;
     }
 
-    private parse_existence_dependencies(json: {}) {
+    private parse_existence_dependencies(json: {}, parentForm: FormulaireDefinition) {
         for (let di in json) {
             let d = json[di];
-            let masterField: FormulaireElement = this.parentForm.getFormulaireElementById(d["refid"]);
+            let masterField: FormulaireElement = parentForm.getFormulaireNodeById(d["refid"]) as FormulaireElement;
             if (masterField != undefined) {
                 let rv = d["refvalue"];
                 if (rv != undefined)
@@ -101,10 +91,10 @@ export abstract class FormulaireElement extends FormulaireNode {
         }
     }
 
-    public parseDependencies(json: {}) {
+    public parseDependencies(json: {}, parentForm: FormulaireDefinition) {
         const dep = json["dep_exist"];
         if (dep != undefined)
-            this.parse_existence_dependencies(dep);
+            this.parse_existence_dependencies(dep, parentForm);
     }
 
     protected abstract verifyDependency(d: Dependency): boolean;
@@ -136,7 +126,7 @@ export abstract class FormulaireElement extends FormulaireNode {
             }
     }
 
-    public applyDependencies() {
+    public applyDependencies(parentForm: FormulaireDefinition) {
         this.prepareExistenceDependencies();
 
         for (let d of this._dependencies) {
@@ -155,7 +145,7 @@ export abstract class FormulaireElement extends FormulaireNode {
                 }
                 */
                 if (master.verifiesDependency(d)) {
-                    let slave = this.parentForm.getFieldById(this.id);
+                    let slave = parentForm.getFieldById(this.id);
                     if (this.isNumber(vd.slaveValue))
                         slave.setValue(+vd.slaveValue);
                     else
@@ -165,7 +155,7 @@ export abstract class FormulaireElement extends FormulaireNode {
         }
 
         for (const k of this.getKids())
-            k.applyDependencies();
+            k.applyDependencies(parentForm);
     }
 
     public printDependencies() {
@@ -211,7 +201,7 @@ export abstract class FormulaireElement extends FormulaireNode {
         }
 
         for (const k of this.kids) {
-            const destKid = dest.getFormulaireElementById(k.id);
+            const destKid = dest.getFormulaireNodeById(k.id) as FormulaireElement;
             (k as FormulaireElement).copyDependencies(destKid, root);
         }
     }
@@ -237,8 +227,4 @@ export abstract class FormulaireElement extends FormulaireNode {
     public toString() {
         return "id:" + this.id + (this._isDisplayed ? " displayed" : " NOT displayed") + " label:" + this.label;
     }
-
-    public getFormulaireElementById(id: string): FormulaireElement {
-        return this.getFormulaireNodeById(id) as FormulaireElement;
-    }
 }
diff --git a/src/app/formulaire/formulaire-node.ts b/src/app/formulaire/formulaire-node.ts
index e2322f518..2613a1b0d 100644
--- a/src/app/formulaire/formulaire-node.ts
+++ b/src/app/formulaire/formulaire-node.ts
@@ -1,3 +1,5 @@
+import { FormulaireDefinition } from "./definition/form-definition";
+
 /**
  * représentation sous forme d'arbre du formulaire et de ses éléments
  */
@@ -128,5 +130,5 @@ export abstract class FormulaireNode {
 
     public abstract parseConfig(json: {}, data?: {});
 
-    public abstract parseDependencies(json: {});
+    public abstract parseDependencies(json: {}, parentForm: FormulaireDefinition);
 }
diff --git a/src/app/formulaire/input-field.ts b/src/app/formulaire/input-field.ts
index f94ba1d7c..56adb6228 100644
--- a/src/app/formulaire/input-field.ts
+++ b/src/app/formulaire/input-field.ts
@@ -1,14 +1,14 @@
 import { ComputeNodeType } from "jalhyd";
 
 import { Field } from "./field"
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 
 
 export abstract class InputField extends Field {
     private _value: any;
 
-    constructor(type: ComputeNodeType, parentForm: FormulaireDefinition, isTmpl = false) {
-        super(type, parentForm, isTmpl);
+    constructor(type: ComputeNodeType, isTmpl = false) {
+        super(type, isTmpl);
     }
 
     public getValue() {
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index ceed56ef8..53e109c6a 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -5,7 +5,7 @@ import { Dependency } from "./dependency/dependency";
 import { DependencyConditionType } from "./dependency/dependency-condition";
 import { ValueDependencyCondition } from "./dependency/value-dependency-condition";
 import { Observable, IObservable, Observer } from "../services/observer";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 import { ApplicationSetupService } from "../services/app-setup/app-setup.service";
 
 export enum ParamRadioConfig {
@@ -80,8 +80,8 @@ export class NgParameter extends InputField implements IObservable {
      */
     private _observable: Observable;
 
-    constructor(private _paramDef: ParamDefinition, parentForm: FormulaireDefinition, isTmpl = false) {
-        super(_paramDef.computeNodeType, parentForm, isTmpl);
+    constructor(private _paramDef: ParamDefinition, isTmpl = false) {
+        super(_paramDef.computeNodeType, isTmpl);
         this._observable = new Observable();
     }
 
@@ -324,7 +324,7 @@ export class NgParameter extends InputField implements IObservable {
      * crée une nouvelle instance
      */
     protected clone(): NgParameter {
-        return new NgParameter(this._paramDef.clone(), this.parentForm);
+        return new NgParameter(this._paramDef.clone());
     }
 
     // interface IObservable
diff --git a/src/app/formulaire/select-field.ts b/src/app/formulaire/select-field.ts
index b433eb706..1b0b02383 100644
--- a/src/app/formulaire/select-field.ts
+++ b/src/app/formulaire/select-field.ts
@@ -7,7 +7,7 @@ import { DependencyConditionType } from "./dependency/dependency-condition";
 import { ValueDependencyCondition } from "./dependency/value-dependency-condition";
 import { StringMap } from "../stringmap";
 import { IObservable, Observable, Observer } from "../services/observer";
-import { FormulaireDefinition } from "./formulaire-definition";
+import { FormulaireDefinition } from "./definition/form-definition";
 
 
 export class SelectField extends Field implements IObservable {
@@ -17,8 +17,8 @@ export class SelectField extends Field implements IObservable {
 
     private _observable: Observable;
 
-    constructor(nodeType: ComputeNodeType, parentForm: FormulaireDefinition, isTmpl = false) {
-        super(nodeType, parentForm, isTmpl);
+    constructor(nodeType: ComputeNodeType, isTmpl = false) {
+        super(nodeType, isTmpl);
         this._entries = [];
         this._observable = new Observable();
     }
@@ -86,7 +86,7 @@ export class SelectField extends Field implements IObservable {
      * crée une nouvelle instance
      */
     protected clone(): SelectField {
-        return new SelectField(this.computeNodeType, this.parentForm);
+        return new SelectField(this.computeNodeType);
     }
 
     public parseConfig(field: {}, data?: {}) {
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index f2b5e5ebc..005b6a8d1 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -9,13 +9,20 @@ import { ParamService } from "../param/param.service";
 import { HttpService } from "../../services/http/http.service";
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+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 { CheckField } from "../../formulaire/check-field";
 import { StringMap } from "../../stringmap";
 import { Observable } from "../observer";
+import { FormulaireConduiteDistributrice } from "../../formulaire/definition/concrete/form-cond-distri";
+import { FormulaireLechaptCalmon } from "../../formulaire/definition/concrete/form-lechapt-calmon";
+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 { FormulairePasseBassinDimensions } from "../../formulaire/definition/concrete/form-passe-bassin-dim";
+import { FormulairePasseBassinPuissance } from "../../formulaire/definition/concrete/form-passe-bassin-puissance";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -123,10 +130,40 @@ export class FormulaireService extends Observable {
     }
 
     public createFormulaire(ct: CalculatorType): Promise<FormulaireDefinition> {
-        if (ct == undefined)
-            throw "FormulaireService.createFormulaire() : invalid undefined CalculatorType"
+        let f: FormulaireDefinition;
+        switch (ct) {
+            case CalculatorType.ConduiteDistributrice:
+                f = new FormulaireConduiteDistributrice(this.paramService, this.appSetupService);
+                break;
+
+            case CalculatorType.LechaptCalmon:
+                f = new FormulaireLechaptCalmon(this.paramService, this.appSetupService);
+                break;
+
+            case CalculatorType.SectionParametree:
+                f = new FormulaireSectionParametree(this.paramService, this.appSetupService, this.intlService);
+                break;
+
+            case CalculatorType.RegimeUniforme:
+                f = new FormulaireRegimeUniforme(this.paramService, this.appSetupService);
+                break;
+
+            case CalculatorType.CourbeRemous:
+                f = new FormulaireCourbeRemous(this.paramService, this.appSetupService);
+                break;
+
+            case CalculatorType.PabDimensions:
+                f = new FormulairePasseBassinDimensions(this.paramService, this.appSetupService);
+                break;
+
+            case CalculatorType.PabPuissance:
+                f = new FormulairePasseBassinPuissance(this.paramService, this.appSetupService);
+                break;
+
+            default:
+                throw new Error(`FormulaireService.createFormulaire() : type de calculette ${ct} non pris en charge`)
+        }
 
-        let f = new FormulaireDefinition(ct, this.paramService, this.intlService, this.appSetupService);
         f.calculatorName = this.getLocalisedTitleFromCalculatorType(ct) + " (" + f.uid + ")";
         this._formulaires.push(f);
         let prom: Promise<Response> = this.loadConfig(f, ct);
@@ -180,9 +217,9 @@ export class FormulaireService extends Observable {
     private getFormulaireElementById(formId: number, elemId: string): FormulaireElement {
         for (let f of this._formulaires)
             if (f.uid == formId) {
-                let s = f.getFormulaireElementById(elemId);
+                let s = f.getFormulaireNodeById(elemId);
                 if (s != undefined)
-                    return s;
+                    return s as FormulaireElement;
             }
         return undefined;
     }
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index d1e36fd25..57706e786 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -1,7 +1,7 @@
 import { ParamDomain, ComputeNodeType, ComputeNodeParameters, ParamsEquation, ParamDefinition, ParamDomainValue, ParamCalculability, CalculatorType } from "jalhyd";
 
 import { NgParameter } from "../../formulaire/ngparam";
-import { FormulaireDefinition } from "../../formulaire/formulaire-definition";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
 
 export class ParamService {
     private createAccuracyParameter(calcType: CalculatorType): ParamDefinition {
@@ -11,7 +11,7 @@ export class ParamService {
         return p;
     }
 
-    public createParameter(calcType: CalculatorType, nodeType: ComputeNodeType, symbol: string, form: FormulaireDefinition, isTmpl = false): NgParameter {
+    public createParameter(calcType: CalculatorType, nodeType: ComputeNodeType, symbol: string, isTmpl = false): NgParameter {
         if (symbol === "Pr")
             var prmDef: ParamDefinition = this.createAccuracyParameter(calcType);
         else
@@ -20,6 +20,6 @@ export class ParamService {
         if (prmDef == undefined)
             throw new Error(`ParamService.createParameter() : pas de paramètre '${symbol}' pour la calculette ${CalculatorType[calcType]}/type de noeud ${ComputeNodeType[nodeType]}`);
 
-        return new NgParameter(prmDef.clone(), form, isTmpl);
+        return new NgParameter(prmDef.clone(), isTmpl);
     }
 }
-- 
GitLab