Skip to content

Commit

Permalink
Merge branch 'main' into deprecate-calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeitsperre committed Jun 11, 2024
2 parents 3fd6889 + 7ebb276 commit 1680be7
Show file tree
Hide file tree
Showing 5 changed files with 538 additions and 152 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ v0.50.0 (unreleased)
--------------------
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Éric Dupuis (:user:`coxipi`).

New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* New properties: Bivariate Spell Length (``xclim.sdba.properties.bivariate_spell_length``), generalized spell lengths with an argument for `window`, and specific spell lengths with `window` fixed to 1 (``xclim.sdba.propertiies.threshold_count``, ``xclim.sdba.propertiies.bivariate_threshold_count``). (:pull:`1758`).

Breaking changes
^^^^^^^^^^^^^^^^
* `pint` has been pinned below v0.24 until `xclim` can be updated to support the latest version. (:issue:`1771`, :pull:`1772`).
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ target-version = [
]

[tool.bumpversion]
current_version = "0.49.1-dev.2"
current_version = "0.49.1-dev.3"
commit = true
commit_args = "--no-verify"
tag = false
Expand Down
172 changes: 115 additions & 57 deletions tests/test_sdba/test_properties.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import annotations

import numpy as np
import pandas as pd
import pytest
import xarray as xr
from xarray import set_options

from xclim import sdba
from xclim.core.units import convert_units_to
Expand Down Expand Up @@ -107,80 +110,135 @@ def test_quantile(self, open_dataset):
)
assert out_season.long_name.startswith("Quantile 0.2")

# TODO: test theshold_count? it's the same a test_spell_length_distribution
def test_spell_length_distribution(self, open_dataset):
sim = (
ds = (
open_dataset("sdba/CanESM2_1950-2100.nc")
.sel(time=slice("1950", "1952"), location="Vancouver")
.pr
).load()
.load()
)

tmean = (
sdba.properties.spell_length_distribution(sim, op="<", group="time.month")
# test pr, with amount method
sim = ds.pr
kws = {"op": "<", "group": "time.month"}
outd = {
stat: sdba.properties.spell_length_distribution(da=sim, **kws, stat=stat)
.sel(month=1)
.values
for stat in ["mean", "max", "min"]
}
np.testing.assert_array_almost_equal(
[outd[k] for k in ["mean", "max", "min"]], [2.44127, 10, 1]
)

# test tasmax, with quantile method
simt = ds.tasmax
kws = {"thresh": 0.9, "op": ">=", "method": "quantile", "group": "time.month"}
outd = {
stat: sdba.properties.spell_length_distribution(
da=simt, **kws, stat=stat
).sel(month=6)
for stat in ["mean", "max", "min"]
}
np.testing.assert_array_almost_equal(
[outd[k].values for k in ["mean", "max", "min"]], [3.0, 6, 1]
)
tmax = (
sdba.properties.spell_length_distribution(
sim, op="<", group="time.month", stat="max"
)
.sel(month=1)
.values

# test varia
with pytest.raises(
ValueError,
match="percentile is not a valid method. Choose 'amount' or 'quantile'.",
):
sdba.properties.spell_length_distribution(simt, method="percentile")

assert (
outd["mean"].long_name
== "Average of spell length distribution when the variable is >= the quantile 0.9 for 1 consecutive day(s)."
)
tmin = (
sdba.properties.spell_length_distribution(
sim, op="<", group="time.month", stat="min"
)
.sel(month=1)
.values

def test_spell_length_distribution_mixed_stat(self, open_dataset):

time = pd.date_range("2000-01-01", periods=2 * 365, freq="D")
tas = xr.DataArray(
np.array([0] * 365 + [40] * 365),
dims=("time"),
coords={"time": time},
attrs={"units": "degC"},
)

np.testing.assert_array_almost_equal([tmean, tmax, tmin], [2.44127, 10, 1])
kws_sum = dict(
thresh="30 degC", op=">=", stat="sum", stat_resample="sum", group="time"
)
out_sum = sdba.properties.spell_length_distribution(tas, **kws_sum).values
kws_mixed = dict(
thresh="30 degC", op=">=", stat="mean", stat_resample="sum", group="time"
)
out_mixed = sdba.properties.spell_length_distribution(tas, **kws_mixed).values

simt = (
open_dataset("sdba/CanESM2_1950-2100.nc")
.sel(time=slice("1950", "1952"), location="Vancouver")
.tasmax
).load()
assert out_sum == 365
assert out_mixed == 182.5

tmean = sdba.properties.spell_length_distribution(
simt, op=">=", group="time.month", method="quantile", thresh=0.9
).sel(month=6)
tmax = (
sdba.properties.spell_length_distribution(
simt,
op=">=",
group="time.month",
stat="max",
method="quantile",
thresh=0.9,
@pytest.mark.parametrize(
"window,expected_amount,expected_quantile",
[
(1, [2.333333, 4, 1], [3, 6, 1]),
(3, [1.333333, 4, 0], [2, 6, 0]),
],
)
def test_bivariate_spell_length_distribution(
self, open_dataset, window, expected_amount, expected_quantile
):
ds = (
open_dataset("sdba/CanESM2_1950-2100.nc").sel(
time=slice("1950", "1952"), location="Vancouver"
)
.sel(month=6)
).load()
tx = ds.tasmax
with set_options(keep_attrs=True):
tn = tx - 5

# test with amount method
kws = {
"thresh1": "0 degC",
"thresh2": "0 degC",
"op1": ">",
"op2": "<=",
"group": "time.month",
"window": window,
}
outd = {
stat: sdba.properties.bivariate_spell_length_distribution(
da1=tx, da2=tn, **kws, stat=stat
)
.sel(month=1)
.values
)
tmin = (
sdba.properties.spell_length_distribution(
simt,
op=">=",
group="time.month",
stat="min",
method="quantile",
thresh=0.9,
for stat in ["mean", "max", "min"]
}
np.testing.assert_array_almost_equal(
[outd[k] for k in ["mean", "max", "min"]], expected_amount
)

# test with quantile method
kws = {
"thresh1": 0.9,
"thresh2": 0.9,
"op1": ">",
"op2": ">",
"method1": "quantile",
"method2": "quantile",
"group": "time.month",
"window": window,
}
outd = {
stat: sdba.properties.bivariate_spell_length_distribution(
da1=tx, da2=tn, **kws, stat=stat
)
.sel(month=6)
.values
)

np.testing.assert_array_almost_equal([tmean.values, tmax, tmin], [3.0, 6, 1])

with pytest.raises(
ValueError,
match="percentile is not a valid method. Choose 'amount' or 'quantile'.",
):
sdba.properties.spell_length_distribution(simt, method="percentile")

assert (
tmean.long_name
== "Average of spell length distribution when the variable is >= the quantile 0.9."
for stat in ["mean", "max", "min"]
}
np.testing.assert_array_almost_equal(
[outd[k] for k in ["mean", "max", "min"]], expected_quantile
)

def test_acf(self, open_dataset):
Expand Down
2 changes: 1 addition & 1 deletion xclim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

__author__ = """Travis Logan"""
__email__ = "logan.travis@ouranos.ca"
__version__ = "0.49.1-dev.2"
__version__ = "0.49.1-dev.3"


with _resources.as_file(_resources.files("xclim.data")) as _module_data:
Expand Down
Loading

0 comments on commit 1680be7

Please sign in to comment.