diff --git a/extreme_data/meteo_france_data/scm_models_data/cluster/__init__.py b/extreme_data/meteo_france_data/scm_models_data/cluster/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/extreme_data/meteo_france_data/scm_models_data/cluster/abstract_cluster.py b/extreme_data/meteo_france_data/scm_models_data/cluster/abstract_cluster.py
new file mode 100644
index 0000000000000000000000000000000000000000..4168f291610c9894201466a65f64508fcd7b035c
--- /dev/null
+++ b/extreme_data/meteo_france_data/scm_models_data/cluster/abstract_cluster.py
@@ -0,0 +1,27 @@
+from root_utils import classproperty
+
+
+class AbstractCluster(object):
+
+    @classproperty
+    def massif_name_to_cluster_id(cls):
+        raise NotImplemented
+
+    @classproperty
+    def cluster_id_to_cluster_name(cls):
+        raise NotImplemented
+
+    @classproperty
+    def cluster_id_to_massif_names(cls):
+        cluster_id_to_massif_names = {}
+        for cluster_id in cls.cluster_ids:
+            massif_names = []
+            for massif_name, cluster_id2 in cls.massif_name_to_cluster_id.items():
+                if cluster_id == cluster_id2:
+                    massif_names.append(massif_name)
+            cluster_id_to_massif_names[cluster_id] = massif_names
+        return cluster_id_to_massif_names
+
+    @classproperty
+    def cluster_ids(cls):
+        return list(cls.cluster_id_to_cluster_name.keys())
\ No newline at end of file
diff --git a/extreme_data/meteo_france_data/scm_models_data/cluster/clustering_total_precip.py b/extreme_data/meteo_france_data/scm_models_data/cluster/clustering_total_precip.py
new file mode 100644
index 0000000000000000000000000000000000000000..a571d574ce92c55c91b8334e948ed0fe7151c68d
--- /dev/null
+++ b/extreme_data/meteo_france_data/scm_models_data/cluster/clustering_total_precip.py
@@ -0,0 +1,83 @@
+from extreme_data.meteo_france_data.scm_models_data.cluster.abstract_cluster import AbstractCluster
+from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranPrecipitation1Day
+import matplotlib.pyplot as plt
+
+from root_utils import classproperty
+
+
+class TotalPrecipCluster(AbstractCluster):
+
+
+
+
+    @classproperty
+    def massif_name_to_cluster_id(cls):
+        return {
+            'Chablais': 1,
+            'Aravis': 1,
+            'Mont-Blanc': 1,
+            'Bauges': 1,
+            'Beaufortain': 1,
+            'Haute-Tarentaise': 2,
+            'Chartreuse': 1,
+            'Belledonne': 1,
+            'Maurienne': 2,
+            'Vanoise': 2,
+            'Haute-Maurienne': 3,
+            'Grandes-Rousses': 2,
+            'Thabor': 3,
+            'Vercors': 1,
+            'Oisans': 2,
+            'Pelvoux': 2,
+            'Queyras': 3,
+            'Devoluy': 2,
+            'Champsaur': 2,
+            'Parpaillon': 3,
+            'Ubaye': 3,
+            'Haut_Var-Haut_Verdon': 4,
+            'Mercantour': 4
+        }
+
+    @classproperty
+    def cluster_id_to_cluster_name(cls):
+        return {
+            1: 'North',
+            2: 'Central',
+            3: 'South',
+            4: 'Extreme south'
+        }
+
+
+def massif_name_to_total_precipitation(altitude=2100):
+    """
+    We split the Alps in 4 regions based on mean total precipitation at 2100 m
+    Extreme South: 2 massifs in the South
+    South: 2 massifs with mean total precipitation < 1200mm
+    Central: 12 massifs with 1200mm < mean < 1500mm
+    North: 7 massifs with mean > 1500mm
+    :param altitude:
+    :return:
+    """
+    study = SafranPrecipitation1Day(altitude=altitude)
+    total_precipitation = study.all_daily_series.sum(axis=0) / study.nb_years
+    massif_name_to_total_precip = dict(zip(study.study_massif_names, total_precipitation))
+    print('\nNorth ALps')
+    for m, t in massif_name_to_total_precip.items():
+        if t > 1500:
+            print(m)
+    print('\nSOuth ALps')
+    for m, t in massif_name_to_total_precip.items():
+        if t < 1200:
+            print(m)
+    print(massif_name_to_total_precip)
+    vmin, vmax = min(total_precipitation), max(total_precipitation)
+    study.visualize_study(massif_name_to_value=massif_name_to_total_precip, vmin=vmin, vmax=vmax,
+                          add_colorbar=True, replace_blue_by_white=True)
+    plt.show()
+    return massif_name_to_total_precip
+
+
+if __name__ == '__main__':
+    d = massif_name_to_total_precipitation()
+
+    print(d)
diff --git a/extreme_fit/distribution/abstract_extreme_params.py b/extreme_fit/distribution/abstract_extreme_params.py
index 53cd11470456213eddf59fd28f4d369d3a4739b6..8c98f1b99b78cba3071fd99680a442601a544116 100644
--- a/extreme_fit/distribution/abstract_extreme_params.py
+++ b/extreme_fit/distribution/abstract_extreme_params.py
@@ -2,12 +2,6 @@ from extreme_fit.distribution.abstract_params import AbstractParams
 
 
 class AbstractExtremeParams(AbstractParams):
-    pass
-
-    # Extreme parameters
-    SCALE = 'scale'
-    LOC = 'loc'
-    SHAPE = 'shape'
 
     def __init__(self, loc: float, scale: float, shape: float):
         self.location = loc
@@ -17,4 +11,4 @@ class AbstractExtremeParams(AbstractParams):
         # (sometimes it happens, when we want to find a quantile for every point of a 2D map
         # then it can happen that a corner point that was not used for fitting correspond to a negative scale,
         # in the case we set all the parameters as equal to np.nan, and we will not display those points)
-        self.has_undefined_parameters = self.scale <= 0
\ No newline at end of file
+        self.has_undefined_parameters = self.scale <= 0
diff --git a/projects/contrasting_trends_in_snow_loads/post thesis committee/__init__.py b/projects/contrasting_trends_in_snow_loads/post thesis committee/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_analysis_cluster_level.py b/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_analysis_cluster_level.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a7372fa88cb9ed1fb77396a044973b2a66977ef
--- /dev/null
+++ b/projects/contrasting_trends_in_snow_loads/post thesis committee/pointwise_gev_analysis_cluster_level.py	
@@ -0,0 +1,154 @@
+import numpy as np
+from cached_property import cached_property
+import matplotlib.pyplot as plt
+
+from extreme_data.meteo_france_data.scm_models_data.cluster.clustering_total_precip import TotalPrecipCluster
+from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranSnowfall1Day
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.estimator.margin_estimator.utils import fitted_stationary_gev
+from extreme_fit.model.margin_model.utils import MarginFitMethod
+from projects.altitude_spatial_model.altitudes_fit.altitudes_studies import AltitudesStudies
+
+
+class PointWIseGevAnalysisForCluster(AltitudesStudies):
+
+    def __init__(self, study_class, altitudes,
+                 spatial_transformation_class=None, temporal_transformation_class=None,
+                 cluster_class=TotalPrecipCluster,
+                 **kwargs_study):
+        super().__init__(study_class, altitudes, spatial_transformation_class, temporal_transformation_class,
+                         **kwargs_study)
+        self.cluster_class = cluster_class
+
+    # Plot for the Altitude
+
+    def cluster_id_to_annual_maxima_list(self, first_year=1959, last_year=2019, altitudes=None):
+        if altitudes is None:
+            altitudes = self.altitudes
+        cluster_id_to_annual_maxima_list = {}
+        for cluster_id in self.cluster_class.cluster_ids:
+            annual_maxima_list = []
+            massif_names = self.cluster_class.cluster_id_to_massif_names[cluster_id]
+            for study in [s for a, s in self.altitude_to_study.items() if a in altitudes]:
+                annual_maxima = []
+                massif_ids = [study.massif_name_to_massif_id[m] for m in massif_names if
+                              m in study.massif_name_to_massif_id]
+                for year in range(first_year, last_year + 1):
+                    annual_maxima.extend(study.year_to_annual_maxima[year][massif_ids])
+                annual_maxima_list.append(annual_maxima)
+            cluster_id_to_annual_maxima_list[cluster_id] = annual_maxima_list
+        return cluster_id_to_annual_maxima_list
+
+    @property
+    def cluster_id_to_gev_params_list(self):
+        cluster_id_to_gev_params_list = {}
+        for cluster_id, annual_maxima_list in self.cluster_id_to_annual_maxima_list().items():
+            gev_params_list = []
+            for annual_maxima in annual_maxima_list:
+                if len(annual_maxima) > 0:
+                    gev_params = fitted_stationary_gev(annual_maxima, fit_method=MarginFitMethod.extremes_fevd_mle)
+                else:
+                    gev_params = GevParams(0, 0, 0)
+                    assert gev_params.has_undefined_parameters
+                gev_params_list.append(gev_params)
+            cluster_id_to_gev_params_list[cluster_id] = gev_params_list
+        return cluster_id_to_gev_params_list
+
+    def plot_gev_parameters_against_altitude(self):
+        for param_name in GevParams.PARAM_NAMES[:]:
+            ax = plt.gca()
+            for cluster_id, gev_param_list in self.cluster_id_to_gev_params_list.items():
+                params, altitudes = zip(*[(gev_param.to_dict()[param_name], altitude) for gev_param, altitude
+                                          in zip(gev_param_list, self.altitudes) if
+                                          not gev_param.has_undefined_parameters])
+                # ax.plot(self.altitudes, params, label=str(cluster_id), linestyle='None', marker='x')
+                label = self.cluster_class.cluster_id_to_cluster_name[cluster_id]
+                ax.plot(altitudes, params, label=label, marker='x')
+            ax.legend()
+            ax.set_xlabel('Altitude')
+            ax.set_ylabel(param_name)
+            plot_name = '{} change 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()
+
+    # Plot for the time
+
+    @property
+    def year_min_and_max_list(self):
+        l = []
+        year_min, year_max = 1959, 1989
+        for shift in range(0, 7):
+            l.append((year_min + 5 * shift, year_max + 5 * shift))
+        return l
+
+    def cluster_id_to_time_annual_maxima_list(self, altitudes):
+        cluster_id_to_time_annual_maxima_list = {cluster_id: [] for cluster_id in self.cluster_class.cluster_ids}
+        for year_min, year_max in self.year_min_and_max_list:
+            d = self.cluster_id_to_annual_maxima_list(first_year=year_min,
+                                                      last_year=year_max,
+                                                      altitudes=altitudes)
+            for cluster_id, annual_maxima_list in d.items():
+                a = np.array(annual_maxima_list)
+                a = a.flatten()
+                print("here")
+                print(a.shape)
+                cluster_id_to_time_annual_maxima_list[cluster_id].append(list(a))
+        return cluster_id_to_time_annual_maxima_list
+
+    def cluster_id_to_time_gev_params_list(self, altitudes):
+        cluster_id_to_gev_params_list = {}
+        for cluster_id, annual_maxima_list in self.cluster_id_to_time_annual_maxima_list(altitudes=altitudes).items():
+            print("cluster", cluster_id)
+            gev_params_list = []
+            for annual_maxima in annual_maxima_list:
+                if len(annual_maxima) > 20:
+                    print(type(annual_maxima))
+                    annual_maxima = np.array(annual_maxima)
+                    print(annual_maxima.shape)
+                    annual_maxima = annual_maxima[annual_maxima != 0]
+                    gev_params = fitted_stationary_gev(annual_maxima)
+                else:
+                    print('here all the time')
+                    gev_params = GevParams(0, 0, 0)
+                    assert gev_params.has_undefined_parameters
+                gev_params_list.append(gev_params)
+            cluster_id_to_gev_params_list[cluster_id] = gev_params_list
+        return cluster_id_to_gev_params_list
+
+    def plot_gev_parameters_against_time(self, altitudes=None):
+        for param_name in GevParams.PARAM_NAMES[:]:
+            ax = plt.gca()
+            for cluster_id, gev_param_list in self.cluster_id_to_time_gev_params_list(altitudes).items():
+                print(gev_param_list)
+                params, years = zip(*[(gev_param.to_dict()[param_name], years) for gev_param, years
+                                      in zip(gev_param_list, self.year_min_and_max_list) if
+                                      not gev_param.has_undefined_parameters])
+                # ax.plot(self.altitudes, params, label=str(cluster_id), linestyle='None', marker='x')
+                label = self.cluster_class.cluster_id_to_cluster_name[cluster_id]
+                years = [year[0] for year in years]
+                ax.plot(years, params, label=label, marker='x')
+            ax.legend()
+            ax.set_xlabel('Year')
+            ax.set_ylabel(param_name)
+            xlabels = ['-'.join([str(e) for e in t]) for t in self.year_min_and_max_list]
+            ax.set_xticklabels(xlabels)
+            plot_name = '{} change with year for altitudes {}'.format(param_name, '+'.join([str(a) for a in altitudes]))
+            self.show_or_save_to_file(plot_name, no_title=True, tight_layout=True, show=False)
+            ax.clear()
+            plt.close()
+
+
+if __name__ == '__main__':
+    altitudes = [600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600]
+    # altitudes = [1800, 2100]
+    pointwise_gev_analysis = PointWIseGevAnalysisForCluster(SafranSnowfall1Day, altitudes=altitudes)
+    # pointwise_gev_analysis.plot_gev_parameters_against_time(altitudes)
+
+    # pointwise_gev_analysis.plot_gev_parameters_against_altitude()
+    for altitudes in [[600, 900],
+                      [1200, 1500, 1800],
+                      [2100, 2400, 2700],
+                      [3000, 3300, 3600]][3:]:
+        print(altitudes)
+        pointwise_gev_analysis.plot_gev_parameters_against_time(altitudes)
diff --git a/projects/exceeding_snow_loads/section_results/plot_trend_curves.py b/projects/exceeding_snow_loads/section_results/plot_trend_curves.py
index bb302a29d58788fc9c098bdeb79148b09d5787b0..54db2b026861121cb13d48d0b9c77019e7ad9550 100644
--- a/projects/exceeding_snow_loads/section_results/plot_trend_curves.py
+++ b/projects/exceeding_snow_loads/section_results/plot_trend_curves.py
@@ -46,7 +46,7 @@ def plot_trend_curves(altitude_to_visualizer: Dict[int, StudyVisualizerForNonSta
 
     # parameters
     width = 150
-    size = 20
+    legend_size = 30
     legend_fontsize = 35
     color = 'white'
     labelsize = 15
@@ -56,7 +56,7 @@ def plot_trend_curves(altitude_to_visualizer: Dict[int, StudyVisualizerForNonSta
     ax.bar(altitudes, percent_decrease_signi, width=width, color=color, edgecolor='black',
            label='significant decreasing trend',
            linewidth=linewidth)
-    ax.legend(loc='upper left', prop={'size': size})
+    ax.legend(loc='upper center', prop={'size': legend_size})
 
     for ax_horizontal in [ax, ax_twiny]:
         if ax_horizontal == ax_twiny:
@@ -92,7 +92,7 @@ def plot_trend_curves(altitude_to_visualizer: Dict[int, StudyVisualizerForNonSta
         else:
             label = 'Mean relative decrease'
         ax_twinx.plot(altitudes, mean_decrease, label=label, linewidth=linewidth, marker='o')
-        ax_twinx.legend(loc='upper right', prop={'size': size})
+        ax_twinx.legend(loc='upper right', prop={'size': legend_size})
 
     # Save plot
     visualizer.plot_name = 'Trend curves'