From 68560237d0f963899e58fbdef7f7e29b21f6cf8c Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Mon, 27 Jul 2020 20:42:12 +0200
Subject: [PATCH] [exceeding] add plot year for the peak. add many altitudinal
 models.

---
 .../gev_altitudinal_models.py                 | 17 +++++-
 ..._altitudinal_models_cross_term_in_scale.py | 45 +++++++++++++++
 .../gev_altitudinal_models_with_scale.py      | 57 +++++++++++++++++++
 .../polynomial_margin_model/utils.py          | 31 ++++++++++
 .../altitudes_fit/main_altitudes_studies.py   | 13 ++---
 ...es_visualizer_for_non_stationary_models.py | 34 +++++++++--
 .../one_fold_analysis/one_fold_fit.py         |  4 +-
 .../one_fold_analysis/plot_total_aic.py       | 15 +++--
 8 files changed, 197 insertions(+), 19 deletions(-)
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_cross_term_in_scale.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_with_scale.py

diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models.py b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models.py
index 5b67925c..218b2780 100644
--- a/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models.py
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models.py
@@ -36,7 +36,9 @@ class AbstractAltitudinalModel(AbstractSpatioTemporalPolynomialModel):
         name += self.dim_to_str_number(GevParams.LOC, self.coordinates.idx_temporal_coordinates)
         name += self.dim_to_str_number(GevParams.SCALE, self.coordinates.idx_temporal_coordinates)
         if isinstance(self, AbstractAddCrossTermForLocation):
-            name += 'x'
+            name += 'l'
+        if isinstance(self, AbstractAddCrossTermForScale):
+            name += 's'
         return name
 
 
@@ -112,6 +114,19 @@ class AbstractAddCrossTermForLocation(AbstractAltitudinalModel):
         d[GevParams.LOC].insert(1, ((self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates), 1))
         return d
 
+class AbstractAddCrossTermForScale(AbstractAltitudinalModel):
+
+    @property
+    def param_name_to_list_dim_and_degree_for_margin_function(self):
+        d = self.param_name_to_list_dim_and_degree
+        # The two insert below enable to check that the insert_index should indeed be 1
+        assert 1 <= len(d[GevParams.SCALE]) <= 2
+        assert self.coordinates.idx_x_coordinates == d[GevParams.SCALE][0][0]
+        insert_index = 1
+        d[GevParams.SCALE].insert(insert_index, ((self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates), 1))
+        return d
+
+
 
 class NonStationaryCrossTermForLocation(AbstractAddCrossTermForLocation, StationaryAltitudinal):
     pass
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_cross_term_in_scale.py b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_cross_term_in_scale.py
new file mode 100644
index 00000000..77ce775b
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_cross_term_in_scale.py
@@ -0,0 +1,45 @@
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAltitudinalModel, \
+    NonStationaryAltitudinalScaleLinear, NonStationaryAltitudinalLocationLinearScaleLinear, \
+    NonStationaryAltitudinalLocationQuadraticScaleLinear, AbstractAddCrossTermForScale
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models_with_scale import \
+    NonStationaryAltitudinalLocationQuadraticScaleQuadratic, NonStationaryAltitudinalScaleQuadratic, \
+    NonStationaryAltitudinalLocationLinearScaleQuadratic
+from extreme_fit.model.margin_model.polynomial_margin_model.polynomial_margin_model import PolynomialMarginModel
+from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_polynomial_model import \
+    AbstractSpatioTemporalPolynomialModel
+
+
+
+
+class NonStationaryAltitudinalScaleLinearCrossTermForScale(AbstractAddCrossTermForScale,
+                                                              NonStationaryAltitudinalScaleLinear):
+    pass
+
+
+class NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForScale(AbstractAddCrossTermForScale,
+                                                                            NonStationaryAltitudinalLocationLinearScaleLinear):
+    pass
+
+
+class NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForScale(AbstractAddCrossTermForScale,
+                                                                               NonStationaryAltitudinalLocationQuadraticScaleLinear):
+    pass
+
+class NonStationaryAltitudinalScaleQuadraticCrossTermForScale(AbstractAddCrossTermForScale, NonStationaryAltitudinalScaleQuadratic):
+    pass
+
+
+class NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForScale(AbstractAddCrossTermForScale,
+                                                                 NonStationaryAltitudinalLocationLinearScaleQuadratic):
+    pass
+
+
+class NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForScale(AbstractAddCrossTermForScale,
+                                                                    NonStationaryAltitudinalLocationQuadraticScaleQuadratic):
+    pass
+
+
+
+
+
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_with_scale.py b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_with_scale.py
new file mode 100644
index 00000000..1bf7701f
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/gev_altitudinal_models_with_scale.py
@@ -0,0 +1,57 @@
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAltitudinalModel, \
+    AbstractAddCrossTermForLocation
+from extreme_fit.model.margin_model.polynomial_margin_model.polynomial_margin_model import PolynomialMarginModel
+from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_polynomial_model import \
+    AbstractSpatioTemporalPolynomialModel
+
+
+
+
+
+
+class NonStationaryAltitudinalScaleQuadratic(AbstractAltitudinalModel):
+
+    @property
+    def param_name_to_list_dim_and_degree(self):
+        return {
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 2)],
+        }
+
+class NonStationaryAltitudinalLocationLinearScaleQuadratic(AbstractAltitudinalModel):
+
+    @property
+    def param_name_to_list_dim_and_degree(self):
+        return {
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 2)],
+        }
+
+class NonStationaryAltitudinalLocationQuadraticScaleQuadratic(AbstractAltitudinalModel):
+
+    @property
+    def param_name_to_list_dim_and_degree(self):
+        return {
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 2)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 2)],
+        }
+
+
+# Add cross terms
+
+
+
+class NonStationaryAltitudinalScaleQuadraticCrossTermForLocation(AbstractAddCrossTermForLocation, NonStationaryAltitudinalScaleQuadratic):
+    pass
+
+
+class NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForLocation(AbstractAddCrossTermForLocation,
+                                                                 NonStationaryAltitudinalLocationLinearScaleQuadratic):
+    pass
+
+
+class NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForLocation(AbstractAddCrossTermForLocation,
+                                                                    NonStationaryAltitudinalLocationQuadraticScaleQuadratic):
+    pass
+
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/utils.py b/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
index 0ff5aaad..1a002b60 100644
--- a/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
@@ -6,6 +6,18 @@ from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_mode
     NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForLocation, \
     NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForLocation, NonStationaryAltitudinalScaleLinear, \
     NonStationaryAltitudinalScaleLinearCrossTermForLocation
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models_cross_term_in_scale import \
+    NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForScale, \
+    NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForScale, \
+    NonStationaryAltitudinalScaleLinearCrossTermForScale, \
+    NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForScale, \
+    NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForScale, \
+    NonStationaryAltitudinalScaleQuadraticCrossTermForScale
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models_with_scale import \
+    NonStationaryAltitudinalScaleQuadraticCrossTermForLocation, NonStationaryAltitudinalScaleQuadratic, \
+    NonStationaryAltitudinalLocationLinearScaleQuadratic, NonStationaryAltitudinalLocationQuadraticScaleQuadratic, \
+    NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForLocation, \
+    NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForLocation
 from extreme_fit.model.margin_model.polynomial_margin_model.gumbel_altitudinal_models import \
     StationaryGumbelAltitudinal, NonStationaryGumbelAltitudinalScaleLinear, \
     NonStationaryGumbelAltitudinalLocationLinear, NonStationaryGumbelAltitudinalLocationQuadratic, \
@@ -22,6 +34,7 @@ from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_poly
     NonStationaryLocationSpatioTemporalLinearityModelAssertError2, \
     NonStationaryLocationSpatioTemporalLinearityModelAssertError3, NonStationaryLocationSpatioTemporalLinearityModel6
 
+
 ALTITUDINAL_GEV_MODELS = [
                              StationaryAltitudinal,
                              NonStationaryAltitudinalScaleLinear,
@@ -36,8 +49,26 @@ ALTITUDINAL_GEV_MODELS = [
                              NonStationaryAltitudinalLocationQuadraticCrossTermForLocation,
                              NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForLocation,
                              NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForLocation,
+
+                             # Quadratic in the scale
+                             NonStationaryAltitudinalScaleQuadratic,
+                             NonStationaryAltitudinalLocationLinearScaleQuadratic,
+                             NonStationaryAltitudinalLocationQuadraticScaleQuadratic,
+                             NonStationaryAltitudinalScaleQuadraticCrossTermForLocation,
+                             NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForLocation,
+                             NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForLocation,
+
+                             # Cross term for the scale
+                             NonStationaryAltitudinalScaleLinearCrossTermForScale,
+                             NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForScale,
+                             NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForScale,
+                             NonStationaryAltitudinalScaleQuadraticCrossTermForScale,
+                             NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForScale,
+                             NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForScale,
+
                          ][:]
 
+
 ALTITUDINAL_GUMBEL_MODELS = [
                                 StationaryGumbelAltitudinal,
                                 NonStationaryGumbelAltitudinalScaleLinear,
diff --git a/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py b/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py
index 5b013a5f..56b470b2 100644
--- a/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py
+++ b/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py
@@ -2,6 +2,7 @@ import matplotlib as mpl
 import matplotlib.pyplot as plt
 import numpy as np
 
+from extreme_fit.model.margin_model.polynomial_margin_model.utils import ALTITUDINAL_GEV_MODELS
 from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.plot_total_aic import plot_total_aic, \
     plot_individual_aic
 
@@ -16,8 +17,6 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranS
     SafranSnowfall5Days, SafranSnowfall7Days, SafranPrecipitation1Day, SafranPrecipitation3Days, \
     SafranPrecipitation5Days, SafranPrecipitation7Days
 from extreme_data.meteo_france_data.scm_models_data.utils import Season
-from extreme_fit.model.margin_model.polynomial_margin_model.utils import ALTITUDINAL_GEV_MODELS, \
-    ALTITUDINAL_GUMBEL_MODELS
 from projects.altitude_spatial_model.altitudes_fit.altitudes_studies import AltitudesStudies
 from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.altitudes_studies_visualizer_for_non_stationary_models import \
     AltitudesStudiesVisualizerForNonStationaryModels
@@ -34,24 +33,23 @@ def plot_moments(studies, massif_names=None):
 
 
 def plot_altitudinal_fit(studies, massif_names=None):
-    model_classes = ALTITUDINAL_GEV_MODELS + ALTITUDINAL_GUMBEL_MODELS
+    model_classes = ALTITUDINAL_GEV_MODELS
     visualizer = AltitudesStudiesVisualizerForNonStationaryModels(studies=studies,
                                                                   model_classes=model_classes,
                                                                   massif_names=massif_names,
                                                                   show=False)
     # Plot the results for the model that minimizes the individual aic
-    plot_individual_aic(visualizer)
+    # plot_individual_aic(visualizer)
     # Plot the results for the model that minimizes the total aic
     plot_total_aic(model_classes, visualizer)
 
 
 def main():
-    altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000][4:7]
-    # altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000][:]
+    altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000][4:6]
     # todo: l ecart  pour les saisons de l automne ou de sprint
     #  vient probablement de certains zéros pas pris en compte pour le fit,
     # mais pris en compte pour le calcul de mon aic
-    # altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600, 3900][:]
+    altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600, 3900][:]
     study_classes = [SafranSnowfall1Day, SafranSnowfall3Days, SafranSnowfall5Days, SafranSnowfall7Days][:2]
     study_classes = [SafranPrecipitation1Day, SafranPrecipitation3Days, SafranPrecipitation5Days,
                      SafranPrecipitation7Days][:]
@@ -59,6 +57,7 @@ def main():
                      SafranSnowfall3Days, SafranPrecipitation3Days][:1]
     # seasons = [Season.automn, Season.winter, Season.spring][::-1]
     seasons = [Season.winter]
+    # seasons = [Season.winter_extended]
 
     massif_names = None
     # massif_names = ['Aravis']
diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py
index 859e661f..351f9c7c 100644
--- a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py
+++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py
@@ -26,7 +26,7 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
                  show=False,
                  massif_names=None,
                  fit_method=MarginFitMethod.extremes_fevd_mle,
-                 display_only_model_that_pass_anderson_test=True):
+                 display_only_model_that_pass_anderson_test=False):
         super().__init__(studies.study, show=show, save_to_file=not show)
         self.studies = studies
         self.non_stationary_models = model_classes
@@ -127,8 +127,9 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
         self.plot_abstract_fast(massif_name_to_best_coef,
                                 label='{}/Coef/{} plot for {} {}'.format(OneFoldFit.folder_for_plots,
                                                                          coef_name,
-                                                                 SCM_STUDY_CLASS_TO_ABBREVIATION[type(self.study)],
-                                                                 self.study.variable_unit),
+                                                                         SCM_STUDY_CLASS_TO_ABBREVIATION[
+                                                                             type(self.study)],
+                                                                         self.study.variable_unit),
                                 add_x_label=False, graduation=graduation, massif_name_to_text=self.massif_name_to_name,
                                 negative_and_positive_values=negative_and_positive_values)
 
@@ -138,5 +139,30 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
                                                                     self.study.variable_unit),
                                 add_x_label=False, graduation=0.1, massif_name_to_text=self.massif_name_to_name)
 
-    def plot_altitude_change_of_sign(self):
+    def plot_altitude_for_the_peak(self):
         pass
+
+    def plot_year_for_the_peak(self):
+        t_list = 1900 + np.arange(200)
+        for massif_name, one_fold_fit in self.massif_name_to_one_fold_fit.items():
+            ax = plt.gca()
+            # One plot for each altitude
+            print(one_fold_fit.dataset.df_dataset.head())
+            altitudes = self.studies.altitudes
+            print(altitudes)
+            for altitude in altitudes:
+
+                mean_list = []
+                for t in t_list:
+                    coordinate = np.array([altitude, t])
+                    gev_params = one_fold_fit.best_function_from_fit.get_params(coordinate, is_transformed=False)
+                    mean_list.append(gev_params.mean)
+                label = '{} m'.format(altitude)
+                ax.plot(t_list, mean_list, label=label)
+            ax.legend()
+            ax.set_xlabel('Year')
+            ax.set_xlabel('Mean annual maxima of ')
+            self.plot_name = 'Peak year for {}'.format(massif_name)
+            self.show_or_save_to_file(no_title=True)
+            plt.close()
+
diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py
index 1a64a7a3..62d514de 100644
--- a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py
+++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py
@@ -163,7 +163,9 @@ class OneFoldFit(object):
         quantiles = self.compute_empirical_quantiles(estimator=self.best_estimator)
         goodness_of_fit_anderson_test = goodness_of_fit_anderson(quantiles, self.SIGNIFICANCE_LEVEL)
         if not goodness_of_fit_anderson_test:
-            print('{} with {} does not pass the anderson test'.format(self.massif_name, self.folder_for_plots))
+            print('{} with {} does not pass the anderson test for model {}'.format(self.massif_name,
+                                                                                   self.folder_for_plots,
+                                                                                   type(self.best_margin_model)))
         return goodness_of_fit_anderson_test
 
     def compute_empirical_quantiles(self, estimator):
diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/plot_total_aic.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/plot_total_aic.py
index 0c9bba51..9c50cc3e 100644
--- a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/plot_total_aic.py
+++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/plot_total_aic.py
@@ -10,11 +10,16 @@ from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.one_fold_fi
 from projects.exceeding_snow_loads.utils import dpi_paper1_figure
 
 
-def plot_individual_aic(visualizer):
-    OneFoldFit.best_estimator_minimizes_total_aic = False
+def plots(visualizer):
     visualizer.plot_moments()
-    # visualizer.plot_best_coef_maps()
+    visualizer.plot_best_coef_maps()
     visualizer.plot_shape_map()
+    visualizer.plot_year_for_the_peak()
+
+
+def plot_individual_aic(visualizer):
+    OneFoldFit.best_estimator_minimizes_total_aic = False
+    plots(visualizer)
 
 
 def plot_total_aic(model_classes, visualizer):
@@ -45,9 +50,7 @@ def plot_total_aic(model_classes, visualizer):
     # Plot the ranking of the model based on their total aic
     plot_total_aic_repartition(visualizer, sorted_labels, sorted_scores)
     # Plot the results for the model that minimizes the mean aic
-    visualizer.plot_moments()
-    visualizer.plot_shape_map()
-    visualizer.plot_best_coef_maps()
+    plots(visualizer)
 
 
 def plot_total_aic_repartition(visualizer, labels, scores):
-- 
GitLab