-
Notifications
You must be signed in to change notification settings - Fork 1.1k
add Boyle/Coello (Humboldt State Univ) soiling model #850
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
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
64d3169
initial_commit_Boyle_Coello_soiling_model
nappaillav 501d48c
stickler-ci_correction
nappaillav c63ca7c
E128_Error
nappaillav 0677b6c
E128_Error
nappaillav 586b6b9
E128_Error
nappaillav 114148d
format_corrections
nappaillav 23e9042
updated soiling_hsu
nappaillav 619b1a4
updated soiling_hsu
nappaillav cd8f7d6
added unit test
nappaillav 49d29ef
added unit test
nappaillav b75a690
added unit test
nappaillav 5752479
added unit test
nappaillav c0a245b
added unit test
nappaillav ed375f3
corrections_to_test_losses
nappaillav 0e5a529
corrections_to_test_losses
nappaillav b3e2e61
cleaning Test function
nappaillav 45c7920
cleaning Test function
nappaillav e83f568
cleaning Test function
nappaillav 2efe2d1
update api.rst, whatsnew
cwhanse 23cf4ad
Merge branch 'master' into soiling_model
cwhanse 920d77b
merge_correction
nappaillav e331f19
merge_corrections
nappaillav cfa5a0f
updated_init
nappaillav File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
This module contains functions for losses of various types: soiling, mismatch, | ||
snow cover, etc. | ||
""" | ||
|
||
import numpy as np | ||
import pandas as pd | ||
from pvlib.tools import cosd | ||
|
||
|
||
def soiling_hsu(rainfall, cleaning_threshold, tilt, pm2_5, pm10, | ||
depo_veloc={'2_5': 0.004, '10': 0.0009}, | ||
rain_accum_period=pd.Timedelta('1h')): | ||
""" | ||
Calculates soiling ratio given particulate and rain data using the model | ||
from Humboldt State University [1]_. | ||
|
||
Parameters | ||
---------- | ||
|
||
rainfall : Series | ||
Rain accumulated in each time period. [mm] | ||
|
||
cleaning_threshold : float | ||
Amount of rain in an accumulation period needed to clean the PV | ||
modules. [mm] | ||
|
||
tilt : float | ||
Tilt of the PV panels from horizontal. [degree] | ||
|
||
pm2_5 : numeric | ||
Concentration of airborne particulate matter (PM) with | ||
aerodynamic diameter less than 2.5 microns. [g/m^3] | ||
|
||
pm10 : numeric | ||
Concentration of airborne particulate matter (PM) with | ||
aerodynamicdiameter less than 10 microns. [g/m^3] | ||
|
||
depo_veloc : dict, default {'2_5': 0.4, '10': 0.09} | ||
Deposition or settling velocity of particulates. [m/s] | ||
|
||
rain_accum_period : Timedelta, default 1 hour | ||
Period for accumulating rainfall to check against `cleaning_threshold` | ||
It is recommended that `rain_accum_period` be between 1 hour and | ||
24 hours. | ||
|
||
Returns | ||
------- | ||
soiling_ratio : Series | ||
Values between 0 and 1. Equal to 1 - transmission loss. | ||
|
||
References | ||
----------- | ||
.. [1] M. Coello and L. Boyle, "Simple Model For Predicting Time Series | ||
Soiling of Photovoltaic Panels," in IEEE Journal of Photovoltaics. | ||
doi: 10.1109/JPHOTOV.2019.2919628 | ||
.. [2] Atmospheric Chemistry and Physics: From Air Pollution to Climate | ||
Change. J. Seinfeld and S. Pandis. Wiley and Sons 2001. | ||
|
||
""" | ||
try: | ||
from scipy.special import erf | ||
except ImportError: | ||
raise ImportError("The soiling_hsu function requires scipy.") | ||
|
||
# accumulate rainfall into periods for comparison with threshold | ||
accum_rain = rainfall.rolling(rain_accum_period, closed='right').sum() | ||
# cleaning is True for intervals with rainfall greater than threshold | ||
cleaning_times = accum_rain.index[accum_rain >= cleaning_threshold] | ||
|
||
horiz_mass_rate = pm2_5 * depo_veloc['2_5']\ | ||
+ np.maximum(pm10 - pm2_5, 0.) * depo_veloc['10'] | ||
tilted_mass_rate = horiz_mass_rate * cosd(tilt) # assuming no rain | ||
|
||
# tms -> tilt_mass_rate | ||
tms_cumsum = np.cumsum(tilted_mass_rate * np.ones(rainfall.shape)) | ||
|
||
mass_no_cleaning = pd.Series(index=rainfall.index, data=tms_cumsum) | ||
mass_removed = pd.Series(index=rainfall.index) | ||
mass_removed[0] = 0. | ||
mass_removed[cleaning_times] = mass_no_cleaning[cleaning_times] | ||
accum_mass = mass_no_cleaning - mass_removed.ffill() | ||
|
||
soiling_ratio = 1 - 0.3437 * erf(0.17 * accum_mass**0.8473) | ||
|
||
return soiling_ratio |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import pandas as pd | ||
from pandas.util.testing import assert_series_equal | ||
from pvlib.losses import soiling_hsu | ||
from conftest import requires_scipy | ||
import pytest | ||
|
||
|
||
@pytest.fixture | ||
def expected_output(): | ||
# Sample output (calculated manually) | ||
dt = pd.date_range(start=pd.datetime(2019, 1, 1, 0, 0, 0), | ||
end=pd.datetime(2019, 1, 1, 23, 59, 0), freq='1h') | ||
|
||
expected_no_cleaning = pd.Series( | ||
data=[0.884980357535360, 0.806308930084762, 0.749974647038078, | ||
0.711804155175089, 0.687489866078621, 0.672927554408964, | ||
0.664714899337491, 0.660345851212099, 0.658149551658860, | ||
0.657104593968981, 0.656633344364056, 0.656431630729954, | ||
0.656349579062171, 0.656317825078228, 0.656306121502393, | ||
0.656302009396500, 0.656300630853678, 0.656300189543417, | ||
0.656300054532516, 0.656300015031680, 0.656300003971846, | ||
0.656300001006533, 0.656300000244750, 0.656300000057132], | ||
index=dt) | ||
|
||
return expected_no_cleaning | ||
|
||
|
||
@pytest.fixture | ||
def expected_output_2(expected_output): | ||
# Sample output (calculated manually) | ||
dt = pd.date_range(start=pd.datetime(2019, 1, 1, 0, 0, 0), | ||
end=pd.datetime(2019, 1, 1, 23, 59, 0), freq='1h') | ||
|
||
expected_no_cleaning = expected_output | ||
|
||
expected = pd.Series(index=dt) | ||
expected[dt[:4]] = expected_no_cleaning[dt[:4]] | ||
expected[dt[4:7]] = 1. | ||
expected[dt[7]] = expected_no_cleaning[dt[0]] | ||
expected[dt[8:12]] = 1. | ||
expected[dt[12:17]] = expected_no_cleaning[dt[:5]] | ||
expected[dt[17:21]] = 1. | ||
expected[dt[21:]] = expected_no_cleaning[:3] | ||
|
||
return expected | ||
|
||
|
||
@pytest.fixture | ||
def rainfall_input(): | ||
|
||
dt = pd.date_range(start=pd.datetime(2019, 1, 1, 0, 0, 0), | ||
end=pd.datetime(2019, 1, 1, 23, 59, 0), freq='1h') | ||
rainfall = pd.Series( | ||
data=[0., 0., 0., 0., 1., 0., 0., 0., 0.5, 0.5, 0., 0., 0., 0., 0., | ||
0., 0.3, 0.3, 0.3, 0.3, 0., 0., 0., 0.], index=dt) | ||
return rainfall | ||
|
||
|
||
@requires_scipy | ||
def test_soiling_hsu_no_cleaning(rainfall_input, expected_output): | ||
"""Test Soiling HSU function""" | ||
|
||
rainfall = rainfall_input | ||
pm2_5 = 1.0 | ||
pm10 = 2.0 | ||
depo_veloc = {'2_5': 1.0, '10': 1.0} | ||
tilt = 0. | ||
expected_no_cleaning = expected_output | ||
|
||
result = soiling_hsu(rainfall=rainfall, cleaning_threshold=10., tilt=tilt, | ||
pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc, | ||
rain_accum_period=pd.Timedelta('1h')) | ||
assert_series_equal(result, expected_no_cleaning) | ||
|
||
|
||
@requires_scipy | ||
def test_soiling_hsu(rainfall_input, expected_output_2): | ||
"""Test Soiling HSU function""" | ||
|
||
rainfall = rainfall_input | ||
pm2_5 = 1.0 | ||
pm10 = 2.0 | ||
depo_veloc = {'2_5': 1.0, '10': 1.0} | ||
tilt = 0. | ||
expected = expected_output_2 | ||
|
||
# three cleaning events at 4:00-6:00, 8:00-11:00, and 17:00-20:00 | ||
result = soiling_hsu(rainfall=rainfall, cleaning_threshold=0.5, tilt=tilt, | ||
pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc, | ||
rain_accum_period=pd.Timedelta('3h')) | ||
|
||
assert_series_equal(result, expected) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh bother. It appears I've sent you off on a fruitless chase, please accept my apologies. I have
numpy.erf
in my local namespace but its not part ofnumpy
: discussion here. I need to figure out hownumpy.erf
was added and undo it.Rather than add an erf function to pvlib, we should use
scipy.special.erf
as you originally coded.To fix the test errors, add the following lines to
test_losses.py
:at the head:
from pvlib.test.conftest import requires_scipy
on the line preceding
def test_soiling_hsu():
@requires_scipy
Example here.
Again, I'm very sorry that I failed to confirm numpy.erf in the numpy documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a problem, It was always a great learning experience for me.