From fd5c724191a32146b6266e2423c94cc69a57cde7 Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Mon, 14 Sep 2020 16:24:38 +0200
Subject: [PATCH] [contrasting] improve pointwise study. add new models based
 on this study. add altitude_group.py

---
 .../visualization/plot_utils.py               |  34 +++--
 .../gev_altitudinal_models.py                 |  59 +++++---
 .../__init__.py                               |   0
 .../cross terms/__init__.py                   |   0
 .../cross terms/gev_with_loc_cross_term.py    |  91 ++++++++++++
 .../cross terms/gev_with_scale_cross_term.py  |  91 ++++++++++++
 .../cross terms/gev_with_shape_cross_term.py  |  91 ++++++++++++
 .../gev_with_constant_shape_wrt_altitude.py   | 130 +++++++++++++++++
 .../gev_with_linear_shape_wrt_altitude.py     | 136 ++++++++++++++++++
 .../polynomial_margin_model/utils.py          |  55 ++++---
 .../altitudes_fit/main_altitudes_studies.py   |  14 +-
 .../one_fold_analysis/altitude_group.py       |  28 ++++
 ...es_visualizer_for_non_stationary_models.py |  11 +-
 .../one_fold_analysis/one_fold_fit.py         |  10 +-
 .../one_fold_analysis/plot_total_aic.py       |  10 +-
 .../snowfall_plot.py                          |   2 +-
 .../pointwise_gev_study_visualizer.py         | 110 ++++++++++++--
 17 files changed, 792 insertions(+), 80 deletions(-)
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/__init__.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/__init__.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_loc_cross_term.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_scale_cross_term.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_shape_cross_term.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_constant_shape_wrt_altitude.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_linear_shape_wrt_altitude.py
 create mode 100644 projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitude_group.py

diff --git a/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py b/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py
index 0c22e10d..f94aa78a 100644
--- a/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py
+++ b/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py
@@ -7,25 +7,31 @@ from extreme_data.meteo_france_data.scm_models_data.visualization.create_shifted
     get_half_colormap
 
 
-def plot_against_altitude(altitudes, ax, massif_id, massif_name, values, fill=False):
-    di = massif_id // 8
-    if di == 0:
-        linestyle = '-'
-    elif di == 1:
-        linestyle = 'dotted'
+def plot_against_altitude(x_ticks, ax, massif_id, massif_name, values, altitude=None, fill=False, massif_name_as_labels=True):
+    if massif_name_as_labels:
+        di = massif_id // 8
+        if di == 0:
+            linestyle = '-'
+        elif di == 1:
+            linestyle = 'dotted'
+        else:
+            linestyle = '--'
+        colors = list(mcolors.TABLEAU_COLORS)
+        colors[-3:-1] = []  # remove gray and olive
+        color = colors[massif_id % 8]
+        # Label
+        massif_name_str = ' '.join(massif_name.split('_'))
+        label = massif_name_str
     else:
-        linestyle = '--'
-    colors = list(mcolors.TABLEAU_COLORS)
-    colors[-3:-1] = []  # remove gray and olive
-    color = colors[massif_id % 8]
-    massif_name_str = ' '.join(massif_name.split('_'))
-    label = massif_name_str
+        color = None
+        linestyle = None
+        label = '{} m'.format(altitude)
     if not fill:
-        ax.plot(altitudes, values, color=color, linewidth=2, label=label, linestyle=linestyle)
+        ax.plot(x_ticks, values, color=color, linewidth=2, label=label, linestyle=linestyle)
     else:
         lower_bound, upper_bound = zip(*values)
         # ax.fill_between(altitudes, lower_bound, upper_bound, color=color, alpha=0.2, label=label + '95\% confidence interval')
-        ax.fill_between(altitudes, lower_bound, upper_bound, color=color, alpha=0.2)
+        ax.fill_between(x_ticks, lower_bound, upper_bound, color=color, alpha=0.2)
 
 
 def load_plot(cmap, graduation, label, massif_name_to_value, altitude, fit_method, add_x_label=True,
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 547f39f1..0ee8a285 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
@@ -34,16 +34,18 @@ class AbstractAltitudinalModel(AbstractSpatioTemporalPolynomialModel):
 
     @property
     def name_str(self):
-        name = self.DISTRIBUTION_STR
-        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)
-        shape_str_number = self.dim_to_str_number(GevParams.SHAPE, self.coordinates.idx_temporal_coordinates)
-        if shape_str_number != '0':
-            name += shape_str_number
-        if isinstance(self, AbstractAddCrossTermForLocation):
-            name += 'x'
-        if isinstance(self, AbstractAddCrossTermForScale):
-            name += 's'
+        name = ''
+        for coordinate_name, idx in zip(['s', 't'], [self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates]):
+            name += coordinate_name
+            for param_name in GevParams.PARAM_NAMES:
+                name += self.dim_to_str_number(param_name, idx)
+        if isinstance(self, AbstractAddCrossTerm):
+            name += 'sxt'
+            for c in [AbstractAddCrossTermForLocation, AbstractAddCrossTermForScale, AbstractAddCrossTermForShape]:
+                if isinstance(self, c):
+                    name += '1'
+                else:
+                    name += '0'
         return name
 
 
@@ -86,6 +88,7 @@ class NonStationaryAltitudinalLocationQuadratic(AbstractAltitudinalModel):
             GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1)]
         }
 
+
 class NonStationaryAltitudinalLocationCubic(AbstractAltitudinalModel):
 
     @property
@@ -95,6 +98,7 @@ class NonStationaryAltitudinalLocationCubic(AbstractAltitudinalModel):
             GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1)]
         }
 
+
 class NonStationaryAltitudinalLocationOrder4(AbstractAltitudinalModel):
 
     @property
@@ -127,7 +131,10 @@ class NonStationaryAltitudinalLocationQuadraticScaleLinear(AbstractAltitudinalMo
 
 # Add cross terms
 
-class AbstractAddCrossTermForLocation(AbstractAltitudinalModel):
+class AbstractAddCrossTerm(AbstractAltitudinalModel):
+    pass
+
+class AbstractAddCrossTermForLocation(AbstractAddCrossTerm):
 
     # @property
     # def param_name_to_list_dim_and_degree_for_margin_function(self):
@@ -147,7 +154,8 @@ class AbstractAddCrossTermForLocation(AbstractAltitudinalModel):
             d[GevParams.LOC] = [cross_term]
         return d
 
-class AbstractAddCrossTermForScale(AbstractAltitudinalModel):
+
+class AbstractAddCrossTermForScale(AbstractAddCrossTerm):
 
     @property
     def param_name_to_list_dim_and_degree_for_margin_function(self):
@@ -156,10 +164,27 @@ class AbstractAddCrossTermForScale(AbstractAltitudinalModel):
         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))
+        d[GevParams.SCALE].insert(insert_index,
+                                  ((self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates), 1))
         return d
 
 
+class AbstractAddCrossTermForShape(AbstractAddCrossTerm):
+
+    @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.SHAPE]) <= 2
+        # assert self.coordinates.idx_x_coordinates == d[GevParams.SHAPE][0][0]
+        if GevParams.SHAPE in d:
+            insert_index = 1 if self.coordinates.idx_x_coordinates == d[GevParams.SHAPE][0][0] else 0
+            d[GevParams.SHAPE].insert(insert_index,
+                                      ((self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates), 1))
+        else:
+            d[GevParams.SHAPE] = [((self.coordinates.idx_x_coordinates, self.coordinates.idx_temporal_coordinates), 1)]
+        return d
+
 
 class NonStationaryCrossTermForLocation(AbstractAddCrossTermForLocation, StationaryAltitudinal):
     pass
@@ -174,16 +199,19 @@ class NonStationaryAltitudinalLocationQuadraticCrossTermForLocation(AbstractAddC
                                                                     NonStationaryAltitudinalLocationQuadratic):
     pass
 
+
 class NonStationaryAltitudinalLocationCubicCrossTermForLocation(AbstractAddCrossTermForLocation,
                                                                 NonStationaryAltitudinalLocationCubic,
                                                                 ):
     pass
 
+
 class NonStationaryAltitudinalLocationOrder4CrossTermForLocation(AbstractAddCrossTermForLocation,
-                                                                NonStationaryAltitudinalLocationOrder4,
-                                                                ):
+                                                                 NonStationaryAltitudinalLocationOrder4,
+                                                                 ):
     pass
 
+
 class NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForLocation(AbstractAddCrossTermForLocation,
                                                                             NonStationaryAltitudinalLocationLinearScaleLinear):
     pass
@@ -197,4 +225,3 @@ class NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForLocation(A
 class NonStationaryAltitudinalScaleLinearCrossTermForLocation(AbstractAddCrossTermForLocation,
                                                               NonStationaryAltitudinalScaleLinear):
     pass
-
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/__init__.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/__init__.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_loc_cross_term.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_loc_cross_term.py
new file mode 100644
index 00000000..732ee63a
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_loc_cross_term.py	
@@ -0,0 +1,91 @@
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAddCrossTermForLocation, \
+    StationaryAltitudinal
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_constant_shape_wrt_altitude import \
+    AltitudinalShapeConstantTimeLocationLinear, AltitudinalShapeConstantTimeScaleLinear, \
+    AltitudinalShapeConstantTimeShapeLinear, AltitudinalShapeConstantTimeLocShapeLinear, \
+    AltitudinalShapeConstantTimeScaleShapeLinear, AltitudinalShapeConstantTimeLocScaleLinear, \
+    AltitudinalShapeConstantTimeLocScaleShapeLinear
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_linear_shape_wrt_altitude import \
+    AltitudinalShapeLinearTimeLocScaleLinear, AltitudinalShapeLinearTimeLocationLinear, \
+    AltitudinalShapeLinearTimeScaleLinear, AltitudinalShapeLinearTimeShapeLinear, \
+    AltitudinalShapeLinearTimeLocShapeLinear, AltitudinalShapeLinearTimeScaleShapeLinear, \
+    AltitudinalShapeLinearTimeLocScaleShapeLinear, AltitudinalShapeLinearTimeStationary
+
+
+class StationaryAltitudinalCrossTermLoc(AbstractAddCrossTermForLocation, StationaryAltitudinal):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocationLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                               AltitudinalShapeConstantTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                            AltitudinalShapeConstantTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                            AltitudinalShapeConstantTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                               AltitudinalShapeConstantTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                                 AltitudinalShapeConstantTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                               AltitudinalShapeConstantTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                                    AltitudinalShapeConstantTimeLocScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeStationaryCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                         AltitudinalShapeLinearTimeStationary):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocationLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                             AltitudinalShapeLinearTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                          AltitudinalShapeLinearTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                          AltitudinalShapeLinearTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                             AltitudinalShapeLinearTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                             AltitudinalShapeLinearTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                               AltitudinalShapeLinearTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleShapeLinearCrossTermLoc(AbstractAddCrossTermForLocation,
+                                                                  AltitudinalShapeLinearTimeLocScaleShapeLinear):
+    pass
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_scale_cross_term.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_scale_cross_term.py
new file mode 100644
index 00000000..9767235a
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_scale_cross_term.py	
@@ -0,0 +1,91 @@
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAddCrossTermForScale, \
+    StationaryAltitudinal
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_constant_shape_wrt_altitude import \
+    AltitudinalShapeConstantTimeLocationLinear, AltitudinalShapeConstantTimeScaleLinear, \
+    AltitudinalShapeConstantTimeShapeLinear, AltitudinalShapeConstantTimeLocShapeLinear, \
+    AltitudinalShapeConstantTimeScaleShapeLinear, AltitudinalShapeConstantTimeLocScaleLinear, \
+    AltitudinalShapeConstantTimeLocScaleShapeLinear
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_linear_shape_wrt_altitude import \
+    AltitudinalShapeLinearTimeLocScaleLinear, AltitudinalShapeLinearTimeLocationLinear, \
+    AltitudinalShapeLinearTimeScaleLinear, AltitudinalShapeLinearTimeShapeLinear, \
+    AltitudinalShapeLinearTimeLocShapeLinear, AltitudinalShapeLinearTimeScaleShapeLinear, \
+    AltitudinalShapeLinearTimeLocScaleShapeLinear, AltitudinalShapeLinearTimeStationary
+
+
+class StationaryAltitudinalCrossTermScale(AbstractAddCrossTermForScale, StationaryAltitudinal):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocationLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                               AltitudinalShapeConstantTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                            AltitudinalShapeConstantTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                            AltitudinalShapeConstantTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                               AltitudinalShapeConstantTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                                 AltitudinalShapeConstantTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                               AltitudinalShapeConstantTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                                    AltitudinalShapeConstantTimeLocScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeStationaryCrossTermScale(AbstractAddCrossTermForScale,
+                                                         AltitudinalShapeLinearTimeStationary):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocationLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                             AltitudinalShapeLinearTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                          AltitudinalShapeLinearTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                          AltitudinalShapeLinearTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                             AltitudinalShapeLinearTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                             AltitudinalShapeLinearTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                               AltitudinalShapeLinearTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleShapeLinearCrossTermScale(AbstractAddCrossTermForScale,
+                                                                  AltitudinalShapeLinearTimeLocScaleShapeLinear):
+    pass
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_shape_cross_term.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_shape_cross_term.py
new file mode 100644
index 00000000..281388d4
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/cross terms/gev_with_shape_cross_term.py	
@@ -0,0 +1,91 @@
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAddCrossTermForShape, \
+    StationaryAltitudinal
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_constant_shape_wrt_altitude import \
+    AltitudinalShapeConstantTimeLocationLinear, AltitudinalShapeConstantTimeScaleLinear, \
+    AltitudinalShapeConstantTimeShapeLinear, AltitudinalShapeConstantTimeLocShapeLinear, \
+    AltitudinalShapeConstantTimeScaleShapeLinear, AltitudinalShapeConstantTimeLocScaleLinear, \
+    AltitudinalShapeConstantTimeLocScaleShapeLinear
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_linear_shape_wrt_altitude import \
+    AltitudinalShapeLinearTimeLocScaleLinear, AltitudinalShapeLinearTimeLocationLinear, \
+    AltitudinalShapeLinearTimeScaleLinear, AltitudinalShapeLinearTimeShapeLinear, \
+    AltitudinalShapeLinearTimeLocShapeLinear, AltitudinalShapeLinearTimeScaleShapeLinear, \
+    AltitudinalShapeLinearTimeLocScaleShapeLinear, AltitudinalShapeLinearTimeStationary
+
+
+class StationaryAltitudinalCrossTermShape(AbstractAddCrossTermForShape, StationaryAltitudinal):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocationLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                               AltitudinalShapeConstantTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                            AltitudinalShapeConstantTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                            AltitudinalShapeConstantTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                               AltitudinalShapeConstantTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeScaleShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                                 AltitudinalShapeConstantTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                               AltitudinalShapeConstantTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeConstantTimeLocScaleShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                                    AltitudinalShapeConstantTimeLocScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeStationaryCrossTermShape(AbstractAddCrossTermForShape,
+                                                         AltitudinalShapeLinearTimeStationary):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocationLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                             AltitudinalShapeLinearTimeLocationLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                          AltitudinalShapeLinearTimeScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                          AltitudinalShapeLinearTimeShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                             AltitudinalShapeLinearTimeLocShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                             AltitudinalShapeLinearTimeLocScaleLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeScaleShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                               AltitudinalShapeLinearTimeScaleShapeLinear):
+    pass
+
+
+class AltitudinalShapeLinearTimeLocScaleShapeLinearCrossTermShape(AbstractAddCrossTermForShape,
+                                                                  AltitudinalShapeLinearTimeLocScaleShapeLinear):
+    pass
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_constant_shape_wrt_altitude.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_constant_shape_wrt_altitude.py
new file mode 100644
index 00000000..5131d80f
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_constant_shape_wrt_altitude.py
@@ -0,0 +1,130 @@
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAltitudinalModel
+
+
+class AltitudinalShapeConstantTimeStationary(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)]
+        }
+
+
+class AltitudinalShapeConstantTimeLocationLinear(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)]
+        }
+
+
+class AltitudinalShapeConstantTimeScaleLinear(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, 1)]
+        }
+
+
+class AltitudinalShapeConstantTimeShapeLinear(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeConstantTimeLocShapeLinear(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeConstantTimeLocScaleLinear(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, 1)],
+        }
+
+
+class AltitudinalShapeConstantTimeScaleShapeLinear(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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeConstantTimeLocScaleShapeLinear(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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+# Quadratic
+
+class AltitudinalShapeConstantTimeLocQuadratic(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)],
+        }
+
+
+class AltitudinalShapeConstantTimeLocQuadraticScaleLinear(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, 1)],
+        }
+
+
+class AltitudinalShapeConstantTimeLocQuadraticShapeLinear(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeConstantTimeLocQuadraticScaleShapeLinear(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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_temporal_coordinates, 1)]
+        }
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_linear_shape_wrt_altitude.py b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_linear_shape_wrt_altitude.py
new file mode 100644
index 00000000..5b9f3abc
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/models_based_on_pariwise_analysis/gev_with_linear_shape_wrt_altitude.py
@@ -0,0 +1,136 @@
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models import AbstractAltitudinalModel
+
+
+class AltitudinalShapeLinearTimeStationary(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocationLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeScaleLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeShapeLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocShapeLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocScaleLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeScaleShapeLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+class AltitudinalShapeLinearTimeLocScaleShapeLinear(AltitudinalShapeLinearTimeStationary):
+
+    @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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+# Quadratic
+
+
+class AltitudinalShapeLinearTimeLocQuadratic(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocQuadraticScaleLinear(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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocQuadraticShapeLinear(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)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
+
+
+class AltitudinalShapeLinearTimeLocQuadraticScaleShapeLinear(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, 1)],
+            GevParams.SHAPE: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)]
+        }
\ No newline at end of file
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 ea4282f8..0afdd4dd 100644
--- a/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
@@ -4,17 +4,9 @@ from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_mode
     NonStationaryCrossTermForLocation, NonStationaryAltitudinalLocationLinearCrossTermForLocation, \
     NonStationaryAltitudinalLocationQuadraticCrossTermForLocation, \
     NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForLocation, \
-    NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForLocation, NonStationaryAltitudinalScaleLinear, \
-    NonStationaryAltitudinalScaleLinearCrossTermForLocation, NonStationaryAltitudinalLocationCubicCrossTermForLocation, \
-    NonStationaryAltitudinalLocationCubic, NonStationaryAltitudinalLocationOrder4CrossTermForLocation, \
-    NonStationaryAltitudinalLocationOrder4
-from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models_cross_term_in_scale import \
-    NonStationaryAltitudinalLocationLinearScaleQuadraticCrossTermForScale, \
-    NonStationaryAltitudinalLocationQuadraticScaleQuadraticCrossTermForScale, \
-    NonStationaryAltitudinalScaleLinearCrossTermForScale, \
-    NonStationaryAltitudinalLocationLinearScaleLinearCrossTermForScale, \
-    NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForScale, \
-    NonStationaryAltitudinalScaleQuadraticCrossTermForScale
+    NonStationaryAltitudinalScaleLinear, \
+    NonStationaryAltitudinalLocationCubicCrossTermForLocation, \
+    NonStationaryAltitudinalLocationCubic
 from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_models_only_altitude_and_scale import \
     StationaryAltitudinalOnlyScale, NonStationaryAltitudinalOnlyScaleLocationLinear, \
     NonStationaryAltitudinalOnlyScaleLocationQuadratic, NonStationaryAltitudinalOnlyScaleLocationCubic, \
@@ -23,17 +15,9 @@ from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_mode
     NonStationaryAltitudinalOnlyScaleLocationQuadraticCrossTermForLocation, \
     NonStationaryAltitudinalOnlyScaleLocationCubicCrossTermForLocation, \
     NonStationaryAltitudinalOnlyScaleLocationOrder4CrossTermForLocation
-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.gev_altitudinal_models_with_scale_2 import \
     NonStationaryAltitudinalScaleLinearCrossTermForLocation, \
-    NonStationaryAltitudinalScaleLinearLocationLinearCrossTermForLocation, \
     NonStationaryAltitudinalLocationQuadraticScaleLinearCrossTermForLocation, \
-    NonStationaryAltitudinalScaleQuadraticLocationLinearCrossTermForLocation, \
-    NonStationaryAltitudinalLocationCubicScaleQuadraticCrossTermForLocation, \
     NonStationaryAltitudinalLocationCubicScaleLinearCrossTermForLocation, \
     NonStationaryAltitudinalLocationCubicScaleLinear
 from extreme_fit.model.margin_model.polynomial_margin_model.gumbel_altitudinal_models import \
@@ -45,6 +29,16 @@ from extreme_fit.model.margin_model.polynomial_margin_model.gumbel_altitudinal_m
     NonStationaryGumbelAltitudinalLocationLinearScaleLinearCrossTermForLocation, \
     NonStationaryGumbelAltitudinalLocationQuadraticScaleLinearCrossTermForLocation, \
     NonStationaryGumbelAltitudinalScaleLinearCrossTermForLocation, NonStationaryGumbelCrossTermForLocation
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_constant_shape_wrt_altitude import \
+    AltitudinalShapeConstantTimeLocShapeLinear, \
+    AltitudinalShapeConstantTimeLocScaleLinear, AltitudinalShapeConstantTimeScaleShapeLinear, \
+    AltitudinalShapeConstantTimeLocScaleShapeLinear, AltitudinalShapeConstantTimeLocationLinear, \
+    AltitudinalShapeConstantTimeScaleLinear, AltitudinalShapeConstantTimeShapeLinear
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_linear_shape_wrt_altitude import \
+    AltitudinalShapeLinearTimeStationary, AltitudinalShapeLinearTimeLocScaleShapeLinear, \
+    AltitudinalShapeLinearTimeLocationLinear, AltitudinalShapeLinearTimeScaleLinear, \
+    AltitudinalShapeLinearTimeShapeLinear, AltitudinalShapeLinearTimeLocShapeLinear, \
+    AltitudinalShapeLinearTimeLocScaleLinear, AltitudinalShapeLinearTimeScaleShapeLinear
 from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_polynomial_model import \
     NonStationaryLocationSpatioTemporalLinearityModel1, NonStationaryLocationSpatioTemporalLinearityModel2, \
     NonStationaryLocationSpatioTemporalLinearityModel3, NonStationaryLocationSpatioTemporalLinearityModel4, \
@@ -97,6 +91,29 @@ ALTITUDINAL_GEV_MODELS_LOCATION_QUADRATIC_MINIMUM = [
 
 ]
 
+ALTITUDINAL_GEV_MODELS_BASED_ON_POINTWISE_ANALYSIS = [
+
+    # With a constant shape for the altitude (8 models)
+    StationaryAltitudinal,
+    AltitudinalShapeConstantTimeLocationLinear,
+    AltitudinalShapeConstantTimeScaleLinear,
+    AltitudinalShapeConstantTimeShapeLinear,
+    AltitudinalShapeConstantTimeLocShapeLinear,
+    AltitudinalShapeConstantTimeLocScaleLinear,
+    AltitudinalShapeConstantTimeScaleShapeLinear,
+    AltitudinalShapeConstantTimeLocScaleShapeLinear,
+    # With a linear shape for the altitude (8 models)
+    AltitudinalShapeLinearTimeStationary,
+    AltitudinalShapeLinearTimeLocationLinear,
+    AltitudinalShapeLinearTimeScaleLinear,
+    AltitudinalShapeLinearTimeShapeLinear,
+    AltitudinalShapeLinearTimeLocShapeLinear,
+    AltitudinalShapeLinearTimeLocScaleLinear,
+    AltitudinalShapeLinearTimeScaleShapeLinear,
+    AltitudinalShapeLinearTimeLocScaleShapeLinear,
+
+]
+
 ALTITUDINAL_GEV_MODELS_LOCATION_ONLY_SCALE_ALTITUDES = [
     StationaryAltitudinalOnlyScale,
     NonStationaryAltitudinalOnlyScaleLocationLinear,
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 87dd6ed5..ee31f000 100644
--- a/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py
+++ b/projects/altitude_spatial_model/altitudes_fit/main_altitudes_studies.py
@@ -5,7 +5,8 @@ import numpy as np
 from extreme_data.meteo_france_data.adamont_data.abstract_simulation_study import SimulationStudy
 from extreme_data.meteo_france_data.adamont_data.snowfall_simulation import SafranSnowfallSimulationRCP85
 from extreme_fit.model.margin_model.polynomial_margin_model.utils import ALTITUDINAL_GEV_MODELS, \
-    ALTITUDINAL_GEV_MODELS_LOCATION_QUADRATIC_MINIMUM, ALTITUDINAL_GEV_MODELS_LOCATION_ONLY_SCALE_ALTITUDES, ALTITUDINAL_GEV_MODELS_LOCATION
+    ALTITUDINAL_GEV_MODELS_LOCATION_QUADRATIC_MINIMUM, ALTITUDINAL_GEV_MODELS_LOCATION_ONLY_SCALE_ALTITUDES, \
+    ALTITUDINAL_GEV_MODELS_LOCATION, ALTITUDINAL_GEV_MODELS_BASED_ON_POINTWISE_ANALYSIS
 from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.plot_total_aic import plot_total_aic, \
     plot_individual_aic
 from spatio_temporal_dataset.coordinates.temporal_coordinates.temperature_covariate import MeanAlpsTemperatureCovariate
@@ -38,7 +39,8 @@ def plot_moments(studies, massif_names=None):
 
 def plot_altitudinal_fit(studies, massif_names=None):
     # model_classes = ALTITUDINAL_GEV_MODELS_LOCATION_ONLY_SCALE_ALTITUDES
-    model_classes = ALTITUDINAL_GEV_MODELS_LOCATION_QUADRATIC_MINIMUM
+    # model_classes = ALTITUDINAL_GEV_MODELS_LOCATION_QUADRATIC_MINIMUM
+    model_classes = ALTITUDINAL_GEV_MODELS_BASED_ON_POINTWISE_ANALYSIS
     # model_classes = ALTITUDINAL_GEV_MODELS_LOCATION
     # model_classes = ALTITUDINAL_GEV_MODELS_LOCATION_CUBIC_MINIMUM
     # model_classes = ALTITUDINAL_GEV_MODELS_QUADRATIC
@@ -73,13 +75,13 @@ def main():
     study_classes = [SafranSnowfall1Day, SafranSnowfall3Days, SafranPrecipitation1Day
                      , SafranPrecipitation3Days][:1]
 
-    # altitudes = [1500, 1800]
-    study_classes = [SafranSnowfall1Day, SafranSnowfallSimulationRCP85][:]
+    altitudes = [1800, 2100, 2400]
+    study_classes = [SafranSnowfall1Day][:]
 
     # Common parameters
-    altitudes = [600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600]
+    # altitudes = [600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600]
     massif_names = None
-    seasons = [Season.winter]
+    seasons = [Season.annual]
 
     for season in seasons:
         for study_class in study_classes:
diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitude_group.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitude_group.py
new file mode 100644
index 00000000..804abddf
--- /dev/null
+++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitude_group.py
@@ -0,0 +1,28 @@
+from enum import Enum
+
+
+class AltitudeGroup(Enum):
+    low = 0
+    mid = 1
+    high = 2
+    unspecfied = 3
+
+
+def altitude_group_to_reference_altitude():
+    return {
+        AltitudeGroup.low: 1000,
+        AltitudeGroup.mid: 2000,
+        AltitudeGroup.high: 3000,
+        AltitudeGroup.unspecfied: 1000,
+    }
+
+def get_altitude_group_from_altitudes(altitudes):
+    s = set(altitudes)
+    if s == {900, 1200, 1500}:
+        return AltitudeGroup.low
+    elif s == {1800, 2100, 2400}:
+        return AltitudeGroup.mid
+    elif s == {2700, 3000, 3300}:
+        return AltitudeGroup.high
+    else:
+        return AltitudeGroup.unspecfied
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 3c7e4d70..3edeca7b 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
@@ -43,7 +43,8 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
         self._massif_name_to_one_fold_fit = {}
         for massif_name in self.massif_names:
             assert top_n_values_to_remove is None
-            dataset = studies.spatio_temporal_dataset(massif_name=massif_name, top_n_values_to_remove=top_n_values_to_remove)
+            dataset = studies.spatio_temporal_dataset(massif_name=massif_name,
+                                                      top_n_values_to_remove=top_n_values_to_remove)
             old_fold_fit = OneFoldFit(massif_name, dataset, model_classes, self.fit_method,
                                       self.temporal_covariate_for_fit)
             self._massif_name_to_one_fold_fit[massif_name] = old_fold_fit
@@ -143,7 +144,8 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
     def plot_shape_map(self):
         self.plot_abstract_fast(self.massif_name_to_shape,
                                 label='Shape parameter for {} maxima of {}'.format(self.study.season_name,
-                                                                                   SCM_STUDY_CLASS_TO_ABBREVIATION[type(self.study)]),
+                                                                                   SCM_STUDY_CLASS_TO_ABBREVIATION[
+                                                                                       type(self.study)]),
                                 add_x_label=False, graduation=0.1, massif_name_to_text=self.massif_name_to_name)
 
     def plot_altitude_for_the_peak(self):
@@ -184,7 +186,8 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
                 ylabel = 'Mean {} maxima'.format(self.study.season_name)
             else:
                 ylabel = '{}-year return level'.format(return_period)
-            ax.set_ylabel('{} of {} in {} ({})'.format(ylabel, SCM_STUDY_CLASS_TO_ABBREVIATION[type(self.study)], massif_name.replace('_', ' '), self.study.variable_unit))
+            ax.set_ylabel('{} of {} in {} ({})'.format(ylabel, SCM_STUDY_CLASS_TO_ABBREVIATION[type(self.study)],
+                                                       massif_name.replace('_', ' '), self.study.variable_unit))
             peak_year_folder = 'Peak year ' + ylabel
             plot_name = '{}/{}/Peak year for {}'.format(OneFoldFit.folder_for_plots, peak_year_folder,
                                                         massif_name.replace('_', ''))
@@ -260,5 +263,3 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer):
         plot_name = 'Switch altitude'
         self.studies.show_or_save_to_file(plot_name=plot_name, show=self.show)
         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 3e8b0409..62704f80 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
@@ -12,7 +12,10 @@ from extreme_fit.model.margin_model.polynomial_margin_model.gev_altitudinal_mode
     AltitudinalOnlyScale, StationaryAltitudinalOnlyScale
 from extreme_fit.model.margin_model.polynomial_margin_model.gumbel_altitudinal_models import \
     StationaryGumbelAltitudinal, AbstractGumbelAltitudinalModel
+from extreme_fit.model.margin_model.polynomial_margin_model.models_based_on_pariwise_analysis.gev_with_linear_shape_wrt_altitude import \
+    AltitudinalShapeLinearTimeStationary
 from extreme_fit.model.margin_model.utils import MarginFitMethod
+from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.altitude_group import AltitudeGroup
 from root_utils import classproperty
 from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset
 
@@ -22,7 +25,9 @@ class OneFoldFit(object):
     best_estimator_minimizes_total_aic = False
 
     def __init__(self, massif_name: str, dataset: AbstractDataset, models_classes,
-                 fit_method=MarginFitMethod.extremes_fevd_mle, temporal_covariate_for_fit=None):
+                 fit_method=MarginFitMethod.extremes_fevd_mle, temporal_covariate_for_fit=None,
+                 altitude_group=AltitudeGroup.unspecfied):
+        self.altitude_group = altitude_group
         self.massif_name = massif_name
         self.dataset = dataset
         self.models_classes = models_classes
@@ -128,6 +133,7 @@ class OneFoldFit(object):
     def best_shape(self):
         # We take any altitude (altitude=1000 for instance) and any year
         # as the shape is constant w.r.t the altitude and the year
+
         return self.get_gev_params(altitude=1000, year=2019).shape
 
     def best_coef(self, param_name, dim, degree):
@@ -153,6 +159,8 @@ class OneFoldFit(object):
             return self.model_class_to_estimator_with_finite_aic[StationaryGumbelAltitudinal]
         elif isinstance(self.best_estimator.margin_model, AltitudinalOnlyScale):
             return self.model_class_to_estimator_with_finite_aic[StationaryAltitudinalOnlyScale]
+        elif isinstance(self.best_estimator.margin_model, AltitudinalShapeLinearTimeStationary):
+            return self.model_class_to_estimator_with_finite_aic[AltitudinalShapeLinearTimeStationary]
         else:
             return self.model_class_to_estimator_with_finite_aic[StationaryAltitudinal]
 
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 c0974137..af5bdaef 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
@@ -12,12 +12,12 @@ from projects.exceeding_snow_loads.utils import dpi_paper1_figure
 
 def plots(visualizer):
     visualizer.plot_shape_map()
-    for plot_mean in [True, False]:
-        visualizer.plot_year_for_the_peak(plot_mean=plot_mean)
+    # for plot_mean in [True, False]:
+    #     visualizer.plot_year_for_the_peak(plot_mean=plot_mean)
     visualizer.plot_moments()
-    visualizer.plot_best_coef_maps()
-    visualizer.plot_peak_year_against_altitude()
-    visualizer.plot_altitude_switch_against_peak_year()
+    # visualizer.plot_best_coef_maps()
+    # visualizer.plot_peak_year_against_altitude()
+    # visualizer.plot_altitude_switch_against_peak_year()
 
 
 def plot_individual_aic(visualizer):
diff --git a/projects/contrasting_trends_in_snow_loads/article2_snowfall_versus_time_and_altitude/snowfall_plot.py b/projects/contrasting_trends_in_snow_loads/article2_snowfall_versus_time_and_altitude/snowfall_plot.py
index e98023f8..03b9c51e 100644
--- a/projects/contrasting_trends_in_snow_loads/article2_snowfall_versus_time_and_altitude/snowfall_plot.py
+++ b/projects/contrasting_trends_in_snow_loads/article2_snowfall_versus_time_and_altitude/snowfall_plot.py
@@ -165,7 +165,7 @@ def plot_mean(altitude_to_visualizer: Dict[int, StudyVisualizerForMeanValues], d
 
 
 def plot_values_against_altitudes(ax, altitudes, massif_id, massif_name, moment, study, values, visualizer):
-    plot_against_altitude(altitudes=altitudes, ax=ax, massif_id=massif_id, massif_name=massif_name, values=values)
+    plot_against_altitude(x_ticks=altitudes, ax=ax, massif_id=massif_id, massif_name=massif_name, values=values)
     plot_name = '{} annual maxima of {}'.format(moment, SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)])
     ax.set_ylabel('{} ({})'.format(plot_name, study.variable_unit), fontsize=15)
     ax.set_xlabel('altitudes', fontsize=15)
diff --git a/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_study_visualizer.py b/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_study_visualizer.py
index 4549b0de..6d848cc1 100644
--- a/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_study_visualizer.py	
+++ b/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_study_visualizer.py	
@@ -1,4 +1,5 @@
 import matplotlib.pyplot as plt
+import numpy as np
 from cached_property import cached_property
 
 from extreme_data.meteo_france_data.scm_models_data.abstract_study import AbstractStudy
@@ -7,11 +8,20 @@ from extreme_data.meteo_france_data.scm_models_data.visualization.plot_utils imp
 from extreme_data.meteo_france_data.scm_models_data.visualization.study_visualizer import StudyVisualizer
 from extreme_fit.distribution.gev.gev_params import GevParams
 from projects.altitude_spatial_model.altitudes_fit.altitudes_studies import AltitudesStudies
+from projects.contrasting_trends_in_snow_loads.article2_snowfall_versus_time_and_altitude.snowfall_plot import \
+    fit_linear_regression
 from projects.exceeding_snow_loads.utils import paper_altitudes
 
 
 class PointwiseGevStudyVisualizer(AltitudesStudies):
 
+    def __init__(self, study_class, altitudes, spatial_transformation_class=None, temporal_transformation_class=None,
+                 **kwargs_study):
+        super().__init__(study_class, altitudes, spatial_transformation_class, temporal_transformation_class,
+                         **kwargs_study)
+        # self.altitudes_for_temporal_hypothesis = [min(self.altitudes), 2100, max(self.altitudes)]
+        self.altitudes_for_temporal_hypothesis = [900, 2100, 3000]
+
     def plot_gev_params_against_altitude(self):
         for param_name in GevParams.PARAM_NAMES[:]:
             ax = plt.gca()
@@ -53,15 +63,17 @@ class PointwiseGevStudyVisualizer(AltitudesStudies):
     def min_years_for_plot_x_axis(self):
         return [c[0] for c in self.year_min_and_max_list]
 
-    def plot_gev_params_against_time(self):
-        for altitude in self.altitudes[:]:
-            self._plot_gev_params_against_time(altitude)
+    def plot_gev_params_against_time_for_all_altitudes(self):
+        for altitude in self.altitudes_for_temporal_hypothesis:
+            self._plot_gev_params_against_time_for_one_altitude(altitude)
 
-    def _plot_gev_params_against_time(self, altitude):
+    def _plot_gev_params_against_time_for_one_altitude(self, altitude):
         for param_name in GevParams.PARAM_NAMES[:]:
             ax = plt.gca()
             for massif_name in self.study.all_massif_names()[:]:
-                self._plot_gev_params_against_time_one_massif(ax, massif_name, param_name, altitude)
+                self._plot_gev_params_against_time_for_one_altitude_and_one_massif(ax, massif_name, param_name,
+                                                                                   altitude,
+                                                                                   massif_name_as_labels=True)
             ax.legend(prop={'size': 7}, ncol=3)
             ax.set_xlabel('Year')
             ax.set_ylabel(param_name + ' for altitude={}'.format(altitude))
@@ -69,27 +81,99 @@ class PointwiseGevStudyVisualizer(AltitudesStudies):
             ax.set_xticks(self.min_years_for_plot_x_axis)
             ax.set_xticklabels(xlabels)
             # ax.tick_params(labelsize=5)
-            plot_name = '{} change /with years for altitude={}'.format(param_name, altitude)
+            plot_name = '{} change /all with years /for altitude={}'.format(param_name, altitude)
             self.show_or_save_to_file(plot_name, no_title=True, tight_layout=True, show=False)
             ax.clear()
             plt.close()
 
-    def _plot_gev_params_against_time_one_massif(self, ax, massif_name, param_name, altitude):
+    def _plot_gev_params_against_time_for_one_altitude_and_one_massif(self, ax, massif_name, param_name, altitude,
+                                                                      massif_name_as_labels):
         study = self.altitude_to_study[altitude]
         if massif_name in study.study_massif_names:
             gev_params_list = study.massif_name_to_gev_param_list(self.year_min_and_max_list)[massif_name]
             params = [gev_params.to_dict()[param_name] for gev_params in gev_params_list]
-            confidence_intervals = [gev_params.param_name_to_confidence_interval[param_name] for gev_params in
-                                    gev_params_list]
+            # params = np.array(params)
+            # param_normalized = params / np.sqrt(np.sum(np.power(params, 2)))
+            # confidence_intervals = [gev_params.param_name_to_confidence_interval[param_name] for gev_params in
+            #                         gev_params_list]
             massif_id = self.study.all_massif_names().index(massif_name)
-            plot_against_altitude(self.min_years_for_plot_x_axis, ax, massif_id, massif_name, params, fill=False)
-            # plot_against_altitude(self.years, ax, massif_id, massif_name, confidence_intervals, fill=True)
+            plot_against_altitude(self.min_years_for_plot_x_axis, ax, massif_id, massif_name, params,
+                                  altitude, False,
+                                  massif_name_as_labels)
+            # plot_against_altitude(self.years, ax, massif_id, massif_name, confidence_intervals, True)
+
+    # plot for each massif against the time
+
+    def plot_gev_params_against_time_for_all_massifs(self):
+        for massif_name in self.study.all_massif_names():
+            self._plot_gev_params_against_time_for_one_massif(massif_name)
+
+    def _plot_gev_params_against_time_for_one_massif(self, massif_name):
+        for param_name in GevParams.PARAM_NAMES[:]:
+            ax = plt.gca()
+            for altitude in self.altitudes_for_temporal_hypothesis:
+                self._plot_gev_params_against_time_for_one_altitude_and_one_massif(ax, massif_name, param_name,
+                                                                                   altitude,
+                                                                                   massif_name_as_labels=False)
+            ax.legend()
+            ax.set_xlabel('Year')
+            ax.set_ylabel(param_name + ' for {}'.format(massif_name))
+            xlabels = ['-'.join([str(e) for e in t]) for t in self.year_min_and_max_list]
+            ax.set_xticks(self.min_years_for_plot_x_axis)
+            ax.set_xticklabels(xlabels)
+            plot_name = '{} change /with years /for {}'.format(param_name, massif_name)
+            self.show_or_save_to_file(plot_name, no_title=True, tight_layout=True, show=False)
+            ax.clear()
+            plt.close()
+
+    # PLot for each massif the derivative against the time for each altitude
+
+    def plot_time_derivative_against_time(self):
+        for param_name in GevParams.PARAM_NAMES[:]:
+            ax = plt.gca()
+            for massif_name in self.study.all_massif_names()[:]:
+                self._plot_gev_params_time_derivative_against_altitude_one_massif(ax, massif_name, param_name)
+            ax.legend(prop={'size': 7}, ncol=3)
+            ax.set_xlabel('Altitude')
+            ax.set_ylabel(param_name)
+            plot_name = '{} change /time derivative with altitude'.format(param_name)
+            self.show_or_save_to_file(plot_name, no_title=True, tight_layout=True, show=False)
+            ax.clear()
+            plt.close()
+
+    def _plot_gev_params_time_derivative_against_altitude_one_massif(self, ax, massif_name, param_name):
+        altitudes = []
+        time_derivatives = []
+        for altitude, study in self.altitude_to_study.items():
+            if (massif_name in study.study_massif_names) and ("Mercan" not in massif_name):
+                gev_params_list = study.massif_name_to_gev_param_list(self.year_min_and_max_list)[massif_name]
+                params = [gev_params.to_dict()[param_name] for gev_params in gev_params_list]
+                x = list(range(len(params)))
+                y = params
+                a = self.get_robust_slope(x, y)
+                time_derivatives.append(a)
+                altitudes.append(altitude)
+        massif_id = self.study.all_massif_names().index(massif_name)
+        plot_against_altitude(altitudes, ax, massif_id, massif_name, time_derivatives, fill=False)
+
+    def get_robust_slope(self, x, y):
+        a, *_ = fit_linear_regression(x=x, y=y)
+        a_list = [a]
+        for i in range(len(x)):
+            x_copy, y_copy = x[:], y[:]
+            x_copy.pop(i)
+            y_copy.pop(i)
+            a, *_ = fit_linear_regression(x=x_copy, y=y_copy)
+            a_list.append(a)
+        return np.mean(np.array(a_list))
 
 
 if __name__ == '__main__':
-    altitudes = [600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600]
+    altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300]
     # altitudes = paper_altitudes
     # altitudes = [1800, 2100]
     visualizer = PointwiseGevStudyVisualizer(SafranSnowfall1Day, altitudes=altitudes)
     visualizer.plot_gev_params_against_altitude()
-    visualizer.plot_gev_params_against_time()
+    visualizer.plot_gev_params_against_time_for_all_altitudes()
+    visualizer.plot_gev_params_against_time_for_all_massifs()
+    # visualizer.plot_time_derivative_against_time()
-- 
GitLab