From 9473d0f3bdc645a0488e548efade5abfc4ebd0d1 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 29 Mar 2021 12:15:11 +0200 Subject: [PATCH] [projection snowfall] refactor first_year and last_year in OneFoldFit. and apply the code to check the difference in spatial patterns between safran 2020 reanalysis and ADAMont v2 --- .../ensemble_fit/abstract_ensemble_fit.py | 4 -- .../one_fold_fit_merge.py | 4 +- .../visualizer_merge.py | 4 +- ...es_visualizer_for_non_stationary_models.py | 57 +++---------------- extreme_trend/one_fold_fit/one_fold_fit.py | 12 ++-- .../main_altitudes_studies.py | 20 +++---- .../results/main_projections_ensemble.py | 18 +++--- test/test_extreme_trend/test_one_fold_fit.py | 24 ++++++-- 8 files changed, 60 insertions(+), 83 deletions(-) diff --git a/extreme_trend/ensemble_fit/abstract_ensemble_fit.py b/extreme_trend/ensemble_fit/abstract_ensemble_fit.py index b9348041..ecaa0db4 100644 --- a/extreme_trend/ensemble_fit/abstract_ensemble_fit.py +++ b/extreme_trend/ensemble_fit/abstract_ensemble_fit.py @@ -27,10 +27,6 @@ class AbstractEnsembleFit(object): self.only_models_that_pass_goodness_of_fit_test = only_models_that_pass_goodness_of_fit_test self.confidence_interval_based_on_delta_method = confidence_interval_based_on_delta_method - # Set appropriate setting - OneFoldFit.last_year = 2100 - OneFoldFit.nb_years = OneFoldFit.last_year - 2005 - @property def altitudes(self): raise self.visualizer_list.studies.altitudes diff --git a/extreme_trend/ensemble_fit/independent_ensemble_fit/one_fold_fit_merge.py b/extreme_trend/ensemble_fit/independent_ensemble_fit/one_fold_fit_merge.py index 4db04016..2345fca5 100644 --- a/extreme_trend/ensemble_fit/independent_ensemble_fit/one_fold_fit_merge.py +++ b/extreme_trend/ensemble_fit/independent_ensemble_fit/one_fold_fit_merge.py @@ -8,13 +8,15 @@ from extreme_trend.one_fold_fit.one_fold_fit import OneFoldFit class OneFoldFitMerge(OneFoldFit): def __init__(self, one_fold_fit_list: List[OneFoldFit], massif_name, altitude_class, temporal_covariate_for_fit, - merge_function=np.median): + first_year, last_year, merge_function=np.median): assert len(one_fold_fit_list) > 0 self.one_fold_fit_list = one_fold_fit_list self.altitude_group = altitude_class() self.massif_name = massif_name self.temporal_covariate_for_fit = temporal_covariate_for_fit self.merge_function = merge_function + self.first_year = first_year + self.last_year = last_year def get_moment(self, altitude, temporal_covariate, order=1): return self.merge_function([o.get_moment(altitude, temporal_covariate, order) for o in self.one_fold_fit_list]) diff --git a/extreme_trend/ensemble_fit/independent_ensemble_fit/visualizer_merge.py b/extreme_trend/ensemble_fit/independent_ensemble_fit/visualizer_merge.py index 1f2361fb..5ed3fcda 100644 --- a/extreme_trend/ensemble_fit/independent_ensemble_fit/visualizer_merge.py +++ b/extreme_trend/ensemble_fit/independent_ensemble_fit/visualizer_merge.py @@ -37,7 +37,9 @@ class VisualizerMerge(AltitudesStudiesVisualizerForNonStationaryModels): if massif_name in v.massif_name_to_one_fold_fit] if len(one_fold_fit_list) > 0: one_fold_fit_merge = OneFoldFitMerge(one_fold_fit_list, massif_name, - type(self.altitude_group), self.temporal_covariate_for_fit) + type(self.altitude_group), self.temporal_covariate_for_fit, + first_year=self.study.year_min, last_year=self.study.year_max, + merge_function=self.merge_function) self._massif_name_to_one_fold_fit[massif_name] = one_fold_fit_merge @property diff --git a/extreme_trend/one_fold_fit/altitudes_studies_visualizer_for_non_stationary_models.py b/extreme_trend/one_fold_fit/altitudes_studies_visualizer_for_non_stationary_models.py index f856a926..7706a557 100644 --- a/extreme_trend/one_fold_fit/altitudes_studies_visualizer_for_non_stationary_models.py +++ b/extreme_trend/one_fold_fit/altitudes_studies_visualizer_for_non_stationary_models.py @@ -80,7 +80,10 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): self.massif_name_to_massif_altitudes[massif_name] = massif_altitudes # Load dataset dataset = self.get_dataset(massif_altitudes, massif_name) - old_fold_fit = OneFoldFit(massif_name, dataset, self.model_classes, self.fit_method, + old_fold_fit = OneFoldFit(massif_name, dataset, self.model_classes, + self.study.year_min, + self.study.year_max, + self.fit_method, self.temporal_covariate_for_fit, type(self.altitude_group), self.display_only_model_that_pass_test, @@ -163,7 +166,7 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): return self._method_name_and_order_to_massif_name_to_value[c] def ratio_groups(self): - return [self.ratio_uncertainty_interval_size(altitude, OneFoldFit.last_year) for altitude in + return [self.ratio_uncertainty_interval_size(altitude, self.first_one_fold_fit.last_year) for altitude in self.studies.altitudes] def ratio_uncertainty_interval_size(self, altitude, year): @@ -264,7 +267,7 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): ax.legend(prop={'size': 7}, ncol=3) moment = ' '.join(method_name.split('_')) moment = moment.replace('moment', - '{} in {}'.format(OneFoldFit.get_moment_str(order=order), OneFoldFit.last_year)) + '{} in {}'.format(OneFoldFit.get_moment_str(order=order), self.first_one_fold_fit.last_year)) plot_name = 'Model {} annual maxima of {}'.format(moment, SCM_STUDY_CLASS_TO_ABBREVIATION[self.studies.study_class]) ax.set_ylabel('{} ({})'.format(plot_name, self.study.variable_unit), fontsize=15) @@ -273,13 +276,6 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): self.studies.show_or_save_to_file(plot_name=plot_name, show=self.show, no_title=True) ax.clear() - # def plot_abstract_fast(self, massif_name_to_value, label, graduation=10.0, cmap=plt.cm.coolwarm, add_x_label=True, - # negative_and_positive_values=True, massif_name_to_text=None): - # plot_name = '{}{}'.format(OneFoldFit.folder_for_plots, label) - # self.plot_map(cmap, self.fit_method, graduation, label, massif_name_to_value, plot_name, add_x_label, - # negative_and_positive_values, - # massif_name_to_text) - @property def massif_name_to_shape(self): return {massif_name: one_fold_fit.best_shape @@ -290,48 +286,9 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): return {massif_name: one_fold_fit.best_name for massif_name, one_fold_fit in self.massif_name_to_one_fold_fit.items()} - def plot_best_coef_maps(self): - for param_name in GevParams.PARAM_NAMES: - coordinate_names = [AbstractCoordinates.COORDINATE_X, AbstractCoordinates.COORDINATE_T] - dim_to_coordinate_name = dict(zip([0, 1], coordinate_names)) - for dim in [0, 1, (0, 1)]: - coordinate_name = LinearCoef.coefficient_name(dim, dim_to_coordinate_name) - for degree in range(4): - coef_name = ' '.join([param_name + coordinate_name + str(degree)]) - massif_name_to_best_coef = {} - for massif_name, one_fold_fit in self.massif_name_to_one_fold_fit.items(): - best_coef = one_fold_fit.best_coef(param_name, dim, degree) - if best_coef is not None: - massif_name_to_best_coef[massif_name] = best_coef - - if len(massif_name_to_best_coef) > 0: - for evaluate_coordinate in [False, True][:1]: - if evaluate_coordinate: - coef_name += 'evaluated at coordinates' - for massif_name in massif_name_to_best_coef.keys(): - if AbstractCoordinates.COORDINATE_X in coordinate_name: - massif_name_to_best_coef[massif_name] *= np.power(1000, degree) - if AbstractCoordinates.COORDINATE_T in coordinate_name: - massif_name_to_best_coef[massif_name] *= np.power(OneFoldFit.last_year, degree) - self.plot_best_coef_map(coef_name.replace('_', ''), massif_name_to_best_coef) - - def plot_best_coef_map(self, coef_name, massif_name_to_best_coef): - values = list(massif_name_to_best_coef.values()) - graduation = (max(values) - min(values)) / 6 - print(coef_name, graduation, max(values), min(values)) - negative_and_positive_values = (max(values) > 0) and (min(values) < 0) - raise NotImplementedError - self.plot_map(massif_name_to_value=massif_name_to_best_coef, - label='Coef/{} plot for {} {}'.format(coef_name, - 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_best_name, - negative_and_positive_values=negative_and_positive_values) - def plot_shape_map(self): - label = 'Shape parameter in {} (no unit)'.format(OneFoldFit.last_year) + label = 'Shape parameter in {} (no unit)'.format(self.first_one_fold_fit.last_year) max_abs_change = self._max_abs_for_shape + 0.05 self.plot_map(massif_name_to_value=self.massif_name_to_shape, label=label, diff --git a/extreme_trend/one_fold_fit/one_fold_fit.py b/extreme_trend/one_fold_fit/one_fold_fit.py index e8a59383..7cdfc50f 100644 --- a/extreme_trend/one_fold_fit/one_fold_fit.py +++ b/extreme_trend/one_fold_fit/one_fold_fit.py @@ -42,11 +42,9 @@ class OneFoldFit(object): SIGNIFICANCE_LEVEL = 0.05 return_period = 100 quantile_level = 1 - (1 / return_period) - nb_years = 60 - last_year = 2019 - last_anomaly = 2 def __init__(self, massif_name: str, dataset: AbstractDataset, models_classes, + first_year, last_year, fit_method=MarginFitMethod.extremes_fevd_mle, temporal_covariate_for_fit=None, altitude_class=DefaultAltitudeGroup, @@ -54,6 +52,9 @@ class OneFoldFit(object): confidence_interval_based_on_delta_method=False, remove_physically_implausible_models=False, ): + self.first_year = first_year + self.last_year = last_year + self.years_of_difference = last_year - first_year self.remove_physically_implausible_models = remove_physically_implausible_models self.confidence_interval_based_on_delta_method = confidence_interval_based_on_delta_method self.only_models_that_pass_goodness_of_fit_test = only_models_that_pass_goodness_of_fit_test @@ -64,6 +65,7 @@ class OneFoldFit(object): self.fit_method = fit_method self.temporal_covariate_for_fit = temporal_covariate_for_fit + # Fit Estimators self.model_class_to_estimator = {} for model_class in models_classes: @@ -133,10 +135,10 @@ class OneFoldFit(object): @property def _covariate_before_and_after(self): if self.temporal_covariate_for_fit in [None, TimeTemporalCovariate]: - return self.last_year - self.nb_years, self.last_year + return self.first_year, self.last_year elif self.temporal_covariate_for_fit is AnomalyTemperatureWithSplineTemporalCovariate: # In 2020, we are roughly at 1 degree. Thus it natural to see the augmentation from 1 to 2 degree. - return 1, self.last_anomaly + return 1, 2 else: raise NotImplementedError diff --git a/projects/past_extreme_snowfall/section_data_and_results/main_altitudes_studies.py b/projects/past_extreme_snowfall/section_data_and_results/main_altitudes_studies.py index 7c389bd6..d04f3860 100644 --- a/projects/past_extreme_snowfall/section_data_and_results/main_altitudes_studies.py +++ b/projects/past_extreme_snowfall/section_data_and_results/main_altitudes_studies.py @@ -43,13 +43,14 @@ def main(): SafranSnowfall5Days, SafranSnowfall7Days][:1] study_classes = [SafranSnowfall2020, SafranSnowfall2019, SafranSnowfallCenterOnDay1day, SafranSnowfallNotCenterOnDay1day, - SafranSnowfallCenterOnDay1dayMeanRate, SafranSnowfall1Day][1:3] - study_classes = [SafranSnowfallNotCenterOnDay1day, SafranSnowfall2019] + SafranSnowfallCenterOnDay1dayMeanRate, SafranSnowfall1Day][:1] + # study_classes = [SafranSnowfallNotCenterOnDay1day, SafranSnowfall2019] seasons = [Season.annual, Season.winter, Season.spring, Season.automn][:1] set_seed_for_test() - model_must_pass_the_test = False + model_must_pass_the_test = True AbstractExtractEurocodeReturnLevel.ALPHA_CONFIDENCE_INTERVAL_UNCERTAINTY = 0.2 + year_max = 2005 fast = False if fast is None: @@ -58,28 +59,27 @@ def main(): altitudes_list = altitudes_for_groups[2:3] elif fast: AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 - massif_names = ['Vanoise', 'Haute-Maurienne', 'Vercors'][:1] + massif_names = ['Vanoise', 'Haute-Maurienne', 'Vercors'][:] altitudes_list = altitudes_for_groups[2:3] else: massif_names = None altitudes_list = altitudes_for_groups[:] start = time.time() - main_loop(altitudes_list, massif_names, seasons, study_classes, model_must_pass_the_test) + main_loop(altitudes_list, massif_names, seasons, study_classes, model_must_pass_the_test, year_max=year_max) end = time.time() duration = str(datetime.timedelta(seconds=end - start)) print('Total duration', duration) -def main_loop(altitudes_list, massif_names, seasons, study_classes, model_must_pass_the_test): +def main_loop(altitudes_list, massif_names, seasons, study_classes, model_must_pass_the_test, year_max=None): assert isinstance(altitudes_list, List) assert isinstance(altitudes_list[0], List) for season in seasons: for study_class in study_classes: print('Inner loop', season, study_class) visualizer_list = load_visualizer_list(season, study_class, altitudes_list, massif_names, - model_must_pass_the_test, - year_max=2019) + model_must_pass_the_test, year_max=year_max) plot_visualizers(massif_names, visualizer_list) for visualizer in visualizer_list: plot_visualizer(massif_names, visualizer) @@ -89,10 +89,10 @@ def main_loop(altitudes_list, massif_names, seasons, study_classes, model_must_p def plot_visualizers(massif_names, visualizer_list): # plot_histogram_all_models_against_altitudes(massif_names, visualizer_list) - plot_histogram_all_trends_against_altitudes(massif_names, visualizer_list, with_significance=True) + plot_histogram_all_trends_against_altitudes(massif_names, visualizer_list, with_significance=False) # plot_shoe_plot_ratio_interval_size_against_altitude(massif_names, visualizer_list) for relative in [True, False]: - plot_shoe_plot_changes_against_altitude(massif_names, visualizer_list, relative=relative, with_significance=True) + plot_shoe_plot_changes_against_altitude(massif_names, visualizer_list, relative=relative, with_significance=False) # plot_coherence_curves(['Vanoise'], visualizer_list) pass diff --git a/projects/projected_extreme_snowfall/results/main_projections_ensemble.py b/projects/projected_extreme_snowfall/results/main_projections_ensemble.py index c44d3cbf..49ea7796 100644 --- a/projects/projected_extreme_snowfall/results/main_projections_ensemble.py +++ b/projects/projected_extreme_snowfall/results/main_projections_ensemble.py @@ -24,7 +24,7 @@ from extreme_fit.model.utils import set_seed_for_test from extreme_data.meteo_france_data.adamont_data.adamont.adamont_safran import AdamontSnowfall from extreme_data.meteo_france_data.adamont_data.adamont_scenario import AdamontScenario, get_gcm_rcm_couples, \ - rcp_scenarios, rcm_scenarios_extended + rcp_scenarios, rcm_scenarios_extended, get_gcm_list from spatio_temporal_dataset.coordinates.temporal_coordinates.abstract_temporal_covariate_for_fit import \ TimeTemporalCovariate @@ -41,14 +41,19 @@ def main(): study_class = AdamontSnowfall ensemble_fit_classes = [IndependentEnsembleFit, TogetherEnsembleFit][1:] temporal_covariate_for_fit = [TimeTemporalCovariate, - AnomalyTemperatureWithSplineTemporalCovariate][1] + AnomalyTemperatureWithSplineTemporalCovariate][0] set_seed_for_test() AbstractExtractEurocodeReturnLevel.ALPHA_CONFIDENCE_INTERVAL_UNCERTAINTY = 0.2 - fast = True + fast = False scenarios = rcp_scenarios[::-1] if fast is False else [AdamontScenario.rcp85] scenarios = rcm_scenarios_extended[::-1] + scenarios = [AdamontScenario.histo] + gcm_to_year_min_and_year_max = { + gcm: (1959, 2005) for gcm in get_gcm_list(adamont_version=2) + } + for scenario in scenarios: gcm_rcm_couples = get_gcm_rcm_couples(scenario) if fast is None: @@ -62,8 +67,8 @@ def main(): AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 altitudes_list = altitudes_for_groups[:1] else: - massif_names = ['Vanoise'] - altitudes_list = altitudes_for_groups[3:] + massif_names = None + altitudes_list = altitudes_for_groups[:] assert isinstance(gcm_rcm_couples, list) @@ -73,7 +78,6 @@ def main(): print('Covariate is {}'.format(temporal_covariate_for_fit)) model_classes = ALTITUDINAL_GEV_MODELS_BASED_ON_POINTWISE_ANALYSIS - assert scenario is not AdamontScenario.histo visualizer = VisualizerForProjectionEnsemble( altitudes_list, gcm_rcm_couples, study_class, Season.annual, scenario, @@ -82,7 +86,7 @@ def main(): massif_names=massif_names, temporal_covariate_for_fit=temporal_covariate_for_fit, remove_physically_implausible_models=True, - gcm_to_year_min_and_year_max=None, + gcm_to_year_min_and_year_max=gcm_to_year_min_and_year_max, ) visualizer.plot() diff --git a/test/test_extreme_trend/test_one_fold_fit.py b/test/test_extreme_trend/test_one_fold_fit.py index 30829f58..80e3e706 100644 --- a/test/test_extreme_trend/test_one_fold_fit.py +++ b/test/test_extreme_trend/test_one_fold_fit.py @@ -41,7 +41,10 @@ class TestOneFoldFit(unittest.TestCase): dataset = self.load_dataset(study_class) one_fold_fit = OneFoldFit(self.massif_name, dataset, models_classes=self.model_classes, temporal_covariate_for_fit=None, - only_models_that_pass_goodness_of_fit_test=False) + only_models_that_pass_goodness_of_fit_test=False, + first_year=1959, + last_year=2019 + ) _ = one_fold_fit.best_estimator.margin_model self.assertTrue(True) @@ -51,7 +54,10 @@ class TestOneFoldFit(unittest.TestCase): one_fold_fit = OneFoldFit(self.massif_name, dataset, models_classes=self.model_classes, temporal_covariate_for_fit=TimeTemporalCovariate, - only_models_that_pass_goodness_of_fit_test=False) + only_models_that_pass_goodness_of_fit_test=False, + first_year=1959, + last_year=2019 + ) _ = one_fold_fit.best_estimator.margin_model self.assertTrue(True) @@ -61,7 +67,10 @@ class TestOneFoldFit(unittest.TestCase): one_fold_fit = OneFoldFit(self.massif_name, dataset, models_classes=self.model_classes, temporal_covariate_for_fit=AnomalyTemperatureWithSplineTemporalCovariate, - only_models_that_pass_goodness_of_fit_test=False) + only_models_that_pass_goodness_of_fit_test=False, + first_year=1959, + last_year=2019 + ) _ = one_fold_fit.best_estimator.margin_model self.assertTrue(True) @@ -75,7 +84,10 @@ class TestOneFoldFit(unittest.TestCase): models_classes=self.model_classes, temporal_covariate_for_fit=None, only_models_that_pass_goodness_of_fit_test=False, - remove_physically_implausible_models=True) + remove_physically_implausible_models=True, + first_year=1959, + last_year=2019 + ) self.assertFalse(one_fold_fit.has_at_least_one_valid_model) def test_assertion_error_for_a_specific_case(self): @@ -94,7 +106,9 @@ class TestOneFoldFit(unittest.TestCase): temporal_covariate_for_fit=AnomalyTemperatureWithSplineTemporalCovariate, altitude_class=VeyHighAltitudeGroup, only_models_that_pass_goodness_of_fit_test=False, - remove_physically_implausible_models=True) + remove_physically_implausible_models=True, + first_year=1959, + last_year=2019) self.assertTrue(one_fold_fit.has_at_least_one_valid_model) if __name__ == '__main__': -- GitLab