Commit 62b35531 authored by Le Roux Erwan's avatar Le Roux Erwan
Browse files

[refactor] improve test coverage for abstract_gev_trend_test.py and safran_variable.py

parent 410cc66c
No related merge requests found
Showing with 77 additions and 59 deletions
+77 -59
...@@ -12,12 +12,15 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran_variable impor ...@@ -12,12 +12,15 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran_variable impor
class Safran(AbstractStudy): class Safran(AbstractStudy):
SAFRAN_VARIABLES = [SafranSnowfallVariable,
SafranRainfallVariable,
SafranTemperatureVariable,
SafranTotalPrecipVariable,
SafranNormalizedPrecipitationRateVariable,
SafranNormalizedPrecipitationRateOnWetDaysVariable]
def __init__(self, variable_class: type, *args, **kwargs): def __init__(self, variable_class: type, *args, **kwargs):
assert variable_class in [SafranSnowfallVariable, SafranRainfallVariable, SafranTemperatureVariable, assert variable_class in self.SAFRAN_VARIABLES
SafranTotalPrecipVariable,
SafranNormalizedPrecipitationRateVariable,
SafranNormalizedPrecipitationRateOnWetDaysVariable]
super().__init__(variable_class, *args, **kwargs) super().__init__(variable_class, *args, **kwargs)
self.model_name = 'Safran' self.model_name = 'Safran'
......
...@@ -79,7 +79,7 @@ class SafranRainfallVariable(SafranSnowfallVariable): ...@@ -79,7 +79,7 @@ class SafranRainfallVariable(SafranSnowfallVariable):
class SafranTotalPrecipVariable(AbstractVariable): class SafranTotalPrecipVariable(AbstractVariable):
NAME = 'Precipitation' 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) super().__init__(None)
snow_precipitation = SafranSnowfallVariable(snow_variable_array, nb_consecutive_days) snow_precipitation = SafranSnowfallVariable(snow_variable_array, nb_consecutive_days)
rain_precipitation = SafranRainfallVariable(rain_variable_array, nb_consecutive_days) rain_precipitation = SafranRainfallVariable(rain_variable_array, nb_consecutive_days)
...@@ -98,9 +98,7 @@ class SafranTotalPrecipVariable(AbstractVariable): ...@@ -98,9 +98,7 @@ class SafranTotalPrecipVariable(AbstractVariable):
class SafranNormalizedPrecipitationRateVariable(AbstractVariable): class SafranNormalizedPrecipitationRateVariable(AbstractVariable):
NAME = 'Normalized Precip' NAME = 'Normalized Precip'
def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days=3):
def __init__(self, temperature_variable_array, snow_variable_array, rain_variable_array, nb_consecutive_days):
super().__init__(None) super().__init__(None)
temperature = SafranTemperatureVariable(temperature_variable_array) temperature = SafranTemperatureVariable(temperature_variable_array)
total_precipitation = SafranTotalPrecipVariable(snow_variable_array, rain_variable_array, nb_consecutive_days) total_precipitation = SafranTotalPrecipVariable(snow_variable_array, rain_variable_array, nb_consecutive_days)
...@@ -119,7 +117,7 @@ class SafranNormalizedPrecipitationRateVariable(AbstractVariable): ...@@ -119,7 +117,7 @@ class SafranNormalizedPrecipitationRateVariable(AbstractVariable):
class SafranNormalizedPrecipitationRateOnWetDaysVariable(SafranNormalizedPrecipitationRateVariable): 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) 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) total_precipitation = SafranTotalPrecipVariable(snow_variable_array, rain_variable_array, nb_consecutive_days)
mask_for_nan_values = total_precipitation.daily_time_serie_array < 0.01 mask_for_nan_values = total_precipitation.daily_time_serie_array < 0.01
......
...@@ -37,28 +37,16 @@ class AbstractGevTrendTest(object): ...@@ -37,28 +37,16 @@ class AbstractGevTrendTest(object):
self.fit_method = fit_method self.fit_method = fit_method
# Load observations, coordinates and datasets # Load observations, coordinates and datasets
self.coordinates, self.dataset = load_temporal_coordinates_and_dataset(self.maxima, self.years) 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 @cached_property
def constrained_estimator(self): def constrained_estimator(self):
try: return fitted_linear_margin_estimator(self.constrained_model_class, self.coordinates, self.dataset,
return fitted_linear_margin_estimator(self.constrained_model_class, self.coordinates, self.dataset, self.starting_year, self.fit_method)
self.starting_year, self.fit_method)
except SafeRunException:
self.crashed = True
@cached_property @cached_property
def unconstrained_estimator(self): 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) self.starting_year, self.fit_method)
except SafeRunException:
self.crashed = True
# Likelihood ratio test # Likelihood ratio test
...@@ -87,25 +75,15 @@ class AbstractGevTrendTest(object): ...@@ -87,25 +75,15 @@ class AbstractGevTrendTest(object):
@property @property
def constrained_model_deviance(self): def constrained_model_deviance(self):
if self.crashed: return self.constrained_estimator.result_from_model_fit.deviance
return np.nan
else:
return self.constrained_estimator.result_from_model_fit.deviance
@property @property
def unconstrained_model_deviance(self): def unconstrained_model_deviance(self):
unconstrained_estimator = self.unconstrained_estimator unconstrained_estimator = self.unconstrained_estimator
if self.crashed: return unconstrained_estimator.result_from_model_fit.deviance
return np.nan
else:
return unconstrained_estimator.result_from_model_fit.deviance
# Evolution of the GEV parameters and corresponding quantiles # 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): def get_non_stationary_linear_coef(self, param_name: str):
return self.unconstrained_estimator.function_from_fit.get_coef(param_name, return self.unconstrained_estimator.function_from_fit.get_coef(param_name,
AbstractCoordinates.COORDINATE_T) AbstractCoordinates.COORDINATE_T)
...@@ -116,12 +94,6 @@ class AbstractGevTrendTest(object): ...@@ -116,12 +94,6 @@ class AbstractGevTrendTest(object):
return self.unconstrained_estimator.function_from_fit.get_params(coordinate=np.array([1958]), return self.unconstrained_estimator.function_from_fit.get_params(coordinate=np.array([1958]),
is_transformed=False) 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): def time_derivative_times_years(self, nb_years):
# Compute the slope strength # Compute the slope strength
slope = self._slope_strength() slope = self._slope_strength()
...@@ -131,10 +103,7 @@ class AbstractGevTrendTest(object): ...@@ -131,10 +103,7 @@ class AbstractGevTrendTest(object):
@property @property
def time_derivative_of_return_level(self): def time_derivative_of_return_level(self):
if self.crashed: return self.time_derivative_times_years(self.nb_years_for_quantile_evolution)
return 0.0
else:
return self.time_derivative_times_years(self.nb_years_for_quantile_evolution)
def relative_change_in_return_level(self, initial_year, final_year): def relative_change_in_return_level(self, initial_year, final_year):
return_level_values = [] return_level_values = []
...@@ -169,10 +138,7 @@ class AbstractGevTrendTest(object): ...@@ -169,10 +138,7 @@ class AbstractGevTrendTest(object):
@property @property
def test_trend_constant_quantile(self): def test_trend_constant_quantile(self):
if self.crashed: return self.unconstrained_estimator_gev_params.quantile(p=self.quantile_level)
return 0.0
else:
return self.unconstrained_estimator_gev_params.quantile(p=self.quantile_level)
# Some class properties for display purpose # Some class properties for display purpose
......
...@@ -10,23 +10,20 @@ import numpy as np ...@@ -10,23 +10,20 @@ import numpy as np
class AbstractComparisonNonStationaryModelOneParameter(GevTrendTestOneParameter): class AbstractComparisonNonStationaryModelOneParameter(GevTrendTestOneParameter):
pass
@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)
class ComparisonAgainstMu(AbstractComparisonNonStationaryModelOneParameter, GevLocationAndScaleTrendTest): 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, super().__init__(years, maxima, starting_year, constrained_model_class=NonStationaryLocationTemporalModel,
quantile_level=quantile_level, fit_method=fit_method) quantile_level=quantile_level, fit_method=fit_method)
class ComparisonAgainstSigma(AbstractComparisonNonStationaryModelOneParameter, GevLocationAndScaleTrendTest): 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, super().__init__(years, maxima, starting_year, constrained_model_class=NonStationaryScaleTemporalModel,
quantile_level=quantile_level, fit_method=fit_method) quantile_level=quantile_level, fit_method=fit_method)
...@@ -11,7 +11,7 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranS ...@@ -11,7 +11,7 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranS
SafranPrecipitation, SafranSnowfall3Days, SafranRainfall3Days, SafranNormalizedPreciptationRateOnWetDays 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.utils import SeasonForTheMaxima
from extreme_data.meteo_france_data.scm_models_data.visualization.main_study_visualizer import \ 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 from root_utils import get_display_name_from_object_type
...@@ -60,6 +60,12 @@ class TestSCMAllStudy(unittest.TestCase): ...@@ -60,6 +60,12 @@ class TestSCMAllStudy(unittest.TestCase):
for study_class in study_classes: for study_class in study_classes:
study_class(altitude=altitude, year_min=year_min, year_max=year_max) 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): class TestSCMSafranNormalizedPrecipitationRateOnWetDays(unittest.TestCase):
...@@ -101,6 +107,7 @@ class TestSCMSafranSnowfall(TestSCMStudy): ...@@ -101,6 +107,7 @@ class TestSCMSafranSnowfall(TestSCMStudy):
self.assertEqual(all_daily_series.shape[1], 23) self.assertEqual(all_daily_series.shape[1], 23)
self.assertEqual(all_daily_series.shape[0], 22280) self.assertEqual(all_daily_series.shape[0], 22280)
class TestSCMPrecipitation(TestSCMStudy): class TestSCMPrecipitation(TestSCMStudy):
def setUp(self) -> None: def setUp(self) -> None:
......
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)
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
...@@ -17,6 +17,16 @@ class TestGevParams(unittest.TestCase): ...@@ -17,6 +17,16 @@ class TestGevParams(unittest.TestCase):
for quantile_name, p in gev_params.quantile_name_to_p.items(): for quantile_name, p in gev_params.quantile_name_to_p.items():
self.assertAlmostEqual(- 1 / np.log(p), quantile_dict[quantile_name]) 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): def test_negative_scale(self):
gev_params = GevParams(loc=1.0, shape=1.0, scale=-1.0) gev_params = GevParams(loc=1.0, shape=1.0, scale=-1.0)
for p in [0.1, 0.5, 0.9]: for p in [0.1, 0.5, 0.9]:
......
...@@ -37,6 +37,7 @@ class TestTwoFoldFit(unittest.TestCase): ...@@ -37,6 +37,7 @@ class TestTwoFoldFit(unittest.TestCase):
best_model_class = two_fold_fit.massif_name_to_best_model()['Vercors'] best_model_class = two_fold_fit.massif_name_to_best_model()['Vercors']
except AssertionError as e: except AssertionError as e:
self.assertTrue(False, msg=e.__str__()) self.assertTrue(False, msg=e.__str__())
best_model_class = None
self.assertEqual(best_model_class, LinearLocationAllDimsMarginModel) self.assertEqual(best_model_class, LinearLocationAllDimsMarginModel)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment