Skip to content

Commit

Permalink
Add heatwave total (#293)
Browse files Browse the repository at this point in the history
* Added heat_wave_total_length

* Added tests and fix small problems in indice

* Updated History.rst

* Simplification of the function call

* blacken and reduce travis CI verbosity

* Updated History.rst
  • Loading branch information
aulemahal authored and Zeitsperre committed Nov 18, 2019
1 parent 12abe92 commit 4884f1d
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
hooks:
- id: black
language_version: python3
args: ['--target-version=py35']
args: ["--target-version", "py35"]
- repo: https://github.com/pycqa/flake8
rev: 3.7.9
hooks:
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ before_install:
install:
- pip install -U tox-travis

script: tox -vv -e $TOXENV
script: tox -e $TOXENV

before_deploy:
- echo "$TRAVIS_TAG" "$TRAVIS_COMMIT"
Expand Down
2 changes: 2 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ History
* Added a distance function computing the geodesic distance to a point.
* Added a `tolerance` argument to `subset_gridpoint` raising an error if distance to closest point is larger than tolerance.
* Created land module for standardized access to streamflow indices.
* Enhancement to utils.Indicator to have more dynamic attributes using callables.
* Added indice `heat_wave_total_length`.

0.11.x-beta (2019-10-17)
------------------------
Expand Down
11 changes: 6 additions & 5 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ current_version = 0.12.0
commit = False
tag = True
parse = (?P<major>\d+)\.(?P<minor>\d+).(?P<patch>\d+)(\-(?P<release>[a-z]+))?
serialize =
serialize =
{major}.{minor}.{patch}-{release}
{major}.{minor}.{patch}

[bumpversion:part:release]
optional_value = gamma
values =
values =
beta
gamma

Expand All @@ -22,14 +22,14 @@ search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"

[flake8]
exclude =
exclude =
.git,
docs,
build,
.eggs,
max-line-length = 88
max-complexity = 12
ignore =
ignore =
C901
E203
E231
Expand All @@ -46,5 +46,6 @@ test = pytest
[tool:pytest]
collect_ignore = ["setup.py"]
addopts = --verbose
filterwarnings =
filterwarnings =
ignore::UserWarning

29 changes: 29 additions & 0 deletions tests/test_indices.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,35 @@ def test_1d(self, tasmax_series, tasmin_series):
np.testing.assert_allclose(hwml.values, 0)


class TestHeatWaveTotalLength:
def test_1d(self, tasmax_series, tasmin_series):
tn = tasmin_series(np.asarray([20, 23, 23, 23, 23, 22, 23, 23, 23, 23]) + K2C)
tx = tasmax_series(np.asarray([29, 31, 31, 31, 29, 31, 31, 31, 31, 31]) + K2C)

# some hw
hwml = xci.heat_wave_total_length(
tn, tx, thresh_tasmin="22 C", thresh_tasmax="30 C"
)
np.testing.assert_allclose(hwml.values, 7)

# one long hw
hwml = xci.heat_wave_total_length(
tn, tx, thresh_tasmin="10 C", thresh_tasmax="10 C"
)
np.testing.assert_allclose(hwml.values, 10)

# no hw
hwml = xci.heat_wave_total_length(
tn, tx, thresh_tasmin="40 C", thresh_tasmax="40 C"
)
np.testing.assert_allclose(hwml.values, 0)

hwml = xci.heat_wave_total_length(
tn, tx, thresh_tasmin="22 C", thresh_tasmax="30 C", window=5
)
np.testing.assert_allclose(hwml.values, 0)


class TestTnDaysBelow:
def test_simple(self, tasmin_series):
a = np.zeros(365)
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ deps =
-e git://github.com/psf/black.git@master#egg=black
commands =
flake8 xclim tests
black --check --target-version=py35 xclim tests
black --check --target-version py35 xclim tests

[testenv:docs]
deps =
Expand Down
17 changes: 17 additions & 0 deletions xclim/atmos/_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,23 @@ def compute(*args, **kwds):
compute=indices.heat_wave_max_length,
)

heat_wave_total_length = TasminTasmax(
identifier="heat_wave_total_length",
units="days",
standard_name="spell_length_of_days_with_air_temperature_above_threshold",
long_name="Total length of heat wave events (Tmin > {thresh_tasmin}"
"and Tmax > {thresh_tasmax} for >= {window} days)",
description="{freq} total length of heat wave events occuring in a given period."
"An event occurs when the minimum and maximum daily "
"temperature both exceeds specific thresholds "
"(Tmin > {thresh_tasmin} and Tmax > {thresh_tasmax}) over "
"a minimum number of days ({window}).",
cell_methods="",
keywords="health,",
compute=indices.heat_wave_total_length,
)


heat_wave_index = Tasmax(
identifier="heat_wave_index",
units="days",
Expand Down
56 changes: 56 additions & 0 deletions xclim/indices/_multivariate.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"fraction_over_precip_thresh",
"heat_wave_frequency",
"heat_wave_max_length",
"heat_wave_total_length",
"liquid_precip_ratio",
"precip_accumulation",
"rain_on_frozen_ground_days",
Expand Down Expand Up @@ -479,6 +480,61 @@ def heat_wave_max_length(
return max_l.where(max_l >= window, 0)


@declare_units(
"days",
tasmin="[temperature]",
tasmax="[temperature]",
thresh_tasmin="[temperature]",
thresh_tasmax="[temperature]",
)
def heat_wave_total_length(
tasmin: xr.DataArray,
tasmax: xr.DataArray,
thresh_tasmin: str = "22.0 degC",
thresh_tasmax: str = "30 degC",
window: int = 3,
freq: Optional[str] = None,
) -> xr.DataArray:
# Dev note : we should decide if it is deg K or C
r"""Heat wave total length
Total length of heat waves over a given period. A heat wave is defined as an event
where the minimum and maximum daily temperature both exceeds specific thresholds
over a minimum number of days. This the sum of all days in such events.
Parameters
----------
tasmin : xr.DataArray
Minimum daily temperature [℃] or [K]
tasmax : xr.DataArray
Maximum daily temperature [℃] or [K]
thresh_tasmin : str
The minimum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '22 degC'
thresh_tasmax : str
The maximum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '30 degC'
window : int
Minimum number of days with temperatures above thresholds to qualify as a heatwave.
freq : Optional[str]
Resampling frequency; Defaults to "YS".
Returns
-------
xr.DataArray
Total length of heatwave at the wanted frequency
Notes
-----
See notes and references of `heat_wave_max_length`
"""
freq = freq or "YS"
thresh_tasmax = utils.convert_units_to(thresh_tasmax, tasmax)
thresh_tasmin = utils.convert_units_to(thresh_tasmin, tasmin)

cond = (tasmin > thresh_tasmin) & (tasmax > thresh_tasmax)
group = cond.resample(time=freq)
return group.apply(rl.windowed_run_count, args=(window,), dim="time")


@declare_units("", pr="[precipitation]", prsn="[precipitation]", tas="[temperature]")
def liquid_precip_ratio(
pr: xr.DataArray,
Expand Down

0 comments on commit 4884f1d

Please sign in to comment.