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

add pvlib clearsky filter test in analysis chain #441

Open
wants to merge 11 commits into
base: development
Choose a base branch
from
1 change: 1 addition & 0 deletions docs/sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
RdTools Change Log
==================
.. include:: changelog/pending.rst
.. include:: changelog/v3.0.0-beta.0.rst
.. include:: changelog/v2.2.0-beta.2.rst
.. include:: changelog/v2.2.0-beta.1.rst
Expand Down
26 changes: 26 additions & 0 deletions docs/sphinx/source/changelog/pending.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
**************************
v3.0.0 (December XX, 2024)
**************************

Enhancements
------------
* Add `CITATION.cff` file for citation information (:pull:`434`)
* Added checks to TrendAnalysis for `filter_params` and `filter_params_aggregated`. Raises an error if unkown filter is supplied. (:pull:`436`)


Bug fixes
---------
* Set marker linewidth to zero in `rdtools.plotting.degradation_summary_plots` (:pull:`433`)
* Fix `energy_from_power`` returns incorrect index for shifted hourly data (:issue:`370`, :pull:`437`)
* Add warning to clearsky workflow when power_expected is passed by user (:pull:`439`)


Requirements
------------
* Updated tornado==6.4.2 in ``notebook_requirements.txt`` (:pull:`438`)


Tests
-----
* Add tests for pvlib clearsky fiter in analysis chain (:pull:`441`)

2 changes: 1 addition & 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,7 @@ 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`)

Bug fixes
---------
Expand Down
2 changes: 1 addition & 1 deletion rdtools/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def pvlib_clearsky_filter(
Plane of array irradiance based on measurments
poa_global_clearsky : pandas.Series
Plane of array irradiance based on a clear sky model
window_length : int, default 10
window_length : int, default 90
Length of sliding time window in minutes. Must be greater than 2
periods.
mean_diff : float, default 75
Expand Down
96 changes: 91 additions & 5 deletions rdtools/test/analysis_chains_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,59 @@ def sensor_analysis_aggregated_no_filter(sensor_parameters):
return rd_analysis


@pytest.fixture
def clearsky_example_data(basic_parameters):
# Import the example data
file_url = (
"https://datahub.duramat.org/dataset/"
"a49bb656-7b36-437a-8089-1870a40c2a7d/"
"resource/d2c3fcf4-4f5f-47ad-8743-fc29"
"f1356835/download/pvdaq_system_4_2010"
"-2016_subset_soil_signal.csv"
)
cache_file = "PVDAQ_system_4_2010-2016_subset_soilsignal.pickle"

try:
df = pd.read_pickle(cache_file)
except FileNotFoundError:
df = pd.read_csv(file_url, index_col=0, parse_dates=True)
df.to_pickle(cache_file)

# Specify the Metadata
meta = {
"latitude": 39.7406,
"longitude": -105.1774,
"timezone": "Etc/GMT+7",
"gamma_pdc": -0.005,
"azimuth": 180,
"tilt": 40,
"power_dc_rated": 1000.0,
"temp_model_params": "open_rack_glass_polymer",
}

# Set the timezone
df.index = df.index.tz_localize(meta["timezone"])

# Select two years of data
df_crop = df[df.index < (df.index[0] + pd.Timedelta(days=2 * 365 + 1))]

basic_parameters["pv"] = df_crop["ac_power"]
basic_parameters["poa_global"] = df_crop["poa_irradiance"]
basic_parameters["temperature_ambient"] = df_crop["ambient_temp"]
basic_parameters["interp_freq"] = "1min"

# Set the pvlib location
loc = pvlib.location.Location(meta["latitude"], meta["longitude"], tz=meta["timezone"])

cs_input = dict(
pvlib_location=loc,
pv_tilt=meta["tilt"],
pv_azimuth=meta["azimuth"],
solar_position_method="ephemeris", # just to improve test execution speed
)
return basic_parameters, cs_input


def test_interpolation(basic_parameters, degradation_trend):

power = degradation_trend
Expand Down Expand Up @@ -436,9 +489,7 @@ def test_no_gamma_pdc(sensor_parameters):


@pytest.fixture
def clearsky_parameters(
basic_parameters, sensor_parameters, cs_input, degradation_trend
):
def clearsky_parameters(basic_parameters, sensor_parameters, cs_input, degradation_trend):
# clear-sky weather data. Uses TrendAnalysis's internal clear-sky
# functions to generate the data.
rd_analysis = TrendAnalysis(**sensor_parameters)
Expand All @@ -461,6 +512,16 @@ def clearsky_analysis(cs_input, clearsky_parameters):
return rd_analysis


@pytest.fixture
def clearsky_pvlib_analysis(clearsky_example_data):
clearsky_parameters_example, cs_input_example = clearsky_example_data
rd_analysis = TrendAnalysis(**clearsky_parameters_example)
rd_analysis.set_clearsky(**cs_input_example)
rd_analysis.filter_params["clearsky_filter"] = {"model": "pvlib"}
rd_analysis.clearsky_analysis(analyses=["yoy_degradation"])
return rd_analysis


@pytest.fixture
def clearsky_optional(cs_input, clearsky_analysis):
# optional parameters to exercise other branches
Expand All @@ -486,15 +547,33 @@ def sensor_clearsky_analysis(cs_input, clearsky_parameters):
return rd_analysis


@pytest.fixture
def sensor_clearsky_pvlib_analysis(clearsky_example_data):
clearsky_parameters_example, cs_input_example = clearsky_example_data
rd_analysis = TrendAnalysis(**clearsky_parameters_example)
rd_analysis.set_clearsky(**cs_input_example)
rd_analysis.filter_params = {} # disable all index-based filters
rd_analysis.filter_params["sensor_clearsky_filter"] = {"model": "pvlib"}
rd_analysis.sensor_analysis(analyses=["yoy_degradation"])
return rd_analysis


def test_clearsky_analysis(clearsky_analysis):
yoy_results = clearsky_analysis.results["clearsky"]["yoy_degradation"]
ci = yoy_results["rd_confidence_interval"]
rd = yoy_results["p50_rd"]
print(ci)
assert pytest.approx(rd, abs=1e-2) == -5.15
assert pytest.approx(ci, abs=1e-2) == [-5.17, -5.13]


def test_clearsky_pvlib_analysis(clearsky_pvlib_analysis):
yoy_results = clearsky_pvlib_analysis.results["clearsky"]["yoy_degradation"]
ci = yoy_results["rd_confidence_interval"]
rd = yoy_results["p50_rd"]
assert pytest.approx(rd, abs=1e-2) == -1.589
assert pytest.approx(ci, abs=1e-2) == [-2.417, -0.861]


def test_clearsky_analysis_filter_components(clearsky_analysis):
columns = clearsky_analysis.clearsky_filter_components_aggregated.columns
assert {'two_way_window_filter'} == set(columns)
Expand Down Expand Up @@ -523,11 +602,18 @@ def test_sensor_clearsky_analysis(sensor_clearsky_analysis):
yoy_results = sensor_clearsky_analysis.results["sensor"]["yoy_degradation"]
ci = yoy_results["rd_confidence_interval"]
rd = yoy_results["p50_rd"]
print(ci)
assert -5.18 == pytest.approx(rd, abs=1e-2)
assert [-5.18, -5.18] == pytest.approx(ci, abs=1e-2)


def test_sensor_clearsky_pvlib_analysis(sensor_clearsky_pvlib_analysis):
yoy_results = sensor_clearsky_pvlib_analysis.results["sensor"]["yoy_degradation"]
ci = yoy_results["rd_confidence_interval"]
rd = yoy_results["p50_rd"]
assert -1.478 == pytest.approx(rd, abs=1e-2)
assert [-2.495, -0.649] == pytest.approx(ci, abs=1e-2)


@pytest.fixture
def clearsky_analysis_exp_power(clearsky_parameters, clearsky_optional):
power_expected = normalization.pvwatts_dc_power(
Expand Down
Loading