From 8a9c7fcb715ee8ade15497034f556c5617bfae63 Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Wed, 24 Jun 2020 16:31:36 +0200
Subject: [PATCH] [contrasting] add altitudinal_models.py and fix for utils.py

---
 .../param_function/polynomial_coef.py         |  4 +-
 .../altitudinal_models.py                     | 48 +++++++++++++++++++
 .../spatio_temporal_polynomial_model.py       |  9 ++++
 .../polynomial_margin_model/utils.py          | 11 +++++
 .../model/result_from_model_fit/utils.py      |  5 +-
 .../test_gev_spatio_temporal_extremes_mle.py  | 16 +++++--
 6 files changed, 85 insertions(+), 8 deletions(-)
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/altitudinal_models.py
 create mode 100644 extreme_fit/model/margin_model/polynomial_margin_model/utils.py

diff --git a/extreme_fit/function/param_function/polynomial_coef.py b/extreme_fit/function/param_function/polynomial_coef.py
index 6a81f224..5a1da889 100644
--- a/extreme_fit/function/param_function/polynomial_coef.py
+++ b/extreme_fit/function/param_function/polynomial_coef.py
@@ -52,7 +52,6 @@ class PolynomialAllCoef(LinearCoef):
                        coordinates: AbstractCoordinates):
         degree0 = coef_dict[cls.coef_template_str(param_name, coefficient_name=cls.INTERCEPT_NAME).format(1)]
         list_dim_and_max_degree = dims
-        j = 2
         if len(list_dim_and_max_degree) == 0:
             dim_to_polynomial_coef = None
             intercept = degree0
@@ -61,8 +60,7 @@ class PolynomialAllCoef(LinearCoef):
             dim_to_polynomial_coef = {}
             for dim, max_degree in list_dim_and_max_degree:
                 coefficient_name = coordinates.coordinates_names[dim]
-                if coefficient_name == AbstractCoordinates.COORDINATE_T:
-                    j = 1
+                j = 1 if coefficient_name == AbstractCoordinates.COORDINATE_T else 2
                 degree_to_coef = {0: degree0}
                 for degree in range(1, max_degree + 1):
                     coef_value = coef_dict[cls.coef_template_str(param_name, coefficient_name).format(j)]
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/altitudinal_models.py b/extreme_fit/model/margin_model/polynomial_margin_model/altitudinal_models.py
new file mode 100644
index 00000000..7b2c68d1
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/altitudinal_models.py
@@ -0,0 +1,48 @@
+from extreme_fit.distribution.gev.gev_params import GevParams
+from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_polynomial_model import \
+    AbstractSpatioTemporalPolynomialModel
+
+
+class StationaryAltitudinal(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1)]
+        })
+
+
+class NonStationaryAltitudinalLocationLinear(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 1)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1)]
+        })
+
+
+class NonStationaryAltitudinalLocationQuadratic(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({
+            GevParams.LOC: [(self.coordinates.idx_x_coordinates, 1), (self.coordinates.idx_temporal_coordinates, 2)],
+            GevParams.SCALE: [(self.coordinates.idx_x_coordinates, 1)]
+        })
+
+
+class NonStationaryAltitudinalLocationLinearScaleLinear(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({
+            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 NonStationaryAltitudinalLocationQuadraticScaleLinear(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({
+            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)],
+        })
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/spatio_temporal_polynomial_model.py b/extreme_fit/model/margin_model/polynomial_margin_model/spatio_temporal_polynomial_model.py
index 4f9cde3d..b862e2ab 100644
--- a/extreme_fit/model/margin_model/polynomial_margin_model/spatio_temporal_polynomial_model.py
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/spatio_temporal_polynomial_model.py
@@ -21,3 +21,12 @@ class NonStationaryLocationSpatioTemporalLinearityModel(AbstractSpatioTemporalPo
             (self.coordinates.idx_temporal_coordinates, 1),
             (self.coordinates.idx_x_coordinates, 1),
         ]})
+
+
+class NonStationaryLocationSpatioTemporalLinearityModel2(AbstractSpatioTemporalPolynomialModel):
+
+    def load_margin_function(self, param_name_to_dims=None):
+        return super().load_margin_function({GevParams.LOC: [
+            (self.coordinates.idx_temporal_coordinates, 2),
+            (self.coordinates.idx_x_coordinates, 1),
+        ]})
diff --git a/extreme_fit/model/margin_model/polynomial_margin_model/utils.py b/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
new file mode 100644
index 00000000..acd15190
--- /dev/null
+++ b/extreme_fit/model/margin_model/polynomial_margin_model/utils.py
@@ -0,0 +1,11 @@
+from extreme_fit.model.margin_model.polynomial_margin_model.altitudinal_models import StationaryAltitudinal, \
+    NonStationaryAltitudinalLocationLinear, NonStationaryAltitudinalLocationQuadratic, \
+    NonStationaryAltitudinalLocationLinearScaleLinear, NonStationaryAltitudinalLocationQuadraticScaleLinear
+
+ALTITUDINAL_MODELS = [
+    StationaryAltitudinal,
+    NonStationaryAltitudinalLocationLinear,
+    NonStationaryAltitudinalLocationQuadratic,
+    NonStationaryAltitudinalLocationLinearScaleLinear,
+    NonStationaryAltitudinalLocationQuadraticScaleLinear
+][:]
diff --git a/extreme_fit/model/result_from_model_fit/utils.py b/extreme_fit/model/result_from_model_fit/utils.py
index 844639a5..35c0dada 100644
--- a/extreme_fit/model/result_from_model_fit/utils.py
+++ b/extreme_fit/model/result_from_model_fit/utils.py
@@ -33,8 +33,9 @@ def get_margin_coef_ordered_dict(param_name_to_dims, mle_values, type_for_mle="G
                 coef_dict[coef_name] = mle_values[i]
                 i += 1
             else:
-                # We assume that time was the first parameter
-                inverted_dims = dims[::-1]
+                # We found (thanks to the test) that time was the first parameter when len(param_name_to_dims) == 1
+                # otherwise time is the second parameter in the order of the mle parameters
+                inverted_dims = dims[::-1] if len(param_name_to_dims) == 1 else dims
                 for dim, max_degree in inverted_dims:
                     coordinate_name = dim_to_coordinate_name[dim]
                     coef_template = LinearCoef.coef_template_str(param_name, coordinate_name)
diff --git a/test/test_extreme_fit/test_estimator/test_gev_spatio_temporal_extremes_mle.py b/test/test_extreme_fit/test_estimator/test_gev_spatio_temporal_extremes_mle.py
index cba6e6f9..7d336ecd 100644
--- a/test/test_extreme_fit/test_estimator/test_gev_spatio_temporal_extremes_mle.py
+++ b/test/test_extreme_fit/test_estimator/test_gev_spatio_temporal_extremes_mle.py
@@ -9,7 +9,8 @@ from extreme_fit.model.margin_model.polynomial_margin_model.polynomial_margin_mo
     NonStationaryQuadraticLocationModel, \
     NonStationaryQuadraticScaleModel, NonStationaryQuadraticLocationGumbelModel, NonStationaryQuadraticScaleGumbelModel
 from extreme_fit.model.margin_model.polynomial_margin_model.spatio_temporal_polynomial_model import \
-    NonStationaryLocationSpatioTemporalLinearityModel
+    NonStationaryLocationSpatioTemporalLinearityModel, NonStationaryLocationSpatioTemporalLinearityModel2
+from extreme_fit.model.margin_model.polynomial_margin_model.utils import ALTITUDINAL_MODELS
 from extreme_trend.abstract_gev_trend_test import fitted_linear_margin_estimator
 from extreme_fit.model.margin_model.utils import \
     MarginFitMethod
@@ -44,13 +45,22 @@ class TestGevTemporalQuadraticExtremesMle(unittest.TestCase):
         estimator = model_fit.estimator_fold_1
         return estimator
 
-    def test_location_spatio_temporal_linearity(self):
-        estimator = self.get_estimator_fitted(NonStationaryLocationSpatioTemporalLinearityModel)
+    def common_test(self, model_class):
+        estimator = self.get_estimator_fitted(model_class)
         # Assert that indicators are correctly computed
         self.assertAlmostEqual(estimator.result_from_model_fit.nllh, estimator.nllh(split=estimator.train_split))
         self.assertAlmostEqual(estimator.result_from_model_fit.aic, estimator.aic(split=estimator.train_split))
         self.assertAlmostEqual(estimator.result_from_model_fit.bic, estimator.bic(split=estimator.train_split))
 
+    def test_location_spatio_temporal_models(self):
+        for model_class in [NonStationaryLocationSpatioTemporalLinearityModel,
+                            NonStationaryLocationSpatioTemporalLinearityModel2]:
+            self.common_test(model_class)
+
+    def test_altitudinal_models(self):
+        for model_class in ALTITUDINAL_MODELS:
+            self.common_test(model_class)
+
 
 if __name__ == '__main__':
     unittest.main()
-- 
GitLab