From 561f8122884e4b38a9acaf82351af5287868344f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 13 Nov 2024 12:30:43 -0500 Subject: [PATCH 01/27] check_matching_time method: ref & hist must match --- CHANGELOG.rst | 3 ++- xclim/sdba/adjustment.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f85d72b51..06ad48731 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,7 +4,7 @@ Changelog v0.54.0 (unreleased) -------------------- -Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Pascal Bourgault (:user:`aulemahal`). +Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Pascal Bourgault (:user:`aulemahal`), Éric Dupuis (:user:`coxipi`). Breaking changes ---------------- @@ -17,6 +17,7 @@ Bug fixes Internal changes ^^^^^^^^^^^^^^^^ * Changed french translations with word "pluvieux" to "avec précipitations". (:issue:`1960`, :pull:`1994`). +* Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). (:issue:`1903`, :pull:``) v0.53.2 (2024-10-31) -------------------- diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 5c8506071..708190146 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -207,6 +207,12 @@ def __convert_units_to(_input_da, _internal_dim, _internal_target): convert_units_to(inda, target, context="infer") for inda in inputs ), target + @classmethod + def _check_matching_time(cls, ref, hist): + """Raise an error ref and hist times don't match.""" + if all(ref.time == hist.time) is False: + raise ValueError("`ref` and `hist` should have the same time arrays.") + @classmethod def _train(cls, ref, hist, **kwargs): raise NotImplementedError() @@ -258,6 +264,9 @@ def train(cls, ref: DataArray, hist: DataArray, **kwargs) -> TrainAdjust: else: train_units = "" + if cls._allow_diff_calendars is False: + cls._check_matching_time(ref, hist) + ds, params = cls._train(ref, hist, **kwargs) obj = cls( _trained=True, @@ -1737,6 +1746,8 @@ class MBCn(TrainAdjust): Only "time" and "time.dayofyear" (with a suitable window) are implemented as possible values for `group`. """ + _allow_diff_calendars = False + @classmethod def _train( cls, From 85f4f9f71f6f972e57c96f753f04c2397a8007ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 13 Nov 2024 12:32:08 -0500 Subject: [PATCH 02/27] add pull number --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 06ad48731..47fbf1380 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,7 @@ Bug fixes Internal changes ^^^^^^^^^^^^^^^^ * Changed french translations with word "pluvieux" to "avec précipitations". (:issue:`1960`, :pull:`1994`). -* Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). (:issue:`1903`, :pull:``) +* Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). (:issue:`1903`, :pull:`1995`) v0.53.2 (2024-10-31) -------------------- From 60cd8303b2c3572160869fff7550e1cef505bc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Mon, 25 Nov 2024 12:40:32 -0500 Subject: [PATCH 03/27] add new class attr --- xclim/sdba/adjustment.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 708190146..5b0e5e70b 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -76,6 +76,7 @@ class BaseAdjustment(ParametrizableWithDataset): """ _allow_diff_calendars = True + _allow_diff_training_times = True _attribute = "_xclim_adjustment" def __init__(self, *args, _trained=False, **kwargs): @@ -264,7 +265,7 @@ def train(cls, ref: DataArray, hist: DataArray, **kwargs) -> TrainAdjust: else: train_units = "" - if cls._allow_diff_calendars is False: + if cls._allow_diff_training_times is False: cls._check_matching_time(ref, hist) ds, params = cls._train(ref, hist, **kwargs) @@ -450,7 +451,7 @@ class EmpiricalQuantileMapping(TrainAdjust): :cite:cts:`sdba-deque_frequency_2007` """ - _allow_diff_calendars = False + _allow_diff_training_times = False @classmethod def _train( @@ -550,7 +551,7 @@ class DetrendedQuantileMapping(TrainAdjust): """ - _allow_diff_calendars = False + _allow_diff_training_times = False @classmethod def _train( @@ -877,7 +878,7 @@ class LOCI(TrainAdjust): :cite:cts:`sdba-schmidli_downscaling_2006` """ - _allow_diff_calendars = False + _allow_diff_training_times = False @classmethod def _train( @@ -929,7 +930,7 @@ class Scaling(TrainAdjust): The interpolation method to use then interpolating the adjustment factors. Defaults to "nearest". """ - _allow_diff_calendars = False + _allow_diff_training_times = False @classmethod def _train( @@ -1746,7 +1747,7 @@ class MBCn(TrainAdjust): Only "time" and "time.dayofyear" (with a suitable window) are implemented as possible values for `group`. """ - _allow_diff_calendars = False + _allow_diff_training_times = False @classmethod def _train( From d42044f855db63c0f7732e813d4aca924e3ff704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Mon, 25 Nov 2024 15:03:51 -0500 Subject: [PATCH 04/27] Adjust can modify sim time if needed --- xclim/sdba/adjustment.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 4c785595d..5a5bec7fc 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -350,6 +350,8 @@ class Adjust(BaseAdjustment): and returning the scen dataset/array. """ + _replace_sim_time = True + @classmethod def adjust( cls, @@ -380,6 +382,13 @@ def adjust( sim = hist.copy() sim.attrs["_is_hist"] = True + # This below implies that ref.time and sim.time have the same size + # Since `ref,hist, sim` are in the same `map_groups` call, they must have + # the same time + if cls.__replace_sim_time: + sim_time = sim.time + sim["time"] = ref["time"] + kwargs = parse_group(cls._adjust, kwargs) skip_checks = kwargs.pop("skip_input_checks", False) @@ -395,6 +404,8 @@ def adjust( out = out.rename("scen").to_dataset() scen = out.scen + if cls.__replace_sim_time: + scen["time"] = sim_time params = ", ".join([f"{k}={repr(v)}" for k, v in kwargs.items()]) infostr = f"{cls.__name__}.adjust(ref, hist, sim, {params})" From 90053c5ec3df45f31ee05b4f5fe0ada78e36120b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Mon, 25 Nov 2024 17:54:24 -0500 Subject: [PATCH 05/27] add tests --- tests/test_sdba/test_adjustment.py | 37 ++++++++++++++++++++++++++++++ xclim/sdba/adjustment.py | 6 ++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index 706bc5a29..9b3438647 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -66,6 +66,16 @@ def test_harmonize_units_multivariate(self, series, random, use_dask): ds, ds2 = unstack_variables(da), unstack_variables(da2) assert (ds.tas.units == ds2.tas.units) & (ds.pr.units == ds2.pr.units) + def test_matching_time(self, series, random): + n = 10 + u = random.random(n) + da = series(u, "tas", start="2000-01-01") + da2 = series(u, "tas", start="2010-01-01") + with pytest.raises( + ValueError, match="`ref` and `hist` should have the same time arrays." + ): + BaseAdjustment._check_matching_time(ref=da, hist=da2) + class TestLoci: @pytest.mark.parametrize("group,dec", (["time", 2], ["time.month", 1])) @@ -1068,6 +1078,33 @@ def test_shape(self, random, series): sim = unstack_variables(sim) assert not np.isin(sim.x[sim.x.isnull()].time.values, scen.time.values).any() + # just check it runs + def test_different_times(self, tasmax_series, tasmin_series): + # `sim` has a different time than `ref,hist` (but same size) + ref = xr.merge( + [ + tasmax_series(np.arange(730).astype(float), start="2000-01-01").chunk( + {"time": -1} + ), + tasmin_series(np.arange(730).astype(float), start="2000-01-01").chunk( + {"time": -1} + ), + ] + ) + hist = ref.copy() + sim = xr.merge( + [ + tasmax_series(np.arange(730).astype(float), start="2020-01-01").chunk( + {"time": -1} + ), + tasmin_series(np.arange(730).astype(float), start="2020-01-01").chunk( + {"time": -1} + ), + ] + ) + ref, hist, sim = (stack_variables(arr) for arr in [ref, hist, sim]) + dOTC.adjust(ref, hist, sim) + def test_raise_on_multiple_chunks(tas_series): ref = tas_series(np.arange(730).astype(float)).chunk({"time": 365}) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 5a5bec7fc..5acfb0e45 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -212,7 +212,7 @@ def __convert_units_to(_input_da, _internal_dim, _internal_target): @classmethod def _check_matching_time(cls, ref, hist): """Raise an error ref and hist times don't match.""" - if all(ref.time == hist.time) is False: + if all(ref.time.values == hist.time.values) is False: raise ValueError("`ref` and `hist` should have the same time arrays.") @classmethod @@ -385,7 +385,7 @@ def adjust( # This below implies that ref.time and sim.time have the same size # Since `ref,hist, sim` are in the same `map_groups` call, they must have # the same time - if cls.__replace_sim_time: + if cls._replace_sim_time: sim_time = sim.time sim["time"] = ref["time"] @@ -404,7 +404,7 @@ def adjust( out = out.rename("scen").to_dataset() scen = out.scen - if cls.__replace_sim_time: + if cls._replace_sim_time: scen["time"] = sim_time params = ", ".join([f"{k}={repr(v)}" for k, v in kwargs.items()]) From c0375429eed1e75d2c92470fe8b36fbb156e2792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Tue, 26 Nov 2024 13:04:54 -0500 Subject: [PATCH 06/27] add skip if OT not installed --- tests/test_sdba/test_adjustment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index 9b3438647..a8775b239 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -1080,6 +1080,7 @@ def test_shape(self, random, series): # just check it runs def test_different_times(self, tasmax_series, tasmin_series): + pytest.importorskip("ot") # `sim` has a different time than `ref,hist` (but same size) ref = xr.merge( [ From 7ed51bef5bec7d8593d10539fc61cb6d48680990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 13:36:02 -0500 Subject: [PATCH 07/27] clearer attrs, more checks --- xclim/sdba/adjustment.py | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 5acfb0e45..0b4c8de54 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -78,6 +78,7 @@ class BaseAdjustment(ParametrizableWithDataset): _allow_diff_calendars = True _allow_diff_training_times = True + _allow_diff_time_sizes = True _attribute = "_xclim_adjustment" def __init__(self, *args, _trained=False, **kwargs): @@ -210,10 +211,24 @@ def __convert_units_to(_input_da, _internal_dim, _internal_target): ), target @classmethod - def _check_matching_time(cls, ref, hist): + def _check_matching_times(cls, ref, hist): """Raise an error ref and hist times don't match.""" if all(ref.time.values == hist.time.values) is False: - raise ValueError("`ref` and `hist` should have the same time arrays.") + raise ValueError( + "`ref` and `hist` have distinct time arrays," + f" this is not supported for {cls.__name__} adjustment." + ) + + @classmethod + def _check_matching_time_sizes(cls, *inputs): + """Raise an error if inputs have different size for the time arrays.""" + ref_size = inputs[0].time.size + for inp in inputs[1:]: + if inp.time.size != ref_size: + raise ValueError( + "Inputs have different size for the time array," + f" this is not supported for {cls.__name__} adjustment." + ) @classmethod def _train(cls, ref, hist, **kwargs): @@ -266,8 +281,9 @@ def train(cls, ref: DataArray, hist: DataArray, **kwargs) -> TrainAdjust: else: train_units = "" - if cls._allow_diff_training_times is False: - cls._check_matching_time(ref, hist) + # For some methods, `ref` and `hist` must share the same time array + if not cls._allow_diff_training_times: + cls._check_matching_times(ref, hist) ds, params = cls._train(ref, hist, **kwargs) obj = cls( @@ -350,8 +366,6 @@ class Adjust(BaseAdjustment): and returning the scen dataset/array. """ - _replace_sim_time = True - @classmethod def adjust( cls, @@ -382,16 +396,16 @@ def adjust( sim = hist.copy() sim.attrs["_is_hist"] = True - # This below implies that ref.time and sim.time have the same size - # Since `ref,hist, sim` are in the same `map_groups` call, they must have - # the same time - if cls._replace_sim_time: + if not cls._allow_diff_time_sizes: + cls._check_matching_time_sizes(ref, hist, sim) + # If `ref,hist, sim` are in the same `map_groups` call, they must have the same time + # As long as `sim` has the same time dimension, we can temporarily replace its time + # with the reference time sim_time = sim.time sim["time"] = ref["time"] kwargs = parse_group(cls._adjust, kwargs) skip_checks = kwargs.pop("skip_input_checks", False) - if not skip_checks: if "group" in kwargs: cls._check_inputs(ref, hist, sim, group=kwargs["group"]) @@ -404,7 +418,7 @@ def adjust( out = out.rename("scen").to_dataset() scen = out.scen - if cls._replace_sim_time: + if not cls._allow_diff_time_sizes: scen["time"] = sim_time params = ", ".join([f"{k}={repr(v)}" for k, v in kwargs.items()]) @@ -1414,6 +1428,8 @@ class OTC(Adjust): :cite:cts:`sdba-robin_2019,sdba-robin_2021` """ + _allow_diff_times = False + @classmethod def _adjust( cls, @@ -1569,6 +1585,9 @@ class dOTC(Adjust): :cite:cts:`sdba-robin_2019,sdba-robin_2021` """ + _allow_diff_training_times = False + _allow_diff_time_sizes = False + @classmethod def _adjust( cls, @@ -1760,6 +1779,7 @@ class MBCn(TrainAdjust): """ _allow_diff_training_times = False + _allow_diff_time_sizes = False @classmethod def _train( From ac12ab54abfecf5b75057d3e3ad3ede07740674b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 13:38:55 -0500 Subject: [PATCH 08/27] update CHANGELOG --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 11e080fcb..fe1b8c653 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,7 +20,7 @@ Bug fixes Internal changes ^^^^^^^^^^^^^^^^ * Changed french translations with word "pluvieux" to "avec précipitations". (:issue:`1960`, :pull:`1994`). -* Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). (:issue:`1903`, :pull:`1995`) +* Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). Methods that combine `ref,hist,sim` in a same `map_groups` also require the time arrays to be equal in size. (:issue:`1903`, :pull:`1995`) * `streamflow` entry replaced with `q` in ``variables.yml``. (:issue:`1912`, :pull:`1996`) * In order to address 403 (forbidden) request errors when retrieving data from GitHub via ReadTheDocs, the ``nimbus`` class has been modified to use an overloaded `fetch` method that appends a User-Agent header to the request. (:pull:`2001`). * Addressed a very rare race condition that can happen if `pytest` is tearing down the test environment when running across multiple workers. (:pull:`1863`). From 4c873feb1622852c797cb0782e88b038354fadf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 13:40:07 -0500 Subject: [PATCH 09/27] typo --- xclim/sdba/adjustment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 0b4c8de54..efdce673b 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -1428,7 +1428,7 @@ class OTC(Adjust): :cite:cts:`sdba-robin_2019,sdba-robin_2021` """ - _allow_diff_times = False + _allow_diff_time_sizes = False @classmethod def _adjust( From 1a11cb65703eb14220587ca1f4a9950a4386e4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 13:44:41 -0500 Subject: [PATCH 10/27] more checks in many classes --- xclim/sdba/adjustment.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index efdce673b..e083b4941 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -477,6 +477,7 @@ class EmpiricalQuantileMapping(TrainAdjust): :cite:cts:`sdba-deque_frequency_2007` """ + _allow_diff_calendars = False _allow_diff_training_times = False @classmethod @@ -577,6 +578,7 @@ class DetrendedQuantileMapping(TrainAdjust): """ + _allow_diff_calendars = False _allow_diff_training_times = False @classmethod @@ -956,6 +958,7 @@ class Scaling(TrainAdjust): The interpolation method to use then interpolating the adjustment factors. Defaults to "nearest". """ + _allow_diff_calendars = False _allow_diff_training_times = False @classmethod @@ -1428,6 +1431,7 @@ class OTC(Adjust): :cite:cts:`sdba-robin_2019,sdba-robin_2021` """ + _allow_diff_calendars = False _allow_diff_time_sizes = False @classmethod @@ -1585,7 +1589,7 @@ class dOTC(Adjust): :cite:cts:`sdba-robin_2019,sdba-robin_2021` """ - _allow_diff_training_times = False + _allow_diff_calendars = False _allow_diff_time_sizes = False @classmethod @@ -1778,6 +1782,7 @@ class MBCn(TrainAdjust): Only "time" and "time.dayofyear" (with a suitable window) are implemented as possible values for `group`. """ + _allow_diff_calendars = False _allow_diff_training_times = False _allow_diff_time_sizes = False From e1aca56b061338367c585608983030dd289e9a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 13:46:29 -0500 Subject: [PATCH 11/27] LOCI check calendars --- xclim/sdba/adjustment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index e083b4941..879f61429 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -906,6 +906,7 @@ class LOCI(TrainAdjust): :cite:cts:`sdba-schmidli_downscaling_2006` """ + _allow_diff_calendars = False _allow_diff_training_times = False @classmethod From 57ccf190deca8c2215c0089c593cfccf40e7219c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 14:11:20 -0500 Subject: [PATCH 12/27] forgot to refactor in tests --- tests/test_sdba/test_adjustment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index a8775b239..393726929 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -74,7 +74,7 @@ def test_matching_time(self, series, random): with pytest.raises( ValueError, match="`ref` and `hist` should have the same time arrays." ): - BaseAdjustment._check_matching_time(ref=da, hist=da2) + BaseAdjustment._check_matching_times(ref=da, hist=da2) class TestLoci: From e4a1a40bb0bc78dc8ba2743e6fbc25cc365a05fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 14:14:32 -0500 Subject: [PATCH 13/27] more refactoring to pass on and add new test --- tests/test_sdba/test_adjustment.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index 393726929..0329baae4 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -66,16 +66,30 @@ def test_harmonize_units_multivariate(self, series, random, use_dask): ds, ds2 = unstack_variables(da), unstack_variables(da2) assert (ds.tas.units == ds2.tas.units) & (ds.pr.units == ds2.pr.units) - def test_matching_time(self, series, random): + def test_matching_times(self, series, random): n = 10 u = random.random(n) da = series(u, "tas", start="2000-01-01") da2 = series(u, "tas", start="2010-01-01") with pytest.raises( - ValueError, match="`ref` and `hist` should have the same time arrays." + ValueError, + match="`ref` and `hist` have distinct time arrays, this is not supported for BaseAdjustment adjustment.", ): BaseAdjustment._check_matching_times(ref=da, hist=da2) + def test_matching_time_sizes(self, series, random): + n = 10 + u = random.random(n) + da = series(u, "tas", start="2000-01-01") + n = 20 + u = random.random(n) + da2 = series(u, "tas", start="2010-01-01") + with pytest.raises( + ValueError, + match="Inputs have different size for the time array, this is not supported for BaseAdjustment adjustment.", + ): + BaseAdjustment._check_matching_time_sizes(ref=da, hist=da2) + class TestLoci: @pytest.mark.parametrize("group,dec", (["time", 2], ["time.month", 1])) From 60a920b2f5d7482bd495e4d69bff205f5e2a5cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 14:15:44 -0500 Subject: [PATCH 14/27] second test has a more general signature --- tests/test_sdba/test_adjustment.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index 0329baae4..b148f107b 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -81,14 +81,12 @@ def test_matching_time_sizes(self, series, random): n = 10 u = random.random(n) da = series(u, "tas", start="2000-01-01") - n = 20 - u = random.random(n) - da2 = series(u, "tas", start="2010-01-01") + da2 = da.isel(time=slice(0, 5)).copy() with pytest.raises( ValueError, match="Inputs have different size for the time array, this is not supported for BaseAdjustment adjustment.", ): - BaseAdjustment._check_matching_time_sizes(ref=da, hist=da2) + BaseAdjustment._check_matching_time_sizes(da, da2) class TestLoci: From e9ea021c5e94e381f053c887de7870e9535d8921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Wed, 27 Nov 2024 15:52:23 -0500 Subject: [PATCH 15/27] fix conda (from :pull:1988) --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1faca5919..53167ebfe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,6 +48,7 @@ jobs: api.electricitymap.org:443 api.github.com:443 api.green-coding.io:443 + conda.anaconda.org:443 files.pythonhosted.org:443 github.com:443 ip-api.com:80 From c8caced4097a5c43301bb98c85443eee5e13f616 Mon Sep 17 00:00:00 2001 From: Zeitsperre <10819524+Zeitsperre@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:47:39 -0500 Subject: [PATCH 16/27] remove defaults, remove conda.anaconda.com override from lint --- .github/workflows/main.yml | 1 - environment.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53167ebfe..1faca5919 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,7 +48,6 @@ jobs: api.electricitymap.org:443 api.github.com:443 api.green-coding.io:443 - conda.anaconda.org:443 files.pythonhosted.org:443 github.com:443 ip-api.com:80 diff --git a/environment.yml b/environment.yml index 88f13bce9..dbe12b892 100644 --- a/environment.yml +++ b/environment.yml @@ -1,7 +1,6 @@ name: xclim channels: - conda-forge - - defaults dependencies: - python >=3.10,<3.14 - boltons >=20.1 From 7846418db3c19a88d62f906ee49611c474c69ddb Mon Sep 17 00:00:00 2001 From: Trevor James Smith <10819524+Zeitsperre@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:51:36 -0500 Subject: [PATCH 17/27] allow connections to conda.anaconda.org --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1faca5919..b2f795152 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -348,6 +348,7 @@ jobs: api.electricitymap.org:443 api.github.com:443 api.green-coding.io:443 + conda.anaconda.org:443 coveralls.io:443 files.pythonhosted.org:443 github.com:443 From c7241a7b6df148fcdd955bc16ea95238f532a6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 10:14:37 -0500 Subject: [PATCH 18/27] use load_dataset with xr.tutorial --- docs/notebooks/customize.ipynb | 2 +- docs/notebooks/sdba-advanced.ipynb | 2 +- docs/notebooks/units.ipynb | 4 ++-- docs/notebooks/usage.ipynb | 2 +- tests/test_sdba/conftest.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/notebooks/customize.ipynb b/docs/notebooks/customize.ipynb index d9d8ab0ef..3d28e5f21 100644 --- a/docs/notebooks/customize.ipynb +++ b/docs/notebooks/customize.ipynb @@ -36,7 +36,7 @@ "outputs": [], "source": [ "tasmax = (\n", - " xr.tutorial.open_dataset(\"air_temperature\")\n", + " xr.tutorial.load_dataset(\"air_temperature\")\n", " .air.resample(time=\"D\")\n", " .max(keep_attrs=True)\n", ")\n", diff --git a/docs/notebooks/sdba-advanced.ipynb b/docs/notebooks/sdba-advanced.ipynb index 0e7b32e32..1acd134dc 100644 --- a/docs/notebooks/sdba-advanced.ipynb +++ b/docs/notebooks/sdba-advanced.ipynb @@ -69,7 +69,7 @@ "outputs": [], "source": [ "# Daily temperature data from xarray's tutorials\n", - "ds = xr.tutorial.open_dataset(\"air_temperature\").resample(time=\"D\").mean()\n", + "ds = xr.tutorial.load_dataset(\"air_temperature\").resample(time=\"D\").mean()\n", "tas = ds.isel(lat=0, lon=0).air\n", "\n", "# Compute the smoothed series\n", diff --git a/docs/notebooks/units.ipynb b/docs/notebooks/units.ipynb index 525d3f22d..b8c4072b8 100644 --- a/docs/notebooks/units.ipynb +++ b/docs/notebooks/units.ipynb @@ -48,7 +48,7 @@ "outputs": [], "source": [ "# See the Usage page for details on opening datasets, subsetting and resampling.\n", - "ds = xr.tutorial.open_dataset(\"air_temperature\")\n", + "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", "tas = (\n", " ds.air.sel(lat=40, lon=270, method=\"nearest\")\n", " .resample(time=\"D\")\n", @@ -193,7 +193,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds = xr.tutorial.open_dataset(\"air_temperature\")\n", + "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", "tas_6h = ds.air.sel(\n", " lat=40, lon=270, method=\"nearest\"\n", ") # no resampling, original data is 6-hourly\n", diff --git a/docs/notebooks/usage.ipynb b/docs/notebooks/usage.ipynb index 527b016a6..175b66016 100644 --- a/docs/notebooks/usage.ipynb +++ b/docs/notebooks/usage.ipynb @@ -139,7 +139,7 @@ "source": [ "# Show that data is not at a daily time frequency\n", "\n", - "ds6h = xr.tutorial.open_dataset(\"air_temperature\")\n", + "ds6h = xr.tutorial.load_dataset(\"air_temperature\")\n", "xr.infer_freq(ds6h.time)" ] }, diff --git a/tests/test_sdba/conftest.py b/tests/test_sdba/conftest.py index d09bc33f9..3732a2eca 100644 --- a/tests/test_sdba/conftest.py +++ b/tests/test_sdba/conftest.py @@ -114,7 +114,7 @@ def ref_hist_sim_tuto(socket_enabled): # noqa: F841 """ def _ref_hist_sim_tuto(sim_offset=3, delta=0.1, smth_win=3, trend=True): - ds = xr.tutorial.open_dataset("air_temperature") + ds = xr.tutorial.load_dataset("air_temperature") ref = ds.air.resample(time="D").mean(keep_attrs=True) hist = ref.rolling(time=smth_win, min_periods=1).mean(keep_attrs=True) + delta hist.attrs["units"] = ref.attrs["units"] From 68cbb8dead587dfd7afd055aaeaed1f354cf3750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 12:15:07 -0500 Subject: [PATCH 19/27] temp deactivate time_size checks for OTC/dOTC --- xclim/sdba/adjustment.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 879f61429..5cdb6fe4d 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -1433,7 +1433,8 @@ class OTC(Adjust): """ _allow_diff_calendars = False - _allow_diff_time_sizes = False + # TODO: uncomment after fixing OTC/dOTC, next PR + # _allow_diff_time_sizes = False @classmethod def _adjust( @@ -1591,7 +1592,8 @@ class dOTC(Adjust): """ _allow_diff_calendars = False - _allow_diff_time_sizes = False + # TODO: uncomment after fixing OTC/dOTC, next PR + # _allow_diff_time_sizes = False @classmethod def _adjust( From 6331679ad8d6ecdd624e278d21fea8cb71f2e28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 12:53:04 -0500 Subject: [PATCH 20/27] remove test_different_times for now --- tests/test_sdba/test_adjustment.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index b148f107b..82acd008e 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -1090,34 +1090,6 @@ def test_shape(self, random, series): sim = unstack_variables(sim) assert not np.isin(sim.x[sim.x.isnull()].time.values, scen.time.values).any() - # just check it runs - def test_different_times(self, tasmax_series, tasmin_series): - pytest.importorskip("ot") - # `sim` has a different time than `ref,hist` (but same size) - ref = xr.merge( - [ - tasmax_series(np.arange(730).astype(float), start="2000-01-01").chunk( - {"time": -1} - ), - tasmin_series(np.arange(730).astype(float), start="2000-01-01").chunk( - {"time": -1} - ), - ] - ) - hist = ref.copy() - sim = xr.merge( - [ - tasmax_series(np.arange(730).astype(float), start="2020-01-01").chunk( - {"time": -1} - ), - tasmin_series(np.arange(730).astype(float), start="2020-01-01").chunk( - {"time": -1} - ), - ] - ) - ref, hist, sim = (stack_variables(arr) for arr in [ref, hist, sim]) - dOTC.adjust(ref, hist, sim) - def test_raise_on_multiple_chunks(tas_series): ref = tas_series(np.arange(730).astype(float)).chunk({"time": 365}) From d385c2efa6513230574564820ab727f742f9d012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 13:22:42 -0500 Subject: [PATCH 21/27] change nan handling in dOTC --- tests/test_sdba/test_adjustment.py | 111 ----------------------------- xclim/sdba/_adjustment.py | 47 ++++++------ xclim/sdba/adjustment.py | 33 +++------ 3 files changed, 38 insertions(+), 153 deletions(-) diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py index b148f107b..efc024de2 100644 --- a/tests/test_sdba/test_adjustment.py +++ b/tests/test_sdba/test_adjustment.py @@ -893,53 +893,6 @@ def test_compare_sbck(self, random, series): scen_sbck = scen_sbck.to_numpy() assert np.allclose(scen, scen_sbck) - def test_shape(self, random, series): - pytest.importorskip("ot") - pytest.importorskip("SBCK", minversion="0.4.0") - ref_ns = 300 - hist_ns = 200 - ref_u = random.random(ref_ns) - hist_u = random.random(hist_ns) - - ref_xd = uniform(loc=1000, scale=100) - ref_yd = norm(loc=0, scale=100) - ref_zd = norm(loc=500, scale=100) - hist_xd = norm(loc=-500, scale=100) - hist_yd = uniform(loc=-1000, scale=100) - hist_zd = uniform(loc=-10, scale=100) - - ref_x = ref_xd.ppf(ref_u) - ref_y = ref_yd.ppf(ref_u) - ref_z = ref_zd.ppf(ref_u) - hist_x = hist_xd.ppf(hist_u) - hist_y = hist_yd.ppf(hist_u) - hist_z = hist_zd.ppf(hist_u) - - ref_na = 10 - hist_na = 15 - ref_idx = random.choice(range(ref_ns), size=ref_na, replace=False) - ref_x[ref_idx] = None - hist_idx = random.choice(range(hist_ns), size=hist_na, replace=False) - hist_x[hist_idx] = None - - ref_x = series(ref_x, "tas").rename("x") - ref_y = series(ref_y, "tas").rename("y") - ref_z = series(ref_z, "tas").rename("z") - ref = xr.merge([ref_x, ref_y, ref_z]) - ref = stack_variables(ref) - - hist_x = series(hist_x, "tas").rename("x") - hist_y = series(hist_y, "tas").rename("y") - hist_z = series(hist_z, "tas").rename("z") - hist = xr.merge([hist_x, hist_y, hist_z]) - hist = stack_variables(hist) - - scen = OTC.adjust(ref, hist) - - assert scen.shape == (3, hist_ns - hist_na) - hist = unstack_variables(hist) - assert not np.isin(hist.x[hist.x.isnull()].time.values, scen.time.values).any() - # TODO: Add tests for normalization methods class TestdOTC: @@ -1026,70 +979,6 @@ def test_compare_sbck(self, random, series, use_dask, cov_factor): scen_sbck = scen_sbck.to_numpy() assert np.allclose(scen, scen_sbck) - def test_shape(self, random, series): - pytest.importorskip("ot") - pytest.importorskip("SBCK", minversion="0.4.0") - ref_ns = 300 - hist_ns = 200 - sim_ns = 400 - ref_u = random.random(ref_ns) - hist_u = random.random(hist_ns) - sim_u = random.random(sim_ns) - - ref_xd = uniform(loc=1000, scale=100) - ref_yd = norm(loc=0, scale=100) - ref_zd = norm(loc=500, scale=100) - hist_xd = norm(loc=-500, scale=100) - hist_yd = uniform(loc=-1000, scale=100) - hist_zd = uniform(loc=-10, scale=100) - sim_xd = norm(loc=0, scale=100) - sim_yd = uniform(loc=0, scale=100) - sim_zd = uniform(loc=10, scale=100) - - ref_x = ref_xd.ppf(ref_u) - ref_y = ref_yd.ppf(ref_u) - ref_z = ref_zd.ppf(ref_u) - hist_x = hist_xd.ppf(hist_u) - hist_y = hist_yd.ppf(hist_u) - hist_z = hist_zd.ppf(hist_u) - sim_x = sim_xd.ppf(sim_u) - sim_y = sim_yd.ppf(sim_u) - sim_z = sim_zd.ppf(sim_u) - - ref_na = 10 - hist_na = 15 - sim_na = 20 - ref_idx = random.choice(range(ref_ns), size=ref_na, replace=False) - ref_x[ref_idx] = None - hist_idx = random.choice(range(hist_ns), size=hist_na, replace=False) - hist_x[hist_idx] = None - sim_idx = random.choice(range(sim_ns), size=sim_na, replace=False) - sim_x[sim_idx] = None - - ref_x = series(ref_x, "tas").rename("x") - ref_y = series(ref_y, "tas").rename("y") - ref_z = series(ref_z, "tas").rename("z") - ref = xr.merge([ref_x, ref_y, ref_z]) - ref = stack_variables(ref) - - hist_x = series(hist_x, "tas").rename("x") - hist_y = series(hist_y, "tas").rename("y") - hist_z = series(hist_z, "tas").rename("z") - hist = xr.merge([hist_x, hist_y, hist_z]) - hist = stack_variables(hist) - - sim_x = series(sim_x, "tas").rename("x") - sim_y = series(sim_y, "tas").rename("y") - sim_z = series(sim_z, "tas").rename("z") - sim = xr.merge([sim_x, sim_y, sim_z]) - sim = stack_variables(sim) - - scen = dOTC.adjust(ref, hist, sim) - - assert scen.shape == (3, sim_ns - sim_na) - sim = unstack_variables(sim) - assert not np.isin(sim.x[sim.x.isnull()].time.values, scen.time.values).any() - # just check it runs def test_different_times(self, tasmax_series, tasmin_series): pytest.importorskip("ot") diff --git a/xclim/sdba/_adjustment.py b/xclim/sdba/_adjustment.py index ed7b4e36c..0beb581fd 100644 --- a/xclim/sdba/_adjustment.py +++ b/xclim/sdba/_adjustment.py @@ -988,6 +988,12 @@ def _otc_adjust( ---------- :cite:cts:`sdba-robin_2021` """ + # nans are removed and put back in place at the end + X_og = X.copy() + mask = (~np.isnan(X)).all(axis=1) + X = X[mask] + Y = Y[(~np.isnan(Y)).all(axis=1)] + # Initialize parameters if bin_width is None: bin_width = u.bin_width_estimator([Y, X]) @@ -1042,7 +1048,11 @@ def _otc_adjust( if jitter_inside_bins: out += np.random.uniform(low=-bin_width / 2, high=bin_width / 2, size=out.shape) - return out + # reintroduce nans + Xadj = X_og + Xadj[mask] = out + Xadj[~mask] = np.nan + return Xadj @map_groups(scen=[Grouper.DIM]) @@ -1102,9 +1112,9 @@ def otc_adjust( ) ref_map = {d: f"ref_{d}" for d in dim} - ref = ref.rename(ref_map).stack(dim_ref=ref_map.values()).dropna(dim="dim_ref") + ref = ref.rename(ref_map).stack(dim_ref=ref_map.values()) - hist = hist.stack(dim_hist=dim).dropna(dim="dim_hist") + hist = hist.stack(dim_hist=dim) if isinstance(bin_width, dict): bin_width = { @@ -1134,12 +1144,7 @@ def otc_adjust( vectorize=True, ) - # Pad dim differences with NA to please map_blocks - ref = ref.unstack().rename({v: k for k, v in ref_map.items()}) scen = scen.unstack().rename("scen") - for d in dim: - full_d = xr.concat([ref[d], scen[d]], dim=d).drop_duplicates(d) - scen = scen.reindex({d: full_d}) return scen.to_dataset() @@ -1193,6 +1198,12 @@ def _dotc_adjust( ---------- :cite:cts:`sdba-robin_2021` """ + # nans are removed and put back in place at the end + X1_og = X1.copy() + mask = ~np.isnan(X1).any(axis=1) + X1 = X1[mask] + X0 = X0[~np.isnan(X0).any(axis=1)] + Y0 = Y0[~np.isnan(Y0).any(axis=1)] # Initialize parameters if isinstance(bin_width, dict): _bin_width = u.bin_width_estimator([Y0, X0, X1]) @@ -1259,7 +1270,7 @@ def _dotc_adjust( Y1[:, j] = Y0[:, j] + motion[:, j] # Map sim to the evolution of ref - Z1 = _otc_adjust( + out = _otc_adjust( X1, Y1, bin_width=bin_width, @@ -1268,6 +1279,10 @@ def _dotc_adjust( jitter_inside_bins=jitter_inside_bins, normalization=normalization, ) + # reintroduce nans + Z1 = X1_og + Z1[mask] = out + Z1[~mask] = np.nan return Z1 @@ -1339,14 +1354,12 @@ def dotc_adjust( # Drop data added by map_blocks and prepare for apply_ufunc hist_map = {d: f"hist_{d}" for d in dim} - hist = ( - hist.rename(hist_map).stack(dim_hist=hist_map.values()).dropna(dim="dim_hist") - ) + hist = hist.rename(hist_map).stack(dim_hist=hist_map.values()) ref_map = {d: f"ref_{d}" for d in dim} - ref = ref.rename(ref_map).stack(dim_ref=ref_map.values()).dropna(dim="dim_ref") + ref = ref.rename(ref_map).stack(dim_ref=ref_map.values()) - sim = sim.stack(dim_sim=dim).dropna(dim="dim_sim") + sim = sim.stack(dim_sim=dim) if kind is not None: kind = { @@ -1387,12 +1400,6 @@ def dotc_adjust( vectorize=True, ) - # Pad dim differences with NA to please map_blocks - hist = hist.unstack().rename({v: k for k, v in hist_map.items()}) - ref = ref.unstack().rename({v: k for k, v in ref_map.items()}) scen = scen.unstack().rename("scen") - for d in dim: - full_d = xr.concat([hist[d], ref[d], scen[d]], dim=d).drop_duplicates(d) - scen = scen.reindex({d: full_d}) return scen.to_dataset() diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 5cdb6fe4d..3d14afed8 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -401,6 +401,7 @@ def adjust( # If `ref,hist, sim` are in the same `map_groups` call, they must have the same time # As long as `sim` has the same time dimension, we can temporarily replace its time # with the reference time + print("here") sim_time = sim.time sim["time"] = ref["time"] @@ -1433,8 +1434,7 @@ class OTC(Adjust): """ _allow_diff_calendars = False - # TODO: uncomment after fixing OTC/dOTC, next PR - # _allow_diff_time_sizes = False + _allow_diff_time_sizes = False @classmethod def _adjust( @@ -1468,7 +1468,10 @@ def _adjust( if isinstance(adapt_freq_thresh, str): adapt_freq_thresh = {v: adapt_freq_thresh for v in hist[pts_dim].values} - if adapt_freq_thresh is not None: + adapt_freq_thresh = ( + {} if adapt_freq_thresh is None else deepcopy(adapt_freq_thresh) + ) + if adapt_freq_thresh != {}: _, units = cls._harmonize_units(sim) for var, thresh in adapt_freq_thresh.items(): adapt_freq_thresh[var] = str( @@ -1487,14 +1490,6 @@ def _adjust( pts_dim=pts_dim, ).scen - if adapt_freq_thresh is not None: - for var in adapt_freq_thresh.keys(): - adapt_freq_thresh[var] = adapt_freq_thresh[var] + " " + units[var] - - for d in scen.dims: - if d != pts_dim: - scen = scen.dropna(dim=d) - return scen @@ -1592,8 +1587,7 @@ class dOTC(Adjust): """ _allow_diff_calendars = False - # TODO: uncomment after fixing OTC/dOTC, next PR - # _allow_diff_time_sizes = False + _allow_diff_time_sizes = False @classmethod def _adjust( @@ -1635,7 +1629,10 @@ def _adjust( if isinstance(adapt_freq_thresh, str): adapt_freq_thresh = {v: adapt_freq_thresh for v in hist[pts_dim].values} - if adapt_freq_thresh is not None: + adapt_freq_thresh = ( + {} if adapt_freq_thresh is None else deepcopy(adapt_freq_thresh) + ) + if adapt_freq_thresh != {}: _, units = cls._harmonize_units(sim) for var, thresh in adapt_freq_thresh.items(): adapt_freq_thresh[var] = str( @@ -1656,14 +1653,6 @@ def _adjust( pts_dim=pts_dim, ).scen - if adapt_freq_thresh is not None: - for var in adapt_freq_thresh.keys(): - adapt_freq_thresh[var] = adapt_freq_thresh[var] + " " + units[var] - - for d in scen.dims: - if d != pts_dim: - scen = scen.dropna(dim=d, how="all") - return scen From 5278a0e0216823c8e66629155f63b5ad5d4ff6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 13:38:55 -0500 Subject: [PATCH 22/27] remove test print --- xclim/sdba/adjustment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 3d14afed8..7bcef8e5e 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -401,7 +401,6 @@ def adjust( # If `ref,hist, sim` are in the same `map_groups` call, they must have the same time # As long as `sim` has the same time dimension, we can temporarily replace its time # with the reference time - print("here") sim_time = sim.time sim["time"] = ref["time"] From ddba1436048a5788ed97ba96573fd2046a628782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 14:05:18 -0500 Subject: [PATCH 23/27] add fix nan handling description --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fe1b8c653..a3e0bc332 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,7 @@ Internal changes ^^^^^^^^^^^^^^^^ * Changed french translations with word "pluvieux" to "avec précipitations". (:issue:`1960`, :pull:`1994`). * Using different time for `ref` and `hist` is now explicitly forbidden in many bias adjustment methods (e.g. `EmpiricalQuantileMapping`). Methods that combine `ref,hist,sim` in a same `map_groups` also require the time arrays to be equal in size. (:issue:`1903`, :pull:`1995`) +* Nans in `OTC` and `dOTC` are only dropped and put back in place at the lowest level so that the size of time array never changes on xarray levels. (:pull:`1995`) * `streamflow` entry replaced with `q` in ``variables.yml``. (:issue:`1912`, :pull:`1996`) * In order to address 403 (forbidden) request errors when retrieving data from GitHub via ReadTheDocs, the ``nimbus`` class has been modified to use an overloaded `fetch` method that appends a User-Agent header to the request. (:pull:`2001`). * Addressed a very rare race condition that can happen if `pytest` is tearing down the test environment when running across multiple workers. (:pull:`1863`). From 880f98c050cafe6922c7ff3fda8e4cb7c9cc6ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= Date: Thu, 28 Nov 2024 14:20:46 -0500 Subject: [PATCH 24/27] refactor var name --- xclim/sdba/_adjustment.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xclim/sdba/_adjustment.py b/xclim/sdba/_adjustment.py index 0beb581fd..9d784a260 100644 --- a/xclim/sdba/_adjustment.py +++ b/xclim/sdba/_adjustment.py @@ -1049,10 +1049,10 @@ def _otc_adjust( out += np.random.uniform(low=-bin_width / 2, high=bin_width / 2, size=out.shape) # reintroduce nans - Xadj = X_og - Xadj[mask] = out - Xadj[~mask] = np.nan - return Xadj + Z = X_og + Z[mask] = out + Z[~mask] = np.nan + return Z @map_groups(scen=[Grouper.DIM]) From 066d3f350a9de38d1efced8c2ba421b1ec92be15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Dupuis?= <71575674+coxipi@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:17:59 -0500 Subject: [PATCH 25/27] add training with different times possibility --- xclim/sdba/adjustment.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 7bcef8e5e..15a55b648 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -284,7 +284,11 @@ def train(cls, ref: DataArray, hist: DataArray, **kwargs) -> TrainAdjust: # For some methods, `ref` and `hist` must share the same time array if not cls._allow_diff_training_times: cls._check_matching_times(ref, hist) - + # We may also use a different time period for `hist` but still require + # it has the same size as `ref`'s time. + elif not cls._allow_diff_time_sizes: + cls._check_matching_time_sizes(ref, hist) + hist["time"] = ref.time ds, params = cls._train(ref, hist, **kwargs) obj = cls( _trained=True, From 58f0adafbbf7e202bd81155b22387089aa851620 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:18:51 +0000 Subject: [PATCH 26/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xclim/sdba/adjustment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py index 15a55b648..2b2df7736 100644 --- a/xclim/sdba/adjustment.py +++ b/xclim/sdba/adjustment.py @@ -286,7 +286,7 @@ def train(cls, ref: DataArray, hist: DataArray, **kwargs) -> TrainAdjust: cls._check_matching_times(ref, hist) # We may also use a different time period for `hist` but still require # it has the same size as `ref`'s time. - elif not cls._allow_diff_time_sizes: + elif not cls._allow_diff_time_sizes: cls._check_matching_time_sizes(ref, hist) hist["time"] = ref.time ds, params = cls._train(ref, hist, **kwargs) From 2ede2885acd7c041acad264748ee5431e88e9657 Mon Sep 17 00:00:00 2001 From: Ouranos Helper Bot Date: Mon, 9 Dec 2024 19:45:24 +0000 Subject: [PATCH 27/27] =?UTF-8?q?Bump=20version:=200.53.3-dev.6=20?= =?UTF-8?q?=E2=86=92=200.53.3-dev.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- xclim/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index daf1cbfe8..d43a32e5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,7 +134,7 @@ target-version = [ ] [tool.bumpversion] -current_version = "0.53.3-dev.6" +current_version = "0.53.3-dev.7" commit = true commit_args = "--no-verify" tag = false diff --git a/xclim/__init__.py b/xclim/__init__.py index c4c1de29a..1db3b7a5b 100644 --- a/xclim/__init__.py +++ b/xclim/__init__.py @@ -13,7 +13,7 @@ __author__ = """Travis Logan""" __email__ = "logan.travis@ouranos.ca" -__version__ = "0.53.3-dev.6" +__version__ = "0.53.3-dev.7" with _resources.as_file(_resources.files("xclim.data")) as _module_data: