Skip to content
Snippets Groups Projects
Commit f6d37f66 authored by leufen1's avatar leufen1
Browse files

many new tests for filters

parent c2b61490
No related branches found
No related tags found
3 merge requests!413update release branch,!412Resolve "release v2.0.0",!358Resolve "filter with future mix"
Pipeline #84191 passed
import gc import gc
import warnings import warnings
from typing import Union, Callable, Tuple from typing import Union, Callable, Tuple, Dict, Any
import logging import logging
import os import os
import time import time
...@@ -71,15 +71,13 @@ class ClimateFIRFilter: ...@@ -71,15 +71,13 @@ class ClimateFIRFilter:
sampling = {1: "1d", 24: "1H"}.get(int(fs)) sampling = {1: "1d", 24: "1H"}.get(int(fs))
logging.debug(f"{plot_name}: create diurnal_anomalies") logging.debug(f"{plot_name}: create diurnal_anomalies")
if apriori_diurnal is True and sampling == "1H": if apriori_diurnal is True and sampling == "1H":
diurnal_anomalies = self.create_seasonal_hourly_mean(data, sel_opts=sel_opts, sampling=sampling, diurnal_anomalies = self.create_seasonal_hourly_mean(data, time_dim, sel_opts=sel_opts, sampling=sampling,
time_dim=time_dim,
as_anomaly=True) as_anomaly=True)
else: else:
diurnal_anomalies = 0 diurnal_anomalies = 0
logging.debug(f"{plot_name}: create monthly apriori") logging.debug(f"{plot_name}: create monthly apriori")
if apriori is None: if apriori is None:
apriori = self.create_monthly_mean(data, sel_opts=sel_opts, sampling=sampling, apriori = self.create_monthly_mean(data, time_dim, sel_opts=sel_opts, sampling=sampling) + diurnal_anomalies
time_dim=time_dim) + diurnal_anomalies
logging.debug(f"{plot_name}: apriori shape = {apriori.shape}") logging.debug(f"{plot_name}: apriori shape = {apriori.shape}")
apriori_list = to_list(apriori) apriori_list = to_list(apriori)
input_data = data.__deepcopy__() input_data = data.__deepcopy__()
...@@ -124,12 +122,9 @@ class ClimateFIRFilter: ...@@ -124,12 +122,9 @@ class ClimateFIRFilter:
if len(apriori_list) <= i + 1: if len(apriori_list) <= i + 1:
logging.info(f"{plot_name}: create diurnal_anomalies") logging.info(f"{plot_name}: create diurnal_anomalies")
if apriori_diurnal is True and sampling == "1H": if apriori_diurnal is True and sampling == "1H":
# diurnal_anomalies = self.create_hourly_mean(input_data.sel({new_dim: 0}, drop=True),
# sel_opts=sel_opts, sampling=sampling,
# time_dim=time_dim, as_anomaly=True)
diurnal_anomalies = self.create_seasonal_hourly_mean(input_data.sel({new_dim: 0}, drop=True), diurnal_anomalies = self.create_seasonal_hourly_mean(input_data.sel({new_dim: 0}, drop=True),
sel_opts=sel_opts, sampling=sampling, time_dim, sel_opts=sel_opts, sampling=sampling,
time_dim=time_dim, as_anomaly=True) as_anomaly=True)
else: else:
diurnal_anomalies = 0 diurnal_anomalies = 0
logging.info(f"{plot_name}: create monthly apriori") logging.info(f"{plot_name}: create monthly apriori")
...@@ -137,9 +132,8 @@ class ClimateFIRFilter: ...@@ -137,9 +132,8 @@ class ClimateFIRFilter:
apriori_list.append(xr.zeros_like(apriori_list[i]) + diurnal_anomalies) apriori_list.append(xr.zeros_like(apriori_list[i]) + diurnal_anomalies)
elif apriori_type == "residuum_stats": # calculate monthly statistic on residuum elif apriori_type == "residuum_stats": # calculate monthly statistic on residuum
apriori_list.append( apriori_list.append(
-self.create_monthly_mean(input_data.sel({new_dim: 0}, drop=True), sel_opts=sel_opts, -self.create_monthly_mean(input_data.sel({new_dim: 0}, drop=True), time_dim, sel_opts=sel_opts,
sampling=sampling, sampling=sampling) + diurnal_anomalies)
time_dim=time_dim) + diurnal_anomalies)
else: else:
raise ValueError(f"Cannot handle unkown apriori type: {apriori_type}. Please choose from None, " raise ValueError(f"Cannot handle unkown apriori type: {apriori_type}. Please choose from None, "
f"`zeros` or `residuum_stats`.") f"`zeros` or `residuum_stats`.")
...@@ -179,7 +173,7 @@ class ClimateFIRFilter: ...@@ -179,7 +173,7 @@ class ClimateFIRFilter:
:param data: data to create monthly unity array from, must contain dimension time_dim :param data: data to create monthly unity array from, must contain dimension time_dim
:param time_dim: name of temporal dimension :param time_dim: name of temporal dimension
:param extend_range: number of days to extend data :param extend_range: number of days to extend data (default 366)
:returns: xarray in monthly resolution (centered at 16th day of month) with all values equal to 1 :returns: xarray in monthly resolution (centered at 16th day of month) with all values equal to 1
""" """
coords = data.coords coords = data.coords
...@@ -196,8 +190,8 @@ class ClimateFIRFilter: ...@@ -196,8 +190,8 @@ class ClimateFIRFilter:
# loffset is required because resampling uses last day in month as resampling timestamp # loffset is required because resampling uses last day in month as resampling timestamp
return new_array.resample({time_dim: "1m"}, loffset=datetime.timedelta(days=-15)).max() return new_array.resample({time_dim: "1m"}, loffset=datetime.timedelta(days=-15)).max()
def create_monthly_mean(self, data: xr.DataArray, sel_opts: dict = None, sampling: str = "1d", def create_monthly_mean(self, data: xr.DataArray, time_dim: str, sel_opts: dict = None, sampling: str = "1d") \
time_dim: str = "datetime") -> xr.DataArray: -> xr.DataArray:
""" """
Calculate monthly means (12 values) and return a data array with same resolution as given data containing these Calculate monthly means (12 values) and return a data array with same resolution as given data containing these
monthly mean values. Sampling points are the 16th of each month (this value is equal to the true monthly mean) monthly mean values. Sampling points are the 16th of each month (this value is equal to the true monthly mean)
...@@ -206,11 +200,11 @@ class ClimateFIRFilter: ...@@ -206,11 +200,11 @@ class ClimateFIRFilter:
calculate the monthly statistic. calculate the monthly statistic.
:param data: data to apply statistical calculation on :param data: data to apply statistical calculation on
:param time_dim: name of temporal axis
:param sel_opts: selection options as dict to select a subset of data (default None). A given sel_opts with :param sel_opts: selection options as dict to select a subset of data (default None). A given sel_opts with
`sel_opts={<time_dim>: "2006"}` forces the method e.g. to derive the monthly means only from data of the `sel_opts={<time_dim>: "2006"}` forces the method e.g. to derive the monthly means only from data of the
year 2006. year 2006.
:param sampling: sampling of the returned data (default 1d) :param sampling: sampling of the returned data (default 1d)
:param time_dim: name of temporal axis
:returns: array in desired resolution containing interpolated monthly values. Months with no valid data are :returns: array in desired resolution containing interpolated monthly values. Months with no valid data are
returned as np.nan which also effects data in the neighbouring months (before / after sampling points which returned as np.nan which also effects data in the neighbouring months (before / after sampling points which
are the 16th of each month). are the 16th of each month).
...@@ -233,28 +227,67 @@ class ClimateFIRFilter: ...@@ -233,28 +227,67 @@ class ClimateFIRFilter:
return monthly.resample({time_dim: sampling}).interpolate() return monthly.resample({time_dim: sampling}).interpolate()
@staticmethod @staticmethod
def create_hourly_mean(data, sel_opts=None, sampling="1H", time_dim="datetime", as_anomaly=True): def _compute_hourly_mean_per_month(data: xr.DataArray, time_dim: str, as_anomaly: bool) -> Dict[int, xr.DataArray]:
"""Calculate hourly statistics. Either the absolute value or the anomaly (as_anomaly=True).""" """
# can only be used for hourly sampling rate Calculate for each hour in each month a separate mean value (12 x 24 values in total). Average is either the
assert sampling == "1H" anomaly of a monthly mean state or the raw mean value.
# create unity xarray in hourly resolution
hourly = xr.ones_like(data)
# apply selection if given (only use subset for hourly means)
if sel_opts is not None:
data = data.sel(**sel_opts)
# create mean for each hour and replace entries in unity array, calculate anomaly if enabled :param data: data to calculate averages on
hourly_mean = data.groupby(f"{time_dim}.hour").mean() :param time_dim: name of temporal dimension
:param as_anomaly: indicates whether to calculate means as anomaly of a monthly mean or as raw mean values.
:returns: dictionary containing 12 months each with a 24-valued array (1 entry for each hour)
"""
seasonal_hourly_means = {}
for month in data.groupby(f"{time_dim}.month").groups.keys():
single_month_data = data.sel({time_dim: (data[f"{time_dim}.month"] == month)})
hourly_mean = single_month_data.groupby(f"{time_dim}.hour").mean()
if as_anomaly is True: if as_anomaly is True:
hourly_mean = hourly_mean - hourly_mean.mean("hour") hourly_mean = hourly_mean - hourly_mean.mean("hour")
for hour in hourly_mean.hour.values: seasonal_hourly_means[month] = hourly_mean
loc = (hourly[f"{time_dim}.hour"] == hour) return seasonal_hourly_means
hourly.loc[{f"{time_dim}": loc}] = hourly_mean.sel(hour=hour)
return hourly @staticmethod
def _create_seasonal_cycle_of_single_hour_mean(result_arr: xr.DataArray, means: Dict[int, xr.DataArray], hour: int,
time_dim: str, sampling: str) -> xr.DataArray:
"""
Use monthly means of a given hour to create an array with interpolated values at the indicated hour for each day
of the full time span indicated by given result_arr.
:param result_arr: template array indicating the full time range and additional dimensions to keep
:param means: dictionary containing 24 hourly averages for each month (12 x 24 values in total)
:param hour: integer of hour of interest
:param time_dim: name of temporal dimension
:param sampling: sampling rate to interpolate
:returns: array with interpolated averages in sampling resolution containing only values for hour of interest
"""
h_coll = xr.ones_like(result_arr) * np.nan
for month in means.keys():
hourly_mean_single_month = means[month].sel(hour=hour, drop=True)
h_coll = xr.where((h_coll[f"{time_dim}.month"] == month), hourly_mean_single_month, h_coll)
h_coll = h_coll.resample({time_dim: sampling}).interpolate()
h_coll = h_coll.sel({time_dim: (h_coll[f"{time_dim}.hour"] == hour)})
return h_coll
def create_seasonal_hourly_mean(self, data: xr.DataArray, time_dim: str, sel_opts: Dict[str, Any] = None,
sampling: str = "1H", as_anomaly: bool = True) -> xr.DataArray:
"""
Compute climatological statistics on hourly base either as raw data or anomalies. For each month, an overall
mean value (only used if requiring anomalies) and the mean of each hour are calculated. The climatological
diurnal cycle is positioned on the 16th of each month and interpolated in between by using a distinct
interpolation for each hour of day. The returned array therefore contains data with a yearly cycle (if anomaly
is not calculated) or data without a yearly cycle (if using anomalies). In both cases, the data have an
amplitude that varies over the year.
:param data: data to apply this method to
:param time_dim: name of temporal axis
:param sel_opts: specific selection options that are applied before calculation of climatological statistics
(default None)
:param sampling: temporal resolution of data (default "1H")
:param as_anomaly: specify whether to use anomalies or raw data including a seasonal cycle of the mean value
(default: True)
:returns: climatological statistics for given data interpolated with given sampling rate
"""
def create_seasonal_hourly_mean(self, data, sel_opts=None, sampling="1H", time_dim="datetime", as_anomaly=True):
"""Calculate hourly statistics. Either the absolute value or the anomaly (as_anomaly=True).""" """Calculate hourly statistics. Either the absolute value or the anomaly (as_anomaly=True)."""
# can only be used for hourly sampling rate # can only be used for hourly sampling rate
assert sampling == "1H" assert sampling == "1H"
...@@ -266,29 +299,18 @@ class ClimateFIRFilter: ...@@ -266,29 +299,18 @@ class ClimateFIRFilter:
# create unity xarray in monthly resolution with sampling point in mid of each month # create unity xarray in monthly resolution with sampling point in mid of each month
monthly = self.create_monthly_unity_array(data, time_dim) * np.nan monthly = self.create_monthly_unity_array(data, time_dim) * np.nan
seasonal_hourly_means = {} # calculate for each hour in each month a separate mean value
seasonal_hourly_means = self._compute_hourly_mean_per_month(data, time_dim, as_anomaly)
for month in data.groupby(f"{time_dim}.month").groups.keys():
# select each month
single_month_data = data.sel({time_dim: (data[f"{time_dim}.month"] == month)})
hourly_mean = single_month_data.groupby(f"{time_dim}.hour").mean()
if as_anomaly is True:
hourly_mean = hourly_mean - hourly_mean.mean("hour")
seasonal_hourly_means[month] = hourly_mean
# create seasonal cycles of these hourly averages
seasonal_coll = [] seasonal_coll = []
for hour in data.groupby(f"{time_dim}.hour").groups.keys(): for hour in data.groupby(f"{time_dim}.hour").groups.keys():
h_coll = monthly.__deepcopy__() mean_single_hour = self._create_seasonal_cycle_of_single_hour_mean(monthly, seasonal_hourly_means, hour,
for month in seasonal_hourly_means.keys(): time_dim, sampling)
hourly_mean_single_month = seasonal_hourly_means[month].sel(hour=hour, drop=True) seasonal_coll.append(mean_single_hour)
h_coll = xr.where((h_coll[f"{time_dim}.month"] == month),
hourly_mean_single_month,
h_coll)
h_coll = h_coll.resample({time_dim: sampling}).interpolate()
h_coll = h_coll.sel({time_dim: (h_coll[f"{time_dim}.hour"] == hour)})
seasonal_coll.append(h_coll)
hourly = xr.concat(seasonal_coll, time_dim).sortby(time_dim).resample({time_dim: sampling}).interpolate()
# combine all cycles in a common data array
hourly = xr.concat(seasonal_coll, time_dim).sortby(time_dim).resample({time_dim: sampling}).interpolate()
return hourly return hourly
@staticmethod @staticmethod
...@@ -383,7 +405,7 @@ class ClimateFIRFilter: ...@@ -383,7 +405,7 @@ class ClimateFIRFilter:
return filter_input_data return filter_input_data
def create_visualization(self, filtered, data, filter_input_data, plot_dates, time_dim, new_dim, sampling, extend_length_history, def create_visualization(self, filtered, data, filter_input_data, plot_dates, time_dim, new_dim, sampling, extend_length_history,
extend_length_future, minimum_length, h, variable_name): extend_length_future, minimum_length, h, variable_name): # pragma: no cover
plot_data = [] plot_data = []
for viz_date in set(plot_dates).intersection(filtered.coords[time_dim].values): for viz_date in set(plot_dates).intersection(filtered.coords[time_dim].values):
try: try:
...@@ -456,7 +478,7 @@ class ClimateFIRFilter: ...@@ -456,7 +478,7 @@ class ClimateFIRFilter:
# calculate apriori information from data if not given and extend its range if not sufficient long enough # calculate apriori information from data if not given and extend its range if not sufficient long enough
if apriori is None: if apriori is None:
apriori = self.create_monthly_mean(data, sel_opts=sel_opts, sampling=sampling, time_dim=time_dim) apriori = self.create_monthly_mean(data, time_dim, sel_opts=sel_opts, sampling=sampling)
apriori = apriori.astype(data.dtype) apriori = apriori.astype(data.dtype)
apriori = self.extend_apriori(data, apriori, time_dim, sampling, station_name=station_name) apriori = self.extend_apriori(data, apriori, time_dim, sampling, station_name=station_name)
......
...@@ -28,14 +28,16 @@ class TestClimateFIRFilter: ...@@ -28,14 +28,16 @@ class TestClimateFIRFilter:
def xr_array(self, data, time_dim): def xr_array(self, data, time_dim):
start = np.datetime64("2010-01-01 00:00") start = np.datetime64("2010-01-01 00:00")
time_index = [start + np.timedelta64(h, "h") for h in range(len(data))] time_index = [start + np.timedelta64(h, "h") for h in range(len(data))]
array = xr.DataArray(data, dims=time_dim, coords={time_dim: time_index}) array = xr.DataArray(data.reshape(len(data), 1), dims=[time_dim, "station"],
coords={time_dim: time_index, "station": ["DE266X"]})
return array return array
@pytest.fixture @pytest.fixture
def xr_array_long(self, data, time_dim): def xr_array_long(self, data, time_dim):
start = np.datetime64("2010-01-01 00:00") start = np.datetime64("2010-01-01 00:00")
time_index = [start + np.timedelta64(175 * h, "h") for h in range(len(data))] time_index = [start + np.timedelta64(175 * h, "h") for h in range(len(data))]
array = xr.DataArray(data, dims=time_dim, coords={time_dim: time_index}) array = xr.DataArray(data.reshape(len(data), 1), dims=[time_dim, "station"],
coords={time_dim: time_index, "station": ["DE266X"]})
return array return array
def test_combine_observation_and_apriori_no_new_dim(self, xr_array, time_dim): def test_combine_observation_and_apriori_no_new_dim(self, xr_array, time_dim):
...@@ -61,11 +63,12 @@ class TestClimateFIRFilter: ...@@ -61,11 +63,12 @@ class TestClimateFIRFilter:
assert xr.testing.assert_equal(first_entry.sel(window=range(1, 10)), apriori.sel({time_dim: date_pos})) is None assert xr.testing.assert_equal(first_entry.sel(window=range(1, 10)), apriori.sel({time_dim: date_pos})) is None
def test_shift_data(self, xr_array, time_dim): def test_shift_data(self, xr_array, time_dim):
remaining_dims = set(xr_array.dims).difference([time_dim])
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
index_values = range(-15, 1) index_values = range(-15, 1)
res = obj._shift_data(xr_array, index_values, time_dim, new_dim="window") res = obj._shift_data(xr_array, index_values, time_dim, new_dim="window")
assert len(res.dims) == 2 assert len(res.dims) == len(remaining_dims) + 2
assert len(set(res.dims).difference([time_dim, "window"])) == 0 assert len(set(res.dims).difference([time_dim, "window", *remaining_dims])) == 0
assert np.testing.assert_array_equal(res.coords["window"].values, np.arange(-15, 1)) is None assert np.testing.assert_array_equal(res.coords["window"].values, np.arange(-15, 1)) is None
sel = res.sel({time_dim: res.coords[time_dim].values[15]}) sel = res.sel({time_dim: res.coords[time_dim].values[15]})
assert sel.sel(window=-15).values == xr_array.sel({time_dim: xr_array.coords[time_dim].values[0]}).values assert sel.sel(window=-15).values == xr_array.sel({time_dim: xr_array.coords[time_dim].values[0]}).values
...@@ -135,8 +138,8 @@ class TestClimateFIRFilter: ...@@ -135,8 +138,8 @@ class TestClimateFIRFilter:
def test_create_monthly_mean(self, xr_array_long, time_dim): def test_create_monthly_mean(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
res = obj.create_monthly_mean(xr_array_long, time_dim=time_dim) res = obj.create_monthly_mean(xr_array_long, time_dim)
assert res.shape == (1462,) assert res.shape == (1462, 1)
assert np.datetime64("2008-12-16") == res.coords[time_dim][0].values assert np.datetime64("2008-12-16") == res.coords[time_dim][0].values
assert np.datetime64("2012-12-16") == res.coords[time_dim][-1].values assert np.datetime64("2012-12-16") == res.coords[time_dim][-1].values
mean_jan = xr_array_long[xr_array_long[f"{time_dim}.month"] == 1].mean() mean_jan = xr_array_long[xr_array_long[f"{time_dim}.month"] == 1].mean()
...@@ -148,10 +151,10 @@ class TestClimateFIRFilter: ...@@ -148,10 +151,10 @@ class TestClimateFIRFilter:
def test_create_monthly_mean_sampling(self, xr_array_long, time_dim): def test_create_monthly_mean_sampling(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
res = obj.create_monthly_mean(xr_array_long, time_dim=time_dim, sampling="1m") res = obj.create_monthly_mean(xr_array_long, time_dim, sampling="1m")
assert res.shape == (49,) assert res.shape == (49, 1)
res = obj.create_monthly_mean(xr_array_long, time_dim=time_dim, sampling="1H") res = obj.create_monthly_mean(xr_array_long, time_dim, sampling="1H")
assert res.shape == (35065,) assert res.shape == (35065, 1)
mean_jun = xr_array_long[xr_array_long[f"{time_dim}.month"] == 6].mean() mean_jun = xr_array_long[xr_array_long[f"{time_dim}.month"] == 6].mean()
assert res.sel({time_dim: "2010-06-15T00:00:00"}) == mean_jun assert res.sel({time_dim: "2010-06-15T00:00:00"}) == mean_jun
assert res.sel({time_dim: "2011-06-15T00:00:00"}) == mean_jun assert res.sel({time_dim: "2011-06-15T00:00:00"}) == mean_jun
...@@ -159,15 +162,57 @@ class TestClimateFIRFilter: ...@@ -159,15 +162,57 @@ class TestClimateFIRFilter:
def test_create_monthly_mean_sel_opts(self, xr_array_long, time_dim): def test_create_monthly_mean_sel_opts(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
sel_opts = {time_dim: slice("2010-05", "2010-08")} sel_opts = {time_dim: slice("2010-05", "2010-08")}
res = obj.create_monthly_mean(xr_array_long, time_dim=time_dim, sel_opts=sel_opts) res = obj.create_monthly_mean(xr_array_long, time_dim, sel_opts=sel_opts)
assert res.dropna(time_dim)[f"{time_dim}.month"].min() == 5 assert res.dropna(time_dim)[f"{time_dim}.month"].min() == 5
assert res.dropna(time_dim)[f"{time_dim}.month"].max() == 8 assert res.dropna(time_dim)[f"{time_dim}.month"].max() == 8
mean_jun_2010 = xr_array_long[xr_array_long[f"{time_dim}.month"] == 6].sel({time_dim: "2010"}).mean() mean_jun_2010 = xr_array_long[xr_array_long[f"{time_dim}.month"] == 6].sel({time_dim: "2010"}).mean()
assert res.sel({time_dim: "2010-06-15T00:00:00"}) == mean_jun_2010 assert res.sel({time_dim: "2010-06-15T00:00:00"}) == mean_jun_2010
def test_create_seasonal_hourly_mean(self): def test_compute_hourly_mean_per_month(self, xr_array_long, time_dim):
#Todo: stopped here obj = object.__new__(ClimateFIRFilter)
pass xr_array_long = xr_array_long.resample({time_dim: "1H"}).interpolate()
res = obj._compute_hourly_mean_per_month(xr_array_long, time_dim, True)
assert len(res.keys()) == 12
assert 6 in res.keys()
assert np.testing.assert_almost_equal(res[12].mean(), 0) is None
assert np.testing.assert_almost_equal(res[3].mean(), 0) is None
assert res[8].shape == (24, 1)
def test_compute_hourly_mean_per_month_no_anomaly(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter)
xr_array_long = xr_array_long.resample({time_dim: "1H"}).interpolate()
res = obj._compute_hourly_mean_per_month(xr_array_long, time_dim, False)
assert len(res.keys()) == 12
assert 9 in res.keys()
assert np.testing.assert_array_less(res[2], res[1]) is None
def test_create_seasonal_cycle_of_hourly_mean(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter)
xr_array_long = xr_array_long.resample({time_dim: "1H"}).interpolate()
monthly = obj.create_monthly_unity_array(xr_array_long, time_dim) * np.nan
seasonal_hourly_means = obj._compute_hourly_mean_per_month(xr_array_long, time_dim, True)
res = obj._create_seasonal_cycle_of_single_hour_mean(monthly, seasonal_hourly_means, 0, time_dim, "1h")
assert res[f"{time_dim}.hour"].sum() == 0
assert np.testing.assert_almost_equal(res.sel({time_dim: "2010-12-01"}), res.sel({time_dim: "2011-12-01"})) is None
res = obj._create_seasonal_cycle_of_single_hour_mean(monthly, seasonal_hourly_means, 13, time_dim, "1h")
assert res[f"{time_dim}.hour"].mean() == 13
assert np.testing.assert_almost_equal(res.sel({time_dim: "2010-12-01"}), res.sel({time_dim: "2011-12-01"})) is None
def test_create_seasonal_hourly_mean(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter)
xr_array_long = xr_array_long.resample({time_dim: "1H"}).interpolate()
res = obj.create_seasonal_hourly_mean(xr_array_long, time_dim)
assert len(set(res.dims).difference(xr_array_long.dims)) == 0
assert res.coords[time_dim][0] < xr_array_long.coords[time_dim][0]
assert res.coords[time_dim][-1] > xr_array_long.coords[time_dim][-1]
def test_create_seasonal_hourly_mean_sel_opts(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter)
xr_array_long = xr_array_long.resample({time_dim: "1H"}).interpolate()
sel_opts = {time_dim: slice("2010-05", "2010-08")}
res = obj.create_seasonal_hourly_mean(xr_array_long, time_dim, sel_opts=sel_opts)
assert res.dropna(time_dim)[f"{time_dim}.month"].min() == 5
assert res.dropna(time_dim)[f"{time_dim}.month"].max() == 8
def test_create_unity_array(self, xr_array, time_dim): def test_create_unity_array(self, xr_array, time_dim):
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
...@@ -176,12 +221,12 @@ class TestClimateFIRFilter: ...@@ -176,12 +221,12 @@ class TestClimateFIRFilter:
assert np.datetime64("2011-01-16") == res.coords[time_dim][-1].values assert np.datetime64("2011-01-16") == res.coords[time_dim][-1].values
assert res.max() == res.min() assert res.max() == res.min()
assert res.max() == 1 assert res.max() == 1
assert res.shape == (26,) assert res.shape == (26, 1)
res = obj.create_monthly_unity_array(xr_array, time_dim, extend_range=0) res = obj.create_monthly_unity_array(xr_array, time_dim, extend_range=0)
assert res.shape == (1,) assert res.shape == (1, 1)
assert np.datetime64("2010-01-16") == res.coords[time_dim][0].values assert np.datetime64("2010-01-16") == res.coords[time_dim][0].values
res = obj.create_monthly_unity_array(xr_array, time_dim, extend_range=28) res = obj.create_monthly_unity_array(xr_array, time_dim, extend_range=28)
assert res.shape == (3,) assert res.shape == (3, 1)
def test_extend_apriori_at_end(self, xr_array_long, time_dim): def test_extend_apriori_at_end(self, xr_array_long, time_dim):
obj = object.__new__(ClimateFIRFilter) obj = object.__new__(ClimateFIRFilter)
...@@ -221,6 +266,15 @@ class TestClimateFIRFilter: ...@@ -221,6 +266,15 @@ class TestClimateFIRFilter:
assert res.stop == np.datetime64("1993-01-01T01:00:00") assert res.stop == np.datetime64("1993-01-01T01:00:00")
assert res.step is None assert res.step is None
def test_properties(self):
obj = object.__new__(ClimateFIRFilter)
obj._h = [1, 2, 3]
obj._filtered = [4, 5, 63]
obj._apriori = [10, 11, 12, 13]
assert obj.filter_coefficients == [1, 2, 3]
assert obj.filtered_data == [4, 5, 63]
assert obj.apriori_data == [10, 11, 12, 13]
assert obj.initial_apriori_data == 10
class TestFirwinKzf: class TestFirwinKzf:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment