From bbe70c68be9399367ac1eb60234eb56f8c493d1f Mon Sep 17 00:00:00 2001 From: RondeauG Date: Thu, 21 Mar 2024 13:59:00 -0400 Subject: [PATCH 1/3] test conversions --- tests/test_data_conversions.py | 61 +++++++++++++++++++++++++++++ xscen/xclim_modules/conversions.py | 18 ++++++--- xscen/xclim_modules/conversions.yml | 2 +- 3 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 tests/test_data_conversions.py diff --git a/tests/test_data_conversions.py b/tests/test_data_conversions.py new file mode 100644 index 00000000..1de15b39 --- /dev/null +++ b/tests/test_data_conversions.py @@ -0,0 +1,61 @@ +import numpy as np +from xclim.testing.helpers import test_timeseries as timeseries + +import xscen.xclim_modules.conversions as conv + + +def test_precipitation(): + prsn = timeseries(np.ones(3), variable="prsn", start="2001-01-01", freq="D") + prlp = timeseries( + np.ones(3) * 10, variable="pr", start="2001-01-01", freq="D", units="mm d-1" + ) + prlp.attrs["standard_name"] = "liquid_precipitation_flux" + + pr = conv.precipitation(prsn, prlp) + assert pr.attrs["units"] == prsn.attrs["units"] + np.testing.assert_array_equal(pr, prsn + prlp / 86400) + + +def test_tasmin_from_dtr(): + dtr = timeseries( + np.ones(3) * 10, variable="tas", start="2001-01-01", freq="D", units="C" + ) + dtr.attrs["standard_name"] = "daily_temperature_range" + tasmax = timeseries( + np.ones(3) * 20, variable="tasmax", start="2001-01-01", freq="D" + ) + + tasmin = conv.tasmin_from_dtr(dtr, tasmax) + assert tasmin.attrs["units"] == tasmax.attrs["units"] + np.testing.assert_array_equal( + tasmin, tasmax - dtr + ) # DTR in Celsius should not matter in the result, for a tasmax in Kelvin + + +def test_tasmax_from_dtr(): + dtr = timeseries( + np.ones(3) * 10, variable="tas", start="2001-01-01", freq="D", units="C" + ) + dtr.attrs["standard_name"] = "daily_temperature_range" + tasmin = timeseries( + np.ones(3) * 10, variable="tasmin", start="2001-01-01", freq="D" + ) + + tasmax = conv.tasmax_from_dtr(dtr, tasmin) + assert tasmax.attrs["units"] == tasmin.attrs["units"] + np.testing.assert_array_equal( + tasmax, tasmin + dtr + ) # DTR in Celsius should not matter in the result, for a tasmin in Kelvin + + +def test_dtr(): + tasmax = timeseries( + np.ones(3) * 20, variable="tasmax", start="2001-01-01", freq="D", units="C" + ) + tasmin = timeseries( + np.ones(3) * 10, variable="tasmin", start="2001-01-01", freq="D" + ) + + dtr = conv.dtr_from_minmax(tasmin, tasmax) + assert dtr.attrs["units"] == "K" + np.testing.assert_array_equal(dtr, (tasmax + 273.15) - tasmin) diff --git a/xscen/xclim_modules/conversions.py b/xscen/xclim_modules/conversions.py index 48ad4b98..72ab7626 100644 --- a/xscen/xclim_modules/conversions.py +++ b/xscen/xclim_modules/conversions.py @@ -24,7 +24,7 @@ def precipitation(prsn: xr.DataArray, prlp: xr.DataArray) -> xr.DataArray: xr.DataArray, [same as prsn] Surface precipitation flux (all phases) """ - prlp = convert_units_to(prlp, prsn) + prlp = convert_units_to(prlp, prsn, context="hydro") pr = prsn + prlp pr.attrs["units"] = prsn.attrs["units"] return pr @@ -48,9 +48,12 @@ def tasmin_from_dtr(dtr: xr.DataArray, tasmax: xr.DataArray) -> xr.DataArray: xr.DataArray, [same as tasmax] Daily minimum temperature """ - dtr = convert_units_to(dtr, tasmax) + out_units = tasmax.units + # To prevent strange behaviors that could arise from changing DTR units, we change the units of tasmax to match DTR + tasmax = convert_units_to(tasmax, dtr) tasmin = tasmax - dtr - tasmin.attrs["units"] = tasmax.units + tasmin.attrs["units"] = dtr.units + tasmin = convert_units_to(tasmin, out_units) return tasmin @@ -72,14 +75,17 @@ def tasmax_from_dtr(dtr: xr.DataArray, tasmin: xr.DataArray) -> xr.DataArray: xr.DataArray, [same as tasmin] Daily maximum temperature """ - dtr = convert_units_to(dtr, tasmin) + out_units = tasmin.attrs["units"] + # To prevent strange behaviors that could arise from changing DTR units, we change the units of tasmin to match DTR + tasmin = convert_units_to(tasmin, dtr) tasmax = tasmin + dtr - tasmax.attrs["units"] = tasmin.units + tasmax.attrs["units"] = dtr.attrs["units"] + tasmax = convert_units_to(tasmax, out_units) return tasmax @declare_units(tasmin="[temperature]", tasmax="[temperature]") -def dtr(tasmin: xr.DataArray, tasmax: xr.DataArray) -> xr.DataArray: +def dtr_from_minmax(tasmin: xr.DataArray, tasmax: xr.DataArray) -> xr.DataArray: """DTR computed from tasmin and tasmax. Dtr as tasmin subtracted from tasmax. diff --git a/xscen/xclim_modules/conversions.yml b/xscen/xclim_modules/conversions.yml index ae9cca50..dc0815c4 100644 --- a/xscen/xclim_modules/conversions.yml +++ b/xscen/xclim_modules/conversions.yml @@ -65,7 +65,7 @@ indicators: - var_name: evspsblpot dtr: src_freq: D - compute: dtr + compute: dtr_from_minmax cf_attrs: units: K description: Daily temperature range. From 954ce969f082256b17f0b16705a8c0996f0834a7 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Thu, 21 Mar 2024 14:01:03 -0400 Subject: [PATCH 2/3] renamed --- tests/{test_data_conversions.py => test_xclimmod_conversions.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_data_conversions.py => test_xclimmod_conversions.py} (100%) diff --git a/tests/test_data_conversions.py b/tests/test_xclimmod_conversions.py similarity index 100% rename from tests/test_data_conversions.py rename to tests/test_xclimmod_conversions.py From 5c6c8fea5b026652dbfc3f5ff3c56905fec74b6a Mon Sep 17 00:00:00 2001 From: RondeauG Date: Thu, 21 Mar 2024 14:12:10 -0400 Subject: [PATCH 3/3] upd changes --- CHANGES.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 284f6eb5..79728a71 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,7 @@ Breaking changes ^^^^^^^^^^^^^^^^ * Removed support for the old instances of the `region` argument in ``spatial_mean``, ``extract_dataset``, and ``subset``. (:pull:`367`). * Removed ``xscen.extract.clisops_subset``. (:pull:`367`). +* ``dtr`` (the function) was renamed to ``dtr_from_minmax`` to avoid confusion with the `dtr` variable. (:pull:`372`). Internal changes ^^^^^^^^^^^^^^^^ @@ -17,7 +18,7 @@ Internal changes * Addresses a handful of misconfigurations in the GitHub Workflows. * Added a few free `grep`-based hooks for finding unwanted artifacts in the code base. * Updated `ruff` to v0.2.0 and `black` to v24.2.0. -* Added more tests. (:pull:`366`, :pull:`367`). +* Added more tests. (:pull:`366`, :pull:`367`, :pull:`372`). * Refactored ``xs.spatial.subset`` into smaller functions. (:pull:`367`). * An `encoding` argument was added to ``xs.config.load_config``. (:pull:`370`). @@ -29,6 +30,7 @@ Bug fixes * Fixed bug for adding the preprocessing attributes inside the `adjust` function. (:pull:`366`). * Fixed a bug to accept `group = False` in `adjust` function. (:pull:`366`). * `creep_weights` now correctly handles the case where the grid is small, `n` is large, and `mode=wrap`. (:issue:`367`). +* Fixed a bug in ``tasmin_from_dtr`` and ``tasmax_from_dtr``, when `dtr` units differed from tasmin/max. (:pull:`372`). v0.8.3 (2024-02-28) -------------------