From 8b191116a10902c5c74fe7bf66082ba1672b1aea Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 17 Sep 2019 15:49:53 +0200
Subject: [PATCH] Fix #289 - add Grille module

---
 jalhyd_branch                                 |   2 +-
 src/app/calculators/grille/grille.config.json |  45 ++++++++
 src/app/calculators/grille/grille.en.json     |  76 +++++++++++++
 src/app/calculators/grille/grille.fr.json     |  83 ++++++++++++++
 src/app/calculators/jet/jet.config.json       |   1 -
 src/app/config.json                           |   2 +-
 .../definition/concrete/form-grille.ts        |  50 +++++++++
 .../definition/form-compute-fixedvar.ts       |   8 +-
 src/app/formulaire/definition/form-compute.ts | 105 ++++++++++--------
 .../formulaire/definition/form-definition.ts  |   7 ++
 src/app/formulaire/fieldset.ts                |  18 +++
 src/app/formulaire/select-field.ts            |  13 ++-
 src/app/services/formulaire.service.ts        |   6 +
 src/locale/messages.en.json                   |   2 +
 src/locale/messages.fr.json                   |   2 +
 15 files changed, 366 insertions(+), 54 deletions(-)
 create mode 100644 src/app/calculators/grille/grille.config.json
 create mode 100644 src/app/calculators/grille/grille.en.json
 create mode 100644 src/app/calculators/grille/grille.fr.json
 create mode 100644 src/app/formulaire/definition/concrete/form-grille.ts

diff --git a/jalhyd_branch b/jalhyd_branch
index 1f7391f92..d51eab3aa 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-master
+114-ajout-du-module-devalaison-pertes-de-charge-grille-de-prise-d-eau
diff --git a/src/app/calculators/grille/grille.config.json b/src/app/calculators/grille/grille.config.json
new file mode 100644
index 000000000..aac755031
--- /dev/null
+++ b/src/app/calculators/grille/grille.config.json
@@ -0,0 +1,45 @@
+[
+    {
+        "id": "fs_section",
+        "type": "fieldset",
+        "fields": [ "QMax", "CRad", "CEau", "CSomGrille", "B" ]
+    },
+    {
+        "id": "fs_plan",
+        "type": "fieldset",
+        "defaultGridType": "Conventional",
+        "fields": [
+            {
+                "id": "select_grid_type",
+                "type": "select",
+                "source": "grille_type"
+            },
+            "Beta",
+            "Alpha"
+        ]
+    },
+    {
+        "id": "fs_grille",
+        "type": "fieldset",
+        "defaultGridProfile": "Rectangular",
+        "fields": [
+            {
+                "id": "select_grid_profile",
+                "type": "select",
+                "source": "grille_profile"
+            },
+            "b",
+            "p",
+            "e",
+            "O",
+            "OEntH",
+            "cIncl"
+        ]
+    },
+    {
+        "type": "options",
+        "gridTypeSelectId": "select_grid_type",
+        "gridProfileSelectId": "select_grid_profile",
+        "help": "devalaison/grille"
+    }
+]
\ No newline at end of file
diff --git a/src/app/calculators/grille/grille.en.json b/src/app/calculators/grille/grille.en.json
new file mode 100644
index 000000000..dcf773e3a
--- /dev/null
+++ b/src/app/calculators/grille/grille.en.json
@@ -0,0 +1,76 @@
+{
+    "fs_section": "Grid plan section characteristics",
+    "fs_plan": "Grid plan characteristics",
+    "fs_grille": "Grid characteristics",
+
+    "QMax": "Maximum turbined flow",
+    "CRad": "Bottom elevation (grid foot)",
+    "CEau": "Water level",
+    "CSomGrille": "Grid plan submerged top elevation",
+    "B": "Section width",
+    "Beta": "Horizontal angle",
+    "Alpha": "Angle towards flow direction",
+    "b": "Bars thickness",
+    "p": "Bars depth",
+    "e": "Free space between bars",
+    "O": "Global obstruction of grid plan",
+    "OEntH": "Effective obstruction due to spacers and transversal elements",
+    "cIncl": "Average shape coefficient of spacers and transversal elements",
+
+    "select_grid_type": "Grid type",
+    "select_grid_profile": "Bars profile",
+
+    "H": "Water height",
+    "HG": "Grid  height",
+    "S": "Water intake approach section",
+    "SPDG": "Grid plan approach section",
+    "VA": "Mean approach speed for maximum turbined flow",
+    "VAPDG": "Mean approach speed for maximum turbined flow, substracting the potentially stoppered upper part",
+    "LG": "Submerged grid length",
+    "D": "Longitudinal distance between emerging point of grid plan and grid foot",
+    "DG": "Longitudinal distance between submerged top and grid foot",
+    "SG": "Submerged grid surface",
+    "VN": "Average normal speed for maximum turbined flow",
+    "RFB": "Bars shape ratio",
+    "REEB": "Bars spacing/thickness ratio",
+    "OB": "Obstruction due to bars only",
+
+    "DH00": "Loss of charge - clogging rate 0%",
+    "DH05": "Loss of charge - clogging rate 5%",
+    "DH10": "Loss of charge - clogging rate 10%",
+    "DH15": "Loss of charge - clogging rate 15%",
+    "DH20": "Loss of charge - clogging rate 20%",
+    "DH25": "Loss of charge - clogging rate 25%",
+    "DH30": "Loss of charge - clogging rate 30%",
+    "DH35": "Loss of charge - clogging rate 35%",
+    "DH40": "Loss of charge - clogging rate 40%",
+    "DH45": "Loss of charge - clogging rate 45%",
+    "DH50": "Loss of charge - clogging rate 50%",
+    "DH55": "Loss of charge - clogging rate 55%",
+    "DH60": "Loss of charge - clogging rate 60%",
+
+    "UNIT_H": "m",
+    "UNIT_HG": "m",
+    "UNIT_S": "m²",
+    "UNIT_SPDG": "m²",
+    "UNIT_VA": "m/s",
+    "UNIT_VAPDG": "m/s",
+    "UNIT_LG": "m",
+    "UNIT_D": "m",
+    "UNIT_DG": "m",
+    "UNIT_SG": "m²",
+    "UNIT_VN": "m/s",
+    "UNIT_DH00": "cm",
+    "UNIT_DH05": "cm",
+    "UNIT_DH10": "cm",
+    "UNIT_DH15": "cm",
+    "UNIT_DH20": "cm",
+    "UNIT_DH25": "cm",
+    "UNIT_DH30": "cm",
+    "UNIT_DH35": "cm",
+    "UNIT_DH40": "cm",
+    "UNIT_DH45": "cm",
+    "UNIT_DH50": "cm",
+    "UNIT_DH55": "cm",
+    "UNIT_DH60": "cm"
+}
\ No newline at end of file
diff --git a/src/app/calculators/grille/grille.fr.json b/src/app/calculators/grille/grille.fr.json
new file mode 100644
index 000000000..c4e976de7
--- /dev/null
+++ b/src/app/calculators/grille/grille.fr.json
@@ -0,0 +1,83 @@
+{
+    "fs_section": "Caractéristiques de la section du plan de grille",
+    "fs_plan": "Caractéristiques du plan de grille",
+    "fs_grille": "Caractéristiques de la grille",
+
+    "QMax": "Débit maximum turbiné",
+    "CRad": "Cote du radier (pied de grille)",
+    "CEau": "Cote du niveau d'eau",
+    "CSomGrille": "Cote du sommet immergé du plan de grille",
+    "B": "Largeur de la section",
+    "Beta": "Inclinaison par rapport à l'horizontale",
+    "Alpha": "Orientation par rapport à la direction de l'écoulement",
+    "b": "Épaisseur des barreaux",
+    "p": "Profondeur des barreaux",
+    "e": "Espacement libre entre les barreaux",
+    "O": "Obstruction globale du plan de grille",
+    "OEntH": "Obstruction effective due aux entretoises et éléments transversaux",
+    "cIncl": "Coefficient de forme moyen des entretoises et éléments transversaux",
+
+    "select_grid_type": "Type de grille",
+    "select_grid_profile": "Profil des barreaux",
+
+    "select_grid_type_0": "Conventionnelle",
+    "select_grid_type_1": "Orientée",
+    "select_grid_type_2": "Inclinée",
+
+    "select_grid_profile_0": "Rectangulaire",
+    "select_grid_profile_1": "Hydrodynamique",
+
+    "H": "Hauteur d'eau",
+    "HG": "Hauteur de grille",
+    "S": "Section d'approche de la prise d'eau",
+    "SPDG": "Section d'approche du plan de grille",
+    "VA": "Vitesse d'approche moyenne pour le débit maximum turbiné",
+    "VAPDG": "Vitesse d'approche moyenne pour le débit maximum turbiné, en soustrayant la partie supérieure éventuellement obturée",
+    "LG": "Longueur de grille immergée",
+    "D": "Distance longitudinale entre le point émergent du plan de grille et le pied de grille",
+    "DG": "Distance longitudinale entre le sommet immergé et le pied de grille",
+    "SG": "Surface de grille immergée",
+    "VN": "Vitesse normale moyenne pour le débit maximum turbiné",
+    "RFB": "Rapport de forme des barreaux",
+    "REEB": "Rapport espacement/épaisseur des barreaux",
+    "OB": "Obstruction due aux barreaux seuls",
+
+    "DH00": "Perte de charge - taux de colmatage 0%",
+    "DH05": "Perte de charge - taux de colmatage 5%",
+    "DH10": "Perte de charge - taux de colmatage 10%",
+    "DH15": "Perte de charge - taux de colmatage 15%",
+    "DH20": "Perte de charge - taux de colmatage 20%",
+    "DH25": "Perte de charge - taux de colmatage 25%",
+    "DH30": "Perte de charge - taux de colmatage 30%",
+    "DH35": "Perte de charge - taux de colmatage 35%",
+    "DH40": "Perte de charge - taux de colmatage 40%",
+    "DH45": "Perte de charge - taux de colmatage 45%",
+    "DH50": "Perte de charge - taux de colmatage 50%",
+    "DH55": "Perte de charge - taux de colmatage 55%",
+    "DH60": "Perte de charge - taux de colmatage 60%",
+
+    "UNIT_H": "m",
+    "UNIT_HG": "m",
+    "UNIT_S": "m²",
+    "UNIT_SPDG": "m²",
+    "UNIT_VA": "m/s",
+    "UNIT_VAPDG": "m/s",
+    "UNIT_LG": "m",
+    "UNIT_D": "m",
+    "UNIT_DG": "m",
+    "UNIT_SG": "m²",
+    "UNIT_VN": "m/s",
+    "UNIT_DH00": "cm",
+    "UNIT_DH05": "cm",
+    "UNIT_DH10": "cm",
+    "UNIT_DH15": "cm",
+    "UNIT_DH20": "cm",
+    "UNIT_DH25": "cm",
+    "UNIT_DH30": "cm",
+    "UNIT_DH35": "cm",
+    "UNIT_DH40": "cm",
+    "UNIT_DH45": "cm",
+    "UNIT_DH50": "cm",
+    "UNIT_DH55": "cm",
+    "UNIT_DH60": "cm"
+}
\ No newline at end of file
diff --git a/src/app/calculators/jet/jet.config.json b/src/app/calculators/jet/jet.config.json
index 857c2018e..0dcb02962 100644
--- a/src/app/calculators/jet/jet.config.json
+++ b/src/app/calculators/jet/jet.config.json
@@ -6,7 +6,6 @@
     },
     {
         "type": "options",
-        "__idCal": "D",
         "help": "devalaison/jet"
     }
 ]
\ No newline at end of file
diff --git a/src/app/config.json b/src/app/config.json
index 41449c8e1..81b753220 100644
--- a/src/app/config.json
+++ b/src/app/config.json
@@ -30,7 +30,7 @@
                 "path": "surface-libre.jpg",
                 "credits": "PENSER À CHANGER CETTE IMAGE"
             },
-            "calculators": [ 18, 3, 9 ]
+            "calculators": [ 18, 19, 3, 9 ]
         },
         {
             "name": "HYDRAULIQUE_A_SURFACE_LIBRE",
diff --git a/src/app/formulaire/definition/concrete/form-grille.ts b/src/app/formulaire/definition/concrete/form-grille.ts
new file mode 100644
index 000000000..2e47d8df5
--- /dev/null
+++ b/src/app/formulaire/definition/concrete/form-grille.ts
@@ -0,0 +1,50 @@
+import { IObservable } from "jalhyd";
+
+import { FormulaireBase } from "./form-base";
+import { FieldSet } from "../../fieldset";
+
+/**
+ * Formulaire pour les Grilles (perte de charge)
+ */
+export class FormulaireGrille extends FormulaireBase {
+
+    /** id of select configuring grid profile */
+    private _gridProfileSelectId: string;
+
+    /** id of select configuring grid type */
+    private _gridTypeSelectId: string;
+
+    protected parseOptions(json: {}) {
+        super.parseOptions(json);
+        this._gridProfileSelectId = this.getOption(json, "gridProfileSelectId");
+        this._gridTypeSelectId = this.getOption(json, "gridTypeSelectId");
+    }
+
+    public afterParseFieldset(fs: FieldSet) {
+        if (this._gridTypeSelectId) {
+            const sel = fs.getFormulaireNodeById(this._gridTypeSelectId);
+            if (sel) {
+                fs.properties.addObserver(this);
+            }
+        }
+        if (this._gridProfileSelectId) {
+            const sel = fs.getFormulaireNodeById(this._gridProfileSelectId);
+            if (sel) {
+                fs.properties.addObserver(this);
+            }
+        }
+    }
+
+    // interface Observer
+
+    public update(sender: IObservable, data: any) {
+        super.update(sender, data);
+        if (data.action === "propertyChange") {
+            if (data.name === "gridType") {
+                this.reset();
+                // Inclined grids have more input fields (OEntH and cIncl)
+                this.getFieldsetById("fs_grille").updateFields();
+            }
+        }
+    }
+}
diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
index 376c47159..9a9bf1d91 100644
--- a/src/app/formulaire/definition/form-compute-fixedvar.ts
+++ b/src/app/formulaire/definition/form-compute-fixedvar.ts
@@ -29,11 +29,15 @@ export class FormComputeFixedVar extends FormCompute {
         if (varParams.length === 0) {
             // pas de paramètre à varier
             this.formResult.fixedResults.result = nub.result;
-            this.formResult.fixedResults.calculatedParameter = computedParam;
+            if (computedParam !== undefined) {
+                this.formResult.fixedResults.calculatedParameter = computedParam;
+            }
         } else {
             // il y a un paramètre à varier
             this.formResult.varResults.variatedParameters = varParams;
-            this.formResult.varResults.calculatedParameter = computedParam;
+            if (computedParam !== undefined) {
+                this.formResult.varResults.calculatedParameter = computedParam;
+            }
 
             this.formResult.varResults.result = nub.result;
             this.formResult.varResults.update();
diff --git a/src/app/formulaire/definition/form-compute.ts b/src/app/formulaire/definition/form-compute.ts
index 14a21c5d6..0917ded92 100644
--- a/src/app/formulaire/definition/form-compute.ts
+++ b/src/app/formulaire/definition/form-compute.ts
@@ -44,59 +44,68 @@ export abstract class FormCompute implements Observer {
             computedParam = nub.calculatedParam;
         }
 
-        // const computedParamValue = computedParam.getValue();
-        const computedParamValue = computedParam.singleValue;
-
-        switch (computedParam.domain.domain) {
-            case ParamDomainValue.ANY:
-                if (computedParam && computedParam.isDefined) {
-                    init = computedParamValue;
-                }
-                if (init === undefined) {
-                    init = 0;
-                }
-                break;
-
-            case ParamDomainValue.POS_NULL:
-                if (computedParam && computedParam.isDefined) {
-                    init = Math.max(computedParamValue, 0);
-                }
-                if (init === undefined) {
-                    init = 0;
-                }
-                break;
-
-            case ParamDomainValue.INTERVAL:
-                init = (computedParam.domain.minValue + computedParam.domain.maxValue) / 2;
-                break;
-
-            case ParamDomainValue.NOT_NULL:
-                if (computedParam && computedParam.isDefined) {
-                    init = computedParamValue;
-                }
-                if (init === undefined || init === 0) {
-                    init = 1e-8;
-                }
-                break;
-
-            case ParamDomainValue.POS:
-                if (computedParam && computedParam.isDefined) {
-                    init = Math.max(computedParamValue, 1e-8);
-                }
-                if (init === undefined) {
-                    init = 1e-8;
-                }
-                break;
-        }
+        if (computedParam === undefined) {
+            // modules that have no calculated param (ex: Grille)
+            return nub.CalcSerie();
+
+        } else {
+            // const computedParamValue = computedParam.getValue();
+            const computedParamValue = computedParam.singleValue;
+
+            switch (computedParam.domain.domain) {
+                case ParamDomainValue.ANY:
+                    if (computedParam && computedParam.isDefined) {
+                        init = computedParamValue;
+                    }
+                    if (init === undefined) {
+                        init = 0;
+                    }
+                    break;
+
+                case ParamDomainValue.POS_NULL:
+                    if (computedParam && computedParam.isDefined) {
+                        init = Math.max(computedParamValue, 0);
+                    }
+                    if (init === undefined) {
+                        init = 0;
+                    }
+                    break;
+
+                case ParamDomainValue.INTERVAL:
+                    init = (computedParam.domain.minValue + computedParam.domain.maxValue) / 2;
+                    break;
 
-        return nub.CalcSerie(init, this.getParameterRefid(computedParam));
+                case ParamDomainValue.NOT_NULL:
+                    if (computedParam && computedParam.isDefined) {
+                        init = computedParamValue;
+                    }
+                    if (init === undefined || init === 0) {
+                        init = 1e-8;
+                    }
+                    break;
+
+                case ParamDomainValue.POS:
+                    if (computedParam && computedParam.isDefined) {
+                        init = Math.max(computedParamValue, 1e-8);
+                    }
+                    if (init === undefined) {
+                        init = 1e-8;
+                    }
+                    break;
+            }
+
+            return nub.CalcSerie(init, this.getParameterRefid(computedParam));
+        }
     }
 
     protected getComputedParameter(): NgParameter {
         const cpd = this._formBase.currentNub.calculatedParam;
-        let ngparam = this._formBase.getParamFromSymbol(cpd.symbol);
-        if (ngparam === undefined) { // calculated parameter is not displayed on screen
-            ngparam = new NgParameter(cpd, this._formBase);
+        let ngparam: NgParameter;
+        if (cpd !== undefined) {
+            ngparam = this._formBase.getParamFromSymbol(cpd.symbol);
+            if (ngparam === undefined) { // calculated parameter is not displayed on screen
+                ngparam = new NgParameter(cpd, this._formBase);
+            }
         }
         return ngparam;
     }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 1266b7c62..699fc83bf 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -312,6 +312,13 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }
     }
 
+    public getFieldsetById(id: string): FieldSet {
+        const res = this.getFormulaireNodeById(id);
+        if (res instanceof FieldSet) {
+            return res;
+        }
+    }
+
     public getParameterValue(symbol: string): number {
         for (const fs of this.allFieldsets) {
             const p = fs.getNodeParameter(symbol);
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 368babb14..6bdc4f1c4 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -8,6 +8,8 @@ import {
     Observer,
     Nub,
     MethodeResolution,
+    GrilleType,
+    GrilleProfile,
 } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
@@ -244,6 +246,14 @@ export class FieldSet extends FormulaireElement implements Observer {
             case "fs_pass_type": // macro-rugo complexe
                 this.setSelectValueFromProperty("select_pass_type", "inclinedApron");
                 break;
+
+            case "fs_plan": // Grille
+                this.setSelectValueFromProperty("select_grid_type", "gridType");
+                break;
+
+            case "fs_grille": // Grille
+                this.setSelectValueFromProperty("select_grid_profile", "gridProfile");
+                break;
         }
     }
 
@@ -308,6 +318,8 @@ export class FieldSet extends FormulaireElement implements Observer {
         this.setPropertyValueFromConfig(json, "defaultLoiDebit", "loiDebit", LoiDebit);
         this.setPropertyValueFromConfig(json, "methodeResolution", "methodeResolution", MethodeResolution);
         this.setPropertyValueFromConfig(json, "defaultMaterial", "material", LCMaterial);
+        this.setPropertyValueFromConfig(json, "defaultGridProfile", "gridProfile", GrilleProfile);
+        this.setPropertyValueFromConfig(json, "defaultGridType", "gridType", GrilleType);
         this.setPropertyValueFromConfig(json, "varCalc", "varCalc");
 
         this.updateFields();
@@ -382,6 +394,12 @@ export class FieldSet extends FormulaireElement implements Observer {
                         case "select_pass_type": // macro-rugo complexe
                             this.setPropValue("inclinedApron", data.value.value);
                             break;
+                        case "select_grid_type": // Grille
+                            this.setPropValue("gridType", data.value.value);
+                            break;
+                        case "select_grid_profile": // Grille
+                            this.setPropValue("gridProfile", data.value.value);
+                            break;
                     }
                     break;
             }
diff --git a/src/app/formulaire/select-field.ts b/src/app/formulaire/select-field.ts
index 80ac74703..ee83f1ae8 100644
--- a/src/app/formulaire/select-field.ts
+++ b/src/app/formulaire/select-field.ts
@@ -1,4 +1,4 @@
-import { LechaptCalmon, acSection, CourbeRemous, Nub, ParallelStructure, StructureType, LoiDebit } from "jalhyd";
+import { LechaptCalmon, acSection, CourbeRemous, Nub, ParallelStructure, StructureType, LoiDebit, GrilleType, GrilleProfile } from "jalhyd";
 
 import { Field } from "./field";
 import { SelectEntry } from "./select-entry";
@@ -161,6 +161,17 @@ export class SelectField extends Field {
                 this.addEntry(new SelectEntry(this._entriesBaseId + "0", false));
                 this.addEntry(new SelectEntry(this._entriesBaseId + "1", true));
                 break;
+
+            case "grille_type": // Grille: type de grille
+                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Conventional, GrilleType.Conventional));
+                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Oriented, GrilleType.Oriented));
+                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Inclined, GrilleType.Inclined));
+                break;
+
+            case "grille_profile": // Grille: profil des barreaux
+                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Rectangular, GrilleProfile.Rectangular));
+                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Hydrodynamic, GrilleProfile.Hydrodynamic));
+                break;
         }
     }
 }
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index c7ec3a6fa..74a2e3100 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -37,6 +37,7 @@ import { FieldsetContainer } from "../formulaire/fieldset-container";
 import { FormulairePab } from "../formulaire/definition/concrete/form-pab";
 import { FormulaireMacrorugoCompound } from "../formulaire/definition/concrete/form-macrorugo-compound";
 import { FormulaireLechaptCalmon } from "../formulaire/definition/concrete/form-lechapt-calmon";
+import { FormulaireGrille } from "../formulaire/definition/concrete/form-grille";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -79,6 +80,7 @@ export class FormulaireService extends Observable {
         this.calculatorPaths[CalculatorType.Pab] = "pab";
         this.calculatorPaths[CalculatorType.MacroRugoCompound] = "macrorugo-compound";
         this.calculatorPaths[CalculatorType.Jet] = "jet";
+        this.calculatorPaths[CalculatorType.Grille] = "grille";
     }
 
     private get _intlService(): I18nService {
@@ -316,6 +318,10 @@ export class FormulaireService extends Observable {
                 f = new FormulaireMacrorugoCompound();
                 break;
 
+            case CalculatorType.Grille:
+                f = new FormulaireGrille();
+                break;
+
             default:
                 f = new FormulaireBase();
         }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 557e53d36..9e2c22df7 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -147,6 +147,8 @@
     "INFO_FIELDSET_MOVE_DOWN": "Move down",
     "INFO_FIELDSET_MOVE_LEFT": "Move left",
     "INFO_FIELDSET_MOVE_RIGHT": "Move right",
+    "INFO_GRILLE_TITRE_COURT": "Grid",
+    "INFO_GRILLE_TITRE": "Loss of charge, water grid",
     "INFO_JET_TITRE_COURT": "Jet",
     "INFO_JET_TITRE": "Jet impact",
     "INFO_WALL_ADDED": "1 wall added",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 871a868f1..6eb67cf76 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -147,6 +147,8 @@
     "INFO_FIELDSET_MOVE_DOWN": "Déplacer vers le bas",
     "INFO_FIELDSET_MOVE_LEFT": "Déplacer vers la gauche",
     "INFO_FIELDSET_MOVE_RIGHT": "Déplacer vers la droite",
+    "INFO_GRILLE_TITRE_COURT": "Grille",
+    "INFO_GRILLE_TITRE": "Perte de charge, grille de prise d'eau",
     "INFO_JET_TITRE_COURT": "Jet",
     "INFO_JET_TITRE": "Impact de jet",
     "INFO_WALL_ADDED": "1 cloison ajoutée",
-- 
GitLab