Skip to content

Commit

Permalink
return number of days, add indicator and translation, add tests
Browse files Browse the repository at this point in the history
Signed-off-by: Trevor James Smith <10819524+Zeitsperre@users.noreply.github.com>
  • Loading branch information
Zeitsperre committed Dec 20, 2024
1 parent 76123e1 commit f9e6c5a
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:
- submitted

env:
XCLIM_TESTDATA_BRANCH: v2024.8.23
XCLIM_TESTDATA_BRANCH: add-snw-prsn

concurrency:
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch except on main.
Expand Down
12 changes: 12 additions & 0 deletions src/xclim/data/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,18 @@
"title": "Jours avec neige",
"abstract": "Nombre de jours où la neige est entre une borne inférieure et supérieure."
},
"HOLIDAY_SNOW_DAYS": {
"long_name": "Nombre de jours de neige durant les jours fériés",
"description": "Nombre de jours de neige durant les jours fériés.",
"title": "Jours de neige durant les jours fériés",
"abstract": "Nombre de jours de neige durant les jours fériés."
},
"HOLIDAY_SNOW_AND_SNOWFALL_DAYS": {
"long_name": "Nombre de jours de neige et de jours de chute de neige durant les jours fériés",
"description": "Nombre de jours de neige et de jours de chute de neige durant les jours fériés.",
"title": "Jours de neige et de chute de neige durant les jours fériés",
"abstract": "Nombre de jours de neige et de jours de chute de neige durant les jours fériés."
},
"SND_SEASON_LENGTH": {
"long_name": "Durée de couvert de neige",
"description": "La saison débute lorsque l'épaisseur de neige est au-dessus de {thresh} durant {window} jours et se termine lorsqu'elle redescend sous {thresh} durant {window} jours.",
Expand Down
25 changes: 25 additions & 0 deletions src/xclim/indicators/land/_snow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

__all__ = [
"blowing_snow",
"holiday_snow_and_snowfall_days",
"holiday_snow_days",
"snd_days_above",
"snd_max_doy",
"snd_season_end",
Expand Down Expand Up @@ -254,3 +256,26 @@ class SnowWithIndexing(ResamplingIndicatorWithIndexing):
abstract="Number of days when the snow amount is greater than or equal to a given threshold.",
compute=xci.snw_days_above,
)

holiday_snow_days = Snow(
title="Christmas snow days",
identifier="holiday_snow_days",
units="1",
long_name="Number of holiday days with snow",
description="The total number of days where snow on the ground was greater than or equal to {snd_thresh} "
"occurring on {date_start} and ending on {date_end}.",
abstract="The total number of days where there is a significant amount of snow on the ground on December 25th.",
compute=xci.holiday_snow_days,
)

holiday_snow_and_snowfall_days = Snow(
title="Perfect Christmas snow days",
identifier="holiday_snow_and_snowfall_days",
units="1",
long_name="Number of holiday days with snow and snowfall",
description="The total number of days where snow on the ground was greater than or equal to {snd_thresh} "
"and snowfall was greater than or equal to {prsn_thresh} occurring on {date_start} and ending on {date_end}.",
abstract="The total number of days where there is a significant amount of snow on the ground "
"and a measurable snowfall occurring on December 25th.",
compute=xci.holiday_snow_and_snowfall_days,
)
32 changes: 16 additions & 16 deletions src/xclim/indices/_threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -3680,8 +3680,8 @@ def holiday_snow_days(
----------
https://www.canada.ca/en/environment-climate-change/services/weather-general-tools-resources/historical-christmas-snowfall-data.html
"""
snow_depth = convert_units_to(snd, "mm", context="hydro")
snow_depth_thresh = convert_units_to(snd_thresh, "mm", context="hydro")
snow_depth = convert_units_to(snd, "m")
snow_depth_thresh = convert_units_to(snd_thresh, "m")
snow_depth_constrained = select_time(
snow_depth,
drop=True,
Expand All @@ -3691,7 +3691,7 @@ def holiday_snow_days(
xmas_days = (
(snow_depth_constrained >= snow_depth_thresh)
.resample(time=freq)
.map(lambda x: x.all(dim="time"))
.map(lambda x: x.sum(dim="time"))
)

xmas_days = xmas_days.assign_attrs({"units": "1"})
Expand All @@ -3708,7 +3708,7 @@ def holiday_snow_and_snowfall_days(
snd: xarray.DataArray,
prsn: xarray.DataArray | None = None,
snd_thresh: Quantified = "20 mm",
prsn_thresh: Quantified = "1 mm",
prsn_thresh: Quantified = "1 cm",
date_start: str = "12-25",
date_end: str | None = None,
freq: str = "YS-JUL",
Expand Down Expand Up @@ -3739,15 +3739,23 @@ def holiday_snow_and_snowfall_days(
Returns
-------
xarray.DataArray, [bool]
Boolean array of years with Perfect Christmas Days.
xarray.DataArray, [int]
The total number of days with snow and snowfall during the holiday.
References
----------
https://www.canada.ca/en/environment-climate-change/services/weather-general-tools-resources/historical-christmas-snowfall-data.html
"""
snow_depth = convert_units_to(snd, "m")
snow_depth_thresh = convert_units_to(snd_thresh, "m")
snow_depth_constrained = select_time(
snow_depth,
drop=True,
date_bounds=(date_start, date_start if date_end is None else date_end),
)

snowfall_rate = rate2amount(
convert_units_to(prsn, "mm/d", context="hydro"), out_units="mm"
convert_units_to(prsn, "mm day-1", context="hydro"), out_units="mm"
)
snowfall_thresh = convert_units_to(prsn_thresh, "mm", context="hydro")
snowfall_constrained = select_time(
Expand All @@ -3756,21 +3764,13 @@ def holiday_snow_and_snowfall_days(
date_bounds=(date_start, date_start if date_end is None else date_end),
)

snow_depth = convert_units_to(snd, "mm", context="hydro")
snow_depth_thresh = convert_units_to(snd_thresh, "mm", context="hydro")
snow_depth_constrained = select_time(
snow_depth,
drop=True,
date_bounds=(date_start, date_start if date_end is None else date_end),
)

perfect_xmas_days = (
(
(snow_depth_constrained >= snow_depth_thresh)
& (snowfall_constrained >= snowfall_thresh)
)
.resample(time=freq)
.map(lambda x: x.all(dim="time"))
.map(lambda x: x.sum(dim="time"))
)

perfect_xmas_days = perfect_xmas_days.assign_attrs({"units": "1"})
Expand Down
58 changes: 58 additions & 0 deletions tests/test_indices.py
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,64 @@ def test_1d(
np.testing.assert_allclose(hwml.values, expected)


class TestHolidayIndices:

def test_xmas_days_simple(self, snd_series):
# 5ish years of data
snd = snd_series(np.zeros(365 * 5), units="cm")

# add snow on ground on December 25 for first 3 years
snd.loc["2000-12-25"] = 2
snd.loc["2001-12-25"] = 1.5 # not enough
snd.loc["2002-12-25"] = 2
snd.loc["2003-12-25"] = 0 # no snow
snd.loc["2004-12-25"] = 6

out = xci.holiday_snow_days(snd)
np.testing.assert_array_equal(out, [1, 0, 1, 0, 1])

def test_xmas_days_range(self, snd_series):
# 5ish years of data
snd = snd_series(np.zeros(365 * 5), units="cm")

# add snow on ground on December 25 for first 3 years
snd.loc["2000-12-25"] = 2
snd.loc["2001-12-25"] = 1.5 # not enough
snd.loc["2002-12-24"] = 10 # a réveillon miracle
snd.loc["2002-12-25"] = 2
snd.loc["2003-12-25"] = 0 # no snow
snd.loc["2004-12-25"] = 6

out = xci.holiday_snow_days(snd, date_start="12-24", date_end="12-25")
np.testing.assert_array_equal(out, [1, 0, 2, 0, 1])

def test_perfect_xmas_days_simple(self, snd_series, prsn_series):
# 5ish years of data
a = np.zeros(365 * 5)
snd = snd_series(a, units="mm")
prsn = prsn_series(a.copy(), units="cm day-1")

# add snow on ground on December 25
snd.loc["2000-12-25"] = 20
snd.loc["2001-12-25"] = 15 # not enough
snd.loc["2001-12-26"] = 30 # too bad it's Boxing Day
snd.loc["2002-12-25"] = 20
snd.loc["2003-12-25"] = 0 # no snow
snd.loc["2004-12-25"] = 60

# add snowfall on December 25
prsn.loc["2000-12-25"] = 5
prsn.loc["2001-12-25"] = 2
prsn.loc["2001-12-26"] = 30 # too bad it's Boxing Day
prsn.loc["2002-12-25"] = 0.5 # not quite enough
prsn.loc["2003-12-25"] = 0 # no snow
prsn.loc["2004-12-25"] = 10
prsn = convert_units_to(prsn, "kg m-2 s-1", context="hydro")

out = xci.holiday_snow_and_snowfall_days(snd, prsn)
np.testing.assert_array_equal(out, [1, 0, 0, 0, 1])


class TestHotSpellFrequency:
@pytest.mark.parametrize(
"thresh,window,op,expected",
Expand Down

0 comments on commit f9e6c5a

Please sign in to comment.