From 6cfb41312e9148fad3a26a067ff85fbad8edcaef Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Wed, 31 Jul 2019 14:52:52 +0200
Subject: [PATCH] [EUROCODE DATA] add display function for eurocode data

---
 .../departementalpesfrancaises.py             | 24 -------
 .../eurocode_data/eurocode_visualizer.py      | 30 +++++++++
 .../massif_name_to_departement.py             | 30 +++++++++
 experiment/eurocode_data/region_eurocode.py   | 65 +++++++++++++++++--
 test/test_experiment/test_region_eurocode.py  | 31 +++++++++
 5 files changed, 151 insertions(+), 29 deletions(-)
 create mode 100644 experiment/eurocode_data/eurocode_visualizer.py
 create mode 100644 experiment/eurocode_data/massif_name_to_departement.py
 create mode 100644 test/test_experiment/test_region_eurocode.py

diff --git a/experiment/eurocode_data/departementalpesfrancaises.py b/experiment/eurocode_data/departementalpesfrancaises.py
index 4b30db05..4467bf7c 100644
--- a/experiment/eurocode_data/departementalpesfrancaises.py
+++ b/experiment/eurocode_data/departementalpesfrancaises.py
@@ -51,27 +51,3 @@ class Drome(AbstractDepartementAlpesFrancaises):
         super().__init__(C2)
 
 
-massif_name_to_departements = {
-    'Chablais': [HauteSavoie],
-    'Aravis': [HauteSavoie, Savoie],
-    'Mont-Blanc': [HauteSavoie],
-    'Bauges': [HauteSavoie, Savoie],
-    'Beaufortain': [HauteSavoie, Savoie],
-    'Haute-Tarentaise': [Savoie],
-    'Chartreuse': [Isere, Savoie],
-    'Belledonne': [Isere, Savoie],
-    'Maurienne': [Savoie],
-    'Vanoise': [Savoie],
-    'Haute-Maurienne': [Savoie],
-    'Grandes-Rousses': [Isere, Savoie],
-    'Thabor': [HauteSavoie],
-    'Vercors': [Isere, Drome],
-    'Oisans': [Isere, HautesAlpes],
-    'Pelvoux': [Isere, HautesAlpes],
-    'Queyras': [HautesAlpes],
-    'Devoluy': [Drome, Isere, HautesAlpes],
-    'Champsaur': [HautesAlpes],
-    'Parpaillon': [HautesAlpes, AlpesDeHauteProvence],
-    'Ubaye': [AlpesDeHauteProvence],
-    'Haut_Var-Haut_Verdon': [AlpesDeHauteProvence],
-    'Mercantour': [AlpesMaritimes, AlpesDeHauteProvence]}
diff --git a/experiment/eurocode_data/eurocode_visualizer.py b/experiment/eurocode_data/eurocode_visualizer.py
new file mode 100644
index 00000000..74d031e2
--- /dev/null
+++ b/experiment/eurocode_data/eurocode_visualizer.py
@@ -0,0 +1,30 @@
+from collections import OrderedDict
+import matplotlib.pyplot as plt
+
+from experiment.eurocode_data.massif_name_to_departement import massif_name_to_departements
+from experiment.eurocode_data.region_eurocode import AbstractRegionType
+from utils import get_display_name_from_object_type
+
+
+def display_region_limit(region_type, altitudes, ordered_massif_name_to_quantiles, ordered_massif_name_to_significances=None,
+                         display=True):
+    assert isinstance(ordered_massif_name_to_quantiles, OrderedDict)
+    assert ordered_massif_name_to_significances is None or isinstance(ordered_massif_name_to_significances, OrderedDict)
+    # First, select massif name correspond to the region
+    massif_name_belong_to_the_region = []
+    for massif_name in ordered_massif_name_to_quantiles.keys():
+        if any([isinstance(dep.region, region_type) for dep in massif_name_to_departements[massif_name]]):
+            massif_name_belong_to_the_region.append(massif_name)
+    region_object = region_type() # type: AbstractRegionType
+    # Then, display the limit for the region
+    fig, ax = plt.subplots(1, 1)
+    ax.plot(altitudes, [region_object.eurocode_max_loading(altitude) for altitude in altitudes], label='Eurocode limit')
+    # Finally, display the massif curve
+    for massif_name in massif_name_belong_to_the_region:
+        ax.plot(altitudes, ordered_massif_name_to_quantiles[massif_name], label=massif_name)
+    ax.set_title('{} Eurocode region'.format(get_display_name_from_object_type(region_type)))
+    ax.set_xlabel('Altitude')
+    ax.set_ylabel('0.98 quantile (in N $m^-2$)')
+    ax.legend()
+    if display:
+        plt.show()
\ No newline at end of file
diff --git a/experiment/eurocode_data/massif_name_to_departement.py b/experiment/eurocode_data/massif_name_to_departement.py
new file mode 100644
index 00000000..fe9807ac
--- /dev/null
+++ b/experiment/eurocode_data/massif_name_to_departement.py
@@ -0,0 +1,30 @@
+from typing import Dict, List
+
+from experiment.eurocode_data.departementalpesfrancaises import HauteSavoie, Savoie, Isere, Drome, HautesAlpes, \
+    AlpesDeHauteProvence, AlpesMaritimes, AbstractDepartementAlpesFrancaises
+
+massif_name_to_departements = {
+    'Chablais': [HauteSavoie],
+    'Aravis': [HauteSavoie, Savoie],
+    'Mont-Blanc': [HauteSavoie],
+    'Bauges': [HauteSavoie, Savoie],
+    'Beaufortain': [HauteSavoie, Savoie],
+    'Haute-Tarentaise': [Savoie],
+    'Chartreuse': [Isere, Savoie],
+    'Belledonne': [Isere, Savoie],
+    'Maurienne': [Savoie],
+    'Vanoise': [Savoie],
+    'Haute-Maurienne': [Savoie],
+    'Grandes-Rousses': [Isere, Savoie],
+    'Thabor': [HauteSavoie],
+    'Vercors': [Isere, Drome],
+    'Oisans': [Isere, HautesAlpes],
+    'Pelvoux': [Isere, HautesAlpes],
+    'Queyras': [HautesAlpes],
+    'Devoluy': [Drome, Isere, HautesAlpes],
+    'Champsaur': [HautesAlpes],
+    'Parpaillon': [HautesAlpes, AlpesDeHauteProvence],
+    'Ubaye': [AlpesDeHauteProvence],
+    'Haut_Var-Haut_Verdon': [AlpesDeHauteProvence],
+    'Mercantour': [AlpesMaritimes, AlpesDeHauteProvence]}
+massif_name_to_departements = {m: [d() for d in deps] for m, deps in massif_name_to_departements.items()}  # type: Dict[str, List[AbstractDepartementAlpesFrancaises]]
diff --git a/experiment/eurocode_data/region_eurocode.py b/experiment/eurocode_data/region_eurocode.py
index 5ede49c6..6c72caf6 100644
--- a/experiment/eurocode_data/region_eurocode.py
+++ b/experiment/eurocode_data/region_eurocode.py
@@ -1,16 +1,71 @@
+class AbstractRegionType(object):
 
+    def __init__(self, sk0, sad) -> None:
+        # Valeurs caracteristique de la charge de neige sur le sol à une altitude inférieure à 200m
+        self.sk0 = sk0
+        # Valeur de calcul de la charge exceptionelle
+        self.sad = sad
 
-class AbstractRegionType(object):
-    pass
+    def eurocode_max_loading(self, altitude):
+        valeur_caracteritique = self.valeur_caracteristique(altitude)
+        if self.sad is None:
+            return valeur_caracteritique
+        else:
+            return max(self.sad, valeur_caracteritique)
+
+    def valeur_caracteristique(self, altitude):
+        return self.sk0 + self.lois_de_variation_de_la_valeur_caracteristique(altitude)
+
+    def lois_de_variation_de_la_valeur_caracteristique(self, altitude):
+        if 200 <= altitude <= 2000:
+            if 200 <= altitude <= 500:
+                a, b = self.lois_de_variation_200_and_500
+            elif 500 <= altitude <= 1000:
+                a, b = self.lois_de_variation_500_and_1000
+            else:
+                a, b = self.lois_de_variation_1000_and_2000
+            return a * altitude / 1000 + b
+        else:
+            raise ValueError('altitude {}m is out of range'.format(altitude))
+
+    @property
+    def lois_de_variation_200_and_500(self):
+        return 1.0, -0.20
+
+    @property
+    def lois_de_variation_500_and_1000(self):
+        return 1.5, -0.45
+
+    @property
+    def lois_de_variation_1000_and_2000(self):
+        return 3.5, -2.45
 
 
 class C1(AbstractRegionType):
-    pass
+
+    def __init__(self) -> None:
+        super().__init__(0.65, None)
 
 
 class C2(AbstractRegionType):
-    pass
+
+    def __init__(self) -> None:
+        super().__init__(0.65, 1.35)
 
 
 class E(AbstractRegionType):
-    pass
\ No newline at end of file
+
+    def __init__(self) -> None:
+        super().__init__(1.40, None)
+
+    @property
+    def lois_de_variation_200_and_500(self):
+        return 1.5, -0.30
+
+    @property
+    def lois_de_variation_500_and_1000(self):
+        return 3.5, -1.30
+
+    @property
+    def lois_de_variation_1000_and_2000(self):
+        return 7, -4.80
diff --git a/test/test_experiment/test_region_eurocode.py b/test/test_experiment/test_region_eurocode.py
new file mode 100644
index 00000000..b9c1ad9b
--- /dev/null
+++ b/test/test_experiment/test_region_eurocode.py
@@ -0,0 +1,31 @@
+import unittest
+from collections import OrderedDict
+
+from experiment.eurocode_data.eurocode_visualizer import display_region_limit
+from experiment.eurocode_data.region_eurocode import C1, E
+from experiment.meteo_france_data.scm_models_data.crocus.crocus import CrocusSweTotal
+from experiment.meteo_france_data.scm_models_data.visualization.study_visualization.main_study_visualizer import \
+    study_iterator_global
+from experiment.meteo_france_data.scm_models_data.visualization.study_visualization.study_visualizer import \
+    StudyVisualizer
+from experiment.trend_analysis.non_stationary_trends import \
+    ConditionalIndedendenceLocationTrendTest
+from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.uniform_normalization import \
+    BetweenZeroAndOneNormalization, BetweenZeroAndOneNormalizationMinEpsilon, BetweenZeroAndOneNormalizationMaxEpsilon
+from utils import get_display_name_from_object_type
+
+
+class TestCoordinateSensitivity(unittest.TestCase):
+    DISPLAY = False
+
+    def test_region_eurocode(self):
+        altitudes = [900, 1200, 1500, 1800]
+        ordered_massif_name_to_quantiles = OrderedDict()
+        ordered_massif_name_to_quantiles['Vanoise'] = [1.2, 1.5, 1.7, 2.1]
+        ordered_massif_name_to_quantiles['Vercors'] = [0.7, 0.8, 1.1, 1.5]
+        display_region_limit(C1, altitudes, ordered_massif_name_to_quantiles, display=self.DISPLAY)
+        display_region_limit(E, altitudes, ordered_massif_name_to_quantiles, display=self.DISPLAY)
+
+
+if __name__ == '__main__':
+    unittest.main()
-- 
GitLab