diff --git a/src/app/calculators/generic/formulaire.ts b/src/app/calculators/generic/formulaire.ts
new file mode 100644
index 0000000000000000000000000000000000000000..626788aafbbcb20909ae3f9e61894037be190c3d
--- /dev/null
+++ b/src/app/calculators/generic/formulaire.ts
@@ -0,0 +1,328 @@
+import { ParamDefinition } from 'jalhyd';
+
+import { NgParameter, ParamRadioConfig } from '../generic/ngparam';
+import { ParamService } from '../../services/param/param.service';
+
+export class FormulaireDefinition {
+    /**
+     * objet JSON chargé depuis le fichier de configuration de la calculette
+     */
+    private _config = {};
+
+    /**
+   * symbole du paramètre à calculer par défaut (cf config "idCal")
+   */
+    private _defaultCalculatedParam: string;
+
+    private _fieldSets: FieldSet[] = [];
+
+    private _dependencies: Dependency[] = [];
+
+    constructor(private paramService: ParamService) {
+    }
+
+    private getFieldSet(id: string) {
+        for (let fs of this._fieldSets) {
+            if (fs.id == id)
+                return fs;
+        }
+        return undefined;
+    }
+
+    public getParamFromSymbol(symbol: string): NgParameter {
+        for (let fs of this._fieldSets) {
+            for (let p of fs.fields) {
+                if (p instanceof NgParameter)
+                    if (p.symbol === symbol)
+                        return p;
+            }
+        }
+        return undefined;
+    }
+
+    public getParamFromState(st: ParamRadioConfig): NgParameter {
+        for (let fs of this._fieldSets) {
+            for (let p of fs.fields) {
+                if (p instanceof NgParameter)
+                    if (p.radioState == st)
+                        return p;
+            }
+        }
+        return undefined;
+    }
+
+
+    /**
+     * remet tous les paramètres à FIX sauf "me" et ceux (celui) à l'état "except"
+     */
+    public resetOther(me: NgParameter, except: ParamRadioConfig) {
+        // console.log("reset me=" + me.symbol + " sauf=" + ParamRadioConfig[except])
+        for (let fs of this._fieldSets) {
+            for (let p of fs.fields) {
+                if (p instanceof NgParameter)
+                    if (p != me && p.radioState != except && p.radioConfig != ParamRadioConfig.FIX) {
+                        // console.log("reset " + p.symbol + " st " + ParamRadioConfig[p.radioState] + " -> FIX");
+                        p.radioState = ParamRadioConfig.FIX;
+                    }
+            }
+        }
+    }
+
+    /**
+     * met le paramètre par défaut à CAL
+     */
+    public setDefault() {
+        let defaultParamCal = this.getParamFromSymbol(this._defaultCalculatedParam);
+        // console.log("setdefault " + defaultParamCal.symbol + " -> CAL")
+        defaultParamCal.radioState = ParamRadioConfig.CAL;
+    }
+
+    public getInputParameters(): NgParameter[] {
+        let res = [];
+        for (let fs of this._fieldSets)
+            for (let p of fs.fields)
+                if (p instanceof NgParameter)
+                    res.push(p);
+        return res;
+    }
+
+    public getParameterValue(symbol: string): number {
+        for (let fs of this._fieldSets) {
+            for (let p of fs.fields) {
+                if (p instanceof NgParameter)
+                    if (p.symbol === symbol) {
+                        switch (p.radioState) {
+                            case ParamRadioConfig.FIX:
+                                return p.v;
+
+                            case ParamRadioConfig.VAR:
+                            case ParamRadioConfig.CAL:
+                                return undefined;
+                        }
+                    }
+            }
+        }
+    }
+
+    public getFormulaireElementById(id: string): FormulaireElement {
+        for (let fs of this._fieldSets) {
+            if (fs.id == id)
+                return fs;
+
+            for (let p of fs.fields)
+                if (p.id === id)
+                    return p;
+        }
+        return undefined;
+    }
+
+    private parse_value_dependencies(json: {}, slave: FormulaireElement) {
+        for (let di in json) {
+            let d = json[di];
+            let refField: FormulaireElement = this.getFormulaireElementById(d["refid"]);
+            if (refField != undefined) {
+                let refVal = d["refvalue"];
+                let dep = new ValueDependency(refField, slave);
+                dep.slaveValue = d["value"];
+                this._dependencies.push(dep);
+            }
+        }
+    }
+
+    private parse_existence_dependencies(json: {}, slave: FormulaireElement) {
+        for (let di in json) {
+            let d = json[di];
+            let refField: FormulaireElement = this.getFormulaireElementById(d["refid"]);
+            if (refField != undefined) {
+                let refVal = d["refvalue"];
+                let dep = new ExistenceDependency(refField, slave);
+                this._dependencies.push(dep);
+            }
+        }
+    }
+
+    private parse_dependencies(slave: FormulaireElement, json: {}) {
+        let dep = json["dep_value"];
+        if (dep != undefined) {
+            this.parse_value_dependencies(dep, slave);
+        }
+        else {
+            dep = json["dep_exist"];
+            if (dep != undefined) {
+                this.parse_existence_dependencies(dep, slave);
+            }
+        }
+    }
+
+    private parse_select(json: {}): SelectField {
+        let id = json["id"];
+        let res: SelectField = new SelectField(id);
+        let values = json["select"];
+        for (let v of values)
+            res.addValue(v["id"]);
+
+        return res;
+    }
+
+    private parse_input(fieldset: {}, field: {}): NgParameter {
+        let input_id = field["id"];
+        let param: NgParameter = this.paramService.getParameter(input_id);
+        if (param != undefined) {
+            param.unit = field["unit"];
+            param.v = +field["value"];
+            param.radioConfig = NgParameter.getRadioConfig(fieldset["option"]);
+            param.radioState = ParamRadioConfig.FIX;
+            param.isDefault = false; // malgré le fait qu'il soit initialisé dans la déclaration de la classe NgParam à false, quand on relit sa valeur, il vaut undefined (merci Microsoft)
+            this.parse_dependencies(param, field);
+        }
+        return param;
+    }
+
+    private parse_fieldset(fieldset: {}, conf_id: string): FieldSet {
+        let res: FieldSet = new FieldSet(conf_id);
+
+        let fields = fieldset["fields"];
+        for (let field_index in fields) {
+            let field = fields[field_index];
+            if (field["type"] === "input") {
+                let param = this.parse_input(fieldset, field);
+                if (param != undefined)
+                    res.addField(param);
+            } else if (field["type"] === "select") {
+                let param = this.parse_select(field);
+                if (param != undefined)
+                    res.addField(param);
+            }
+        }
+        return res;
+    }
+
+    public parseConfig(config: {}) {
+        this._config = config;
+        this._dependencies = [];
+        this._defaultCalculatedParam = undefined;
+
+        for (let conf_index in this._config) {
+
+            let conf = this._config[conf_index];
+            let conf_id: string = conf["id"];
+
+            // field set
+            if (conf_id.startsWith("fs_")) {
+                let fieldSet: FieldSet = this.parse_fieldset(conf, conf_id);
+                if (fieldSet.fields.length > 0) {
+                    this._fieldSets.push(fieldSet);
+                }
+            }
+            // options globales
+            else if (conf_id === "options") {
+                // id du paramètre à calculer par défaut
+                this._defaultCalculatedParam = conf["idCal"];
+                let p = this.getParamFromSymbol(this._defaultCalculatedParam);
+                p.isDefault = true;
+                p.radioState = ParamRadioConfig.CAL;
+            }
+        }
+    }
+
+    public updateLanguage(localisation: {}) {
+        for (let conf_index in this._config) {
+            let conf = this._config[conf_index];
+            let conf_id: string = conf["id"];
+
+            if (conf_id.startsWith("fs_")) {
+                let fieldSet: FieldSet = this.getFieldSet(conf_id);
+                if (fieldSet != undefined)
+                    fieldSet.title = localisation[conf_id];
+            }
+        }
+    }
+}
+
+abstract class FormulaireElement {
+    private _id: string;
+    private _isDisplayed: boolean;
+
+    constructor(id: string) {
+        this._id = id;
+        this._isDisplayed = true;
+    }
+
+    get id() {
+        return this._id;
+    }
+}
+
+export abstract class Field extends FormulaireElement {
+}
+
+export class FieldSet extends FormulaireElement {
+    title: string;
+    private _fields: Field[];
+
+    constructor(id: string) {
+        super(id);
+        this._fields = [];
+    }
+
+    public get fields() {
+        return this._fields;
+    }
+
+    public addField(f: Field) {
+        this._fields.push(f);
+    }
+
+    public get isEmpty(): boolean {
+        return this._fields.length == 0;
+    }
+
+    public getInput(i: number): NgParameter {
+        let n = 0;
+        for (let f of this._fields) {
+            if (f instanceof NgParameter) {
+                if (n == i)
+                    return f;
+                n++;
+            }
+        }
+        return undefined;
+    }
+}
+
+export class SelectField extends Field {
+    private _values: string[];
+
+    constructor(id: string) {
+        super(id)
+        this._values = [];
+    }
+
+    public addValue(value: string) {
+        this._values.push(value);
+    }
+}
+
+abstract class Dependency {
+    private _master: FormulaireElement;
+    private _masterValue: any;
+
+    private _slave: FormulaireElement;
+
+    constructor(m: FormulaireElement, s: FormulaireElement) {
+        this._master = m;
+        this._slave = s;
+    }
+}
+
+export class ValueDependency extends Dependency {
+    public slaveValue: any;
+}
+
+export class ExistenceDependency extends Dependency {
+    /**
+     * true : l'élément slave est affiché si le master est affiché
+     * false : l'élément slave est affiché si le master n'est pas affiché
+     */
+    // private _direct: boolean;
+}
diff --git a/src/app/services/ngparam.ts b/src/app/calculators/generic/ngparam.ts
similarity index 91%
rename from src/app/services/ngparam.ts
rename to src/app/calculators/generic/ngparam.ts
index c90df03f9f18b5ac6af21246edecb671fad1678c..889c0bf1f8e2af0b864ab201fed66fb6ad299fe1 100644
--- a/src/app/services/ngparam.ts
+++ b/src/app/calculators/generic/ngparam.ts
@@ -1,5 +1,7 @@
 import { ParamDefinition, ParamDomainValue, ErrorMessage } from 'jalhyd';
 
+import { Field } from './formulaire';
+
 export enum ParamRadioConfig {
     /**
      * pas de radio, paramètre modifiable à la main uniquement
@@ -20,7 +22,7 @@ export enum ParamRadioConfig {
 /**
  * class englobante de ParamDefinition (champs supplémentaires pour l'affichage, radio boutons, ...)
  */
-export class NgParameter {
+export class NgParameter extends Field {
     public unit: string;
     public label: string;
     public radioConfig: ParamRadioConfig;
@@ -30,7 +32,8 @@ export class NgParameter {
     public maxValue: number; // valeur max dans le cas ParamRadioConfig.VAR
     public stepValue: number; // pas de progression dans le cas ParamRadioConfig.VAR
 
-    constructor(private _paramDef: ParamDefinition) {
+    constructor(private _paramDef: ParamDefinition, id: string = undefined) {
+        super(id == undefined ? _paramDef.symbol : id);
         switch (this._paramDef.getDomain().domain) {
             case ParamDomainValue.ANY:
                 this.minValue = -10;
diff --git a/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json.jacase b/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json.jacase
deleted file mode 100644
index 7331aa1b32f052a33d19f76d921905df32cfe29d..0000000000000000000000000000000000000000
--- a/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json.jacase
+++ /dev/null
@@ -1,237 +0,0 @@
-{
-    "saisies":[
-        {
-            "id":"fs_materiau",
-            "name":"Type du matériau",
-            "option":"var",
-            "fields":[{
-                "type":"select",
-                "name": "Choix du matériau",
-                "value": 1,
-                
-                "select":[
-                {
-                    "id": 1,
-                    "name":"Fonte ou acier non revêtus - Béton grossier (eau corrosive)",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.863"
-                        },
-                        {
-                            "id":"M",
-                            "value":"2"
-                        },
-                        {
-                            "id":"N",
-                            "value":"5.33"
-                        }
-                    ]                    
-            },
-            {
-                    "id": 2,
-                    "name":"Fonte ou acier non revêtus - Béton grossier (eau peu corrosive)",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.601"
-                        },
-                        {
-                            "id":"M",
-                            "value":"1.975"
-                        },
-                        {
-                            "id":"N",
-                            "value":"5.25"
-                        }
-                    ]                    
-            },
-            {
-                    "id": 3,    
-                    "name":"Fonte ou acier revêtement ciment",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.40"
-                        },
-                        {
-                            "id":"M",
-                            "value":"1.96"
-                        },
-                        {
-                            "id":"N",
-                            "value":"5.19"
-                        }
-                    ]                    
-            },
-            {
-                    "id": 4,
-                    "name":"Fonte ou acier revêtement bitume - Béton centrifugé",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.16"
-                        },
-                        {
-                            "id":"M",
-                            "value":"1.93"
-                        },
-                        {
-                            "id":"N",
-                            "value":"5.11"
-                        }
-                    ]                    
-            },
-            {
-                    "id": 5,
-                    "name":"Acier laminé - Béton lisse",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.1"
-                        },
-                        {
-                            "id":"M",
-                            "value":"1.89"
-                        },
-                        {
-                            "id":"N",
-                            "value":"5.01"
-                        }
-                    ]                    
-            },
-            {
-                    "id": 6,
-                    "name":"Fonte ou acier revêtement centrifugé",
-                    "parameters":[
-                        {
-                            "id":"L",
-                            "value":"1.049"
-                        },
-                        {
-                            "id":"M",
-                            "value":"1.86"
-                        },
-                        {
-                            "id":"N",
-                            "value":"4.93"
-                        }
-                    ]                    
-                },
-            {
-                "id": 7,
-                "name":"PVC - Polyéthylène",
-                "parameters":[
-                    {
-                        "id":"L",
-                        "value":"1.01"
-                    },
-                    {
-                        "id":"M",
-                        "value":"1.84"
-                    },
-                    {
-                        "id":"N",
-                        "value":"4.88"
-                    }
-                ]                    
-            },
-            {
-                "id": 8,
-                "name":"Tuyau hydrauliquement lisse - 0.05 ≤ D ≤ 0.2",
-                "parameters":[
-                    {
-                        "id":"L",
-                        "value":"0.916"
-                    },
-                    {
-                        "id":"M",
-                        "value":"1.78"
-                    },
-                    {
-                        "id":"N",
-                        "value":"4.78"
-                    }
-                ]                    
-            },
-            {
-                "id": 9,
-                "name":"Tuyau hydrauliquement lisse - 0.25 ≤ D ≤ 1",
-                "parameters":[
-                    {
-                        "id":"L",
-                        "value":"0.971"
-                    },
-                    {
-                        "id":"M",
-                        "value":"1.81"
-                    },
-                    {
-                        "id":"N",
-                        "value":"4.81"
-                    }
-                ]                    
-            }
-            ]
-            }]
-        },
-
-        {
-            "id":"fs_hydraulique",
-            "name":"Caractéristiques hydrauliques",
-            "option":"cal",
-            "fields":[
-            {
-                "type":"input",
-                "id" : "Q",
-                "name":"Débit",
-                "unit":"m³/s",
-                "value":3
-            },
-            {
-                "type":"input",
-                "id" : "D", 
-                "name":"Diamètre du tuyau",
-                "unit":"m",
-                "value":1.2
-                
-            },
-            {
-                "type":"input",
-                "id" : "J",
-                "name":"Perte de charge",
-                "unit":"m",
-                "value":0.6
-
-            },
-            {
-                "type":"input",
-                "id" : "Lg",
-                "name":"Longueur du tuyau",
-                "unit":"m",           
-                "value":100
-
-            }       
-            ]
-        },
-
-        {
-                "id":"fs_param_calc",                
-                "name":"Paramètres de calcul",
-                "option":"fix",
-                "fields":[{
-                    "type":"input",
-                    "id" : "Pr",
-                    "name":"Précision de calcul",
-                    "unit":"m",            
-                    "value":0.001 
-                }]
-        },
-
-        {
-            "id":"options",      
-            "idCal" : "J"
-        }
-    ]
-    
-}
\ No newline at end of file
diff --git a/src/app/components/calculator-results/calculator-results.component.ts b/src/app/components/calculator-results/calculator-results.component.ts
index c315e23e6f4d2db7d057c29f24d3b7f8d89ef603..a586149bb674a971f8adb00606e07e6ab9b73c50 100644
--- a/src/app/components/calculator-results/calculator-results.component.ts
+++ b/src/app/components/calculator-results/calculator-results.component.ts
@@ -1,6 +1,6 @@
 import { Component } from '@angular/core';
 
-import { NgParameter } from '../../services/ngparam';
+import { NgParameter } from '../../calculators/generic/ngparam';
 
 @Component({
     selector: 'calc-results',
diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts
index c22ee9320e12857da2d980621aae705953a6edde..a25b1fe667a4079805641f6ab8c42832d89a303a 100644
--- a/src/app/components/field-set/field-set.component.ts
+++ b/src/app/components/field-set/field-set.component.ts
@@ -2,26 +2,8 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
 
 import { ParamDefinition } from 'jalhyd';
 
-import { NgParameter, ParamRadioConfig } from '../../services/ngparam';
-
-export class FieldSet {
-    private _id: string;
-    title: string;
-    params: NgParameter[];
-
-    constructor(id: string) {
-        this.params = [];
-        this._id = id;
-    }
-
-    get id() {
-        return this._id;
-    }
-
-    public addParameter(prm: ParamDefinition) {
-        this.params.push(new NgParameter(prm));
-    }
-}
+import { NgParameter, ParamRadioConfig } from '../../calculators/generic/ngparam';
+import { FieldSet } from '../../calculators/generic/formulaire';
 
 @Component({
     selector: "field-set",
@@ -52,8 +34,8 @@ export class FieldSetComponent {
     }
 
     private hasRadioFix(): boolean {
-        if (this._fieldSet.params.length > 0)
-            switch (this._fieldSet.params[0].radioConfig) {
+        if (!this._fieldSet.isEmpty)
+            switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.FIX:
                     return false;
 
@@ -64,8 +46,8 @@ export class FieldSetComponent {
     }
 
     private hasRadioVar(): boolean {
-        if (this._fieldSet.params.length > 0)
-            switch (this._fieldSet.params[0].radioConfig) {
+        if (!this._fieldSet.isEmpty)
+            switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.VAR:
                 case ParamRadioConfig.CAL:
                     return true;
@@ -77,8 +59,8 @@ export class FieldSetComponent {
     }
 
     private hasRadioCal(): boolean {
-        if (this._fieldSet.params.length > 0)
-            switch (this._fieldSet.params[0].radioConfig) {
+        if (!this._fieldSet.isEmpty)
+            switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.CAL:
                     return true;
 
diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts
index affee7f79d04a7f8c198a818c05639ca7302554d..c17289fded2fc87bc8e6b1e1f4c60cf266478f9d 100644
--- a/src/app/components/param-field-line/param-field-line.component.ts
+++ b/src/app/components/param-field-line/param-field-line.component.ts
@@ -1,7 +1,7 @@
 import { Component, Input, Output, DoCheck, EventEmitter } from '@angular/core';
 
 import { ParamService } from '../../services/param/param.service';
-import { NgParameter, ParamRadioConfig } from '../../services/ngparam';
+import { NgParameter, ParamRadioConfig } from '../../calculators/generic/ngparam';
 
 @Component({
     selector: "param-field-line",
diff --git a/src/app/components/param-input/param-input.component.ts b/src/app/components/param-input/param-input.component.ts
index d6359b1df977aa202451577ba7de94711a3a2bf2..60ac6f369f9e6db8392a13707d6c53a8a2b52f9f 100644
--- a/src/app/components/param-input/param-input.component.ts
+++ b/src/app/components/param-input/param-input.component.ts
@@ -7,7 +7,7 @@ import { ParamDefinition, NumericalString, ErrorMessage } from 'jalhyd';
 
 import { ParamService } from '../../services/param/param.service';
 import { InternationalisationService, LanguageCode } from '../../services/internationalisation/internationalisation.service';
-import { NgParameter } from '../../services/ngparam';
+import { NgParameter } from '../../calculators/generic/ngparam';
 
 @Component({
     selector: 'param-input[symbol]',
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index 72867cbb2a70d4d1f579aa5a7ae4adb3b5b6abfb..935cc3f8acb0f336052550920df497181d8555ee 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -1,6 +1,6 @@
 import { ComputeNodeParameters, IParamsEquation, ParamDefinition, ParamDomainValue, ParamCalculability } from 'jalhyd';
 
-import { NgParameter } from "../ngparam";
+import { NgParameter } from "../../calculators/generic/ngparam";
 
 export class ParamService {
     // private _params: ParamDefinition[];