Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
438e2f0
Initial instance of pytests for system_analysis. coverage: 70% for t…
cdeline Nov 14, 2019
b82cc53
Merge remote-tracking branch 'remotes/origin/model_chains' into model…
cdeline Jan 10, 2020
24474c9
Merge branch 'model_chains' into modelchain_pytests
cdeline Mar 10, 2020
aa844d6
Merge branch 'master' into development
mdeceglie Aug 18, 2020
1c01ac3
Merge remote-tracking branch 'remotes/origin/model_chains' into model…
cdeline Sep 2, 2020
8fb2889
rename system_analysis.py to analysis.py. Rename class to RdAnalysis.…
cdeline Sep 3, 2020
c2c37d6
Allow temp_model_params to either be string or dict with 'a','b', 'de…
cdeline Sep 3, 2020
4d84869
update calc_cell_temperature for pvlib > 0.6.3, use energy_normalized…
cdeline Sep 3, 2020
33fd244
Notebook example running
cdeline Sep 3, 2020
8b9b029
Remove empty cells from notebook
cdeline Sep 3, 2020
0ef396b
Rename system_analysis_test.py. test_sensor_analysis working
cdeline Sep 3, 2020
b68b809
clearsky test functional
cdeline Sep 3, 2020
927ad13
Warn if temp coefficient not passed into normalize_with_Pvwatts inste…
cdeline Sep 3, 2020
4ae5c00
SRR soiling analysis pytest
cdeline Sep 3, 2020
a9211d8
Add tables=3.6.1 to requirements.txt to allow clearsky analysis
cdeline Sep 4, 2020
632b222
add tables to setup.py since it appears to be a required pvlib for th…
cdeline Sep 4, 2020
498b8f1
Test fixture attempt - Failing (analysis_test.test_srr_soiling_fixture)
cdeline Sep 4, 2020
17f208a
Coverage increase to 83%. Figured out test fixtures kinda
cdeline Sep 4, 2020
2840311
Test coverage 93%
cdeline Sep 4, 2020
9bc0e99
Test coverage 95%. Include tests for some error messages
cdeline Sep 4, 2020
d7677fa
Add RdAnalysis notebook for pvdaq4 system
cdeline Sep 4, 2020
5552f29
Sphinx API updates
cdeline Sep 8, 2020
243d2e8
Updated SRR example for pvdaq4
cdeline Sep 14, 2020
63e7fa9
Add nameplate rating as input to runRdAnalysis()
cdeline Sep 17, 2020
d0f40bb
Update pvdaq4 examples to run on the synthetic soiling * power data.
cdeline Sep 17, 2020
ce1bf2d
notebook font change on one documentation block
cdeline Sep 17, 2020
feac3c0
add max_timedelta=15T to pvdaq4 notebook example interpolation
cdeline Sep 21, 2020
b4f0bed
Merge remote-tracking branch 'remotes/origin/development' into modelc…
cdeline Sep 21, 2020
f896bc6
Sphinx release notes for 2.1.0 updated
cdeline Sep 22, 2020
0380aeb
Change pvlib version check with exception handling per @kanderson-nre…
cdeline Sep 23, 2020
dc6d77f
Update sphinx references, including :meth: update and specific analys…
cdeline Sep 23, 2020
9ad5225
remove unused lines in analysis_test.py
cdeline Sep 23, 2020
7205658
Make test1 and test2 consistent in test_clearsky_analysis_fixture by …
cdeline Sep 23, 2020
073d1ea
Squashed commit of the following:
cdeline Sep 24, 2020
55f7b9a
Update docs/sphinx/source/changelog/v2.1.0.rst
cdeline Sep 24, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
723 changes: 723 additions & 0 deletions docs/RdAnalysis_example.ipynb

Large diffs are not rendered by default.

778 changes: 778 additions & 0 deletions docs/RdAnalysis_example_pvdaq4.ipynb

Large diffs are not rendered by default.

753 changes: 0 additions & 753 deletions docs/SystemAnalysis_example.ipynb

This file was deleted.

2 changes: 1 addition & 1 deletion docs/degradation_and_soiling_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
"version": "3.7.4"
}
},
"nbformat": 4,
Expand Down
250 changes: 162 additions & 88 deletions docs/degradation_and_soiling_example_pvdaq_4.ipynb

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ analysis workflow.
.. autosummary::
:toctree: generated/

analysis
degradation
soiling
filtering
Expand All @@ -22,7 +23,24 @@ analysis workflow.
clearsky_temperature
plotting

Analysis
===========

Conduct end-to-end Degradation and Soiling analysis with sensor_analysis or clearsky_analysis

.. autosummary::
:toctree: generated/

analysis.RdAnalysis
analysis.RdAnalysis.sensor_analysis
analysis.RdAnalysis.clearsky_analysis
analysis.RdAnalysis.plot_degradation_summary
analysis.RdAnalysis.plot_soiling_rate_histogram
analysis.RdAnalysis.plot_soiling_interval
analysis.RdAnalysis.plot_soiling_monte_carlo
analysis.RdAnalysis.plot_pv_vs_irradiance


Degradation
===========

Expand Down
2 changes: 2 additions & 0 deletions docs/sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
RdTools Change Log
==================

.. include:: changelog/v2.1.0.rst
.. include:: changelog/v2.0.0b0.rst

54 changes: 54 additions & 0 deletions docs/sphinx/source/changelog/v2.1.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
**************************
v2.1.0 (October XX, 2020)
**************************

API Changes
-----------
* Add :py:class:`~rdtools.analysis.RdAnalysis` class for single-line analysis. (:pull:`117`).


Enhancements
------------
* Add new :py:mod:`~rdtools.analysis` module to focus on single-line analysis workflow
(:pull:`117`).
* Add :py:class:`~rdtools.analysis.RdAnalysis` class for single-line analysis.
Degradataion analysis is run by :py:meth:`~rdtools.analysis.RdAnalysis.sensor_analysis`
and :py:meth:`~rdtools.analysis.RdAnalysis.clearsky_analysis`. Soiling analysis
is run by including 'srr_soiling' option when calling
:py:meth:`~rdtools.analysis.RdAnalysis.sensor_analysis` (:pull:`117`).


Bug fixes
---------


Testing
-------
* Complete testing for functions and plotting of :py:mod:`~rdtools.analysis` module (:pull:`196`).


Documentation
-------------
* :py:class:`~rdtools.analysis.RdAnalysis` docstrings (:pull:`117`).


Requirements
------------
* tables=3.6.1 now added to requirements.txt and setup.py (:pull:`196`).

Example Updates
---------------
* New example notebook based on PVDAQ system #4 for the new :py:class:`~rdtools.analysis.RdAnalysis`
analysis workflow (:pull:`196`).
* Update the standard PVDAQ system #4 workbook to match best practice, including
`pvlib.get_total_irradiance()` and `max_timedelta = '15T'` in rdtools.interpolate (:pull:`196`).
* Update the standard PVDAQ system #4 workbook to include a single `soiling * ac_power`
analysis (:pull:`196`).


Contributors
------------
* Mike Deceglie (:ghuser:`mdeceglie`)
* Kevin Anderson (:ghuser:`kanderso-nrel`)
* Chris Deline (:ghuser:`cdeline`)

2 changes: 1 addition & 1 deletion rdtools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from rdtools.filtering import clip_filter
from rdtools.filtering import normalized_filter
from rdtools.soiling import soiling_srr
from rdtools.system_analysis import SystemAnalysis
from rdtools.analysis import RdAnalysis
from rdtools.plotting import degradation_summary_plots
from rdtools.plotting import soiling_monte_carlo_plot
from rdtools.plotting import soiling_interval_plot
Expand Down
98 changes: 51 additions & 47 deletions rdtools/system_analysis.py → rdtools/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from . import normalization
from . import filtering
from . import aggregation
from . import degradation
from . import soiling
from . import clearsky_temperature
from . import plotting
from rdtools import normalization, filtering, aggregation, degradation
from rdtools import soiling, clearsky_temperature, plotting


class SystemAnalysis():

class RdAnalysis():
'''
Class for end-to-end analysis
Class for end-to-end degradation and soiling analysis using :py:meth:`~rdtools.RdAnalysis.sensor_analysis`
or :py:meth:`~rdtools.RdAnalysis.clearsky_analysis`

Parameters
----------
Expand Down Expand Up @@ -207,27 +204,32 @@ def calc_cell_temperature(self, poa, windspeed, ambient_temperature):
numeric
calculated cell temperature
'''
if self.temperature_model is None:
cell_temp = pvlib.pvsystem.sapm_celltemp(poa_global=poa,
wind_speed=windspeed,
temp_air=ambient_temperature)
else:
#pvlib 0.7+
try:
model_params = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][self.temperature_model]
cell_temp = pvlib.temperature.sapm_cell(poa_global=poa,
temp_air=ambient_temperature,
wind_speed=windspeed,
a=model_params['a'],
b=model_params['b'],
deltaT=model_params['deltaT']
)
except: #pvlib < 0.7
cell_temp = pvlib.pvsystem.sapm_celltemp(poa_global=poa, wind_speed=windspeed,
temp_air=ambient_temperature,
model=self.temperature_model)
cell_temp = cell_temp['temp_cell']

try: # workflow for pvlib >= 0.7

if self.temperature_model is None:
self.temperature_model = "open_rack_glass_polymer" # default

# check if self.temperature_model is a string or dict with keys 'a', 'b' and 'deltaT'
if isinstance(self.temperature_model,str):
model_params = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][self.temperature_model]
elif (isinstance(self.temperature_model,dict) &
('a' in self.temperature_model) &
('b' in self.temperature_model) &
('deltaT' in self.temperature_model)):
model_params = self.temperature_model
else:
raise Exception('pvlib temperature_model entry is neither '
'a string nor a dictionary with correct '
'entries. Try "open_rack_glass_polymer"')
cell_temp = pvlib.temperature.sapm_cell(poa_global=poa,
temp_air=ambient_temperature,
wind_speed=windspeed,
**model_params
)
except AttributeError as e:
print('Error: PVLib > 0.7 required')
raise e
return cell_temp

def calc_clearsky_tamb(self):
Expand Down Expand Up @@ -261,6 +263,7 @@ def pvwatts_norm(self, poa, cell_temperature):
pandas.Series
Associated insolation
'''
import warnings
if self.pv_nameplate is None:
renorm = True
pv_nameplate = 1.0
Expand All @@ -269,26 +272,27 @@ def pvwatts_norm(self, poa, cell_temperature):
pv_nameplate = self.pv_nameplate

if self.temperature_coefficient is None:
raise ValueError('Temperature coeffcient must be available to perform pvwatts_norm')

#raise ValueError('Temperature coefficient must be available to perform pvwatts_norm')
warnings.warn('Temperature coefficient not passed in to RdAnalysis'
'. No temperature correction will be conducted.')
pvwatts_kws = {"poa_global": poa,
"P_ref": pv_nameplate,
"T_cell": cell_temperature,
"G_ref": 1000,
"T_ref": 25,
"power_dc_rated": pv_nameplate,
"temperature_cell": cell_temperature,
"poa_global_ref": 1000,
"temperature_cell_ref": 25,
"gamma_pdc": self.temperature_coefficient}

normalized, insolation = normalization.normalize_with_pvwatts(self.pv_energy, pvwatts_kws)
energy_normalized, insolation = normalization.normalize_with_pvwatts(self.pv_energy, pvwatts_kws)

if renorm:
# Normalize to the 95th percentile for convenience, this is renormalized out
# in the calculations but is relevant to normalized_filter()
x = normalized[np.isfinite(normalized)]
normalized = normalized / x.quantile(0.95)
x = energy_normalized[np.isfinite(energy_normalized)]
energy_normalized = energy_normalized / x.quantile(0.95)

return normalized, insolation
return energy_normalized, insolation

def filter(self, normalized, case):
def filter(self, energy_normalized, case):
'''
Calculate filters based on those in rdtools.filtering. Uses
self.filter_params, which is a dict, the keys of which are names of
Expand All @@ -298,7 +302,7 @@ def filter(self, normalized, case):

Parameters
----------
normalized : pandas.Series
energy_normalized : pandas.Series
Time series of normalized PV energy
case : str
'sensor' or 'clearsky' which filtering protocol to apply. Affects
Expand All @@ -319,7 +323,7 @@ def filter(self, normalized, case):
cell_temp = self.clearsky_cell_temperature

if 'normalized_filter' in self.filter_params.keys():
f = filtering.normalized_filter(normalized, **self.filter_params['normalized_filter'])
f = filtering.normalized_filter(energy_normalized, **self.filter_params['normalized_filter'])
bool_filter = bool_filter & f
if 'poa_filter' in self.filter_params.keys():
if poa is None:
Expand Down Expand Up @@ -351,7 +355,7 @@ def filter(self, normalized, case):
elif case == 'clearsky':
self.clearsky_filter = bool_filter

def aggregate(self, normalized, insolation):
def aggregate(self, energy_normalized, insolation):
'''
Return insolation-weighted normalized PV energy and the associated aggregated insolation

Expand All @@ -369,7 +373,7 @@ def aggregate(self, normalized, insolation):
pandas.Series
Aggregated insolation
'''
aggregated = aggregation.aggregation_insol(normalized, insolation, self.aggregation_freq)
aggregated = aggregation.aggregation_insol(energy_normalized, insolation, self.aggregation_freq)
aggregated_insolation = insolation.resample(self.aggregation_freq).sum()

return aggregated, aggregated_insolation
Expand Down Expand Up @@ -453,9 +457,9 @@ def sensor_preprocess(self):
raise ValueError('either cell or ambient temperature must be available to perform sensor_preprocess')
if self.cell_temperature is None:
self.cell_temperature = self.calc_cell_temperature(self.poa, self.windspeed, self.ambient_temperature)
normalized, insolation = self.pvwatts_norm(self.poa, self.cell_temperature)
self.filter(normalized, 'sensor')
aggregated, aggregated_insolation = self.aggregate(normalized[self.sensor_filter], insolation[self.sensor_filter])
energy_normalized, insolation = self.pvwatts_norm(self.poa, self.cell_temperature)
self.filter(energy_normalized, 'sensor')
aggregated, aggregated_insolation = self.aggregate(energy_normalized[self.sensor_filter], insolation[self.sensor_filter])
self.sensor_aggregated_performance = aggregated
self.sensor_aggregated_insolation = aggregated_insolation

Expand Down
Loading