From 62b35531548700e5d8c56a8241ace38250ac8cd1 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Sat, 18 Apr 2020 15:27:10 +0200 Subject: [PATCH] [refactor] improve test coverage for abstract_gev_trend_test.py and safran_variable.py --- .../scm_models_data/safran/safran.py | 11 +++-- .../scm_models_data/safran/safran_variable.py | 8 ++-- extreme_trend/abstract_gev_trend_test.py | 48 +++---------------- ...bstract_comparison_non_stationary_model.py | 13 ++--- ..._result.py => main_constrasting_result.py} | 0 .../test_meteo_france_data/test_SCM_study.py | 9 +++- .../test_meteo_france_data/test_variables.py | 26 ++++++++++ .../test_visualization.py | 10 ++++ .../test_gev/test_gev_params.py | 10 ++++ .../test_contrasting/test_two_fold_fit.py | 1 + 10 files changed, 77 insertions(+), 59 deletions(-) rename projects/contrasting_trends_in_snow_loads/spatial trends/{main_result.py => main_constrasting_result.py} (100%) create mode 100644 test/test_extreme_data/test_meteo_france_data/test_visualization.py diff --git a/extreme_data/meteo_france_data/scm_models_data/safran/safran.py b/extreme_data/meteo_france_data/scm_models_data/safran/safran.py index ac0024d7..81a95f70 100644 --- a/extreme_data/meteo_france_data/scm_models_data/safran/safran.py +++ b/extreme_data/meteo_france_data/scm_models_data/safran/safran.py @@ -12,12 +12,15 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran_variable impor class Safran(AbstractStudy): + SAFRAN_VARIABLES = [SafranSnowfallVariable, + SafranRainfallVariable, + SafranTemperatureVariable, + SafranTotalPrecipVariable, + SafranNormalizedPrecipitationRateVariable, + SafranNormalizedPrecipitationRateOnWetDaysVariable] def __init__(self, variable_class: type, *args, **kwargs): - assert variable_class in [SafranSnowfallVariable, SafranRainfallVariable, SafranTemperatureVariable, - SafranTotalPrecipVariable, - SafranNormalizedPrecipitationRateVariable, - SafranNormalizedPrecipitationRateOnWetDaysVariable] + assert variable_class in self.SAFRAN_VARIABLES super().__init__(variable_class, *args, **kwargs) self.model_name = 'Safran' diff --git a/extreme_data/meteo_france_data/scm_models_data/safran/safran_variable.py b/extreme_data/meteo_france_data/scm_models_data/safran/safran_variable.py index 66dcc8f5..55d8d7b5 100644 --- a/extreme_data/meteo_france_data/scm_models_data/safran/safran_variable.py +++ b/extreme_data/meteo_france_data/scm_models_data/safran/safran_variable.py @@ -79,7 +79,7 @@ class SafranRainfallVariable(SafranSnowfallVariable): class SafranTotalPrecipVariable(AbstractVariable): NAME = 'Precipitation' - def __init__(self, snow_variable_array, rain_variable_array, nb_consecutive_days): + def __init__(self, snow_variable_array, rain_variable_array, nb_consecutive_days=3): super().__init__(None) snow_precipitation = SafranSnowfallVariable(snow_variable_array, nb_consecutive_days) rain_precipitation = SafranRainfallVariable(rain_variable_array, nb_consecutive_days) @@ -98,9 +98,7 @@ class SafranTotalPrecipVariable(AbstractVariable): class SafranNormalizedPrecipitationRateVariable(AbstractVariable): NAME = 'Normalized Precip' - - - def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days): + def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days=3): super().__init__(None) temperature = SafranTemperatureVariable(temperature_variable_array) total_precipitation = SafranTotalPrecipVariable(snow_variable_array, rain_variable_array, nb_consecutive_days) @@ -119,7 +117,7 @@ class SafranNormalizedPrecipitationRateVariable(AbstractVariable): class SafranNormalizedPrecipitationRateOnWetDaysVariable(SafranNormalizedPrecipitationRateVariable): - def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days): + def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days=3): super().__init__(temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days) total_precipitation = SafranTotalPrecipVariable(snow_variable_array, rain_variable_array, nb_consecutive_days) mask_for_nan_values = total_precipitation.daily_time_serie_array < 0.01 diff --git a/extreme_trend/abstract_gev_trend_test.py b/extreme_trend/abstract_gev_trend_test.py index 5cbfa164..bcee5a5e 100644 --- a/extreme_trend/abstract_gev_trend_test.py +++ b/extreme_trend/abstract_gev_trend_test.py @@ -37,28 +37,16 @@ class AbstractGevTrendTest(object): self.fit_method = fit_method # Load observations, coordinates and datasets self.coordinates, self.dataset = load_temporal_coordinates_and_dataset(self.maxima, self.years) - # By default crashed boolean is False - self.crashed = False - try: - pass - except SafeRunException: - self.crashed = True @cached_property def constrained_estimator(self): - try: - return fitted_linear_margin_estimator(self.constrained_model_class, self.coordinates, self.dataset, - self.starting_year, self.fit_method) - except SafeRunException: - self.crashed = True + return fitted_linear_margin_estimator(self.constrained_model_class, self.coordinates, self.dataset, + self.starting_year, self.fit_method) @cached_property def unconstrained_estimator(self): - try: - return fitted_linear_margin_estimator(self.unconstrained_model_class, self.coordinates, self.dataset, + return fitted_linear_margin_estimator(self.unconstrained_model_class, self.coordinates, self.dataset, self.starting_year, self.fit_method) - except SafeRunException: - self.crashed = True # Likelihood ratio test @@ -87,25 +75,15 @@ class AbstractGevTrendTest(object): @property def constrained_model_deviance(self): - if self.crashed: - return np.nan - else: - return self.constrained_estimator.result_from_model_fit.deviance + return self.constrained_estimator.result_from_model_fit.deviance @property def unconstrained_model_deviance(self): unconstrained_estimator = self.unconstrained_estimator - if self.crashed: - return np.nan - else: - return unconstrained_estimator.result_from_model_fit.deviance + return unconstrained_estimator.result_from_model_fit.deviance # Evolution of the GEV parameters and corresponding quantiles - @property - def test_sign(self) -> int: - return np.sign(self.time_derivative_of_return_level) - def get_non_stationary_linear_coef(self, param_name: str): return self.unconstrained_estimator.function_from_fit.get_coef(param_name, AbstractCoordinates.COORDINATE_T) @@ -116,12 +94,6 @@ class AbstractGevTrendTest(object): return self.unconstrained_estimator.function_from_fit.get_params(coordinate=np.array([1958]), is_transformed=False) - @cached_property - def constrained_estimator_gev_params(self) -> GevParams: - # Constant parameters correspond to any gev params - return self.constrained_estimator.function_from_fit.get_params(coordinate=np.array([1958]), - is_transformed=False) - def time_derivative_times_years(self, nb_years): # Compute the slope strength slope = self._slope_strength() @@ -131,10 +103,7 @@ class AbstractGevTrendTest(object): @property def time_derivative_of_return_level(self): - if self.crashed: - return 0.0 - else: - return self.time_derivative_times_years(self.nb_years_for_quantile_evolution) + return self.time_derivative_times_years(self.nb_years_for_quantile_evolution) def relative_change_in_return_level(self, initial_year, final_year): return_level_values = [] @@ -169,10 +138,7 @@ class AbstractGevTrendTest(object): @property def test_trend_constant_quantile(self): - if self.crashed: - return 0.0 - else: - return self.unconstrained_estimator_gev_params.quantile(p=self.quantile_level) + return self.unconstrained_estimator_gev_params.quantile(p=self.quantile_level) # Some class properties for display purpose diff --git a/extreme_trend/trend_test_one_parameter/abstract_comparison_non_stationary_model.py b/extreme_trend/trend_test_one_parameter/abstract_comparison_non_stationary_model.py index 56a6c6ce..cbf6789a 100644 --- a/extreme_trend/trend_test_one_parameter/abstract_comparison_non_stationary_model.py +++ b/extreme_trend/trend_test_one_parameter/abstract_comparison_non_stationary_model.py @@ -10,23 +10,20 @@ import numpy as np class AbstractComparisonNonStationaryModelOneParameter(GevTrendTestOneParameter): - - @property - def test_sign(self) -> int: - # Test sign correspond to the difference between the 2 likelihoods - # Therefore, colors sum up which non stationary model explain best the data - return np.sign(self.likelihood_ratio) + pass class ComparisonAgainstMu(AbstractComparisonNonStationaryModelOneParameter, GevLocationAndScaleTrendTest): - def __init__(self, years, maxima, starting_year, quantile_level=EUROCODE_QUANTILE, fit_method=MarginFitMethod.extremes_fevd_mle): + def __init__(self, years, maxima, starting_year, quantile_level=EUROCODE_QUANTILE, + fit_method=MarginFitMethod.extremes_fevd_mle): super().__init__(years, maxima, starting_year, constrained_model_class=NonStationaryLocationTemporalModel, quantile_level=quantile_level, fit_method=fit_method) class ComparisonAgainstSigma(AbstractComparisonNonStationaryModelOneParameter, GevLocationAndScaleTrendTest): - def __init__(self, years, maxima, starting_year, quantile_level=EUROCODE_QUANTILE, fit_method=MarginFitMethod.extremes_fevd_mle): + def __init__(self, years, maxima, starting_year, quantile_level=EUROCODE_QUANTILE, + fit_method=MarginFitMethod.extremes_fevd_mle): super().__init__(years, maxima, starting_year, constrained_model_class=NonStationaryScaleTemporalModel, quantile_level=quantile_level, fit_method=fit_method) diff --git a/projects/contrasting_trends_in_snow_loads/spatial trends/main_result.py b/projects/contrasting_trends_in_snow_loads/spatial trends/main_constrasting_result.py similarity index 100% rename from projects/contrasting_trends_in_snow_loads/spatial trends/main_result.py rename to projects/contrasting_trends_in_snow_loads/spatial trends/main_constrasting_result.py diff --git a/test/test_extreme_data/test_meteo_france_data/test_SCM_study.py b/test/test_extreme_data/test_meteo_france_data/test_SCM_study.py index 71a468cf..cc218d4b 100644 --- a/test/test_extreme_data/test_meteo_france_data/test_SCM_study.py +++ b/test/test_extreme_data/test_meteo_france_data/test_SCM_study.py @@ -11,7 +11,7 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranS SafranPrecipitation, SafranSnowfall3Days, SafranRainfall3Days, SafranNormalizedPreciptationRateOnWetDays from extreme_data.meteo_france_data.scm_models_data.utils import SeasonForTheMaxima from extreme_data.meteo_france_data.scm_models_data.visualization.main_study_visualizer import \ - study_iterator_global, SCM_STUDIES, ALL_ALTITUDES + study_iterator_global, SCM_STUDIES, ALL_ALTITUDES, SCM_STUDY_CLASS_TO_ABBREVIATION from root_utils import get_display_name_from_object_type @@ -60,6 +60,12 @@ class TestSCMAllStudy(unittest.TestCase): for study_class in study_classes: study_class(altitude=altitude, year_min=year_min, year_max=year_max) + def test_variables(self): + for study_class in SCM_STUDY_CLASS_TO_ABBREVIATION.keys(): + study = study_class(year_max=1959) + _ = study.year_to_annual_maxima[1959] + self.assertTrue(True) + class TestSCMSafranNormalizedPrecipitationRateOnWetDays(unittest.TestCase): @@ -101,6 +107,7 @@ class TestSCMSafranSnowfall(TestSCMStudy): self.assertEqual(all_daily_series.shape[1], 23) self.assertEqual(all_daily_series.shape[0], 22280) + class TestSCMPrecipitation(TestSCMStudy): def setUp(self) -> None: diff --git a/test/test_extreme_data/test_meteo_france_data/test_variables.py b/test/test_extreme_data/test_meteo_france_data/test_variables.py index e69de29b..be047683 100644 --- a/test/test_extreme_data/test_meteo_france_data/test_variables.py +++ b/test/test_extreme_data/test_meteo_france_data/test_variables.py @@ -0,0 +1,26 @@ +import unittest + +import numpy as np + +from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranSnowfall, Safran +from extreme_data.meteo_france_data.scm_models_data.safran.safran_variable import SafranTemperatureVariable + + +class TestSafranVariables(unittest.TestCase): + + def setUp(self) -> None: + super().setUp() + study = SafranSnowfall(year_max=1960) + self.dataset = study.year_to_dataset_ordered_dict[1959] + + def test_variables(self): + for variable_class in Safran.SAFRAN_VARIABLES: + keywords = variable_class.keyword() + names = keywords if isinstance(keywords, list) else [keywords] + variable_arrays = [np.array(self.dataset.variables[name]) for name in names] + variable_class(*variable_arrays) + self.assertTrue(True) + + + + diff --git a/test/test_extreme_data/test_meteo_france_data/test_visualization.py b/test/test_extreme_data/test_meteo_france_data/test_visualization.py new file mode 100644 index 00000000..fcac9479 --- /dev/null +++ b/test/test_extreme_data/test_meteo_france_data/test_visualization.py @@ -0,0 +1,10 @@ +import unittest + +from extreme_data.meteo_france_data.scm_models_data.visualization.main_study_visualizer import \ + SCM_STUDY_CLASS_TO_ABBREVIATION + + +class TestVisualization(unittest.TestCase): + pass + + diff --git a/test/test_extreme_fit/test_distribution/test_gev/test_gev_params.py b/test/test_extreme_fit/test_distribution/test_gev/test_gev_params.py index c20b5782..bf4c2d33 100644 --- a/test/test_extreme_fit/test_distribution/test_gev/test_gev_params.py +++ b/test/test_extreme_fit/test_distribution/test_gev/test_gev_params.py @@ -17,6 +17,16 @@ class TestGevParams(unittest.TestCase): for quantile_name, p in gev_params.quantile_name_to_p.items(): self.assertAlmostEqual(- 1 / np.log(p), quantile_dict[quantile_name]) + def test_time_derivative_return_level(self): + p = 0.99 + for mu1 in [-1, 0, 1]: + for sigma1 in [1, 10]: + for shape in [-1, 0, 1]: + params = GevParams(loc=mu1, scale=sigma1, shape=shape) + quantile = params.quantile(p) + time_derivative = params.time_derivative_of_return_level(p, mu1, sigma1) + self.assertEqual(quantile, time_derivative) + def test_negative_scale(self): gev_params = GevParams(loc=1.0, shape=1.0, scale=-1.0) for p in [0.1, 0.5, 0.9]: diff --git a/test/test_projects/test_contrasting/test_two_fold_fit.py b/test/test_projects/test_contrasting/test_two_fold_fit.py index 27e7421a..7051fd87 100644 --- a/test/test_projects/test_contrasting/test_two_fold_fit.py +++ b/test/test_projects/test_contrasting/test_two_fold_fit.py @@ -37,6 +37,7 @@ class TestTwoFoldFit(unittest.TestCase): best_model_class = two_fold_fit.massif_name_to_best_model()['Vercors'] except AssertionError as e: self.assertTrue(False, msg=e.__str__()) + best_model_class = None self.assertEqual(best_model_class, LinearLocationAllDimsMarginModel) -- GitLab