def test_missing(tas_series): a = tas_series(np.ones(365, float), start="1/1/2000") # By default, missing is set to "from_context", and the default missing option is "any" # Cannot set missing_options with "from_context" with pytest.raises(ValueError, match="Cannot set `missing_options`"): uniClim.__class__(missing_options={"tolerance": 0.01}) # Null value a[5] = np.nan m = uniIndTemp(a, freq="MS") assert m[0].isnull() with xclim.set_options(check_missing="pct", missing_options={"pct": { "tolerance": 0.05 }}): m = uniIndTemp(a, freq="MS") assert not m[0].isnull() with xclim.set_options(check_missing="wmo"): m = uniIndTemp(a, freq="YS") assert m[0].isnull() # With freq=None c = uniClim(a) assert c.isnull() # With indexer ci = uniClim(a, month=[2]) assert not ci.isnull() out = uniClim(a, month=[1]) assert out.isnull()
def test_register_missing_method(): @register_missing_method("test") class MissingTest(MissingBase): def is_missing(self, null, count, a_param=2): return True @staticmethod def validate(a_param): return a_param < 3 with pytest.raises(ValueError): set_options(missing_options={"test": {"a_param": 5}}) with set_options(check_missing="test"): assert OPTIONS["check_missing"] == "test"
def test_renaming_variable(tas_series, tmp_path): tas = tas_series(np.ones(366), start="1/1/2000") input_file = tmp_path / "tas.nc" output_file = tmp_path / "out.nc" tas.name = "tas" tas.to_netcdf(input_file) with xclim.set_options(cf_compliance="warn"): runner = CliRunner() results = runner.invoke( cli, [ "-i", str(input_file), "-o", str(output_file), "-v", "tn_mean", "--tasmin", "tas", ], ) assert "Processing : tn_mean" in results.output assert "100% Completed" in results.output out = xr.open_dataset(output_file) assert out.tn_mean[0] == 1.0
def test_missing(tas_series): a = tas_series(np.ones(360, float), start="1/1/2000") # By default, missing is set to "from_context", and the default missing option is "any" ind = UniIndTemp() clim = UniClim() # Null value a[5] = np.nan m = ind(a, freq="MS") assert m[0].isnull() with xclim.set_options(check_missing="pct", missing_options={"pct": { "tolerance": 0.05 }}): m = ind(a, freq="MS") assert not m[0].isnull() # With freq=None c = clim(a) assert c.isnull() # With indexer ci = clim(a, month=[2]) assert not ci.isnull() out = clim(a, month=[1]) assert out.isnull()
def adjust_quantiledeltamapping_year( simulation, qdm, year, variable, halfyearwindow_n=10, include_quantiles=False ): """Apply QDM to adjust a year within a simulation. Parameters ---------- simulation : xr.Dataset Daily simulation data to be adjusted. Must have sufficient observations around `year` to adjust. Target variable must have a units attribute. qdm : xr.Dataset or sdba.adjustment.QuantileDeltaMapping Trained ``xclim.sdba.adjustment.QuantileDeltaMapping``, or Dataset representation that will be instantiate ``xclim.sdba.adjustment.QuantileDeltaMapping``. year : int Target year to adjust, with rolling years and day grouping. variable : str Target variable in `simulation` to adjust. Adjusted output will share the same name. halfyearwindow_n : int, optional Half-length of the annual rolling window to extract along either side of `year`. include_quantiles : bool, optional Whether or not to output quantiles (sim_q) as a coordinate on the bias corrected data variable in output. Returns ------- out : xr.Dataset QDM-adjusted values from `simulation`. May be a lazy-evaluated future, not yet computed. """ year = int(year) variable = str(variable) halfyearwindow_n = int(halfyearwindow_n) if isinstance(qdm, xr.Dataset): qdm = sdba.adjustment.QuantileDeltaMapping.from_dataset(qdm) # Slice to get 15 days before and after our target year. This accounts # for the rolling 31 day rolling window. timeslice = slice( f"{year - halfyearwindow_n - 1}-12-17", f"{year + halfyearwindow_n + 1}-01-15" ) simulation = simulation[variable].sel( time=timeslice ) # TODO: Need a check to ensure we have all the data in this slice! if include_quantiles: # include quantile information in output with set_options(sdba_extra_output=True): out = qdm.adjust(simulation, interp="nearest").sel(time=str(year)) # make quantiles a coordinate of bias corrected output variable out = out["scen"].assign_coords(sim_q=out.sim_q) else: out = qdm.adjust(simulation, interp="nearest").sel(time=str(year)) return out.to_dataset(name=variable)
def test_set_options_valid(option, value): old = OPTIONS[option] with set_options(**{option: value}): if option != "missing_options": assert OPTIONS[option] == value else: for k, opts in value.items(): curr_opts = OPTIONS["missing_options"][k].copy() assert curr_opts == opts assert OPTIONS[option] == old
def test_first_snowfall(self): with set_options(check_missing="skip"): fs = atmos.first_snowfall(prsn=self.get_snowfall(), thresh="0.5 mm/day") np.testing.assert_array_equal( fs[:, [0, 45, 82], [10, 105, 155]], np.array([ [[1, 1, 1], [1, 1, 1], [11, np.nan, np.nan]], [[254, 256, 277], [274, 292, 275], [300, np.nan, np.nan]], ]), )
def test_last_snowfall(self): with set_options(check_missing="skip"): ls = atmos.last_snowfall(prsn=self.get_snowfall(), thresh="0.5 mm/day") np.testing.assert_array_equal( ls[:, [0, 45, 82], [10, 105, 155]], np.array([ [[155, 151, 129], [127, 157, 110], [106, np.nan, np.nan]], [[365, 363, 363], [365.0, 364, 364], [362, np.nan, np.nan]], ]), )
def test_cf_compliance_options(tas_series, caplog): tas = tas_series(np.ones(365)) tas.attrs["standard_name"] = "not the right name" with caplog.at_level(logging.INFO): with set_options(cf_compliance="log"): cfchecks.check_valid_temperature(tas, "degK") assert all([rec.levelname == "INFO" for rec in caplog.records]) assert ("Variable has a non-conforming standard_name" in caplog.records[0].msg) assert "Variable has a non-conforming units" in caplog.records[ 1].msg with pytest.warns(UserWarning, match="Variable has a non-conforming"): with set_options(cf_compliance="warn"): cfchecks.check_valid_temperature(tas, "degK") with pytest.raises(ValidationError, match="Variable has a non-conforming standard_name"): with set_options(cf_compliance="raise"): cfchecks.check_valid_temperature(tas, "degK")
def test_generated_cfchecks(): with set_options(cf_compliance="raise"): tas = xr.DataArray(attrs=dict(standard_name="air_temperature", cell_methods="time: mean within days")) cfchecks.generate_cfcheck("tas")(tas) tas.attrs["standard_name"] = "air_feeling_of_heat" with pytest.raises(ValidationError): cfchecks.generate_cfcheck("tas")(tas) sfcwind = xr.DataArray(attrs=dict( standard_name="wind_speed", cell_methods="time: max within hours")) with pytest.raises(ValidationError): cfchecks.generate_cfcheck("sfcWind")(sfcwind)
def test_basic(self): check_units("%", "[]") check_units("pct", "[]") check_units("mm/day", "[precipitation]") check_units("mm/s", "[precipitation]") check_units("kg/m2/s", "[precipitation]") check_units("kg/m2", "[length]") check_units("cms", "[discharge]") check_units("m3/s", "[discharge]") check_units("m/s", "[speed]") check_units("km/h", "[speed]") with set_options(data_validation="raise"): with pytest.raises(ValidationError): check_units("mm", "[precipitation]") with pytest.raises(ValidationError): check_units("m3", "[discharge]")
def test_input_dataset(): ds = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc") # Use defaults out = xclim.atmos.daily_temperature_range(freq="YS", ds=ds) # Use non-defaults (inverted on purpose) with xclim.set_options(cf_compliance="log"): out = xclim.atmos.daily_temperature_range("tasmax", "tasmin", freq="YS", ds=ds) # Use a mix out = xclim.atmos.daily_temperature_range(tasmax=ds.tasmax, freq="YS", ds=ds) # Inexistent variable: dsx = ds.drop_vars("tasmin") with pytest.raises(MissingVariableError): out = xclim.atmos.daily_temperature_range(freq="YS", ds=dsx) # noqa
def test_liquid_precip_ratio(): ds = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc") out = atmos.liquid_precip_ratio(pr=ds.pr, tas=ds.tas, thresh="0 degC", freq="YS") np.testing.assert_allclose(out[:, 0], np.array([0.919, 0.805, 0.525, 0.740, 0.993]), atol=1e3) with set_options(cf_compliance="raise"): # Test if tasmax is allowed out = atmos.liquid_precip_ratio(pr=ds.pr, tas=ds.tasmax, thresh="33 degF", freq="YS") np.testing.assert_allclose(out[:, 0], np.array( [0.975, 0.921, 0.547, 0.794, 0.999]), atol=1e3) assert "where temperature is above 33 degf." in out.description
def test_input_dataset(): dsx = open_dataset("NRCANdaily/nrcan_canada_daily_tasmax_1990") dsn = open_dataset("NRCANdaily/nrcan_canada_daily_tasmin_1990") ds = xr.merge([dsx, dsn]) # Use defaults out = xclim.atmos.daily_temperature_range(freq="YS", ds=ds) # Use non-defaults (inverted on purpose) with xclim.set_options(cf_compliance="log"): out = xclim.atmos.daily_temperature_range("tasmax", "tasmin", freq="YS", ds=ds) # Use a mix out = xclim.atmos.daily_temperature_range(tasmax=ds.tasmax, freq="YS", ds=ds) # Inexistent variable: with pytest.raises(MissingVariableError): out = xclim.atmos.daily_temperature_range(freq="YS", ds=dsx) # noqa
def test_set_options_invalid(option, value): old = OPTIONS[option] with pytest.raises(ValueError): set_options(**{option: value}) assert old == OPTIONS[option]
def setup_module(module): set_options(cf_compliance="raise", data_validation="raise")
def teardown_module(module): set_options(cf_compliance="warn", data_validation="raise")
import numpy as np import pandas as pd import pytest import xarray as xr from xclim import set_options from xclim.core import cfchecks from xclim.core.utils import ValidationError from xclim.indicators.atmos import tg_mean K2C = 273.15 TESTS_HOME = Path(__file__).absolute().parent TESTS_DATA = Path(TESTS_HOME, "testdata") set_options(cf_compliance="raise", data_validation="raise") TestObj = namedtuple("TestObj", ["test"]) @pytest.fixture(scope="module", params=[xr.cftime_range, pd.date_range]) def date_range(request): return request.param @pytest.mark.parametrize("value,expected", [("a string", "a string"), ("a long string", "a * string")]) def test_check_valid_ok(value, expected): d = TestObj(value) cfchecks.check_valid(d, "test", expected)
def test_options(self, q_series): q = q_series(np.random.rand(19)) with set_options(missing_options={"at_least_n": {"n": 10}}): out = land.fit(q, dist="norm") np.testing.assert_array_equal(out.isnull(), False)