diff --git a/src/devalaison/grille.ts b/src/devalaison/grille.ts
index bb96d7140ea771979fa03695e28e61c041aa83ef..698814d74a2ab5990c507967f3179ffc98aa7168 100644
--- a/src/devalaison/grille.ts
+++ b/src/devalaison/grille.ts
@@ -106,17 +106,21 @@ export class Grille extends Nub implements Observer {
         const t = this.gridType;
 
         // Préconisations d'inclinaison
-        if (t === GrilleType.Oriented) {
-            if (this.prms.Alpha.v > 45) {
-                r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_ALPHA_GREATER_THAN_45));
+        if (this.gridPlanParamsOK) {
+            if (t === GrilleType.Oriented) {
+                if (this.prms.Alpha.v > 45) {
+                    r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_ALPHA_GREATER_THAN_45));
+                }
             }
-        }
-        if (t === GrilleType.Inclined) {
-            if (this.prms.Beta.v > 26) {
-                r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_BETA_GREATER_THAN_26));
+            if (t === GrilleType.Inclined) {
+                if (this.prms.Beta.v > 26) {
+                    r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_BETA_GREATER_THAN_26));
+                }
             }
         }
 
+        // 1st calculation step
+
         // Hauteur d'eau
         const H = this.prms.CEau.v - this.prms.CRad.v;
         r.resultElement.values.H = H;
@@ -136,55 +140,61 @@ export class Grille extends Nub implements Observer {
         const VAPDG = this.prms.QMax.v / SPDG;
         r.resultElement.values.VAPDG = VAPDG;
 
-        // Rapport de forme des barreaux
-        const RFB = this.prms.b.v / this.prms.p.v;
-        r.resultElement.values.RFB = RFB;
-        // Rapport espacement/épaisseur des barreaux
-        const REEB = this.prms.e.v / this.prms.b.v;
-        r.resultElement.values.REEB = REEB;
-        // Obstruction due aux barreaux seuls
-        const OB = this.prms.b.v / (this.prms.b.v + this.prms.e.v);
-        r.resultElement.values.OB = OB;
-
-        let VN: number;
-
-        if (t === GrilleType.Conventional || t === GrilleType.Inclined) {
-            // Longueur de grille immergée
-            const LG = HG / Math.sin(this.prms.Beta.v * Math.PI / 180);
-            r.resultElement.values.LG = LG;
-            // Distance longitudinale entre le point émergent du plan de grille et le pied de grille
-            const D = H / Math.tan(this.prms.Beta.v * Math.PI / 180);
-            r.resultElement.values.D = D;
-            // Distance longitudinale entre le sommet immergé et le pied de grille
-            const DG = HG / Math.tan(this.prms.Beta.v * Math.PI / 180);
-            r.resultElement.values.DG = DG;
-            // Surface de grille immergée
-            const SG = LG * this.prms.B.v;
-            r.resultElement.values.SG = SG;
-            // Vitesse normale moyenne pour le débit maximum turbiné
-            VN = this.prms.QMax.v / SG;
-            r.resultElement.values.VN = VN;
-        }
+        // 2nd calculation step
+        if (this.gridPlanParamsOK) {
+            let VN: number;
+
+            if (t === GrilleType.Conventional || t === GrilleType.Inclined) {
+                // Longueur de grille immergée
+                const LG = HG / Math.sin(this.prms.Beta.v * Math.PI / 180);
+                r.resultElement.values.LG = LG;
+                // Distance longitudinale entre le point émergent du plan de grille et le pied de grille
+                const D = H / Math.tan(this.prms.Beta.v * Math.PI / 180);
+                r.resultElement.values.D = D;
+                // Distance longitudinale entre le sommet immergé et le pied de grille
+                const DG = HG / Math.tan(this.prms.Beta.v * Math.PI / 180);
+                r.resultElement.values.DG = DG;
+                // Surface de grille immergée
+                const SG = LG * this.prms.B.v;
+                r.resultElement.values.SG = SG;
+                // Vitesse normale moyenne pour le débit maximum turbiné
+                VN = this.prms.QMax.v / SG;
+                r.resultElement.values.VN = VN;
+            }
 
-        if (t === GrilleType.Oriented) {
-            // Largeur du plan de grille
-            const BG = this.prms.B.v / Math.sin(this.prms.Alpha.v * Math.PI / 180);
-            // ... BG is not exposed as a result !
-            // Surface de grille immergée
-            const SG = BG * HG;
-            r.resultElement.values.SG = SG;
-            // Vitesse normale moyenne pour le débit maximum turbiné
-            VN = this.prms.QMax.v / SG;
-            r.resultElement.values.VN = VN;
-        }
+            if (t === GrilleType.Oriented) {
+                // Largeur du plan de grille
+                const BG = this.prms.B.v / Math.sin(this.prms.Alpha.v * Math.PI / 180);
+                // ... BG is not exposed as a result !
+                // Surface de grille immergée
+                const SG = BG * HG;
+                r.resultElement.values.SG = SG;
+                // Vitesse normale moyenne pour le débit maximum turbiné
+                VN = this.prms.QMax.v / SG;
+                r.resultElement.values.VN = VN;
+            }
 
-        // Préconisation pour éviter le placage des poissons sur le plan de grille
-        if (VN > 0.5) {
-            r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_VN_GREATER_THAN_05));
+            // Préconisation pour éviter le placage des poissons sur le plan de grille
+            if (VN > 0.5) {
+                r.resultElement.addMessage(new Message(MessageCode.WARNING_GRILLE_VN_GREATER_THAN_05));
+            }
         }
 
-        // perte de charge
-        this.calcDH(r, VAPDG);
+        // 3rd calculation step
+        if (this.gridPlanParamsOK && this.gridParamsOK) {
+            // Rapport de forme des barreaux
+            const RFB = this.prms.b.v / this.prms.p.v;
+            r.resultElement.values.RFB = RFB;
+            // Rapport espacement/épaisseur des barreaux
+            const REEB = this.prms.e.v / this.prms.b.v;
+            r.resultElement.values.REEB = REEB;
+            // Obstruction due aux barreaux seuls
+            const OB = this.prms.b.v / (this.prms.b.v + this.prms.e.v);
+            r.resultElement.values.OB = OB;
+
+            // perte de charge
+            this.calcDH(r, VAPDG);
+        }
 
         return r;
     }
@@ -280,6 +290,47 @@ export class Grille extends Nub implements Observer {
         return this.Calc();
     }
 
+    /**
+     * Returns true if every "grid plan" parameter (2nd fieldset in NgHyd)
+     * has a defined value; allows to perform 2nd calculation step
+     */
+    private get gridPlanParamsOK(): boolean {
+        if (this.gridType === GrilleType.Oriented) {
+            return this.prms.Alpha.singleValue !== undefined;
+        } else {
+            return this.prms.Beta.singleValue !== undefined;
+        }
+    }
+
+    /**
+     * Returns true if every "grid" parameter (3rd fieldset in NgHyd)
+     * has a defined value; allows to perform 3rd calculation step
+     */
+    private get gridParamsOK(): boolean {
+        let optionalFieldsOk: boolean = true;
+        if (this.gridProfile === GrilleProfile.Custom) {
+            optionalFieldsOk = optionalFieldsOk && (this.prms.a.singleValue !== undefined);
+            if (this.gridType === GrilleType.Oriented) {
+                optionalFieldsOk = optionalFieldsOk && (this.prms.c.singleValue !== undefined);
+            }
+        }
+        if (this.gridType === GrilleType.Inclined) {
+            optionalFieldsOk = (
+                optionalFieldsOk
+                && (this.prms.OEntH.singleValue !== undefined)
+                && (this.prms.cIncl.singleValue !== undefined)
+            );
+        }
+        return (
+            optionalFieldsOk
+            // mandatory fields
+            && this.prms.b.singleValue !== undefined
+            && this.prms.p.singleValue !== undefined
+            && this.prms.e.singleValue !== undefined
+            && this.prms.O.singleValue !== undefined
+        );
+    }
+
     /**
      * Perte de charge pour un taux de colmatage allant de 0 à 60% par pas de 5%.
      * @param r Result to complete with calculated DH values