Skip to content

Commit 8f20a34

Browse files
authored
Standardized Streamflow Index and Standardized Groundwater level Index (#1877)
<!--Please ensure the PR fulfills the following requirements! --> <!-- If this is your first PR, make sure to add your details to the AUTHORS.rst! --> ### Pull Request Checklist: - [x] This PR addresses an already opened issue (for bug fixes / features) - This PR fixes #1444 - [x] Tests for the changes have been added (for bug fixes / features) - [x] (If applicable) Documentation has been added / updated (for bug fixes / features) - [x] CHANGELOG.rst has been updated (with summary of main changes) - [x] Link to issue (:issue:`number`) and pull request (:pull:`number`) has been added ### What kind of change does this PR introduce? * 2 new indices/indicators : SSI and SGI ### Does this PR introduce a breaking change? No ### Other information: * SSI will use GEV or log-logistic (scipy does not support tweedie) * SGI will use log-normal, gamma or GEV
2 parents 3ea2649 + fa1596b commit 8f20a34

16 files changed

+744
-40
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ on:
1919
- submitted
2020

2121
env:
22-
XCLIM_TESTDATA_BRANCH: v2025.1.8
22+
XCLIM_TESTDATA_BRANCH: v2025.3.11
2323

2424
concurrency:
2525
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch except on main.

CHANGELOG.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Changelog
44

55
v0.56.0 (unreleased)
66
--------------------
7-
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Hui-Min Wang (:user:`Hem-W`), Jack Kit-tai Wong(:user:`jack-ktw`), Éric Dupuis (:user:`coxipi`).
7+
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Hui-Min Wang (:user:`Hem-W`), Jack Kit-tai Wong(:user:`jack-ktw`), Adrien Lamarche (:user:`LamAdr`), Éric Dupuis (:user:`coxipi`).
88

99
Bug fixes
1010
^^^^^^^^^
@@ -28,6 +28,11 @@ Internal changes
2828
* The `xclim` documentation now has a ``support`` page for detailing the project's usage and version support policies. (:pull:`2100`).
2929
* The indicator `heat_wave_index` now uses `hot_spell_total_length` index. The `heat_wave_index` index is identitical to `hot_spell_total_length` and will be dropped in future versions. (:issue:`2031`, :pull:`2102`).
3030

31+
New indicators
32+
^^^^^^^^^^^^^^
33+
* Added standardized indicators for hydrology: ``xclim.land.standardized_streamflow_index`` and ``xclim.landstandardized_groundwater_index``. (:issue:`1444`, :pull:`1877`).
34+
35+
3136
v0.55.1 (2025-02-26)
3237
--------------------
3338
Contributors to this version: Éric Dupuis (:user:`coxipi`).

docs/references.bib

+26
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,32 @@ @article{knol_1989
22362236
number = "1",
22372237
}
22382238

2239+
@article{vicente-serrano_2012,
2240+
author = {Sergio M. Vicente-Serrano and Juan I. López-Moreno and Santiago Beguería and Jorge Lorenzo-Lacruz and Cesar Azorin-Molina and Enrique Morán-Tejeda},
2241+
title = {Accurate Computation of a Streamflow Drought Index},
2242+
journal = {Journal of Hydrologic Engineering},
2243+
volume = {17},
2244+
number = {2},
2245+
pages = {318-332},
2246+
year = {2012},
2247+
doi = {10.1061/(ASCE)HE.1943-5584.0000433},
2248+
URL = {https://ascelibrary.org/doi/abs/10.1061/%28ASCE%29HE.1943-5584.0000433},
2249+
eprint = {https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29HE.1943-5584.0000433},
2250+
abstract = "In this study, the authors investigated an approach to calculate the standardized streamflow index (SSI), which allows accurate spatial and temporal comparison of the hydrological conditions of a stream or set of streams. For this purpose, the capability of six three-parameter distributions (lognormal, Pearson Type III, log-logistic, general extreme value, generalized Pareto, and Weibull) and two different approaches to select the most suitable distribution the best monthly fit (BMF) and the minimum orthogonal distance (MD), were tested by using a monthly streamflow data set for the Ebro Basin (Spain). This large Mediterranean basin is characterized by high variability in the magnitude of streamflows and in seasonal regimes. The results show that the most commonly used probability distributions for flow frequency analysis provided good fits to the streamflow series. Thus, the visual inspection of the L-moment diagrams and the results of the Kolmogorov-Smirnov test did not enable the selection of a single optimum probability distribution. However, no single probability distribution for all the series was suitable for obtaining a robust standardized streamflow series because each of the distributions had one or more limitations. The BMF and MD approaches improved the results in the expected average, standard deviation, and the frequencies of extreme events of the SSI series in relation to the selection of a unique distribution for each station. The BMF and MD approaches involved using different probability distributions for each gauging station and month of the year to calculate the SSI. Both approaches are easy to apply and they provide very similar results in the quality of the obtained hydrological drought indexes. The proposed procedures are very flexible for analyses involving contrasting hydrological regimes and flow characteristics."
2251+
}
2252+
2253+
@article{bloomfield_2013,
2254+
AUTHOR = {Bloomfield, J. P. and Marchant, B. P.},
2255+
TITLE = {Analysis of groundwater drought building on the standardised precipitation index approach},
2256+
JOURNAL = {Hydrology and Earth System Sciences},
2257+
VOLUME = {17},
2258+
YEAR = {2013},
2259+
NUMBER = {12},
2260+
PAGES = {4769--4787},
2261+
URL = {https://hess.copernicus.org/articles/17/4769/2013/},
2262+
DOI = {10.5194/hess-17-4769-2013}
2263+
}
2264+
22392265
@article{luedeling_chill_2009,
22402266
title = {Climate change impacts on winter chill for temperate fruit and nut production: A review},
22412267
journal = {Scientia Horticulturae},

src/xclim/core/indicator.py

+7
Original file line numberDiff line numberDiff line change
@@ -1939,3 +1939,10 @@ def _merge_attrs(dbase, dextra, attr, sep):
19391939
load_locale(loc_dict, locale)
19401940

19411941
return mod
1942+
1943+
1944+
class StandardizedIndexes(ResamplingIndicator):
1945+
"""Resampling but flexible inputs indicators."""
1946+
1947+
src_freq = ["D", "MS"]
1948+
context = "hydro"

src/xclim/data/fr.json

+12
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@
269269
"title": "Précipitation liquide accumulée totale",
270270
"abstract": "Précipitation liquide accumulée totale. Les précipitations sont considérées liquides lorsque la température quotidienne moyenne est au-dessus de 0°C."
271271
},
272+
"SGI": {
273+
"long_name": "Indice d'eau souterraine standardisé (SGI)",
274+
"description": "Niveau de l'eau souterraine sur une fenêtre mobile de {window} {freq:nom}, normalisé telle que la moyenne du SGI est 0 pour les données de calibration. L'unité de la fenêtre 'X' est l'unité de temps déterminée par la fréquence de rééchantillonage,",
275+
"title": "Indice d'eau souterraine standardisé (SGI)",
276+
"abstract": "Niveau de l'eau souterraine sur une fenêtre mobile, normalisée telle que la moyenne du SGI est 0 pour les données de calibration. L'unité de la fenêtre est l'unité de temps déterminée par la fréquence de rééchantillonnage."
277+
},
272278
"SOLIDPRCPTOT": {
273279
"long_name": "Précipitation totale lorsque la température moyenne est en dessous ou égale à {thresh}",
274280
"description": "Précipitation solide totale {freq:f}, estimée comme la précipitation lorsque la température moyenne est en dessous ou égale à {thresh}.",
@@ -287,6 +293,12 @@
287293
"title": "Indice de précipitation évapotranspiration standardisé (SPEI)",
288294
"abstract": "Budget d'eau (précipitation - évapotranspiration) sur une fenêtre mobile, normalisé tel que la moyenne du SPEI est 0 pour les données de calibration. L'unité de la fenêtre est l'unité de temps déterminée par la fréquence de rééchantillonnage."
289295
},
296+
"SSI": {
297+
"long_name": "Indice d'écoulement standardisé (SSI)",
298+
"description": "Écoulement sur une fenêtre mobile de {window} {freq:nom}, normalisée telle que la moyenne du SSI est 0 pour les données de calibration. L'unité de la fenêtre 'X' est l'unité de temps déterminée par la fréquence de rééchantillonage,",
299+
"title": "Indice d'écoulement standardisé (SSI)",
300+
"abstract": "Écoulement sur une fenêtre mobile, normalisée telle que la moyenne du SSI est 0 pour les données de calibration. L'unité de la fenêtre est l'unité de temps déterminée par la fréquence de rééchantillonnage."
301+
},
290302
"DC": {
291303
"long_name": "Indice de sécheresse",
292304
"description": "Code numérique estimant la teneur en humidité moyenne des couches organiques.",

src/xclim/data/variables.yml

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ variables:
3030
standard_name: water_potential_evapotranspiration_flux
3131
data_flags:
3232
- negative_accumulation_values:
33+
gwl:
34+
canonical_units: m
35+
description: Groundwater level.
36+
dimensions: "[length]"
3337
hurs:
3438
canonical_units: '%'
3539
cell_methods: "time: mean"

src/xclim/indicators/atmos/_precip.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
Daily,
1111
Hourly,
1212
Indicator,
13-
ResamplingIndicator,
1413
ResamplingIndicatorWithIndexing,
14+
StandardizedIndexes,
1515
)
1616
from xclim.core.utils import InputKind
1717

@@ -115,13 +115,6 @@ def cfcheck(pr: DataArray, tas: DataArray):
115115
cfchecks.check_valid(tas, "standard_name", "air_temperature")
116116

117117

118-
class StandardizedIndexes(ResamplingIndicator):
119-
"""Resampling but flexible inputs indicators."""
120-
121-
src_freq = ["D", "MS"]
122-
context = "hydro"
123-
124-
125118
class HrPrecip(Hourly):
126119
"""Indicator involving hourly pr series."""
127120

@@ -372,6 +365,7 @@ class HrPrecip(Hourly):
372365
)
373366

374367
standardized_precipitation_index = StandardizedIndexes(
368+
realm="atmos",
375369
title="Standardized Precipitation Index (SPI)",
376370
identifier="spi",
377371
units="",
@@ -387,6 +381,7 @@ class HrPrecip(Hourly):
387381
)
388382

389383
standardized_precipitation_evapotranspiration_index = StandardizedIndexes(
384+
realm="atmos",
390385
title="Standardized Precipitation Evapotranspiration Index (SPEI)",
391386
identifier="spei",
392387
units="",

src/xclim/indicators/land/_streamflow.py

+39
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from xclim.core.indicator import (
99
ReducingIndicator,
1010
ResamplingIndicator,
11+
StandardizedIndexes,
1112
)
1213
from xclim.core.units import declare_units
1314
from xclim.indices import (
@@ -17,6 +18,8 @@
1718
high_flow_frequency,
1819
low_flow_frequency,
1920
rb_flashiness_index,
21+
standardized_groundwater_index,
22+
standardized_streamflow_index,
2023
)
2124

2225
__all__ = [
@@ -27,6 +30,8 @@
2730
"high_flow_frequency",
2831
"low_flow_frequency",
2932
"rb_flashiness_index",
33+
"standardized_groundwater_index",
34+
"standardized_streamflow_index",
3035
]
3136

3237

@@ -97,6 +102,7 @@ def cfcheck(q: DataArray):
97102
parameters={"op": generic.doymin, "out_units": None},
98103
)
99104

105+
100106
flow_index = ReducingIndicator(
101107
realm="land",
102108
context="hydro",
@@ -130,3 +136,36 @@ def cfcheck(q: DataArray):
130136
units="days",
131137
compute=low_flow_frequency,
132138
)
139+
140+
standardized_streamflow_index = StandardizedIndexes(
141+
realm="land",
142+
title="Standardized Streamflow Index (SSI)",
143+
identifier="ssi",
144+
units="",
145+
standard_name="ssi",
146+
long_name="Standardized Streamflow Index (SSI)",
147+
description="Streamflow over a moving {window}-X window, normalized such that SSI averages to 0 for "
148+
"calibration data. The window unit `X` is the minimal time period defined by resampling frequency {freq}.",
149+
abstract="Streamflow over a moving window, normalized such that SSI averages to 0 for the calibration data. "
150+
"The window unit `X` is the minimal time period defined by the resampling frequency.",
151+
cell_methods="",
152+
keywords="streamflow",
153+
compute=standardized_streamflow_index,
154+
)
155+
156+
157+
standardized_groundwater_index = StandardizedIndexes(
158+
realm="land",
159+
title="Standardized Groundwater Index (SGI)",
160+
identifier="sgi",
161+
units="",
162+
standard_name="sgi",
163+
long_name="Standardized Groundwater Index (SGI)",
164+
description="Groundwater over a moving {window}-X window, normalized such that SGI averages to 0 for "
165+
"calibration data. The window unit `X` is the minimal time period defined by resampling frequency {freq}.",
166+
abstract="Groundwater over a moving window, normalized such that SGI averages to 0 for the calibration data. "
167+
"The window unit `X` is the minimal time period defined by the resampling frequency.",
168+
cell_methods="",
169+
keywords="groundwater",
170+
compute=standardized_groundwater_index,
171+
)

src/xclim/indices/_agro.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1113,8 +1113,8 @@ def standardized_precipitation_index(
11131113
pr : xarray.DataArray
11141114
Daily precipitation.
11151115
freq : str, optional
1116-
Resampling frequency. A monthly or daily frequency is expected. Option `None` assumes that desired resampling
1117-
has already been applied input dataset and will skip the resampling step.
1116+
Resampling frequency. A monthly or daily frequency is expected. Option `None` assumes
1117+
that the desired resampling has already been applied input dataset and will skip the resampling step.
11181118
window : int
11191119
Averaging window length relative to the resampling frequency. For example, if `freq="MS"`,
11201120
i.e. a monthly resampling, the window is an integer number of months.
@@ -1254,8 +1254,8 @@ def standardized_precipitation_evapotranspiration_index(
12541254
wb : xarray.DataArray
12551255
Daily water budget (pr - pet).
12561256
freq : str, optional
1257-
Resampling frequency. A monthly or daily frequency is expected. Option `None` assumes that desired resampling
1258-
has already been applied input dataset and will skip the resampling step.
1257+
Resampling frequency. A monthly or daily frequency is expected. Option `None` assumes
1258+
that the desired resampling has already been applied input dataset and will skip the resampling step.
12591259
window : int
12601260
Averaging window length relative to the resampling frequency. For example, if `freq="MS"`, i.e. a monthly
12611261
resampling, the window is an integer number of months.

0 commit comments

Comments
 (0)