diff --git a/spec/structure/structure_vanlev.spec.ts b/spec/structure/structure_vanlev.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..54eaee2c453b300c0758c40a1837f4c23c9b29db
--- /dev/null
+++ b/spec/structure/structure_vanlev.spec.ts
@@ -0,0 +1,19 @@
+import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params";
+import { StructureVanLevLarinier, StructureVanLevParams } from "../../src/structure/structure_vanlev";
+import { StructureVanLevVillemonte } from "../../src/structure/structure_vanlev";
+
+function getStructTest(bFente: boolean = false): StructureVanLevLarinier | StructureVanLevVillemonte {
+    const structPrm = new StructureVanLevParams(0.773, 73, 75.090, 74.86, 0.6, 0.4, 0.217, 73.5, 74);
+    if (bFente) {
+        return new StructureVanLevLarinier(structPrm, false);
+    } else {
+        return new StructureVanLevVillemonte(structPrm, false);
+    }
+}
+
+describe("class StructureVanLevVillemonte", () => {
+    it("Calc(Z1) should return 75.077 and extraResults.ZDV should be 73.95", () => {
+        expect(getStructTest().Calc("Z1").vCalc).toBeCloseTo(75.077, 3);
+        expect(getStructTest().Calc("Z1").extraResults.ZDV).toBeCloseTo(73.95, 2);
+    });
+});
diff --git a/spec/structure/structure_weir_free.spec.ts b/spec/structure/structure_weir_free.spec.ts
index a6f0f01f789751263a68a6a1288138bf80a13e14..7484c8f9ce3326ab6da96060928ac1bd4fd38cbc 100644
--- a/spec/structure/structure_weir_free.spec.ts
+++ b/spec/structure/structure_weir_free.spec.ts
@@ -12,8 +12,9 @@ import { StructureWeirFree } from "../../src/structure/structure_weir_free";
 import { Result } from "../../src/util/result";
 import { itCalcQ } from "./functions";
 
-const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0);
-const structTest: StructureWeirFree = new StructureWeirFree(structPrm, false);
+function getStructTest(): StructureWeirFree {
+    return new StructureWeirFree(new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0), false);
+}
 
 describe("Class StructureWeirFree: ", () => {
     describe("Calcul Q avec W croissant: ", () => {
@@ -25,7 +26,7 @@ describe("Class StructureWeirFree: ", () => {
             6.987191, 6.987191, 6.987191, 6.987191, 6.987191, 6.987191, 6.987191, 6.987191];
 
         for (let i = 0; i < Q.length; i++) {
-            itCalcQ(structTest, h1, W[i], Q[i]);
+            itCalcQ(getStructTest(), h1, W[i], Q[i]);
         }
     });
     describe("Calcul Q en charge avec h1 croissant: ", () => {
@@ -38,7 +39,7 @@ describe("Class StructureWeirFree: ", () => {
             StructureFlowRegime.FREE, StructureFlowRegime.FREE, StructureFlowRegime.FREE];
 
         for (let i = 0; i < Q.length; i++) {
-            itCalcQ(structTest, h1[i], W, Q[i], mode[i], regime[i]);
+            itCalcQ(getStructTest(), h1[i], W, Q[i], mode[i], regime[i]);
         }
     });
     describe("Calcul Q a surface libre avec h1 croissant: ", () => {
@@ -51,7 +52,7 @@ describe("Class StructureWeirFree: ", () => {
             StructureFlowRegime.FREE, StructureFlowRegime.FREE];
 
         for (let i = 0; i < Q.length; i++) {
-            itCalcQ(structTest, h1[i], W, Q[i], mode[i], regime[i]);
+            itCalcQ(getStructTest(), h1[i], W, Q[i], mode[i], regime[i]);
         }
     });
 });
diff --git a/spec/structure/structure_weir_submerged_larinier.spec.ts b/spec/structure/structure_weir_submerged_larinier.spec.ts
index 217491c52244d3bd3a85f5d1695fc17f4f6930c0..88649eee5a5e423205bf759fc057771d5106ec22 100644
--- a/spec/structure/structure_weir_submerged_larinier.spec.ts
+++ b/spec/structure/structure_weir_submerged_larinier.spec.ts
@@ -12,8 +12,9 @@ import { RectangularStructureParams, StructureWeirSubmergedLarinier } from "../.
 import { itCalcQ } from "../structure/functions";
 import { precDigits } from "../test_config";
 
-const prms: RectangularStructureParams = new RectangularStructureParams(0, 101, 102, 101.5, 0.2, 0.65);
-const test: StructureWeirSubmergedLarinier = new StructureWeirSubmergedLarinier(prms, false);
+function getStructTest(): StructureWeirSubmergedLarinier {
+    return  new StructureWeirSubmergedLarinier(new RectangularStructureParams(0, 101, 102, 101.5, 0.2, 0.65), false);
+}
 
 describe("Class StructureWeirSubmergedLarinier: ", () => {
     xdescribe("Calc(Q): ", () => {
@@ -22,7 +23,7 @@ describe("Class StructureWeirSubmergedLarinier: ", () => {
         const mode: StructureFlowMode = StructureFlowMode.WEIR;
         const regime: StructureFlowRegime = StructureFlowRegime.SUBMERGED;
         for (let i = 0; i < Q.length; i++) {
-            itCalcQ(test, Z1[i], Infinity, Q[i], mode, regime);
+            itCalcQ(getStructTest(), Z1[i], Infinity, Q[i], mode, regime);
         }
     });
     describe("Calc(Z1): ", () => {
diff --git a/src/structure/structure_props.ts b/src/structure/structure_props.ts
index 659b45574cef7fdf277451997c182b59d395b332..8ca19b93e414c6ea18a4fec856f350c5788da1b9 100644
--- a/src/structure/structure_props.ts
+++ b/src/structure/structure_props.ts
@@ -38,7 +38,11 @@ export enum LoiDebit {
     // Loi de débit orifice noyé
     OrificeSubmerged,
     // Loi de seuil noyée Villemonte
-    WeirVillemonte
+    WeirVillemonte,
+    // Vanne levante Larinier
+    VanLevLarinier,
+    // Vanne levante Villemonte
+    VanLevVillemonte
 }
 
 export const loiAdmissiblesOuvrages: { [key: string]: LoiDebit[] } = {
diff --git a/src/structure/structure_vanlev.ts b/src/structure/structure_vanlev.ts
new file mode 100644
index 0000000000000000000000000000000000000000..609c561046a4f838562ea770ab0661474e386d24
--- /dev/null
+++ b/src/structure/structure_vanlev.ts
@@ -0,0 +1,122 @@
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
+import { ParamDomainValue } from "../param/param-domain";
+import { Message, MessageCode } from "../util/message";
+import { Result } from "../util/result";
+import { RectangularStructureParams } from "./rectangular_structure";
+import { LoiDebit } from "./structure_props";
+import { StructureWeirSubmergedLarinier } from "./structure_weir_submerged_larinier";
+import { StructureWeirVillemonte } from "./structure_weir_villemonte";
+
+/**
+ * Parameters of an automatic weir with crest elevation regulation
+ */
+export class StructureVanLevParams extends RectangularStructureParams {
+    /** Maximum weir crest elevation (m) */
+    public minZDV: ParamDefinition;
+    /** Minimum weir crest elevation (m) */
+    public maxZDV: ParamDefinition;
+    /** Imposed fall (m) */
+    public DH: 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 rZ2   Cote de l'eau aval (m)
+     * @param rL    Largeur de la vanne ou du déversoir (m)
+     * @param rCd   Coefficient de débit (-)
+     * @param rMinZDV Minimum weir crest elevation (m)
+     * @param rMaxZDV Maximum weir crest elevation (m)
+     * @param rW    Ouverture de la vanne (m) (Valeur par défaut +infinity pour les déversoirs)
+     */
+    constructor(
+        rQ: number, rZDV: number, rZ1: number, rZ2: number, rL: number, rCd: number, rDH: number,
+        rMinZDV: number, rMaxZDV: number,
+        rW: number = Infinity) {
+        super(rQ, rZDV, rZ1, rZ2, rL, rCd, rW);
+        this.minZDV = new ParamDefinition(this, "minZDV", ParamDomainValue.ANY, rMinZDV, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.minZDV);
+        this.maxZDV = new ParamDefinition(this, "maxZDV", ParamDomainValue.ANY, rMaxZDV, ParamFamily.ELEVATIONS);
+        this.addParamDefinition(this.maxZDV);
+        this.DH = new ParamDefinition(this, "DH", ParamDomainValue.ANY, rDH, ParamFamily.BASINFALLS);
+        this.addParamDefinition(this.DH);
+    }
+}
+
+function CalcVanneLevante(
+    s: StructureVanLevVillemonte | StructureVanLevLarinier,
+    sVarCalc: string, rInit: number
+): Result {
+
+    if (sVarCalc !== "Z1") {
+        throw new Error("CalcVanneLevante sVarCalc should be Z1");
+    }
+    // Calculation of ZDV
+    s.prms.Z1.v = s.prms.Z2.v + s.prms.DH.v;
+    const r1: Result = s.superCalc("ZDV", rInit);
+    s.prms.ZDV.v = r1.vCalc;
+    // Check if calculated ZDV is between minZDV and maxZDV
+    let m: Message;
+    if (r1.vCalc < s.prms.minZDV.v) {
+        m = new Message(MessageCode.WARNING_VANLEV_ZDV_INF_MIN);
+        s.prms.ZDV.v = s.prms.minZDV.v;
+    } else if (r1.vCalc > s.prms.maxZDV.v) {
+        m = new Message(MessageCode.WARNING_VANLEV_ZDV_SUP_MAX);
+        s.prms.ZDV.v = s.prms.maxZDV.v;
+    }
+    const r2: Result = s.superCalc("Z1", rInit);
+    r2.extraResults.ZDV = s.prms.ZDV.v;
+    if (m !== undefined) {
+        r2.addMessage(m);
+    }
+    return r2;
+}
+
+// tslint:disable-next-line:max-classes-per-file
+export class StructureVanLevVillemonte extends StructureWeirVillemonte {
+
+    constructor(prms: StructureVanLevParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this._loiDebit = LoiDebit.VanLevVillemonte;
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): StructureVanLevParams {
+        return this._prms as StructureVanLevParams;
+    }
+
+    public Calc(sVarCalc: string, rInit?: number): Result {
+        return CalcVanneLevante(this, sVarCalc, rInit);
+    }
+
+    public superCalc(sVarCalc: string, rInit: number): Result {
+        return super.Calc(sVarCalc, rInit);
+    }
+}
+
+// tslint:disable-next-line:max-classes-per-file
+export class StructureVanLevLarinier extends StructureWeirSubmergedLarinier {
+
+    constructor(prms: StructureVanLevParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this._loiDebit = LoiDebit.VanLevLarinier;
+    }
+
+    public Calc(sVarCalc: string, rInit?: number): Result {
+        return CalcVanneLevante(this, sVarCalc, rInit);
+    }
+
+    /**
+     * paramètres castés au bon type
+     */
+    get prms(): StructureVanLevParams {
+        return this._prms as StructureVanLevParams;
+    }
+
+    public superCalc(sVarCalc: string, rInit: number): Result {
+        return super.Calc(sVarCalc, rInit);
+    }
+}
diff --git a/src/util/message.ts b/src/util/message.ts
index 52e3730ecf6ca1d7bde6a969a0c2f67f0ee69a73..d9d752af499d9463fd323db2806b6d6922094f96 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -255,6 +255,16 @@ export enum MessageCode {
      * StructureKivi : h/p ne doit pas être supérieur à 2,5. h/p est forcé à 2,5.
      */
     WARNING_STRUCTUREKIVI_HP_TROP_ELEVE,
+
+    /**
+     * Vanne levante : ZDV > ZDV max
+     */
+    WARNING_VANLEV_ZDV_SUP_MAX,
+
+    /**
+     * Vanne levante : ZDV < ZDV min
+     */
+    WARNING_VANLEV_ZDV_INF_MIN,
 }
 
 /**
@@ -277,9 +287,9 @@ export class Message {
      */
     private _code: MessageCode;
 
-    constructor(c: MessageCode) {
+    constructor(c: MessageCode, extraVar: { [key: string]: any } = {}) {
         this._code = c;
-        this.extraVar = {};
+        this.extraVar = extraVar;
     }
 
     get code() { return this._code; }