Skip to content

Commit

Permalink
Fix/issue 205 (#207)
Browse files Browse the repository at this point in the history
* Clean up debugging cell in notebook

* Update annual_soiling_ratios

* Run example notebook with new calculation

* Update tests

* update changelog

* pin nbconvert version

* consolidate changelog entries

* adjust docstring

* typo

* Handle overlap between insolation and soiling profiles

* fix typos

* ensure insolation sum is correct in normalization for monte carlo

* bump nbsphinx version

* Run notebooks

* get rid of print statements

* Explicitly test warning message
  • Loading branch information
mdeceglie authored Oct 8, 2020
1 parent 1cb2a08 commit e85ed0a
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 123 deletions.
59 changes: 33 additions & 26 deletions docs/degradation_and_soiling_example.ipynb

Large diffs are not rendered by default.

116 changes: 43 additions & 73 deletions docs/degradation_and_soiling_example_pvdaq_4.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -616,37 +616,6 @@
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 2010-02-25 00:00:00-07:00\n",
"1 2010-03-08 00:00:00-07:00\n",
"2 2010-03-12 00:00:00-07:00\n",
"3 2010-04-09 00:00:00-07:00\n",
"4 2010-04-12 00:00:00-07:00\n",
" ... \n",
"59 2016-04-10 00:00:00-07:00\n",
"60 2016-04-16 00:00:00-07:00\n",
"61 2016-05-04 00:00:00-07:00\n",
"62 2016-07-13 00:00:00-07:00\n",
"63 2016-12-06 00:00:00-07:00\n",
"Name: start, Length: 64, dtype: datetime64[ns, Etc/GMT+7]"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"soiling_summary['start']"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
Expand All @@ -673,7 +642,7 @@
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 18,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -835,7 +804,7 @@
"11 6 "
]
},
"execution_count": 19,
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -848,7 +817,7 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 19,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -882,81 +851,82 @@
" <tr>\n",
" <th>0</th>\n",
" <td>2010</td>\n",
" <td>0.975022</td>\n",
" <td>0.934111</td>\n",
" <td>0.992382</td>\n",
" <td>0.963661</td>\n",
" <td>0.951828</td>\n",
" <td>0.971463</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2011</td>\n",
" <td>0.958594</td>\n",
" <td>0.872132</td>\n",
" <td>0.984363</td>\n",
" <td>0.944819</td>\n",
" <td>0.936342</td>\n",
" <td>0.950665</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2012</td>\n",
" <td>0.945495</td>\n",
" <td>0.867414</td>\n",
" <td>0.989819</td>\n",
" <td>0.939456</td>\n",
" <td>0.931768</td>\n",
" <td>0.945988</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2013</td>\n",
" <td>0.957287</td>\n",
" <td>0.906841</td>\n",
" <td>0.987823</td>\n",
" <td>0.954258</td>\n",
" <td>0.944068</td>\n",
" <td>0.961534</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2014</td>\n",
" <td>0.959787</td>\n",
" <td>0.902334</td>\n",
" <td>0.991943</td>\n",
" <td>0.950645</td>\n",
" <td>0.929716</td>\n",
" <td>0.966537</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2015</td>\n",
" <td>0.959014</td>\n",
" <td>0.899179</td>\n",
" <td>0.985713</td>\n",
" <td>0.951059</td>\n",
" <td>0.921407</td>\n",
" <td>0.966395</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>2016</td>\n",
" <td>0.964605</td>\n",
" <td>0.842394</td>\n",
" <td>0.987011</td>\n",
" <td>0.937259</td>\n",
" <td>0.925394</td>\n",
" <td>0.944943</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" year soiling_ratio_median soiling_ratio_low soiling_ratio_high\n",
"0 2010 0.975022 0.934111 0.992382\n",
"1 2011 0.958594 0.872132 0.984363\n",
"2 2012 0.945495 0.867414 0.989819\n",
"3 2013 0.957287 0.906841 0.987823\n",
"4 2014 0.959787 0.902334 0.991943\n",
"5 2015 0.959014 0.899179 0.985713\n",
"6 2016 0.964605 0.842394 0.987011"
"0 2010 0.963661 0.951828 0.971463\n",
"1 2011 0.944819 0.936342 0.950665\n",
"2 2012 0.939456 0.931768 0.945988\n",
"3 2013 0.954258 0.944068 0.961534\n",
"4 2014 0.950645 0.929716 0.966537\n",
"5 2015 0.951059 0.921407 0.966395\n",
"6 2016 0.937259 0.925394 0.944943"
]
},
"execution_count": 20,
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Calculate and view annual soiling ratios and their confidence intervals\n",
"# based on the Monte Carlo simulation. Note that these losses include the\n",
"# Calculate and view annual insolation-weighted soiling ratios and their confidence\n",
"# intervals based on the Monte Carlo simulation. Note that these losses include the\n",
"# assumptions of the cleaning assumptions associated with the method parameter\n",
"# of rdtools.soiling_srr(). For anything but 'perfect_clean', each year's soiling\n",
"# ratio may be impacted by prior years' soiling profiles. The default behavior of\n",
"# rdtools.soiling_srr uses method='half_norm_clean'\n",
"\n",
"rdtools.annual_soiling_ratios(soiling_info['stochastic_soiling_profiles'],\n",
" daily_insolation,\n",
" confidence_level=cl)"
]
},
Expand Down Expand Up @@ -985,7 +955,7 @@
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -1018,7 +988,7 @@
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -1049,7 +1019,7 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -1075,7 +1045,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -1093,7 +1063,7 @@
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 24,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -1140,7 +1110,7 @@
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 25,
"metadata": {},
"outputs": [
{
Expand All @@ -1150,7 +1120,7 @@
"<Figure size 720x216 with 2 Axes>"
]
},
"execution_count": 26,
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -1178,7 +1148,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
"version": "3.7.9"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/changelog/pending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Enhancements
------------

* Add new function :py:func:`~rdtools.soiling.monthly_soiling_rates` (:pull:`193`).
* Add new function :py:func:`~rdtools.annual_soiling_ratios` (:pull:`193`).
* Add new function :py:func:`~rdtools.annual_soiling_ratios` (:pull:`193`, :pull:`207`).
* Create new module :py:mod:`~rdtools.availability` and class
:py:class:`~rdtools.availability.AvailabilityAanlysis` for estimating
timeseries system availability (:pull:`131`)
Expand Down
37 changes: 28 additions & 9 deletions rdtools/soiling.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'''Functions for calculating soiling metrics from photovoltaic system data.'''

import warnings
import pandas as pd
import numpy as np
from scipy.stats.mstats import theilslopes
Expand Down Expand Up @@ -273,7 +274,7 @@ def _calc_result_df(self, trim=False, max_relative_slope_error=500.0,
results.next_inferred_start_loss - results.inferred_end_loss,
0, 1)

# Don't consider data outside of first and last valid interverals
# Don't consider data outside of first and last valid intervals
if len(results[results.valid]) == 0:
raise NoValidIntervalError('No valid soiling intervals were found')
new_start = results[results.valid].start.iloc[0]
Expand Down Expand Up @@ -443,7 +444,7 @@ def _calc_monte(self, monte, method='half_norm_clean'):

df_rand['soil_insol'] = df_rand.loss * df_rand.insol

monte_losses.append(df_rand.soil_insol.sum() / df_rand.insol.sum())
monte_losses.append(df_rand.soil_insol.sum() / df_rand.insol[~df_rand.soil_insol.isnull()].sum())
random_profile = df_rand['loss'].copy()
random_profile.name = 'stochastic_soiling_profile'
random_profiles.append(random_profile)
Expand Down Expand Up @@ -778,7 +779,7 @@ def _count_month_days(start, end):
return out_dict


def annual_soiling_ratios(stochastic_soiling_profiles, confidence_level=68.2):
def annual_soiling_ratios(stochastic_soiling_profiles, insolation_daily, confidence_level=68.2):
'''
Return annualized soiling ratios and associated confidence intervals based
on stochastic soiling profiles from SRR. Note that each year may be affected
Expand All @@ -791,7 +792,8 @@ def annual_soiling_ratios(stochastic_soiling_profiles, confidence_level=68.2):
List of pd.Series representing profile realizations from the SRR monte carlo.
Typically ``soiling_interval_summary['stochastic_soiling_profiles']`` obtained with
:py:func:`rdtools.soiling.soiling_srr` or :py:meth:`rdtools.soiling.SRRAnalysis.run`
insolation_daily : pd.Series
Daily plane-of-array insolation with DatetimeIndex. Arbitrary units.
confidence_level : float, default 68.2
The size of the confidence interval to use in determining the upper and lower
quantiles reported in the returned DataFrame. (The median is always included in
Expand Down Expand Up @@ -820,12 +822,29 @@ def annual_soiling_ratios(stochastic_soiling_profiles, confidence_level=68.2):
+------------------------+-------------------------------------------+
'''

all_profiles = pd.concat(stochastic_soiling_profiles)
annual_groups = all_profiles.groupby(all_profiles.index.year)
# Create a df with each realization as a column
all_profiles = pd.concat(stochastic_soiling_profiles, axis=1)
all_profiles = all_profiles.dropna()

if not all_profiles.index.isin(insolation_daily.index).all():
warnings.warn('The indexes of stochastic_soiling_profiles are not entirely contained '
'within the index of insolation_daily. Every day in stochastic_soiling_profiles '
'should be represented in insolation_daily. This may cause erroneous results.')

insolation_daily = insolation_daily.reindex(all_profiles.index)

# Weight each day by insolation
all_profiles_weighted = all_profiles.multiply(insolation_daily, axis=0)

# Compute the insolation-weighted soiling ratio (IWSR) for each realization
annual_insolation = insolation_daily.groupby(insolation_daily.index.year).sum()
all_annual_weighted_sums = all_profiles_weighted.groupby(all_profiles_weighted.index.year).sum()
all_annual_iwsr = all_annual_weighted_sums.multiply(1/annual_insolation, axis=0)

annual_soiling = pd.DataFrame({
'soiling_ratio_median': annual_groups.quantile(0.5),
'soiling_ratio_low': annual_groups.quantile(0.5 - confidence_level/2/100),
'soiling_ratio_high': annual_groups.quantile(0.5 + confidence_level/2/100),
'soiling_ratio_median': all_annual_iwsr.quantile(0.5, axis=1),
'soiling_ratio_low': all_annual_iwsr.quantile(0.5 - confidence_level/2/100, axis=1),
'soiling_ratio_high': all_annual_iwsr.quantile(0.5 + confidence_level/2/100, axis=1),
})
annual_soiling.index.name = 'year'
annual_soiling = annual_soiling.reset_index()
Expand Down
Loading

0 comments on commit e85ed0a

Please sign in to comment.