Skip to content

Commit

Permalink
Merge branch 'split_from_xclim' of github.com:Ouranosinc/xsdba into s…
Browse files Browse the repository at this point in the history
…plit_from_xclim
  • Loading branch information
coxipi committed Jul 25, 2024
2 parents b15a67c + bee1a17 commit 683c663
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 41 deletions.
6 changes: 4 additions & 2 deletions src/xsdba/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@

from __future__ import annotations

import datetime as pydt
from collections.abc import Sequence
from inspect import _empty, signature # noqa
from typing import Callable

import cftime
import dask.array as dsk
import jsonpickle
import numpy as np
import xarray as xr
from boltons.funcutils import wraps

from xsdba.options import OPTIONS, SDBA_ENCODE_CF
import datetime as pydt
import cftime


# ## Base class for the sdba module
Expand Down Expand Up @@ -94,6 +95,7 @@ def set_dataset(self, ds: xr.Dataset) -> None:
self.ds = ds
self.ds.attrs[self._attribute] = jsonpickle.encode(self)


# XC put here to avoid circular import
def uses_dask(*das: xr.DataArray | xr.Dataset) -> bool:
"""Evaluate whether dask is installed and array is loaded as a dask array.
Expand Down
14 changes: 9 additions & 5 deletions src/xsdba/testing.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"""Testing utilities for xsdba."""

import warnings
import collections
import hashlib
import logging
import os
import warnings
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.request import urlopen, urlretrieve
from urllib.parse import urljoin, urlparse
from urllib.request import urlopen, urlretrieve

import pandas as pd
import xarray as xr
from platformdirs import user_cache_dir
from xarray import open_dataset as _open_dataset
import collections

__all__ = ["test_timeseries", "test_timelonlatseries"]
__all__ = ["test_timelonlatseries", "test_timeseries"]

# keeping xclim-testdata for now, since it's still this on gitHub
_default_cache_dir = Path(user_cache_dir("xclim-testdata"))
Expand Down Expand Up @@ -47,6 +47,7 @@
except ImportError:
SocketBlockedError = None


def test_timelonlatseries(values, name, start="2000-01-01"):
"""Create a DataArray with time, lon and lat dimensions."""
coords = collections.OrderedDict()
Expand Down Expand Up @@ -81,6 +82,7 @@ def test_timelonlatseries(values, name, start="2000-01-01"):
attrs=attrs,
)


# XC
def test_timeseries(
values,
Expand Down Expand Up @@ -113,7 +115,8 @@ def file_md5_checksum(f_name):
hash_md5.update(f.read())
return hash_md5.hexdigest()

# XC

# XC
def audit_url(url: str, context: str = None) -> str:
"""Check if the URL is well-formed.
Expand All @@ -134,6 +137,7 @@ def audit_url(url: str, context: str = None) -> str:
raise URLError(msg)
return url


# XC (oh dear)
def _get(
fullname: Path,
Expand Down
3 changes: 0 additions & 3 deletions src/xsdba/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from typing import Callable
from warnings import warn


import numpy as np
import xarray as xr
from boltons.funcutils import wraps
Expand Down Expand Up @@ -95,8 +94,6 @@ def ecdf(x: xr.DataArray, value: float, dim: str = "time") -> xr.DataArray:
return (x <= value).sum(dim) / x.notnull().sum(dim)




# XC
def ensure_chunk_size(da: xr.DataArray, **minchunks: int) -> xr.DataArray:
r"""Ensure that the input DataArray has chunks of at least the given size.
Expand Down
3 changes: 2 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from xsdba.testing import TESTDATA_BRANCH
from xsdba.testing import open_dataset as _open_dataset
from xsdba.testing import test_timeseries, test_timelonlatseries
from xsdba.testing import test_timelonlatseries, test_timeseries

# import xclim
# from xclim import __version__ as __xclim_version__
Expand Down Expand Up @@ -93,6 +93,7 @@ def _open_session_scoped_file(file: str | os.PathLike, branch: str = TESTDATA_BR
def timelonlatseries():
return test_timelonlatseries


@pytest.fixture
def lat_series():
def _lat_series(values):
Expand Down
1 change: 1 addition & 0 deletions tests/test_nbutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import numpy as np
import pytest
import xarray as xr

from xsdba import nbutils as nbu


Expand Down
39 changes: 9 additions & 30 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from xsdba.base import Grouper



def test_ecdf(timelonlatseries, random):
dist = norm(5, 2)
r = dist.rvs(10000, random_state=random)
Expand Down Expand Up @@ -66,9 +65,7 @@ def test_equally_spaced_nodes():
np.testing.assert_almost_equal(x[0], 0.5)


@pytest.mark.parametrize(
"interp,expi", [("nearest", 2.9), ("linear", 2.95), ("cubic", 2.95)]
)
@pytest.mark.parametrize("interp,expi", [("nearest", 2.9), ("linear", 2.95), ("cubic", 2.95)])
@pytest.mark.parametrize("extrap,expe", [("constant", 4.4), ("nan", np.NaN)])
def test_interp_on_quantiles_constant(interp, expi, extrap, expe):
quantiles = np.linspace(0, 1, num=25)
Expand All @@ -95,9 +92,7 @@ def test_interp_on_quantiles_constant(interp, expi, extrap, expe):
yq = yq.expand_dims(lat=[1, 2, 3])
newx = newx.expand_dims(lat=[1, 2, 3])

out = u.interp_on_quantiles(
newx, xq, yq, group="time", method=interp, extrapolation=extrap
)
out = u.interp_on_quantiles(newx, xq, yq, group="time", method=interp, extrapolation=extrap)

if np.isnan(expe):
assert out.isel(time=0).isnull().all()
Expand All @@ -108,9 +103,7 @@ def test_interp_on_quantiles_constant(interp, expi, extrap, expe):

xq = xq.where(xq != 220)
yq = yq.where(yq != 3)
out = u.interp_on_quantiles(
newx, xq, yq, group="time", method=interp, extrapolation=extrap
)
out = u.interp_on_quantiles(newx, xq, yq, group="time", method=interp, extrapolation=extrap)

if np.isnan(expe):
assert out.isel(time=0).isnull().all()
Expand All @@ -124,21 +117,15 @@ def test_interp_on_quantiles_monthly(random):
t = xr.cftime_range("2000-01-01", "2030-12-31", freq="D", calendar="noleap")
ref = xr.DataArray(
(
-20 * np.cos(2 * np.pi * t.dayofyear / 365)
+ 2 * random.random(t.size)
+ 273.15
+ 0.1 * (t - t[0]).days / 365
-20 * np.cos(2 * np.pi * t.dayofyear / 365) + 2 * random.random(t.size) + 273.15 + 0.1 * (t - t[0]).days / 365
), # "warming" of 1K per decade,
dims=("time",),
coords={"time": t},
attrs={"units": "K"},
)
sim = xr.DataArray(
(
-18 * np.cos(2 * np.pi * t.dayofyear / 365)
+ 2 * random.random(t.size)
+ 273.15
+ 0.11 * (t - t[0]).days / 365
-18 * np.cos(2 * np.pi * t.dayofyear / 365) + 2 * random.random(t.size) + 273.15 + 0.11 * (t - t[0]).days / 365
), # "warming" of 1.1K per decade
dims=("time",),
coords={"time": t},
Expand All @@ -155,15 +142,11 @@ def test_interp_on_quantiles_monthly(random):
af = u.get_correction(hist_q, ref_q, "+")

for interp in ["nearest", "linear", "cubic"]:
afi = u.interp_on_quantiles(
sim, hist_q, af, group="time.month", method=interp, extrapolation="constant"
)
afi = u.interp_on_quantiles(sim, hist_q, af, group="time.month", method=interp, extrapolation="constant")
assert afi.isnull().sum("time") == 0, interp


@pytest.mark.parametrize(
"interp,expi", [("nearest", 2.9), ("linear", 2.95), ("cubic", 2.95)]
)
@pytest.mark.parametrize("interp,expi", [("nearest", 2.9), ("linear", 2.95), ("cubic", 2.95)])
@pytest.mark.parametrize("extrap,expe", [("constant", 4.4), ("nan", np.NaN)])
def test_interp_on_quantiles_constant_with_nan(interp, expi, extrap, expe):
quantiles = np.linspace(0, 1, num=30)
Expand All @@ -190,9 +173,7 @@ def test_interp_on_quantiles_constant_with_nan(interp, expi, extrap, expe):
yq = yq.expand_dims(lat=[1, 2, 3])
newx = newx.expand_dims(lat=[1, 2, 3])

out = u.interp_on_quantiles(
newx, xq, yq, group="time", method=interp, extrapolation=extrap
)
out = u.interp_on_quantiles(newx, xq, yq, group="time", method=interp, extrapolation=extrap)

if np.isnan(expe):
assert out.isel(time=0).isnull().all()
Expand All @@ -203,9 +184,7 @@ def test_interp_on_quantiles_constant_with_nan(interp, expi, extrap, expe):

xq = xq.where(xq != 220)
yq = yq.where(yq != 3)
out = u.interp_on_quantiles(
newx, xq, yq, group="time", method=interp, extrapolation=extrap
)
out = u.interp_on_quantiles(newx, xq, yq, group="time", method=interp, extrapolation=extrap)

if np.isnan(expe):
assert out.isel(time=0).isnull().all()
Expand Down

0 comments on commit 683c663

Please sign in to comment.