diff --git a/.gitignore b/.gitignore
index 095e29f0467249459c9aa1370185a0f77b6bd3d3..2361e48f30486ea49428eed2338c6b9ce5f62e44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,7 +22,7 @@
 .vscode/*
 !.vscode/settings.json
 !.vscode/tasks.json
-!.vscode/launch.json
+# !.vscode/launch.json
 !.vscode/extensions.json
 
 # misc
@@ -46,4 +46,20 @@ Thumbs.db
 /jalhyd_class_diagram.png
 
 # distribution output
-/jalhyd-*.tgz
\ No newline at end of file
+/jalhyd-*.tgz
+
+.vscode/launch.json
+Makefile
+check_message_codes
+commit
+debug_jasmine
+graphviz
+newton
+parse_spip_log
+run_testjs
+spec/support/jasmine-remous.json
+spec/test.ts
+spec/test2.ts
+spec/tsconfig-test.spec.json
+spec/tsconfig-test2.spec.json
+src/util/http.ts
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 7ca0dc5577d8533754f994538ca949512c6368b5..be37e2d1bdf7fef954f0e29a3c64ca397f7415a1 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -14,7 +14,7 @@
                 "${workspaceRoot}/build/**/*.js"
             ],
             "cwd": "${workspaceRoot}",
-            "preLaunchTask": "buildspec"
+            // "preLaunchTask": "buildspec"
         }
     ]
 }
\ No newline at end of file
diff --git a/spec/structure/dever.spec.ts b/spec/structure/dever.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc43499aa55727f4983a572c5ddb9b34ab4c8bec
--- /dev/null
+++ b/spec/structure/dever.spec.ts
@@ -0,0 +1,44 @@
+/**
+ * IMPORTANT !
+ * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
+ * Pour exécuter ce code dans le débugger.
+ * Faire de même avec le fichier test_func.ts
+ */
+// import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";
+
+import { Dever, DeverParams } from "../../src/structure/dever";
+import { CreateStructure } from "../../src/structure/factory_structure";
+import { LoiDebit, StructureType } from "../../src/structure/structure_props";
+import { Result } from "../../src/util/result";
+
+const dever: Dever = new Dever(
+    new DeverParams(
+        0,     // rQ Débit total (m3/s)
+        102,   // rZ1 Cote de l'eau amont (m)
+        2,     // rBR Largeur du cours d'eau amont (m)
+        100    // rZR Cote du lit du cours d'eau amont (m)
+    ),
+    false // debug
+);
+
+dever.addStructure(CreateStructure(StructureType.SeuilTriangulaireTrunc, LoiDebit.TriangularTruncWeirFree, false));
+
+describe("Class Dever: ", () => {
+    describe("Calc(Q) Seuil Triangulaire Trunc", () => {
+        it("vCalc should return 5.407", () => {
+            expect(dever.Calc("Q").vCalc).toBeCloseTo(5.407, 3);
+        });
+        it("extraResults.V should return 1.352", () => {
+            expect(dever.Calc("Q").extraResults.V).toBeCloseTo(1.352, 3);
+        });
+        it("extraResults.Ec should return 0.093", () => {
+            expect(dever.Calc("Q").extraResults.Ec).toBeCloseTo(0.093, 3);
+        });
+        it("extraResults.Cv should return 1.116", () => {
+            expect(dever.Calc("Q").extraResults.Cv).toBeCloseTo(1.116, 3);
+        });
+        it("extraResults.CvQT should return 6.036", () => {
+            expect(dever.Calc("Q").extraResults.CvQT).toBeCloseTo(6.036, 3);
+        });
+    });
+});
diff --git a/spec/structure/rectangular_structure.ts b/spec/structure/functions.ts
similarity index 78%
rename from spec/structure/rectangular_structure.ts
rename to spec/structure/functions.ts
index 8895e09c1200f0101ebfbb1b63e4633494615069..853eecc881d2d7c2c0664b6683830320e41f99d9 100644
--- a/spec/structure/rectangular_structure.ts
+++ b/spec/structure/functions.ts
@@ -5,15 +5,15 @@
  */
 // import { describe, expect, it, xdescribe } from "../mock_jasmine";
 
-import { RectangularStructure } from "../../src/structure/rectangular_structure";
+import { Structure } from "../../src/structure/structure";
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { Describer } from "../../src/util/describer";
 import { Result } from "../../src/util/result";
 import { precDigits } from "../test_config";
 
 export function itCalcQ(
-    struct: RectangularStructure, Z1: number, W: number, Q: number,
-    mode?: StructureFlowMode, regime?: StructureFlowRegime) {
+    struct: Structure, Z1: number, W: number, Q: number,
+    mode?: StructureFlowMode, regime?: StructureFlowRegime, precDigits2?: number) {
 
     struct.debug("itCalQ " + Describer.getName(struct) + " Z1=" + Z1 + " W=" + W + " Q=" + Q);
 
@@ -23,8 +23,9 @@ export function itCalcQ(
     struct.debug("struct.Calc(Q)=" + res.vCalc);
 
     it("Q(Z1=" + Z1 + ",W=" + W + ") should be " + Q, () => {
+        if (precDigits2 === undefined) { precDigits2 = precDigits; }
         struct.debug("struct.Calc(Q)=" + res.vCalc);
-        expect(res.vCalc).toBeCloseTo(Q, precDigits);
+        expect(res.vCalc).toBeCloseTo(Q, precDigits2);
     });
     if (mode !== undefined) {
         it("Q(Z1=" + Z1 + ",W=" + W + ") Mode should be " + mode, () => {
diff --git a/spec/structure/parallel_structure.spec.ts b/spec/structure/parallel_structure.spec.ts
index b7b9f9884b9b19786a0f951a6b11813fc941a0cb..d7bf22a27ade7686274e5996f6a318bc23386497 100644
--- a/spec/structure/parallel_structure.spec.ts
+++ b/spec/structure/parallel_structure.spec.ts
@@ -8,11 +8,10 @@
 
 import { ParamCalculability } from "../../src/param/param-definition";
 import { CreateStructure } from "../../src/structure/factory_structure";
-import { LoiDebit, StructureType, loiAdmissibles } from "../../src/structure/structure_props";
 import { ParallelStructure } from "../../src/structure/parallel_structure";
 import { ParallelStructureParams } from "../../src/structure/parallel_structure_params";
 import { Structure } from "../../src/structure/structure";
-import { Describer } from "../../src/util/describer";
+import { loiAdmissibles, LoiDebit, StructureType } from "../../src/structure/structure_props";
 import { EnumEx } from "../../src/util/enum";
 import { MessageCode } from "../../src/util/message";
 import { Result } from "../../src/util/result";
@@ -84,7 +83,6 @@ const ps2: ParallelStructure = new ParallelStructure(
     false // debug
 );
 
-// tslint:disable-next-line:prefer-for-of
 describe("Class ParallelStructure: ", () => {
     // Ajout d'une structure de chaque type dans ParallelStructure
     const iLoiDebits: number[] = [];
@@ -136,6 +134,14 @@ describe("Class ParallelStructure: ", () => {
                                 ps2.Calc(i + "." + prm.symbol).code
                             ).toBe(MessageCode.ERROR_STRUCTURE_ZDV_PAS_CALCULABLE);
                         });
+                    } else if (
+                        iLoiDebits[i] === LoiDebit.TriangularWeirFree &&
+                        prm.symbol === "alpha2"
+                    ) {
+                        // Le calcul de l'angle de l'équation triangulaire n'est pas assez précis
+                        it(`Calc(${prm.symbol}) should return ${ref}`, () => {
+                            checkResult(ps2.Calc(i + "." + prm.symbol), ref, 1);
+                        });
                     } else {
                         // Cas normal : On teste la valeur calculée
                         it(`Calc(${prm.symbol}) should return ${ref}`, () => {
diff --git a/spec/structure/structure_cem88d.spec.ts b/spec/structure/structure_cem88d.spec.ts
index 42521b8d504b04cc5149adef88d7e86e4e575de7..f44d486f6c27b1f34c53ebaf1fcec96e1c59ff6c 100644
--- a/spec/structure/structure_cem88d.spec.ts
+++ b/spec/structure/structure_cem88d.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureCem88d } from "../../src/structure/structure_cem88d";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureCem88d = new StructureCem88d(structPrm, false);
diff --git a/spec/structure/structure_cem88v.spec.ts b/spec/structure/structure_cem88v.spec.ts
index fe40920cfa0a6637ecb83faf2ac32e0946b5e277..5927b9fc47cf1f5830e70970b2495938ea72bba4 100644
--- a/spec/structure/structure_cem88v.spec.ts
+++ b/spec/structure/structure_cem88v.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureCem88v } from "../../src/structure/structure_cem88v";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureCem88v = new StructureCem88v(structPrm, false);
diff --git a/spec/structure/structure_cunge80.spec.ts b/spec/structure/structure_cunge80.spec.ts
index 0940fce515add3c730bd89b412ca0485aae88bf6..45ee33c62ba4531f2d79b44a6abfd3cd7ff5fed8 100644
--- a/spec/structure/structure_cunge80.spec.ts
+++ b/spec/structure/structure_cunge80.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureCunge80 } from "../../src/structure/structure_cunge80";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureCunge80 = new StructureCunge80(structPrm, false);
diff --git a/spec/structure/structure_kivi.spec.ts b/spec/structure/structure_kivi.spec.ts
index 1286b02b87ea3183cbb4ea328586eccb8d205414..d0700be77cbc097c6ecee5709196544fddb8e800 100644
--- a/spec/structure/structure_kivi.spec.ts
+++ b/spec/structure/structure_kivi.spec.ts
@@ -6,11 +6,10 @@
  */
 // import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";
 
-import { StructureFlowMode, StructureFlowRegime, MessageCode } from "../../src";
+import { MessageCode, StructureFlowMode, StructureFlowRegime } from "../../src";
 import { CreateStructure } from "../../src/structure/factory_structure";
-import { LoiDebit, StructureType } from "../../src/structure/structure_props";
 import { StructureKivi } from "../../src/structure/structure_kivi";
-import { StructureKiviParams } from "../../src/structure/structure_kivi_params";
+import { LoiDebit, StructureType } from "../../src/structure/structure_props";
 import { testStructure } from "./structure_test";
 
 const structTest: StructureKivi = CreateStructure(
diff --git a/spec/structure/structure_orifice_free.spec.ts b/spec/structure/structure_orifice_free.spec.ts
index 0cefcda138e7e9ce69e938888858c6b059b26fae..708f8ae1a0c7e96a775ce169ed07abb72b212aa4 100644
--- a/spec/structure/structure_orifice_free.spec.ts
+++ b/spec/structure/structure_orifice_free.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureOrificeFree } from "../../src/structure/structure_orifice_free";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureOrificeFree = new StructureOrificeFree(structPrm, false);
diff --git a/spec/structure/structure_orifice_submerged.spec.ts b/spec/structure/structure_orifice_submerged.spec.ts
index 37537f16f9708a8d3739e40e4f2fd984d5fd48b9..d303605c006e0280ac1e8ad7acef8e8959e365a1 100644
--- a/spec/structure/structure_orifice_submerged.spec.ts
+++ b/spec/structure/structure_orifice_submerged.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureOrificeSubmerged } from "../../src/structure/structure_orifice_submerged";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureOrificeSubmerged = new StructureOrificeSubmerged(structPrm, false);
diff --git a/spec/structure/structure_test.ts b/spec/structure/structure_test.ts
index 6ff1af5f39e0eee3857d1fca6445608079c34e18..fd9a2a1b4d8fb415ae5203ba8cf0313cd861848d 100644
--- a/spec/structure/structure_test.ts
+++ b/spec/structure/structure_test.ts
@@ -42,6 +42,13 @@ class StructureTest extends Structure {
         return new Result(this.prms.Z1.v - this.prms.Z2.v, data);
     }
 
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
+     */
+    public calcA(): number {
+        return Math.min(Math.max(this.prms.h1.v, this.prms.h2.v), this.prms.W.v);
+    }
+
 }
 
 /* Test structure with :
diff --git a/spec/structure/structure_triangular_trunc_weir_free.spec.ts b/spec/structure/structure_triangular_trunc_weir_free.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f0e771dc22e8980e24039838f8173c26d7926660
--- /dev/null
+++ b/spec/structure/structure_triangular_trunc_weir_free.spec.ts
@@ -0,0 +1,31 @@
+/**
+ * IMPORTANT !
+ * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
+ * Pour exécuter ce code dans le débugger.
+ * Faire de même avec ./functions.ts
+ */
+// import { describe, expect, it, xdescribe } from "../mock_jasmine";
+
+import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
+import { StructureTriangularTruncWeirFree } from "../../src/structure/structure_triangular_trunc_weir_free";
+import { TriangularTruncStructureParams } from "../../src/structure/structure_triangular_trunc_weir_free_params";
+import { itCalcQ } from "./functions";
+
+const structPrm: TriangularTruncStructureParams =
+    new TriangularTruncStructureParams(0, 100.1, 100, 0.9, 101, 1.36);
+const structTest: StructureTriangularTruncWeirFree = new StructureTriangularTruncWeirFree(structPrm, false);
+
+describe("Class StructureTriangularTruncWeirFree: ", () => {
+    describe("Calcul Q a surface libre avec h1 croissant: ", () => {
+        const h1: number[] =
+            [100.1, 100.2, 100.3, 100.4, 100.5, 100.6, 100.7, 100.8, 100.9, 101, 101.1, 101.5, 101.8, 102];
+        const Q: number[] =
+            [0., 0.004, 0.024, 0.067, 0.138, 0.240, 0.379, 0.558, 0.778, 1.045, 1.356, 2.914, 4.346, 5.407];
+        const mode: StructureFlowMode = StructureFlowMode.WEIR;
+        const regime: StructureFlowRegime = StructureFlowRegime.FREE;
+        itCalcQ(structTest, h1[0], Infinity, Q[0], StructureFlowMode.NULL, StructureFlowRegime.NULL);
+        for (let i = 1; i < Q.length; i++) {
+            itCalcQ(structTest, h1[i], Infinity, Q[i], mode, regime);
+        }
+    });
+});
diff --git a/spec/structure/structure_triangular_weir_free.spec.ts b/spec/structure/structure_triangular_weir_free.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3ee65c5848d52d849767445f1c619cb2ff5f6b91
--- /dev/null
+++ b/spec/structure/structure_triangular_weir_free.spec.ts
@@ -0,0 +1,28 @@
+/**
+ * IMPORTANT !
+ * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
+ * Pour exécuter ce code dans le débugger.
+ * Faire de même avec le fichier rectangular_structure.ts
+ */
+// import { describe, expect, it, xdescribe } from "../mock_jasmine";
+
+import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
+import { StructureTriangularWeirFree } from "../../src/structure/structure_triangular_weir_free";
+import { TriangularStructureParams } from "../../src/structure/structure_triangular_weir_free_params";
+import { itCalcQ } from "./functions";
+
+const structPrm: TriangularStructureParams = new TriangularStructureParams(0, 100.1, 100.1, 45, 1.36);
+const structTest: StructureTriangularWeirFree = new StructureTriangularWeirFree(structPrm, false);
+
+describe("Class StructureTriangularWeirFree: ", () => {
+    describe("Calcul Q a surface libre avec h1 croissant: ", () => {
+        const h1: number[] = [100.1, 100.2, 100.3, 100.4, 100.5, 100.6, 100.7, 100.8, 100.9, 101, 102];
+        const Q: number[] = [0., 0.004, 0.024, 0.067, 0.138, 0.240, 0.379, 0.558, 0.778, 1.045, 6.767];
+        const mode: StructureFlowMode = StructureFlowMode.WEIR;
+        const regime: StructureFlowRegime = StructureFlowRegime.FREE;
+        itCalcQ(structTest, h1[0], Infinity, Q[0], StructureFlowMode.NULL, StructureFlowRegime.NULL);
+        for (let i = 1; i < Q.length; i++) {
+            itCalcQ(structTest, h1[i], Infinity, Q[i], mode, regime);
+        }
+    });
+});
diff --git a/spec/structure/structure_weir_free.spec.ts b/spec/structure/structure_weir_free.spec.ts
index 6b04ce6a65737f30b8e687bbeb1aba08ba68f4be..a6f0f01f789751263a68a6a1288138bf80a13e14 100644
--- a/spec/structure/structure_weir_free.spec.ts
+++ b/spec/structure/structure_weir_free.spec.ts
@@ -10,7 +10,7 @@ import { RectangularStructureParams } from "../../src/structure/rectangular_stru
 import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
 import { StructureWeirFree } from "../../src/structure/structure_weir_free";
 import { Result } from "../../src/util/result";
-import { itCalcQ } from "./rectangular_structure";
+import { itCalcQ } from "./functions";
 
 const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
 const structTest: StructureWeirFree = new StructureWeirFree(structPrm, false);
diff --git a/src/base.ts b/src/base.ts
index 7ab2bd593ae09221a212033076f395370f355f3a..068ce95cedc2f01654d9bb5005fff9ddbdb45a17 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -5,9 +5,11 @@
  */
 
 export interface IDebug {
-    debug(s: any): void;
 
     readonly DBG: boolean;
+
+    debug(s: any): void;
+
 }
 
 // tslint:disable-next-line:max-classes-per-file
diff --git a/src/compute-node.ts b/src/compute-node.ts
index e7efe419b52f24d324a8db8ca78420c29fece627..6d98e09d1519e9f34f343bef92eca91cad07da8d 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -1,17 +1,18 @@
 import { Debug, IDebug } from "./base";
-import { ParamsEquation, IParamDefinitionIterator } from "./param/params-equation";
-import { ParamDefinition } from "./param/param-definition";
 import { JalhydObject } from "./jalhyd_object";
+import { ParamDefinition } from "./param/param-definition";
+import { IParamDefinitionIterator, ParamsEquation } from "./param/params-equation";
 
 /**
  * type de calculette
  */
 export enum CalculatorType {
     ConduiteDistributrice, LechaptCalmon, SectionParametree, RegimeUniforme, CourbeRemous,
-    PabDimensions, // passe à bassin rectangulaire
-    PabPuissance, // passe à bassin : puissance dissipée
-    Structure,  // ouvrages hydrauliques simples
-    ParallelStructure  // ouvrages hydrauliques en parallèle
+    PabDimensions,      // passe à bassin rectangulaire
+    PabPuissance,       // passe à bassin : puissance dissipée
+    Structure,          // ouvrages hydrauliques simples
+    ParallelStructure,  // ouvrages hydrauliques en parallèle
+    Dever               // Outil Cassiopée Dever
 }
 
 /**
@@ -50,16 +51,20 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
     }
 
     public getParameter(name: string): ParamDefinition {
-        for (const p of this.parameterIterator)
-            if (p.symbol === name)
+        for (const p of this.parameterIterator) {
+            if (p.symbol === name) {
                 return p;
+            }
+        }
         return undefined;
     }
 
     public getFirstAnalyticalParameter(): ParamDefinition {
-        for (const p of this.parameterIterator)
-            if (p.isAnalytical())
+        for (const p of this.parameterIterator) {
+            if (p.isAnalytical()) {
                 return p;
+            }
+        }
         return undefined;
     }
 
@@ -67,15 +72,15 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
         return this._prms.iterator;
     }
 
-    protected abstract setParametersCalculability(): void;
-
     // interface IDebug
-
-    debug(s: any) {
+    public debug(s: any) {
         this._debug.debug(s);
     }
 
     public get DBG(): boolean {
         return this._debug.DBG;
     }
+
+    protected abstract setParametersCalculability(): void;
+
 }
diff --git a/src/cond_distri.ts b/src/cond_distri.ts
index f88c82296655cee706445c6a4cf0abfd0a197bd5..f1ab56df89c5e2ceb141be483d761821514c7878 100644
--- a/src/cond_distri.ts
+++ b/src/cond_distri.ts
@@ -1,35 +1,37 @@
-import { Result } from "./util/result";
-import { ParamsEquation } from "./param/params-equation";
-import { ParamDefinition, ParamCalculability } from "./param/param-definition";
-import { ParamDomainValue } from "./param/param-domain";
 import { Nub } from "./nub";
+import { ParamCalculability, ParamDefinition } from "./param/param-definition";
+import { ParamDomainValue } from "./param/param-domain";
+import { ParamsEquation } from "./param/params-equation";
+import { Result } from "./util/result";
 
 /**
  * paramètres pour la conduite distributrice
  */
 export class ConduiteDistribParams extends ParamsEquation {
     /** Débit */
-    Q: ParamDefinition;
+    public Q: ParamDefinition;
 
     /** Diamètre */
-    D: ParamDefinition;
+    public D: ParamDefinition;
 
     /** Perte de charge */
-    J: ParamDefinition;
+    public J: ParamDefinition;
 
     /** Longueur de la conduite */
-    Lg: ParamDefinition;
+    // tslint:disable-next-line:variable-name
+    public Lg: ParamDefinition;
 
     /** Viscosité dynamique nu */
-    Nu: ParamDefinition;
+    // tslint:disable-next-line:variable-name
+    public Nu: ParamDefinition;
 
     constructor(rQ: number, rD: number, rJ: number, rLg: number, rNu: number) {
         super();
-        this.Q = new ParamDefinition('Q', ParamDomainValue.POS, rQ);
-        this.D = new ParamDefinition('D', ParamDomainValue.POS, rD);
-        this.J = new ParamDefinition('J', ParamDomainValue.POS, rJ);
-        this.Lg = new ParamDefinition('Lg', ParamDomainValue.POS, rLg);
-        this.Nu = new ParamDefinition('Nu', ParamDomainValue.POS, rNu);
+        this.Q = new ParamDefinition("Q", ParamDomainValue.POS, rQ);
+        this.D = new ParamDefinition("D", ParamDomainValue.POS, rD);
+        this.J = new ParamDefinition("J", ParamDomainValue.POS, rJ);
+        this.Lg = new ParamDefinition("Lg", ParamDomainValue.POS, rLg);
+        this.Nu = new ParamDefinition("Nu", ParamDomainValue.POS, rNu);
 
         this.addParamDefinition(this.Q);
         this.addParamDefinition(this.D);
@@ -42,27 +44,18 @@ export class ConduiteDistribParams extends ParamsEquation {
 /**
  * classe de calcul sur la conduite distributrice
  */
+// tslint:disable-next-line:max-classes-per-file
 export class ConduiteDistrib extends Nub {
+
     constructor(prms: ConduiteDistribParams, dbg: boolean = false) {
         super(prms, dbg);
     }
 
-    /**
-     * paramétrage de la calculabilité des paramètres
-     */
-    protected setParametersCalculability() {
-        this.prms.J.calculability = ParamCalculability.EQUATION;
-        this.prms.D.calculability = ParamCalculability.EQUATION;
-        this.prms.Q.calculability = ParamCalculability.EQUATION;
-        this.prms.Lg.calculability = ParamCalculability.EQUATION;
-        this.prms.Nu.calculability = ParamCalculability.EQUATION;
-    }
-
     /**
      * paramètres castés au bon type
      */
     get prms(): ConduiteDistribParams {
-        return <ConduiteDistribParams>this._prms;
+        return this._prms as ConduiteDistribParams;
     }
 
     /**
@@ -70,36 +63,53 @@ export class ConduiteDistrib extends Nub {
      * @param sVarCalc nom du paramètre
      * @return valeur calculée
      */
-    Equation(sVarCalc: string): Result {
+    public Equation(sVarCalc: string): Result {
         let v: number;
 
-        let K = 0.3164 * Math.pow(4, 1.75) / (5.5 * 9.81 * Math.pow(3.1415, 1.75)); // Constante de la formule
+        const K = 0.3164 * Math.pow(4, 1.75) / (5.5 * 9.81 * Math.pow(3.1415, 1.75)); // Constante de la formule
 
         switch (sVarCalc) {
             case "J":
-                v = K * Math.pow(this.prms.Nu.v, 0.25) * Math.pow(this.prms.Q.v, 1.75) * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75);
+                v = K * Math.pow(this.prms.Nu.v, 0.25) * Math.pow(this.prms.Q.v, 1.75)
+                    * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75);
                 break;
 
             case "D":
-                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25) * Math.pow(this.prms.Q.v, 1.75) * this.prms.Lg.v), 1 / 4.75);
+                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25)
+                    * Math.pow(this.prms.Q.v, 1.75) * this.prms.Lg.v), 1 / 4.75);
                 break;
 
             case "Q":
-                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25) * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75)), 1 / 1.75)
+                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25)
+                    * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75)), 1 / 1.75);
                 break;
 
             case "Lg":
-                v = this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25) * Math.pow(this.prms.Q.v, 1.75) / Math.pow(this.prms.D.v, 4.75));
+                v = this.prms.J.v / (K * Math.pow(this.prms.Nu.v, 0.25)
+                    * Math.pow(this.prms.Q.v, 1.75) / Math.pow(this.prms.D.v, 4.75));
                 break;
 
             case "Nu":
-                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Q.v, 1.75) * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75)), 1 / 0.25);
+                v = Math.pow(this.prms.J.v / (K * Math.pow(this.prms.Q.v, 1.75)
+                    * this.prms.Lg.v / Math.pow(this.prms.D.v, 4.75)), 1 / 0.25);
                 break;
 
             default:
-                throw 'ConduiteDistrib.Equation() : invalid parameter name ' + sVarCalc;
+                throw new Error("ConduiteDistrib.Equation() : invalid parameter name " + sVarCalc);
         }
 
         return new Result(v);
     }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.J.calculability = ParamCalculability.EQUATION;
+        this.prms.D.calculability = ParamCalculability.EQUATION;
+        this.prms.Q.calculability = ParamCalculability.EQUATION;
+        this.prms.Lg.calculability = ParamCalculability.EQUATION;
+        this.prms.Nu.calculability = ParamCalculability.EQUATION;
+    }
+
 }
diff --git a/src/jalhyd_object.ts b/src/jalhyd_object.ts
index 0432d3f76326f2439eb3b8505e3bcdeaca46abce..994ee0be245817bfaa403daa0dfb29f4eca6d305 100644
--- a/src/jalhyd_object.ts
+++ b/src/jalhyd_object.ts
@@ -26,7 +26,7 @@ export abstract class JalhydObject implements IJalhydObject {
     }
 
     public static get nextUID(): number {
-        let res = this._uidSequence;
+        const res = this._uidSequence;
         this._uidSequence++;
         return res;
     }
diff --git a/src/lechaptcalmon.ts b/src/lechaptcalmon.ts
index d59753b3deefdf87dca5f0e842dbf7f828f8a0e5..6e2c1122f40ed50da3941a919ae91b82927a109c 100644
--- a/src/lechaptcalmon.ts
+++ b/src/lechaptcalmon.ts
@@ -1,8 +1,8 @@
-import { Result } from "./util/result";
-import { ParamsEquation } from "./param/params-equation";
-import { ParamDefinition, ParamCalculability } from "./param/param-definition";
-import { ParamDomainValue } from "./param/param-domain";
 import { Nub } from "./nub";
+import { ParamCalculability, ParamDefinition } from "./param/param-definition";
+import { ParamDomainValue } from "./param/param-domain";
+import { ParamsEquation } from "./param/params-equation";
+import { Result } from "./util/result";
 
 /**
  * paramètres pour le calcul Lechapt et Calmon
@@ -31,13 +31,13 @@ export class LechaptCalmonParams extends ParamsEquation {
 
     constructor(rQ: number, rD: number, rJ: number, rLg: number, rL: number, rM: number, rN: number) {
         super();
-        this._Q = new ParamDefinition('Q', ParamDomainValue.POS, rQ);
-        this._D = new ParamDefinition('D', ParamDomainValue.POS, rD);
-        this._J = new ParamDefinition('J', ParamDomainValue.POS, rJ);
-        this._Lg = new ParamDefinition('Lg', ParamDomainValue.POS, rLg);
-        this._L = new ParamDefinition('L', ParamDomainValue.POS, rL);
-        this._M = new ParamDefinition('M', ParamDomainValue.POS, rM);
-        this._N = new ParamDefinition('N', ParamDomainValue.POS, rN);
+        this._Q = new ParamDefinition("Q", ParamDomainValue.POS, rQ);
+        this._D = new ParamDefinition("D", ParamDomainValue.POS, rD);
+        this._J = new ParamDefinition("J", ParamDomainValue.POS, rJ);
+        this._Lg = new ParamDefinition("Lg", ParamDomainValue.POS, rLg);
+        this._L = new ParamDefinition("L", ParamDomainValue.POS, rL);
+        this._M = new ParamDefinition("M", ParamDomainValue.POS, rM);
+        this._N = new ParamDefinition("N", ParamDomainValue.POS, rN);
 
         this.addParamDefinition(this._Q);
         this.addParamDefinition(this._D);
@@ -80,55 +80,61 @@ export class LechaptCalmonParams extends ParamsEquation {
 /**
  * Calcul des pertes de charge dans un tube à partir des tables de Lechapt et Calmon
  */
+// tslint:disable-next-line:max-classes-per-file
 export class LechaptCalmon extends Nub {
     constructor(prms: LechaptCalmonParams, dbg: boolean = false) {
         super(prms, dbg);
     }
 
-    /**
-     * paramétrage de la calculabilité des paramètres
-     */
-    protected setParametersCalculability() {
-        this.prms.Q.calculability = ParamCalculability.EQUATION;
-        this.prms.D.calculability = ParamCalculability.EQUATION;
-        this.prms.J.calculability = ParamCalculability.EQUATION;
-        this.prms.Lg.calculability = ParamCalculability.EQUATION;
-        this.prms.L.calculability = ParamCalculability.FREE;
-        this.prms.M.calculability = ParamCalculability.FREE;
-        this.prms.N.calculability = ParamCalculability.FREE;
-    }
-
     /**
      * paramètres castés au bon type
      */
     get prms(): LechaptCalmonParams {
-        return <LechaptCalmonParams>this._prms;
+        return this._prms as LechaptCalmonParams;
     }
 
-    Equation(sVarCalc: string): Result {
+    public Equation(sVarCalc: string): Result {
         let v: number;
 
         switch (sVarCalc) {
             case "Q":
-                v = Math.pow((((this.prms.J.v * Math.pow(this.prms.D.v, this.prms.N.v)) / this.prms.L.v) * (1000 / this.prms.Lg.v)), 1 / this.prms.M.v);
+                v = Math.pow((((this.prms.J.v * Math.pow(this.prms.D.v, this.prms.N.v)) / this.prms.L.v)
+                    * (1000 / this.prms.Lg.v)), 1 / this.prms.M.v);
                 break;
 
             case "D":
-                v = Math.pow((((this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v)) / this.prms.J.v) * (this.prms.Lg.v / 1000)), 1 / this.prms.N.v);
-                break
+                v = Math.pow((((this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v)) / this.prms.J.v)
+                    * (this.prms.Lg.v / 1000)), 1 / this.prms.N.v);
+                break;
 
             case "J":
-                v = ((this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v)) / Math.pow(this.prms.D.v, this.prms.N.v)) * (this.prms.Lg.v / 1000);
+                v = ((this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v)) / Math.pow(this.prms.D.v, this.prms.N.v))
+                    * (this.prms.Lg.v / 1000);
                 break;
 
             case "Lg":
-                v = ((this.prms.J.v * Math.pow(this.prms.D.v, this.prms.N.v)) / (this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v))) * 1000;
+                v = ((this.prms.J.v * Math.pow(this.prms.D.v, this.prms.N.v))
+                    / (this.prms.L.v * Math.pow(this.prms.Q.v, this.prms.M.v))) * 1000;
                 break;
 
             default:
-                throw "LechaptCalmon.Equation() : invalid variable name " + sVarCalc;
+                throw new Error("LechaptCalmon.Equation() : invalid variable name " + sVarCalc);
         }
 
         return new Result(v);
     }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.Q.calculability = ParamCalculability.EQUATION;
+        this.prms.D.calculability = ParamCalculability.EQUATION;
+        this.prms.J.calculability = ParamCalculability.EQUATION;
+        this.prms.Lg.calculability = ParamCalculability.EQUATION;
+        this.prms.L.calculability = ParamCalculability.FREE;
+        this.prms.M.calculability = ParamCalculability.FREE;
+        this.prms.N.calculability = ParamCalculability.FREE;
+    }
+
 }
diff --git a/src/nub_factory.ts b/src/nub_factory.ts
index 0f8b2afa960c9c5f40e16ff0db0916b8a395dc83..ecf899377dd4960e0cb0e6e89262f72f408b5423 100644
--- a/src/nub_factory.ts
+++ b/src/nub_factory.ts
@@ -19,7 +19,7 @@ import { StructureType, LoiDebit } from "./structure/structure_props";
 import { Structure } from "./structure/structure";
 import { ParallelStructure } from "./structure/parallel_structure";
 import { ParallelStructureParams } from "./structure/parallel_structure_params";
-import { RectangularStructureParams } from "./structure/structure_cem88d";
+import { DeverParams, Dever } from "./structure/dever";
 
 export class NubFactory {
     private _defaultPrecision: number = 0.001;
@@ -294,6 +294,16 @@ export class NubFactory {
                     return new ParallelStructure(prms);
                 }
 
+            case CalculatorType.Dever:
+                {
+                    const prms = new DeverParams(0.5, // Q
+                        102, // Z1
+                        10, // BR
+                        1 // ZR
+                    );
+                    return new Dever(prms);
+                }
+
             default:
                 throw new Error(`NubFactory.createNub() : calculatrice '${CalculatorType[calcType]}' / noeud de calcul '${ComputeNodeType[nodeType]}' non pris en charge`);
         }
diff --git a/src/pab/pab_dimension.ts b/src/pab/pab_dimension.ts
index 319e4e13e53989af868a497c8ab8087a98d5e41b..fe7594a48811d920992f6c6a256850f2ef2c59b2 100644
--- a/src/pab/pab_dimension.ts
+++ b/src/pab/pab_dimension.ts
@@ -1,8 +1,8 @@
-import { Result } from "../util/result";
-import { ParamsEquation } from "../param/params-equation";
-import { ParamDefinition, ParamCalculability } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
 import { Nub } from "../nub";
+import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../param/params-equation";
+import { Result } from "../util/result";
 
 export class PabDimensionParams extends ParamsEquation {
     [key: string]: any; // pour pouvoir faire this['methode]();
@@ -19,12 +19,12 @@ export class PabDimensionParams extends ParamsEquation {
     /** Volume V */
     private _V: ParamDefinition;
 
-    constructor(rL: number, rW: number, rY: number, rV: number = undefined) {
+    constructor(rL: number, rW: number, rY: number, rV?: number) {
         super();
-        this._L = new ParamDefinition('L', ParamDomainValue.POS, rL);
-        this._W = new ParamDefinition('W', ParamDomainValue.POS, rW);
-        this._Y = new ParamDefinition('Y', ParamDomainValue.POS, rY);
-        this._V = new ParamDefinition('V', ParamDomainValue.POS, rV);
+        this._L = new ParamDefinition("L", ParamDomainValue.POS, rL);
+        this._W = new ParamDefinition("W", ParamDomainValue.POS, rW);
+        this._Y = new ParamDefinition("Y", ParamDomainValue.POS, rY);
+        this._V = new ParamDefinition("V", ParamDomainValue.POS, rV);
 
         this.addParamDefinition(this._L);
         this.addParamDefinition(this._W);
@@ -48,6 +48,8 @@ export class PabDimensionParams extends ParamsEquation {
         return this._V;
     }
 }
+
+// tslint:disable-next-line:max-classes-per-file
 export class PabDimension extends Nub {
     constructor(prms: PabDimensionParams, dbg: boolean = false) {
         super(prms, dbg);
@@ -57,20 +59,10 @@ export class PabDimension extends Nub {
      * paramètres castés au bon type
      */
     get prms(): PabDimensionParams {
-        return <PabDimensionParams>this._prms;
+        return this._prms as PabDimensionParams;
     }
 
-    /**
-     * paramétrage de la calculabilité des paramètres
-     */
-    protected setParametersCalculability() {
-        this.prms.L.calculability = ParamCalculability.EQUATION;
-        this.prms.W.calculability = ParamCalculability.EQUATION;
-        this.prms.Y.calculability = ParamCalculability.EQUATION;
-        this.prms.V.calculability = ParamCalculability.EQUATION;
-    }
-
-    Equation(sVarCalc: string): Result {
+    public Equation(sVarCalc: string): Result {
         let v: number;
 
         switch (sVarCalc) {
@@ -80,7 +72,7 @@ export class PabDimension extends Nub {
 
             case "L":
                 v = this.prms.V.v / this.prms.W.v / this.prms.Y.v;
-                break
+                break;
 
             case "W":
                 v = this.prms.V.v / this.prms.L.v / this.prms.Y.v;
@@ -91,9 +83,20 @@ export class PabDimension extends Nub {
                 break;
 
             default:
-                throw "PabDimension.Equation() : invalid variable name " + sVarCalc;
+                throw new Error("PabDimension.Equation() : invalid variable name " + sVarCalc);
         }
 
         return new Result(v);
     }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.L.calculability = ParamCalculability.EQUATION;
+        this.prms.W.calculability = ParamCalculability.EQUATION;
+        this.prms.Y.calculability = ParamCalculability.EQUATION;
+        this.prms.V.calculability = ParamCalculability.EQUATION;
+    }
+
 }
diff --git a/src/pab/pab_puissance.ts b/src/pab/pab_puissance.ts
index df0b1ff400c404346c81387869d4b9228a65b599..a0729bfc104157fd3ab6a91b77afc02f72a1ae97 100644
--- a/src/pab/pab_puissance.ts
+++ b/src/pab/pab_puissance.ts
@@ -1,8 +1,8 @@
-import { Result } from "../util/result";
-import { ParamsEquation } from "../param/params-equation";
-import { ParamDefinition, ParamCalculability } from "../param/param-definition";
-import { ParamDomainValue } from "../param/param-domain";
 import { Nub } from "../nub";
+import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../param/params-equation";
+import { Result } from "../util/result";
 
 export class PabPuissanceParams extends ParamsEquation {
     [key: string]: any; // pour pouvoir faire this['methode]();
@@ -19,12 +19,12 @@ export class PabPuissanceParams extends ParamsEquation {
     /** Puissance dissipée PV */
     private _Pv: ParamDefinition;
 
-    constructor(rDH: number, rQ: number, rV: number, rPV: number = undefined) {
+    constructor(rDH: number, rQ: number, rV: number, rPV?: number) {
         super();
-        this._DH = new ParamDefinition('DH', ParamDomainValue.POS, rDH);
-        this._Q = new ParamDefinition('Q', ParamDomainValue.POS, rQ);
-        this._V = new ParamDefinition('V', ParamDomainValue.POS, rV);
-        this._Pv = new ParamDefinition('Pv', ParamDomainValue.POS, rPV);
+        this._DH = new ParamDefinition("DH", ParamDomainValue.POS, rDH);
+        this._Q = new ParamDefinition("Q", ParamDomainValue.POS, rQ);
+        this._V = new ParamDefinition("V", ParamDomainValue.POS, rV);
+        this._Pv = new ParamDefinition("Pv", ParamDomainValue.POS, rPV);
 
         this.addParamDefinition(this._DH);
         this.addParamDefinition(this._Q);
@@ -48,6 +48,8 @@ export class PabPuissanceParams extends ParamsEquation {
         return this._Pv;
     }
 }
+
+// tslint:disable-next-line:max-classes-per-file
 export class PabPuissance extends Nub {
     constructor(prms: PabPuissanceParams, dbg: boolean = false) {
         super(prms, dbg);
@@ -57,20 +59,10 @@ export class PabPuissance extends Nub {
      * paramètres castés au bon type
      */
     get prms(): PabPuissanceParams {
-        return <PabPuissanceParams>this._prms;
-    }
-
-    /**
-     * paramétrage de la calculabilité des paramètres
-     */
-    protected setParametersCalculability() {
-        this.prms.DH.calculability = ParamCalculability.DICHO;
-        this.prms.Q.calculability = ParamCalculability.DICHO;
-        this.prms.V.calculability = ParamCalculability.DICHO;
-        this.prms.Pv.calculability = ParamCalculability.EQUATION;
+        return this._prms as PabPuissanceParams;
     }
 
-    Equation(sVarCalc: string): Result {
+    public Equation(sVarCalc: string): Result {
         let v: number;
 
         switch (sVarCalc) {
@@ -81,9 +73,20 @@ export class PabPuissance extends Nub {
                 break;
 
             default:
-                throw "PabPuissance.Equation() : invalid variable name " + sVarCalc;
+                throw new Error("PabPuissance.Equation() : invalid variable name " + sVarCalc);
         }
 
         return new Result(v);
     }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.DH.calculability = ParamCalculability.DICHO;
+        this.prms.Q.calculability = ParamCalculability.DICHO;
+        this.prms.V.calculability = ParamCalculability.DICHO;
+        this.prms.Pv.calculability = ParamCalculability.EQUATION;
+    }
+
 }
diff --git a/src/session_nub.ts b/src/session_nub.ts
index 09675b0d5e5ec2935ee4c52ef38ab9ed74d08964..4a80ed6d6c84bcdb0d56487f0e3e798a1ba16bda 100644
--- a/src/session_nub.ts
+++ b/src/session_nub.ts
@@ -20,9 +20,11 @@ export class Props implements IObservable {
         // if (keys.length != Object.keys(p).length)
         //     return false;
 
-        for (const k of keys)
-            if (this._props[k] !== p[k])
+        for (const k of keys) {
+            if (this._props[k] !== p[k]) {
                 return false;
+            }
+        }
 
         return true;
     }
@@ -31,30 +33,6 @@ export class Props implements IObservable {
         return this._props[key];
     }
 
-    /**
-     * notification de changement de la valeur d'une propriété
-     * @param prop nom de la propriété modifiée
-     * @param val nouvelle valeur
-     * @param sender objet ayant changé la valeur
-     */
-    private notifyPropChange(prop: string, val: any, sender: any) {
-        this.notifyObservers({
-            "action": "propertyChange",
-            "name": prop,
-            "value": val
-        }, sender);
-    }
-
-    /**
-     * notification de changement de la valeur de toutes les propriétés
-     * @param sender objet ayant changé les valeurs
-     */
-    private notifyPropsChange(sender: any) {
-        this.notifyObservers({
-            "action": "propertiesChange",
-        }, sender);
-    }
-
     public setPropValue(key: string, val: any, sender?: any): boolean {
         const oldValue = this._props[key];
         const changed = oldValue !== val;
@@ -65,47 +43,26 @@ export class Props implements IObservable {
         return changed;
     }
 
-    /**
-     * compare 2 objets (clés et valeurs)
-     * @return true s'il existe une différence
-     */
-    private compareObjects(o1: { [key: string]: any }, o2: { [key: string]: any }) {
-        const oldKeys: string[] = Object.keys(o1).sort();
-        const newKeys: string[] = Object.keys(o2).sort();
-
-        // nombre de clés
-        let changed = oldKeys.length !== newKeys.length;
-        if (changed)
-            return true;
-
-        // nom des clés
-        for (const i in oldKeys)
-            if (oldKeys[i] !== newKeys[i])
-                return true;
-
-        // valeurs
-        for (const i in o1)
-            if (o1[i] != o2[i])
-                return true;
-
-        return false;
-    }
-
     /**
      * fixe la valeur de toutes les propriétés
      * @param props nouvelles valeurs
      * @param sender objet modificateur
      */
     public setProps(props: {}, sender?: any) {
-        if (props instanceof Props)
-            var p = props._props;
-        else
+        let p;
+        if (props instanceof Props) {
+            p = props._props;
+        } else {
             p = props;
+        }
         const changed = this.compareObjects(this._props, p);
         if (changed) {
             this._props = {};
-            for (const k in p)
-                this._props[k] = p[k];
+            for (const k in p) {
+                if (p.hasOwnProperty(k)) {
+                    this._props[k] = p[k];
+                }
+            }
 
             this.notifyPropsChange(sender);
         }
@@ -117,19 +74,25 @@ export class Props implements IObservable {
 
     public clone(): Props {
         const res = new Props();
-        for (const k in this._props)
-            res._props[k] = this._props[k];
+        for (const k in this._props) {
+            if (this._props.hasOwnProperty(k)) {
+                res._props[k] = this._props[k];
+            }
+        }
         return res;
     }
 
     public toString(): string {
         let res = "[";
         for (const k in this._props) {
-            if (res != "[")
-                res += ", ";
-            res += `${k}:${this._props[k]}`;
+            if (this._props.hasOwnProperty(k)) {
+                if (res !== "[") {
+                    res += ", ";
+                }
+                res += `${k}:${this._props[k]}`;
+            }
         }
-        res += "]"
+        res += "]";
         return res;
     }
 
@@ -155,22 +118,81 @@ export class Props implements IObservable {
     public notifyObservers(data: any, sender?: any) {
         this._observable.notifyObservers(data, sender);
     }
+
+    /**
+     * notification de changement de la valeur de toutes les propriétés
+     * @param sender objet ayant changé les valeurs
+     */
+    private notifyPropsChange(sender: any) {
+        this.notifyObservers({
+            action: "propertiesChange",
+        }, sender);
+    }
+
+    /**
+     * notification de changement de la valeur d'une propriété
+     * @param prop nom de la propriété modifiée
+     * @param val nouvelle valeur
+     * @param sender objet ayant changé la valeur
+     */
+    private notifyPropChange(prop: string, val: any, sender: any) {
+        this.notifyObservers({
+            action: "propertyChange",
+            name: prop,
+            value: val
+        }, sender);
+    }
+
+    /**
+     * compare 2 objets (clés et valeurs)
+     * @return true s'il existe une différence
+     */
+    private compareObjects(o1: { [key: string]: any }, o2: { [key: string]: any }) {
+        const oldKeys: string[] = Object.keys(o1).sort();
+        const newKeys: string[] = Object.keys(o2).sort();
+
+        // nombre de clés
+        const changed = oldKeys.length !== newKeys.length;
+        if (changed) {
+            return true;
+        }
+
+        // nom des clés
+        for (const i in oldKeys) {
+            if (oldKeys[i] !== newKeys[i]) {
+                return true;
+            }
+        }
+
+        // valeurs
+        for (const i in o1) {
+            if (o1[i] !== o2[i]) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
 }
 
 /**
  * Nub utilisé dans une session
  */
+// tslint:disable-next-line:max-classes-per-file
 export class SessionNub {
     private _props: Props;
 
     constructor(private _nub: Nub, props: Props | {}) {
-        if (this._nub == undefined)
+        if (this._nub === undefined) {
             throw new Error(`NgNub.constructor() : argument invalide`);
+        }
 
-        if (props instanceof Props)
+        if (props instanceof Props) {
             this._props = props.clone();
-        else
+        } else {
             this._props = new Props(props);
+        }
     }
 
     public get nub() {
diff --git a/src/structure/dever.ts b/src/structure/dever.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2f9355881bd8ee3a03edb1bad4d63603305b0a6f
--- /dev/null
+++ b/src/structure/dever.ts
@@ -0,0 +1,88 @@
+import { Nub } from "../nub";
+import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { Result } from "../util/result";
+import { DeverParams } from "./dever_params";
+import { ParallelStructure } from "./parallel_structure";
+
+export { DeverParams };
+
+export class Dever extends ParallelStructure {
+    constructor(prms: DeverParams, dbg: boolean = false) {
+        super(prms, dbg);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): DeverParams {
+        return this._prms as DeverParams;
+    }
+
+    /**
+     * Calcul pour tous les paramètres
+     * @param sVarCalc Paramètre à calculer
+     * @returns Résultat avec résultats complémentaires et message
+     */
+    public Equation(sVarCalc: string): Result {
+        const r: Result = super.Equation(sVarCalc);
+        let QT: number;
+        if (sVarCalc === "Q") {
+            QT = r.vCalc;
+        } else {
+            QT = this.prms.Q.v;
+        }
+        // Vitesse dans le cours d'eau amont
+        r.extraResults.V = QT / (this.prms.BR.v * Math.max(0, this.prms.Z1.v - this.prms.ZR.v));
+        // Energie cinétique dans le cours d'eau amont
+        r.extraResults.Ec = r.extraResults.V * r.extraResults.V / (2 * 9.81);
+        // Calcul du rapport des aires sur les seuils et de l'aire du cours d'eau amont
+        const rA: number = this.calcA() / (this.prms.BR.v * Math.max(0, this.prms.Z1.v - this.prms.ZR.v));
+        // Calcul de Cv
+        r.extraResults.Cv = this.calcCv(rA);
+        // Calcul de CV.QT
+        r.extraResults.CvQT = r.extraResults.Cv * QT;
+        return r;
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        super.setParametersCalculability();
+        this.prms.BR.calculability = ParamCalculability.FREE;
+        this.prms.ZR.calculability = ParamCalculability.FREE;
+        // On supprime Z2 de l'interface car régime dénoyé uniquement
+        this.prms.Z2.calculability = ParamCalculability.NONE;
+    }
+
+    /**
+     * Calcul de la somme des aires des ouvrages.
+     * @note N.B. : doit être appelé après calcul si le calcul porte sur Z1 ou
+     */
+    private calcA(): number {
+        let A: number = 0;
+        for (const st of this.structures) {
+            A += st.calcA();
+        }
+        return A;
+    }
+
+    /**
+     * Calcul du facteur de la correction du coefficient de débit dû à la vitesse d'approche
+     * @param rA Rapport entre l'aire d'écoulement des seuils et l'aire de la section amont
+     */
+    private calcCv(rA: number): number {
+        const aA: number[] = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8];
+        const aCv: number[] = [1, 1.005, 1.015, 1.022, 1.035, 1.065, 1.09, 1.14, 1.21];
+        // tslint:disable-next-line:prefer-for-of
+        for (let i = 1; i < aA.length; i++) {
+            if (rA < aA[i]) {
+                const k: number = (rA - aA[i - 1]) / (aA[i] - aA[i - 1]);
+                return aCv[i - 1] * (1 - k) + k * aCv[i];
+            }
+        }
+        // Rapport des aires supérieur à 0.8 => Cv = 1.21
+        return aCv[aCv.length - 1];
+    }
+
+}
diff --git a/src/structure/dever_params.ts b/src/structure/dever_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..02bad78a7edb5257425ce8807e2ae0a83db797ea
--- /dev/null
+++ b/src/structure/dever_params.ts
@@ -0,0 +1,29 @@
+import { ParamDefinition } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { ParallelStructureParams } from "./parallel_structure_params";
+
+/**
+ * Common parameters of hydraulic structure equations
+ */
+export class DeverParams extends ParallelStructureParams {
+    /** Largeur du cours d'eau amont (m) */
+    public BR: ParamDefinition;
+
+    /** Cote du lit du cours d'eau amont (m) */
+    public ZR: ParamDefinition;
+
+    /**
+     * Paramètres communs à toutes les équations de structure
+     * @param rQ Débit total (m3/s)
+     * @param rZ1 Cote de l'eau amont (m)
+     * @param rBR Largeur du cours d'eau amont (m)
+     * @param rZR Cote du lit du cours d'eau amont (m)
+     */
+    constructor(rQ: number, rZ1: number, rBR: number, rZR: number) {
+        super(rQ, rZ1, - Infinity);
+        this.BR = new ParamDefinition("BR", ParamDomainValue.ANY, rBR);
+        this.addParamDefinition(this.BR);
+        this.ZR = new ParamDefinition("ZR", ParamDomainValue.ANY, rZR);
+        this.addParamDefinition(this.ZR);
+    }
+}
diff --git a/src/structure/factory_structure.ts b/src/structure/factory_structure.ts
index abda575bea35b86a4986a4b28f3ef1e73465997f..912003139efb808efcbcdb37fe04b14a001fe4cc 100644
--- a/src/structure/factory_structure.ts
+++ b/src/structure/factory_structure.ts
@@ -7,52 +7,59 @@ import { StructureKivi } from "./structure_kivi";
 import { StructureKiviParams } from "./structure_kivi_params";
 import { StructureOrificeFree } from "./structure_orifice_free";
 import { StructureOrificeSubmerged } from "./structure_orifice_submerged";
+import { LoiDebit, StructureProperties, StructureType } from "./structure_props";
+// tslint:disable-next-line:max-line-length
+import { StructureTriangularTruncWeirFree, TriangularTruncStructureParams } from "./structure_triangular_trunc_weir_free";
+import { StructureTriangularWeirFree, TriangularStructureParams } from "./structure_triangular_weir_free";
 import { StructureWeirFree } from "./structure_weir_free";
-import { StructureType, LoiDebit, StructureProperties } from "./structure_props";
+
 
 export function CreateStructure(structureType: StructureType, loiDebit: LoiDebit, dbg: boolean = false): Structure {
+    const oCd: {[s: string]: number} = {SeuilR: 0.4, VanneR: 0.6, SeuilT: 1.36};
     const rectStructPrms: RectangularStructureParams = new RectangularStructureParams(
         0,  // Q
         100,        // ZDV
         102,        // Z1
         101.5,      // Z2
         2,          // L
-        0.4        // Cd pour un seuil rectangulaire
+        oCd.SeuilR        // Cd pour un seuil rectangulaire
         // W = Infinity par défaut pour un seuil
     );
+
+    // Control of validity of structure type and definition of parameters
     switch (structureType) {
         case StructureType.VanneRectangulaire:
             rectStructPrms.W.v = 0.5;
-            rectStructPrms.Cd.v = 0.6; // Cd pour une vanne rectangulaire
-            if (!(StructureProperties.isCompatibleValues(StructureType.VanneRectangulaire, loiDebit))) {
-                throw new Error(
-                    `la loi de débit ${LoiDebit[loiDebit]} n'est pas admissible pour les vannes rectangulaires`
-                );
-            }
+            rectStructPrms.Cd.v = oCd.VanneR; // Cd pour une vanne rectangulaire
             break;
         case StructureType.SeuilRectangulaire:
-            if (!(StructureProperties.isCompatibleValues(StructureType.SeuilRectangulaire, loiDebit))) {
-                throw new Error(
-                    `la loi de débit ${LoiDebit[loiDebit]} n'est pas admissible pour les seuils rectangulaires`
-                );
-            }
+        case StructureType.SeuilTriangulaire:
+        case StructureType.SeuilTriangulaireTrunc:
             break;
 
         default:
             throw new Error(`type de structure ${StructureType[structureType]} non pris en charge`);
     }
 
+    // Control validity of the couple Structure Type / Discharge equation
+    if (!(StructureProperties.isCompatibleValues(structureType, loiDebit))) {
+        throw new Error(
+            `La loi de débit ${LoiDebit[loiDebit]} n'est pas admissible pour le type ${StructureType[structureType]}`
+        );
+    }
+
+    // Instanciation of the equation
     switch (loiDebit) {
         case LoiDebit.Cem88d:
-            rectStructPrms.Cd.v = 0.4; // Cd Cem88d qu'on soit en seuil ou vanne
+            rectStructPrms.Cd.v = oCd.SeuilR; // Cd Cem88d qu'on soit en seuil ou vanne
             return new StructureCem88d(rectStructPrms, dbg);
 
         case LoiDebit.Cem88v:
-            rectStructPrms.Cd.v = 0.6; // Cd Cem88d qu'on soit en seuil ou vanne
+            rectStructPrms.Cd.v = oCd.VanneR; // Cd Cem88d qu'on soit en seuil ou vanne
             return new StructureCem88v(rectStructPrms, dbg);
 
         case LoiDebit.Cunge80:
-            rectStructPrms.Cd.v = 0.6; // Cd Cunge80 qu'on soit en seuil ou vanne
+            rectStructPrms.Cd.v = oCd.VanneR; // Cd Cunge80 qu'on soit en seuil ou vanne
             return new StructureCunge80(rectStructPrms, dbg);
 
         case LoiDebit.OrificeFree:
@@ -66,15 +73,36 @@ export function CreateStructure(structureType: StructureType, loiDebit: LoiDebit
 
         case LoiDebit.KIVI:
             const structKiviPrm: StructureKiviParams = new StructureKiviParams(
-                8.516, // Q
-                101,    // ZDV
-                103,    // Z1
-                102,    // Z2
-                2,      // L
-                0.4,  // alpha
-                0.001,  // béta
-                100);    // ZRAM : cote Radier Amont
+                8.516,      // Q
+                101,        // ZDV
+                103,        // Z1
+                102,        // Z2
+                2,          // L
+                oCd.SeuilR, // alpha
+                0.001,      // béta
+                100);       // ZRAM : cote Radier Amont
             return new StructureKivi(structKiviPrm, dbg);
+            case LoiDebit.TriangularWeirFree:
+            const structTriangPrms: TriangularStructureParams = new TriangularStructureParams(
+                0,          // Q
+                100,        // ZDV
+                102,        // Z1
+                45,         // Alpha2
+                oCd.SeuilT  // Cd pour un seuil triangulaire
+                // W = Infinity par défaut pour un seuil
+            );
+            return new StructureTriangularWeirFree(structTriangPrms, dbg);
+            case LoiDebit.TriangularTruncWeirFree:
+            const structTriTruncPrms: TriangularTruncStructureParams = new TriangularTruncStructureParams(
+                0,          // Q
+                100.1,        // ZDV
+                102,        // Z1
+                0.9,        // BT
+                101,        // ZT
+                oCd.SeuilT  // Cd pour un seuil triangulaire
+                // W = Infinity par défaut pour un seuil
+            );
+            return new StructureTriangularTruncWeirFree(structTriTruncPrms, dbg);
 
         default:
             throw new Error(`type de LoiDebit ${LoiDebit[loiDebit]} non pris en charge`);
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index 982c914607180694ae18ec069d0e2cbec5f94358..5c2e115f731f7ffa81ebee42a9e2e35179f456ea 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -52,8 +52,9 @@ export class ParallelStructure extends Nub {
     public get parameterIterator(): IParamDefinitionIterator {
         const prms: ParamsEquation[] = [];
         prms.push(this._prms);
-        for (const st of this.structures)
+        for (const st of this.structures) {
             prms.push(st.parameters);
+        }
         return new ParamsEquationArrayIterator(prms);
     }
 
@@ -63,10 +64,11 @@ export class ParallelStructure extends Nub {
      * @param after position après laquelle insérer la structure, à la fin sinon
      */
     public addStructure(structure: Structure, after?: number) {
-        if (after !== undefined)
+        if (after !== undefined) {
             this.structures.splice(after + 1, 0, structure);
-        else
+        } else {
             this.structures.push(structure);
+        }
     }
 
     /**
@@ -86,9 +88,11 @@ export class ParallelStructure extends Nub {
      * @return true si la structure donnée est dans la liste
      */
     public hasStructure(structure: Nub): boolean {
-        for (const s of this.structures)
-            if (s.uid == structure.uid)
+        for (const s of this.structures) {
+            if (s.uid === structure.uid) {
                 return true;
+            }
+        }
         return false;
     }
 
@@ -98,7 +102,7 @@ export class ParallelStructure extends Nub {
     public moveStructureUp(structure: Structure) {
         let i = 0;
         for (const s of this.structures) {
-            if (s.uid == structure.uid && i > 0) {
+            if (s.uid === structure.uid && i > 0) {
                 const t = this.structures[i - 1];
                 this.structures[i - 1] = this.structures[i];
                 this.structures[i] = t;
@@ -114,7 +118,7 @@ export class ParallelStructure extends Nub {
     public moveStructureDown(structure: Structure) {
         let i = 0;
         for (const s of this.structures) {
-            if (s.uid == structure.uid && i < this.structures.length - 1) {
+            if (s.uid === structure.uid && i < this.structures.length - 1) {
                 const t = this.structures[i];
                 this.structures[i] = this.structures[i + 1];
                 this.structures[i + 1] = t;
@@ -238,12 +242,14 @@ export class ParallelStructure extends Nub {
     private getStructureVarCalc(sVarCalc: string): IStructureVarCalc {
         let sIndex: string;
         let sPrm: string;
-        if (sVarCalc.indexOf(".") == -1)
+        if (sVarCalc.indexOf(".") === -1) {
             throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc}, (pas de la forme n.X)`);
+        }
         [sIndex, sPrm] = sVarCalc.split(".");
         const i = parseInt(sIndex, 10);
-        if (i === NaN)
+        if (isNaN(i)) {
             throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc} (${sIndex} n'est pas un nombre)`);
+        }
         return { index: i, prm: sPrm };
     }
 
diff --git a/src/structure/parallel_structure_params.ts b/src/structure/parallel_structure_params.ts
index 71c037a59395b8602aaf2557a00d494eecec529e..40426c827c01707f1bd35ada4052c4eb130ef2fb 100644
--- a/src/structure/parallel_structure_params.ts
+++ b/src/structure/parallel_structure_params.ts
@@ -1,7 +1,6 @@
-import { Nub } from "../nub";
-import { ParamsEquation } from "../param/params-equation";
 import { ParamDefinition } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
+import { ParamsEquation } from "../param/params-equation";
 
 /**
  * Common parameters of hydraulic structure equations
diff --git a/src/structure/rectangular_structure.ts b/src/structure/rectangular_structure.ts
index da1956dc03148990cfa8b4b4fcbcccbf174ad72f..d127725e6d4a0643ce1ee87ad18c2ad886483b6c 100644
--- a/src/structure/rectangular_structure.ts
+++ b/src/structure/rectangular_structure.ts
@@ -20,6 +20,13 @@ export abstract class RectangularStructure extends Structure {
         return this._prms as RectangularStructureParams;
     }
 
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
+     */
+    public calcA(): number {
+            return Math.min(Math.max(this.prms.h1.v, this.prms.h2.v), this.prms.W.v) * this.prms.L.v;
+    }
+
     /**
      * paramétrage de la calculabilité des paramètres
      */
diff --git a/src/structure/rectangular_structure_params.ts b/src/structure/rectangular_structure_params.ts
index 5a2df407a594766af77d17233280c27a82c00f69..0f157d445e65601c36c4a716f011eeaa273dc272 100644
--- a/src/structure/rectangular_structure_params.ts
+++ b/src/structure/rectangular_structure_params.ts
@@ -1,6 +1,5 @@
 import { ParamDefinition } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
-import { Structure } from "./structure";
 import { StructureParams } from "./structure_params";
 
 /**
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index 69ce4fea56d0962496d4b83b722be91fc48254d4..8965a98e88998f5072715bb6c92c961b4df3985e 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -67,6 +67,11 @@ export abstract class Structure extends Nub {
         return this._prms as StructureParams;
     }
 
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
+     */
+    public abstract calcA(): number;
+
     /**
      * Calcul d'une équation quelque soit l'inconnue à calculer.
      * Gestion du débit nul et de l'inversion de débit
diff --git a/src/structure/structure_kivi.ts b/src/structure/structure_kivi.ts
index 6df85dd19b29c59246d92d38d3bfb705b06259db..e1bade6082007e4557476505f40156c0785a2c0a 100644
--- a/src/structure/structure_kivi.ts
+++ b/src/structure/structure_kivi.ts
@@ -52,6 +52,13 @@ export class StructureKivi extends Structure {
 
     }
 
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
+     */
+    public calcA(): number {
+        return Math.min(Math.max(this.prms.h1.v, this.prms.h2.v), this.prms.W.v) * this.prms.L.v;
+    }
+
     protected getFlowRegime(): StructureFlowRegime {
         if (this.prms.h2.v > 0) {
             return StructureFlowRegime.SUBMERGED;
diff --git a/src/structure/structure_props.ts b/src/structure/structure_props.ts
index 7c7d63a4b41962f54cd52afee7203785cadc1ac5..d7835ef44d4fed4e57e5f6bacc58b0d644eb3e78 100644
--- a/src/structure/structure_props.ts
+++ b/src/structure/structure_props.ts
@@ -1,5 +1,5 @@
 export enum StructureType {
-    SeuilRectangulaire, VanneRectangulaire
+    SeuilRectangulaire, VanneRectangulaire, SeuilTriangulaire, SeuilTriangulaireTrunc
     // VanneCirculaire,
     // VanneTrapezoidale, SeuilTrapezoidal
 }
@@ -18,7 +18,11 @@ export enum LoiDebit {
     // loi de débit pour seuil dénoyé
     WeirFree,
     // Loi Kindsvater-Carter et Villemonte
-    KIVI
+    KIVI,
+    // Loi de débit seuil triangulaire dénoyé
+    TriangularWeirFree,
+    // Loi de débit seuil triangulaire tronqué
+    TriangularTruncWeirFree
 }
 
 export const loiAdmissibles: { [key: string]: LoiDebit[] } = {
@@ -26,6 +30,12 @@ export const loiAdmissibles: { [key: string]: LoiDebit[] } = {
         LoiDebit.Cem88d, LoiDebit.Cem88v, LoiDebit.Cunge80, LoiDebit.WeirFree,
         LoiDebit.KIVI
     ],
+    SeuilTriangulaire: [
+        LoiDebit.TriangularWeirFree
+    ],
+    SeuilTriangulaireTrunc: [
+        LoiDebit.TriangularTruncWeirFree
+    ],
     VanneRectangulaire: [
         LoiDebit.Cem88d, LoiDebit.Cem88v, LoiDebit.Cunge80, LoiDebit.OrificeFree,
         LoiDebit.OrificeSubmerged
@@ -45,10 +55,12 @@ export class StructureProperties {
      */
     public static findCompatibleStructure(loi: LoiDebit): StructureType {
         for (const st in loiAdmissibles) {
-            const lds: LoiDebit[] = loiAdmissibles[st];
-            for (const ld of lds)
-                if (ld === loi)
-                    return (<any>StructureType)[st];
+            if (loiAdmissibles.hasOwnProperty(st)) {
+                const lds: LoiDebit[] = loiAdmissibles[st];
+                for (const ld of lds) {
+                    if (ld === loi) { return (StructureType as any)[st]; }
+                }
+            }
         }
         return undefined;
     }
@@ -60,4 +72,4 @@ export class StructureProperties {
         const sst: string = StructureType[struct];
         return loiAdmissibles[sst][0];
     }
-}
\ No newline at end of file
+}
diff --git a/src/structure/structure_triangular_trunc_weir_free.ts b/src/structure/structure_triangular_trunc_weir_free.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3a6a21f3f8f136fc8d7898f2626c74e6153666c
--- /dev/null
+++ b/src/structure/structure_triangular_trunc_weir_free.ts
@@ -0,0 +1,74 @@
+import { ParamCalculability } from "../param/param-definition";
+import { Result } from "../util/result";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
+import { TriangularTruncStructureParams } from "./structure_triangular_trunc_weir_free_params";
+
+export { TriangularTruncStructureParams };
+
+/**
+ * Equation classique seuil triangulaire dénoyé
+ */
+export class StructureTriangularTruncWeirFree extends Structure {
+
+    constructor(prms: TriangularTruncStructureParams, dbg: boolean = false) {
+        super(prms, dbg);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): TriangularTruncStructureParams {
+        return this._prms as TriangularTruncStructureParams;
+    }
+
+    /**
+     * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
+     * @param sVarCalc Variable à calculer (doit être "Q")
+     */
+    public Equation(sVarCalc: string): Result {
+        Structure.CheckEquation(sVarCalc);
+        const data = this.getResultData();
+
+        let v: number = this.prms.Cd.v * this.prms.BT.v / (this.prms.ZT.v - this.prms.ZDV.v);
+        if (this.prms.Z1.v <= this.prms.ZT.v) {
+            v = v * Math.pow(this.prms.h1.v, 2.5);
+        } else {
+            v = v * (Math.pow(this.prms.h1.v, 2.5) - Math.pow(this.prms.Z1.v - this.prms.ZT.v, 2.5));
+        }
+
+        return new Result(v, data);
+    }
+
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil
+     */
+    public calcA(): number {
+        if (this.prms.Z1.v <= this.prms.ZT.v) {
+            const h: number = Math.max(this.prms.h1.v, this.prms.h2.v);
+            return h * h * this.prms.BT.v / (this.prms.ZT.v - this.prms.ZDV.v);
+        } else {
+            const Z: number = Math.max(this.prms.Z1.v, this.prms.Z2.v);
+            return this.prms.BT.v * (this.prms.ZT.v - this.prms.ZDV.v)
+                + 2 * this.prms.BT.v * (Z - this.prms.ZT.v);
+        }
+    }
+
+    protected getFlowRegime() {
+        return StructureFlowRegime.FREE;
+    }
+
+    protected getFlowMode() {
+        return StructureFlowMode.WEIR;
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        super.setParametersCalculability();
+        this.prms.BT.calculability = ParamCalculability.DICHO;
+        this.prms.ZT.calculability = ParamCalculability.DICHO;
+        this.prms.Cd.calculability = ParamCalculability.DICHO;
+    }
+
+}
diff --git a/src/structure/structure_triangular_trunc_weir_free_params.ts b/src/structure/structure_triangular_trunc_weir_free_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b3687b97e08529329e649b02d5ccf0b36c80193
--- /dev/null
+++ b/src/structure/structure_triangular_trunc_weir_free_params.ts
@@ -0,0 +1,41 @@
+import { ParamDefinition } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { StructureParams } from "./structure_params";
+
+/**
+ * Parameters for rectangular structures (common for all rectangular structure equations)
+ */
+export class TriangularTruncStructureParams extends StructureParams {
+    /** Demi-ouverture du triangle (m) */
+    public BT: ParamDefinition;
+
+    /** Cote haute du triangle (m) */
+    public ZT: ParamDefinition;
+
+    /** Discharge coefficient */
+    // tslint:disable-next-line:variable-name
+    public Cd: ParamDefinition;
+
+    /**
+     * Constructeur d'une structure rectangulaire
+     * @param rQ    Débit (m3/s)
+     * @param rZDV  Cote de la crête du déversoir ou du radier de la vanne (m)
+     * @param rZ1   Cote de l'eau amont (m)
+     * @param rBT   Demi-ouverture du triangle (m)
+     * @param rZT   Cote haute du triangle (m)
+     * @param rCd   Coefficient de débit (-)
+     * @param rW    Ouverture de la vanne (m) (Valeur par défaut +infinity pour les déversoirs)
+     */
+    constructor(
+        rQ: number, rZDV: number, rZ1: number,
+        rBT: number, rZT: number, rCd: number, rW: number = Infinity
+    ) {
+        super(rQ, rZDV, rZ1, - Infinity, rW);
+        this.BT = new ParamDefinition("BT", ParamDomainValue.POS, rBT);
+        this.addParamDefinition(this.BT);
+        this.ZT = new ParamDefinition("ZT", ParamDomainValue.POS, rZT);
+        this.addParamDefinition(this.ZT);
+        this.Cd = new ParamDefinition("Cd", ParamDomainValue.POS, rCd);
+        this.addParamDefinition(this.Cd);
+    }
+}
diff --git a/src/structure/structure_triangular_weir_free.ts b/src/structure/structure_triangular_weir_free.ts
new file mode 100644
index 0000000000000000000000000000000000000000..beb63a2b7c9236e0357da08f1f0d0b2aa0c2d49a
--- /dev/null
+++ b/src/structure/structure_triangular_weir_free.ts
@@ -0,0 +1,69 @@
+import { ParamCalculability } from "../param/param-definition";
+import { Result } from "../util/result";
+import { Structure, StructureFlowMode, StructureFlowRegime } from "./structure";
+import { TriangularStructureParams } from "./structure_triangular_weir_free_params";
+
+export { TriangularStructureParams };
+
+/**
+ * Equation classique seuil triangulaire dénoyé
+ */
+export class StructureTriangularWeirFree extends Structure {
+
+    constructor(prms: TriangularStructureParams, dbg: boolean = false) {
+        super(prms, dbg);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): TriangularStructureParams {
+        return this._prms as TriangularStructureParams;
+    }
+
+    /**
+     * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé
+     * @param sVarCalc Variable à calculer (doit être "Q")
+     */
+    public Equation(sVarCalc: string): Result {
+        Structure.CheckEquation(sVarCalc);
+        const data = this.getResultData();
+
+        const v = this.prms.Cd.v * this.getTanFromDegrees(this.prms.alpha2.v)
+            * Math.pow(this.prms.h1.v, 2.5);
+
+        return new Result(v, data);
+    }
+
+    /**
+     * Calcul de l'aire d'écoulement sur le seuil
+     */
+    public calcA(): number {
+        return Math.pow(Math.max(this.prms.h1.v, this.prms.h2.v), 2) * this.getTanFromDegrees(this.prms.alpha2.v);
+    }
+
+    protected getFlowRegime() {
+        return StructureFlowRegime.FREE;
+    }
+
+    protected getFlowMode() {
+        return StructureFlowMode.WEIR;
+    }
+
+    /**
+     * Compute Tangent with angle in degrees
+     * @param degrees Angle (degrees)
+     */
+    protected getTanFromDegrees(degrees: number) {
+        return Math.tan(degrees * Math.PI / 180);
+    }
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        super.setParametersCalculability();
+        this.prms.alpha2.calculability = ParamCalculability.DICHO;
+        this.prms.Cd.calculability = ParamCalculability.DICHO;
+    }
+}
diff --git a/src/structure/structure_triangular_weir_free_params.ts b/src/structure/structure_triangular_weir_free_params.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7cfe3544665cc5baf041d100f783d13cf3563dfe
--- /dev/null
+++ b/src/structure/structure_triangular_weir_free_params.ts
@@ -0,0 +1,35 @@
+import { ParamDefinition } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { StructureParams } from "./structure_params";
+
+/**
+ * Parameters for rectangular structures (common for all rectangular structure equations)
+ */
+export class TriangularStructureParams extends StructureParams {
+    /** half angle of the triangle top (degrees) */
+    public alpha2: ParamDefinition;
+
+    /** Discharge coefficient */
+    // tslint:disable-next-line:variable-name
+    public Cd: ParamDefinition;
+
+    /**
+     * Constructeur d'une structure rectangulaire
+     * @param rQ    Débit (m3/s)
+     * @param rZDV  Cote de la crête du déversoir ou du radier de la vanne (m)
+     * @param rZ1   Cote de l'eau amont (m)
+     * @param rAlpha2    Demi-angle au sommet du triangle (degrés)
+     * @param rCd   Coefficient de débit (-)
+     * @param rW    Ouverture de la vanne (m) (Valeur par défaut +infinity pour les déversoirs)
+     */
+    constructor(
+        rQ: number, rZDV: number, rZ1: number,
+        rAlpha2: number, rCd: number, rW: number = Infinity
+    ) {
+        super(rQ, rZDV, rZ1, - Infinity, rW);
+        this.alpha2 = new ParamDefinition("alpha2", ParamDomainValue.POS, rAlpha2);
+        this.addParamDefinition(this.alpha2);
+        this.Cd = new ParamDefinition("Cd", ParamDomainValue.POS, rCd);
+        this.addParamDefinition(this.Cd);
+    }
+}
diff --git a/src/util/message.ts b/src/util/message.ts
index f30b1fa04e624689e28e67de5de562b39eebf792..5224ca5aea76ef6e55510224537c61d2089c8104 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -114,7 +114,8 @@ export enum MessageCode {
     INFO_REMOUS_CALCUL_FLUVIAL,
 
     /**
-     * courbe de remous : Condition limite amont <= Hauteur critique : calcul de la partie torrentielle à partir de l'amont
+     * courbe de remous : Condition limite amont <= Hauteur critique :
+     * calcul de la partie torrentielle à partir de l'amont
      */
     INFO_REMOUS_CALCUL_TORRENTIEL,
 
@@ -174,12 +175,14 @@ export enum MessageCode {
     ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG,
 
     /**
-     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton) pour le calcul de la hauteur fluviale
+     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton)
+     * pour le calcul de la hauteur fluviale
      */
     ERROR_SECTION_NON_CONVERGENCE_NEWTON_HFLU,
 
     /**
-     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton) pour le calcul de la hauteur torrentielle
+     * section : Non convergence du calcul de la hauteur correspondante (Méthode de Newton)
+     * pour le calcul de la hauteur torrentielle
      */
     ERROR_SECTION_NON_CONVERGENCE_NEWTON_HTOR,
 
@@ -240,17 +243,18 @@ export enum MessageSeverity {
  * Résultat de calcul comprenant la valeur du résultat et des calculs annexes (flag, calculs intermédiaires...)
  */
 export class Message {
+
+    /** Variables intermédiaires, flags d'erreur */
+    public extraVar: { [key: string]: any };
+
     /**
      * code du message
      */
     private _code: MessageCode;
 
-    /** Variables intermédiaires, flags d'erreur */
-    public extraVar: { [key: string]: any };
-
     constructor(c: MessageCode) {
         this._code = c;
-        this.extraVar = {}
+        this.extraVar = {};
     }
 
     get code() { return this._code; }
@@ -259,12 +263,15 @@ export class Message {
      * retourne le niveau de criticité (erreur, warning, info) du message
      */
     public getSeverity(): MessageSeverity {
-        let m: string = MessageCode[this._code];
-        let prefix: string = m.split("_")[0];
-        for (let s in MessageSeverity) // pas nécessaire, mais permet d'avoir un contrôle de validité
-            if (MessageSeverity[s] == prefix)
+        const m: string = MessageCode[this._code];
+        const prefix: string = m.split("_")[0];
+        for (const s in MessageSeverity) { // pas nécessaire, mais permet d'avoir un contrôle de validité
+            if (MessageSeverity[s] === prefix) {
+                // tslint:disable-next-line:no-eval
                 return eval("MessageSeverity." + prefix);
-        throw "Message.getSeverity() : valeur de code '" + this._code + "' invalide";
+            }
+        }
+        throw new Error("Message.getSeverity() : valeur de code '" + this._code + "' invalide");
     }
 
     public toString(): string {
diff --git a/src/util/observer.ts b/src/util/observer.ts
index fea87f9cf42d50e533150b989c8586b9547fa71c..c34c7deef25f870607c24c7b13322ba840d2d056 100644
--- a/src/util/observer.ts
+++ b/src/util/observer.ts
@@ -30,25 +30,28 @@ export class Observable implements IObservable {
      * ajoute un observateur à la liste
      */
     public addObserver(o: Observer) {
-        if (this._observers.indexOf(o) == -1)
+        if (this._observers.indexOf(o) === -1) {
             this._observers.push(o);
+        }
     }
 
     /**
      * supprime un observateur de la liste
      */
     public removeObserver(o: Observer) {
-        this._observers = this._observers.filter(a => a !== o);
+        this._observers = this._observers.filter((a) => a !== o);
     }
 
     /**
      * notifie un événement aux observateurs
      */
     public notifyObservers(data: any, sender?: any) {
-        if (sender == undefined)
+        if (sender === undefined) {
             sender = this;
-        for (let o of this._observers)
+        }
+        for (const o of this._observers) {
             o.update(sender, data);
+        }
     }
 }
 
diff --git a/src/util/pair.ts b/src/util/pair.ts
index ab9c56b168bf9a102bf7bd622308b7de6c584e3c..1ea1b6b35ab3affcfe0987a2db1825d5e9cb76ea 100644
--- a/src/util/pair.ts
+++ b/src/util/pair.ts
@@ -17,16 +17,16 @@ export class Pair {
         return this._val2;
     }
 
-    setValues(v1: number, v2: number) {
+    public setValues(v1: number, v2: number) {
         this._val1 = v1;
         this._val2 = v2;
     }
 
-    setPair(p: Pair) {
+    public setPair(p: Pair) {
         this.setValues(p._val1, p._val2);
     }
 
-    undefine() {
+    public undefine() {
         this._val1 = undefined;
         this._val2 = undefined;
     }
@@ -39,11 +39,11 @@ export class Pair {
         return Math.max(this._val1, this._val2);
     }
 
-    intervalHasValue(v: number) {
+    public intervalHasValue(v: number) {
         return this.min <= v && v <= this.max;
     }
 
-    toString(): string {
+    public toString(): string {
         return "[" + this.min + "," + this.max + "]";
     }
 }