Skip to content

Adds ability for soiling.Hsu to accept arbitrary time intervals (other than 1 hour) #980

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 30 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c8c3758
bug fixes to hsu soiling function. Addresses (#970)
jsstein May 20, 2020
3a77400
Made changes to the soiling tests Addresses (#970)
jsstein Jun 9, 2020
bff444f
update what's new documentation
jsstein Jun 9, 2020
f412ddb
Fixed stickler-ci issues in test_soiling.py
jsstein Jun 11, 2020
db6bb16
Fixed errant character in test
jsstein Jun 11, 2020
13bf88f
allowed function to accept aribtrary time intervals
jsstein Jun 12, 2020
820b87c
updated v0.8.0.rst file
jsstein Jun 12, 2020
ffb3c35
Add variable time interval functionality and testing to soiling.hsu()…
jsstein Jun 17, 2020
5e5e360
fixed typo in test_soiling.py
jsstein Jun 17, 2020
bc73f51
fixed stickler-ci errors
jsstein Jun 17, 2020
617e445
fixed more formatting errors
jsstein Jun 17, 2020
875f298
more stickler-ci issues fixed
jsstein Jun 17, 2020
971cdcd
fixed formatting issues
jsstein Jun 18, 2020
254bffa
fixed more stickler-ci issues
jsstein Jun 18, 2020
5f83509
formatting issues
jsstein Jun 18, 2020
d25d6b2
formatting issues
jsstein Jun 18, 2020
551ab85
formatting...
jsstein Jun 18, 2020
400a992
formatting.....
jsstein Jun 18, 2020
f888276
changed variable time interval calculation in hsu model and test
jsstein Jun 19, 2020
0662215
formatting changes
jsstein Jun 19, 2020
6cd354e
formatting
jsstein Jun 19, 2020
9122281
formatting
jsstein Jun 19, 2020
b864eb9
formatting
jsstein Jun 19, 2020
020b7d2
whatsnew PR links
kandersolar Aug 27, 2020
a8aed01
remove needs_pandas_22 from test_soiling
kandersolar Aug 27, 2020
6445227
Merge remote-tracking branch 'upstream/master' into pr/980
kandersolar Aug 27, 2020
6cce797
move time interval note from bug fixes to enhancements
kandersolar Aug 27, 2020
89b0452
stickler
kandersolar Aug 27, 2020
fb3f71e
review improvements
kandersolar Aug 27, 2020
f1da82f
Merge remote-tracking branch 'upstream/master' into pr/980
kandersolar Aug 27, 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
3 changes: 2 additions & 1 deletion docs/sphinx/source/whatsnew/v0.8.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ Enhancements
* Added *racking_model*, *module_type*, and *temperature_model_parameters* to
PVSystem, LocalizedPVSystem, SingleAxisTracker, and
LocalizedSingleAxisTracker repr methods. (:issue:`1027`)
* Added ability for :py:func:`pvlib.soiling.hsu` to accept arbitrary time intervals. (:pull:`980`)

Bug fixes
~~~~~~~~~
* Fixed unit and default value errors in :py:func:`pvlib.soiling.hsu`. (:pull:`XXX`)
* Fixed unit and default value errors in :py:func:`pvlib.soiling.hsu`. (:pull:`977`, :pull:`980`)
* Handle NUL characters and fix version column dtype in
:py:func:`~pvlib.iotools.crn.read_crn`. (:issue:`1025`)

Expand Down
17 changes: 13 additions & 4 deletions pvlib/soiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
def hsu(rainfall, cleaning_threshold, tilt, pm2_5, pm10,
depo_veloc=None, rain_accum_period=pd.Timedelta('1h')):
"""
Calculates soiling ratio given particulate and rain data using the model
from Humboldt State University (HSU).
Calculates soiling ratio given particulate and rain data using the
Fixed Velocity model from Humboldt State University (HSU).

The HSU soiling model [1]_ returns the soiling ratio, a value between zero
and one which is equivalent to (1 - transmission loss). Therefore a soiling
Expand Down Expand Up @@ -76,8 +76,17 @@ def hsu(rainfall, cleaning_threshold, tilt, pm2_5, pm10,
# 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'] * 3600
# determine the time intervals in seconds (dt_sec)
dt = rainfall.index
# subtract shifted values from original and convert to seconds
dt_diff = (dt[1:] - dt[:-1]).total_seconds()
# ensure same number of elements in the array, assuming that the interval
# prior to the first value is equal in length to the first interval
dt_sec = np.append(dt_diff[0], dt_diff).astype('float64')

horiz_mass_rate = (
pm2_5 * depo_veloc['2_5'] + np.maximum(pm10 - pm2_5, 0.)
* depo_veloc['10']) * dt_sec
tilted_mass_rate = horiz_mass_rate * cosd(tilt) # assuming no rain

# tms -> tilt_mass_rate
Expand Down
74 changes: 54 additions & 20 deletions pvlib/tests/test_soiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@ def expected_output():
end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')

expected_no_cleaning = pd.Series(
data=[0.97230454, 0.95036146, 0.93039061, 0.91177978, 0.89427556,
0.8777455 , 0.86211038, 0.84731759, 0.83332881, 0.82011354,
0.80764549, 0.79590056, 0.78485556, 0.77448749, 0.76477312,
0.75568883, 0.74721046, 0.73931338, 0.73197253, 0.72516253,
0.7188578 , 0.71303268, 0.7076616 , 0.70271919],
data=[0.96998483, 0.94623958, 0.92468139, 0.90465654, 0.88589707,
0.86826366, 0.85167258, 0.83606715, 0.82140458, 0.80764919,
0.79476875, 0.78273241, 0.77150951, 0.76106905, 0.75137932,
0.74240789, 0.73412165, 0.72648695, 0.71946981, 0.7130361,
0.70715176, 0.70178307, 0.69689677, 0.69246034],
index=dt)
return expected_no_cleaning

@pytest.fixture
def expected_output_1():
dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
expected_output_1 = pd.Series(
data=[0.9872406 , 0.97706269, 0.96769693, 0.95884032, 1.,
0.9872406 , 0.97706269, 0.96769693, 1. , 1. ,
0.9872406 , 0.97706269, 0.96769693, 0.95884032, 0.95036001,
0.94218263, 0.93426236, 0.92656836, 0.91907873, 0.91177728,
0.9046517 , 0.89769238, 0.89089165, 0.88424329],
data=[0.98484972, 0.97277367, 0.96167471, 0.95119603, 1.,
0.98484972, 0.97277367, 0.96167471, 1., 1.,
0.98484972, 0.97277367, 0.96167471, 0.95119603, 0.94118234,
0.93154854, 0.922242, 0.91322759, 0.90448058, 0.89598283,
0.88772062, 0.87968325, 0.8718622, 0.86425049],
index=dt)
return expected_output_1

Expand All @@ -44,15 +44,31 @@ def expected_output_2():
dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
expected_output_2 = pd.Series(
data=[0.97229869, 0.95035106, 0.93037619, 0.91176175, 1.,
1. , 1. , 0.97229869, 1. , 1. ,
1. , 1. , 0.97229869, 0.95035106, 0.93037619,
0.91176175, 0.89425431, 1. , 1. , 1. ,
1. , 0.97229869, 0.95035106, 0.93037619],
data=[0.95036261, 0.91178179, 0.87774818, 0.84732079, 1.,
1., 1., 0.95036261, 1., 1.,
1., 1., 0.95036261, 0.91178179, 0.87774818,
0.84732079, 0.8201171, 1., 1., 1.,
1., 0.95036261, 0.91178179, 0.87774818],
index=dt)

return expected_output_2


@pytest.fixture
def expected_output_3():
dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
timedelta = [0, 0, 0, 0, 0, 30, 0, 30, 0, 30, 0, -30,
-30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
dt_new = dt + pd.to_timedelta(timedelta, 'm')
expected_output_3 = pd.Series(
data=[0.96576705, 0.9387675, 0.91437615, 0.89186852, 1.,
1., 0.98093819, 0.9387675, 1., 1.,
1., 1., 0.96576705, 0.9387675, 0.90291005,
0.88122293, 0.86104089, 1., 1., 1.,
0.96576705, 0.9387675, 0.91437615, 0.89186852],
index=dt_new)
return expected_output_3

@pytest.fixture
def rainfall_input():

Expand Down Expand Up @@ -105,12 +121,30 @@ def test_hsu_defaults(rainfall_input, expected_output_1):
Test Soiling HSU function with default deposition velocity and default rain
accumulation period.
"""
result = hsu(
rainfall=rainfall_input, cleaning_threshold=0.5, tilt=0.0,
pm2_5=1.0e-2,pm10=2.0e-2)
result = hsu(rainfall=rainfall_input, cleaning_threshold=0.5, tilt=0.0,
pm2_5=1.0e-2, pm10=2.0e-2)
assert np.allclose(result.values, expected_output_1)


@requires_scipy
def test_hsu_variable_time_intervals(rainfall_input, expected_output_3):
"""
Test Soiling HSU function with variable time intervals.
"""
depo_veloc = {'2_5': 1.0e-4, '10': 1.0e-4}
rain = pd.DataFrame(data=rainfall_input)
# define time deltas in minutes
timedelta = [0, 0, 0, 0, 0, 30, 0, 30, 0, 30, 0, -30,
-30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
rain['mins_added'] = pd.to_timedelta(timedelta, 'm')
rain['new_time'] = rain.index + rain['mins_added']
rain_var_times = rain.set_index('new_time').iloc[:, 0]
result = hsu(
rainfall=rain_var_times, cleaning_threshold=0.5, tilt=50.0,
pm2_5=1, pm10=2, depo_veloc=depo_veloc,
rain_accum_period=pd.Timedelta('2h'))
assert np.allclose(result, expected_output_3)

@pytest.fixture
def greensboro_rain():
# get TMY3 data with rain
Expand Down