Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support xclim v0.48.0 #99

Merged
merged 9 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
- python-version: "3.9"
- python-version: "3.10"
- python-version: "3.11"
# - python-version: "3.12"
- python-version: "3.12"
defaults:
run:
shell: bash -l {0}
Expand All @@ -71,10 +71,11 @@ jobs:
create-args: >-
mamba
python=${{ matrix.python-version }}
- name: Downgrade intake-esm (for xscen)
- name: Downgrade intake-esm (for xscen) and xclim
if: matrix.python-version == '3.9'
run: |
micromamba install -y intake-esm=2023.11.10
micromamba install -y xclim=0.47.0
- name: Conda and Mamba versions
run: |
mamba --version
Expand Down
2 changes: 1 addition & 1 deletion environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
- spotpy
- statsmodels
- xarray
- xclim >=0.47.0 # FIXME: Remove pin once our dependencies (xclim, xscen) support pandas 2.2.0
- xclim >=0.47.0
- xscen >=0.7.1
- pip
- pip:
Expand Down
4 changes: 2 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: xhydro
channels:
- conda-forge
dependencies:
- python >=3.9,<3.12
- python >=3.9,<3.13
# Don't forget to sync changes between environment.yml, environment-dev.yml, and pyproject.toml!
# Main packages
- numpy
Expand All @@ -11,7 +11,7 @@ dependencies:
- spotpy
- statsmodels
- xarray
- xclim >=0.47.0 # FIXME: Remove pin once our dependencies (xclim, xscen) support pandas 2.2.0
- xclim >=0.47.0
- xscen >=0.7.1
- pip
- pip:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
# "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering :: GIS",
"Topic :: Scientific/Engineering :: Hydrology"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest

from xhydro.modelling.calibration import perform_calibration
from xhydro.modelling.hydrological_modelling import _dummy_model
from xhydro.modelling.hydrological_modelling import _dummy_model # noqa
from xhydro.modelling.obj_funcs import get_objective_function, transform_flows


Expand Down
26 changes: 19 additions & 7 deletions tests/test_indicators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import numpy as np
import pytest
from packaging.version import parse
from xclim import __version__ as __xclim_version__
from xclim.testing.helpers import test_timeseries as timeseries

import xhydro as xh
Expand All @@ -25,10 +27,14 @@ def test_compute_volume(self, freq):
mult = 86400 if freq == "D" else 86400 * 365
np.testing.assert_array_equal(out, da * mult)
assert out.attrs["long_name"] == "Foo"
assert out.attrs["units"] == "m^3"
assert out.attrs["cell_methods"] == "time: sum"
assert out.attrs["description"] == "Volume of water"

if parse(__xclim_version__) < parse("0.48.0"):
assert out.attrs["units"] == "m^3"
else:
assert out.attrs["units"] == "m3"

def test_units(self):
da = timeseries(
np.tile(np.arange(1, 366), 3),
Expand All @@ -38,9 +44,15 @@ def test_units(self):
)

out_m3 = xh.indicators.compute_volume(da)
assert out_m3.attrs["units"] == "m^3"
out_hm3 = xh.indicators.compute_volume(da, out_units="hm3")
assert out_hm3.attrs["units"] == "hm^3"

if parse(__xclim_version__) < parse("0.48.0"):
assert out_m3.attrs["units"] == "m^3"
assert out_hm3.attrs["units"] == "hm^3"
else:
assert out_m3.attrs["units"] == "m3"
assert out_hm3.attrs["units"] == "hm3"

np.testing.assert_array_equal(out_m3 * 1e-6, out_hm3)


Expand All @@ -57,9 +69,9 @@ class TestGetYearlyOp:
def test_get_yearly_op(self, op):
timeargs = {
"annual": {},
"winterdate": {"date_bounds": ["12-01", "02-28"], "freq": "AS-DEC"},
"winterdoy": {"doy_bounds": [335, 59], "freq": "AS-DEC"},
"winterdjf": {"season": ["DJF"], "freq": "AS-DEC"},
"winterdate": {"date_bounds": ["12-01", "02-28"], "freq": "YS-DEC"},
"winterdoy": {"doy_bounds": [335, 59], "freq": "YS-DEC"},
"winterdjf": {"season": ["DJF"], "freq": "YS-DEC"},
"summer": {"doy_bounds": [200, 300]},
}

Expand Down Expand Up @@ -227,7 +239,7 @@ def test_errors(self):
op="max",
timeargs={"annual": {"season": ["DJF"], "doy_bounds": [200, 300]}},
)
with pytest.warns(UserWarning, match="The frequency is not AS-DEC"):
with pytest.warns(UserWarning, match="The frequency is not YS-DEC"):
xh.indicators.get_yearly_op(
self.ds, op="max", timeargs={"annual": {"season": ["DJF"]}}
)
Expand Down
63 changes: 38 additions & 25 deletions tests/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from xclim.testing.helpers import test_timeseries as timeseries

import xhydro.frequency_analysis as xhfa
from xhydro.frequency_analysis.local import _get_plotting_positions, _prepare_plots
from xhydro.frequency_analysis.local import ( # noqa
_get_plotting_positions,
_prepare_plots,
)


class TestFit:
Expand All @@ -29,10 +32,12 @@ def test_fit(self):

np.testing.assert_array_almost_equal(
params.streamflow,
[
[9.95357815e00, np.nan, -3.07846650e01, 1.56498193e01],
[np.nan, -2.25674044e-05, 1.25012261e02, 4.74238877e01],
],
np.array(
[
[9.95357815e00, np.nan, -3.07846650e01, 1.56498193e01],
[np.nan, -2.25674044e-05, 1.25012261e02, 4.74238877e01],
]
),
)

def test_default(self):
Expand Down Expand Up @@ -73,9 +78,11 @@ def test_min_years(self, miny):
np.testing.assert_array_almost_equal(
params.streamflow,
(
[[9.95357815e00, -3.07846650e01, 1.56498193e01]]
if miny == 10
else [[np.nan, np.nan, np.nan]]
np.array(
[[9.95357815e00, -3.07846650e01, 1.56498193e01]]
if miny == 10
else [[np.nan, np.nan, np.nan]]
)
),
)

Expand Down Expand Up @@ -110,7 +117,7 @@ def test_quantiles(mode):
assert rp.streamflow.attrs["cell_methods"] == "dparams: ppf"
assert rp.streamflow.attrs["mode"] == mode

ans = (
ans = np.array(
[[190.66041057, 214.08102761], [185.78830382, 203.01731036]]
if mode == "max"
else [[66.00067153, 53.58658639], [64.23598869, 47.00660287]]
Expand Down Expand Up @@ -150,10 +157,12 @@ def test_criteria():

np.testing.assert_array_almost_equal(
crit.streamflow,
[
[118.19066549, 118.58856076, 118.63510993],
[118.12140939, 118.51930466, 118.56585383],
],
np.array(
[
[118.19066549, 118.58856076, 118.63510993],
[118.12140939, 118.51930466, 118.56585383],
]
),
)


Expand All @@ -166,7 +175,7 @@ def test_default(self):
freq="YS",
as_dataset=True,
)
expected = [1.16666667, 1.61538462, 2.625, 7.0]
expected = np.array([1.16666667, 1.61538462, 2.625, 7.0])
result = _get_plotting_positions(data)
np.testing.assert_array_almost_equal(result.streamflow_pp, expected)
np.testing.assert_array_almost_equal(result.streamflow, data.streamflow)
Expand All @@ -184,7 +193,7 @@ def test_nan(self):
freq="YS",
as_dataset=True,
)
expected = [1.23076923, np.nan, 2.0, 5.33333333]
expected = np.array([1.23076923, np.nan, 2.0, 5.33333333])
result = _get_plotting_positions(data)
np.testing.assert_array_almost_equal(result.streamflow_pp, expected)
np.testing.assert_array_almost_equal(result.streamflow, data.streamflow)
Expand All @@ -202,7 +211,7 @@ def test_return_period(self):
freq="YS",
as_dataset=True,
)
expected = [0.14285714, 0.38095238, 0.61904762, 0.85714286]
expected = np.array([0.14285714, 0.38095238, 0.61904762, 0.85714286])
result = _get_plotting_positions(data, return_period=False)
np.testing.assert_array_almost_equal(result.streamflow_pp, expected)
np.testing.assert_array_almost_equal(result.streamflow, data.streamflow)
Expand All @@ -220,7 +229,7 @@ def test_alpha_beta(self):
freq="YS",
as_dataset=True,
)
expected = [1.25, 1.66666667, 2.5, 5.0]
expected = np.array([1.25, 1.66666667, 2.5, 5.0])
result = _get_plotting_positions(data, alpha=0, beta=0)
np.testing.assert_array_almost_equal(result.streamflow_pp, expected)
np.testing.assert_array_almost_equal(result.streamflow, data.streamflow)
Expand All @@ -246,19 +255,23 @@ def test_prepare_plots_default(self):
assert result.streamflow.shape == (2, 100)
assert result.return_period.min() == 1
assert result.return_period.max() == 10000
expected = [
[-30.78466504, 63.64266447, 78.19229358, 88.62699148, 97.15369501],
[-np.inf, 61.08708903, 79.72126025, 92.05411647, 101.59650405],
]
expected = np.array(
[
[-30.78466504, 63.64266447, 78.19229358, 88.62699148, 97.15369501],
[-np.inf, 61.08708903, 79.72126025, 92.05411647, 101.59650405],
]
)
np.testing.assert_array_almost_equal(result.streamflow.head(), expected)

def test_prepare_plots_linear(self):
result = _prepare_plots(self.params, log=False)

expected = [
[-30.78466504, 262.72577254, 281.56238078, 292.27851004, 299.75980757],
[-np.inf, 235.6878466, 247.41104463, 253.8825982, 258.32114457],
]
expected = np.array(
[
[-30.78466504, 262.72577254, 281.56238078, 292.27851004, 299.75980757],
[-np.inf, 235.6878466, 247.41104463, 253.8825982, 258.32114457],
]
)
np.testing.assert_array_almost_equal(result.streamflow.head(), expected)

def test_prepare_plots_range(self):
Expand Down
14 changes: 12 additions & 2 deletions tests/test_testing_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

import pytest

import xhydro as xh
Expand All @@ -7,7 +9,11 @@
@pytest.mark.requires_docs
def test_publish_release_notes(tmp_path):
temp_md_filename = tmp_path.joinpath("version_info.md")
xhu.publish_release_notes(style="md", file=temp_md_filename)
xhu.publish_release_notes(
style="md",
file=temp_md_filename,
changes=Path(__file__).parent.parent.joinpath("CHANGES.rst"),
)

with open(temp_md_filename) as f:
changelog = f.read()
Expand All @@ -28,7 +34,11 @@ def test_publish_release_notes(tmp_path):
assert ":pull:`" not in changelog

temp_rst_filename = tmp_path.joinpath("version_info.rst")
xhu.publish_release_notes(style="rst", file=temp_rst_filename)
xhu.publish_release_notes(
style="rst",
file=temp_rst_filename,
changes=Path(__file__).parent.parent.joinpath("CHANGES.rst"),
)
with open(temp_rst_filename) as f:
changelog_rst = f.read()
assert changelog_rst.startswith("=========\nChangelog\n=========")
14 changes: 7 additions & 7 deletions xhydro/indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ def get_yearly_op(
Dictionary of time arguments for the operation.
Keys are the name of the period that will be added to the results (e.g. "winter", "summer", "annual").
Values are up to two dictionaries, with both being optional.
The first is {'freq': str}, where str is a frequency supported by xarray (e.g. "YS", "AS-JAN", "AS-DEC").
It needs to be a yearly frequency. Defaults to "AS-JAN".
The first is {'freq': str}, where str is a frequency supported by xarray (e.g. "YS", "YS-JAN", "YS-DEC").
It needs to be a yearly frequency. Defaults to "YS-JAN".
Zeitsperre marked this conversation as resolved.
Show resolved Hide resolved
The second is an indexer as supported by :py:func:`xclim.core.calendar.select_time`.
Defaults to {}, which means the whole year.
See :py:func:`xclim.core.calendar.select_time` for more information.
Examples: {"winter": {"freq": "AS-DEC", "date_bounds": ["12-01", "02-28"]}}, {"jan": {"freq": "YS", "month": 1}}, {"annual": {}}.
Examples: {"winter": {"freq": "YS-DEC", "date_bounds": ["12-01", "02-28"]}}, {"jan": {"freq": "YS", "month": 1}}, {"annual": {}}.
missing : str
How to handle missing values. One of "skip", "any", "at_least_n", "pct", "wmo".
See :py:func:`xclim.core.missing` for more information.
Expand Down Expand Up @@ -159,7 +159,7 @@ def get_yearly_op(
"DEC",
]
for i in timeargs:
freq = timeargs[i].get("freq", "AS-JAN")
freq = timeargs[i].get("freq", "YS-JAN")
if not xc.core.calendar.compare_offsets(freq, "==", "YS"):
raise ValueError(
f"Frequency {freq} is not supported. Please use a yearly frequency."
Expand All @@ -172,10 +172,10 @@ def get_yearly_op(
if (
"season" in indexer.keys()
and "DJF" in indexer["season"]
and freq != "AS-DEC"
and freq != "YS-DEC"
):
warnings.warn(
"The frequency is not AS-DEC, but the season indexer includes DJF. "
"The frequency is not YS-DEC, but the season indexer includes DJF. "
"This will lead to misleading results."
)
elif (
Expand Down Expand Up @@ -207,7 +207,7 @@ def get_yearly_op(
if freq == "YS" or (month_start != month_labels.index(freq.split("-")[1])):
warnings.warn(
f"The frequency is {freq}, but the bounds are between months {month_start} and {month_end}. "
f"You should use 'AS-{month_labels[month_start - 1]}' as the frequency."
f"You should use 'YS-{month_labels[month_start - 1]}' as the frequency."
)

identifier = f"{input_var}{window if window > 1 else ''}_{op}_{i.lower()}"
Expand Down
2 changes: 1 addition & 1 deletion xhydro/modelling/hydrological_modelling.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import pandas as pd
import xarray as xr

__all__ = ["run_hydrological_model"]
__all__ = ["get_hydrological_model_inputs", "run_hydrological_model"]


def run_hydrological_model(model_config: dict):
Expand Down
2 changes: 1 addition & 1 deletion xhydro/modelling/obj_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import numpy as np
import xarray as xr

__all__ = ["get_objective_function"]
__all__ = ["get_objective_function", "transform_flows"]


def get_objective_function(
Expand Down
Loading