Skip to content
3 changes: 2 additions & 1 deletion docs/sphinx/source/changelog/v3.0.0-beta.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ Enhancements
* Added codecov.yml configuration file (:pull:`420`)
* Availability module no longer considered experimental (:pull:`429`)
* Add capability to seed the CircularBlockBootstrap (:pull:`429`)
* Allow sub-daily aggregation in :py:func:`~rdtools.degradation.degradation_year_on_year` (:pull:`390`)
* Allow sub-daily aggregation in :py:func:`~rdtools.degradation.degradation_year_on_year` (:pull:`390`)
* Added checks to TrendAnalysis for `filter_params` and `filter_params_aggregated`. Raises an error if unkown filter is supplied. (:pull:`436`)
Comment thread
martin-springer marked this conversation as resolved.
Outdated

Bug fixes
---------
Expand Down
89 changes: 85 additions & 4 deletions rdtools/analysis_chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,23 +155,80 @@ def __init__(
self.max_timedelta = max_timedelta
self.results = {}

# Initialize to use default filter parameters
self.filter_params = {
# Define valid filter parameters
self.valid_filter_params = [
"normalized_filter",
"poa_filter",
"tcell_filter",
"clip_filter",
"hour_angle_filter",
"clearsky_filter",
"sensor_clearsky_filter",
"ad_hoc_filter",
]

self.valid_filter_params_aggregated = [
"two_way_window_filter",
"insolation_filter",
"hampel_filter",
"directional_tukey_filter",
"ad_hoc_filter",
]

# Define default filter parameters
self.default_filter_params = {
"normalized_filter": {},
"poa_filter": {},
"tcell_filter": {},
"clip_filter": {},
"clearsky_filter": {},
"ad_hoc_filter": None, # use this to include an explict filter
}
self.filter_params_aggregated = {

self.default_filter_params_aggregated = {
"two_way_window_filter": {},
"ad_hoc_filter": None
"ad_hoc_filter": None,
}

# Initialize to use default filter parameters
self._filter_params = ValidatedFilterDict(
self.valid_filter_params, self.default_filter_params
)
self._filter_params_aggregated = ValidatedFilterDict(
self.valid_filter_params_aggregated, self.default_filter_params_aggregated
)
# remove tcell_filter from list if power_expected is passed in
if power_expected is not None and temperature_cell is None:
del self.filter_params["tcell_filter"]

@property
def filter_params(self):
return self._filter_params

@filter_params.setter
def filter_params(self, new_filter_params):
if not isinstance(new_filter_params, dict):
raise ValueError("Attribute `filter_params` must be a dictionary.")

# If dictionary passed, check the new filter_params and set new filters.
self._filter_params = ValidatedFilterDict(self.valid_filter_params, new_filter_params)
print(f"Attribute `filter_params` changed to: {new_filter_params}")

@property
def filter_params_aggregated(self):
return self._filter_params_aggregated

@filter_params_aggregated.setter
def filter_params_aggregated(self, new_filter_params_aggregated):
if not (isinstance(new_filter_params_aggregated, dict) or None):
raise ValueError("Attribute `filter_params_aggregated` must be a dictionary.")

# If dictionary passed, check the new filter_params and set new filters.
self._filter_params_aggregated = ValidatedFilterDict(
self.valid_filter_params_aggregated, new_filter_params_aggregated
)
print(f"Attribute `filter_params_aggregated` changed to: {new_filter_params_aggregated}")

def set_clearsky(
self,
pvlib_location=None,
Expand Down Expand Up @@ -1205,3 +1262,27 @@ def plot_degradation_timeseries(self, case, rolling_days=365, **kwargs):

fig = plotting.degradation_timeseries_plot(yoy_info, rolling_days, **kwargs)
return fig


class ValidatedFilterDict(dict):
def __init__(self, valid_keys, *args, **kwargs):
self.valid_keys = valid_keys
self._err_msg = "Key '{0}' is not a valid filter parameters."
super(ValidatedFilterDict, self).__init__(*args, **kwargs)
self._validate_keys()

def __setitem__(self, key, value):
if key not in self.valid_keys:
raise KeyError(self._err_msg.format(key))
super(ValidatedFilterDict, self).__setitem__(key, value)

def update(self, *args, **kwargs):
for key in dict(*args, **kwargs).keys():
if key not in self.valid_keys:
raise KeyError(self._err_msg.format(key))
super(ValidatedFilterDict, self).update(*args, **kwargs)

def _validate_keys(self):
for key in self.keys():
if key not in self.valid_keys:
raise KeyError(self._err_msg.format(key))