Skip to content

Commit 01a23e3

Browse files
authored
Horizon coefficient should be allowed to go negative in the Perez transposition model (#1239)
* Merged PR 13463: Horizon coefficient should be allowed to go negative in the Perez transposition model Horizon coefficient should be allowed to go negative in the Perez transposition model Link to the original paper: https://www.osti.gov/servlets/purl/7024029 Section III.2 states this explicitly for the horizon component: "(2) The horizon brightening coefficient, F2, is negative for overcast and low E occurrences -- indicative of brightening of the zenithal region of the sky for these conditions. This becomes positive past intermediate conditions and increases substantially with clearness." Note that this change also impacts results from the DIRINT model (used to generate DNI from GHI). This change corresponds to revision 8 of the SAM vs PVLib comparison, found here: https://cleanpower1.sharepoint.com/sites/SolarAnywhere/Shared%20Documents/Power%20Model%20Discussions/PVLib_Comparison_Rev8_FixPvLibPerezModelF2Bound.zip * Merged PR 13472: Fix reported Stickler issues Fix reported Stickler issues This is an attempt to fix all formatting requirement failures reported by Stickler CI for PR 1239 to the pvlib-python project. Related work items: #18784 * Merged PR 13479: Final changes to meet formatting requirements I was shown how to validate this locally and fixed all issues, so this should be the last round. I couldn't cherry pick due to conflicts. but this shouldn't include any other changes. Related work items: #18784 * Add appropriate details of the bug fix to the 'what's new' content.
1 parent 276a30d commit 01a23e3

File tree

3 files changed

+59
-7
lines changed

3 files changed

+59
-7
lines changed

docs/sphinx/source/whatsnew/v0.9.0.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ Enhancements
149149

150150
Bug fixes
151151
~~~~~~~~~
152+
* Corrected an error in :py:func:`~pvlib.irradiance.perez` where the horizon
153+
irradiance component was prevented from taking negative values. Negative
154+
values are intentional according to the original publication. Changes in
155+
output are expected to be small and primarily occur at low irradiance
156+
conditions.
157+
(:issue:`1238`, :pull:`1239`)
152158
* Pass weather data to solar position calculations in
153159
:py:meth:`~pvlib.modelchain.ModelChain.prepare_inputs_from_poa`.
154160
(:issue:`1065`, :pull:`1140`)
@@ -192,3 +198,4 @@ Contributors
192198
* Tony Lorenzo (:ghuser:`alorenzo175`)
193199
* Damjan Postolovski (:ghuser:`dpostolovski`)
194200
* Joe Ranalli (:ghuser:`jranalli`)
201+
* Chas Schweizer (:ghuser:`cpr-chas`)

pvlib/irradiance.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,6 @@ def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
11261126
F1 = np.maximum(F1, 0)
11271127

11281128
F2 = (F2c[ebin, 0] + F2c[ebin, 1] * delta + F2c[ebin, 2] * z)
1129-
F2 = np.maximum(F2, 0)
11301129

11311130
A = aoi_projection(surface_tilt, surface_azimuth,
11321131
solar_zenith, solar_azimuth)

pvlib/tests/test_irradiance.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,52 @@ def test_perez_components(irrad_data, ephem_data, dni_et, relative_airmass):
248248
assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
249249

250250

251+
def test_perez_negative_horizon():
252+
times = pd.date_range(start='20190101 11:30:00', freq='1H',
253+
periods=5, tz='US/Central')
254+
255+
# Avoid test dependencies on functionality not being tested by hard-coding
256+
# the inputs. This data corresponds to Goodwin Creek in the afternoon on
257+
# 1/1/2019.
258+
# dni_e is slightly rounded from irradiance.get_extra_radiation
259+
# airmass from atmosphere.get_relative_airmas
260+
inputs = pd.DataFrame(np.array(
261+
[[ 158, 19, 1, 0, 0],
262+
[ 249, 165, 136, 93, 50],
263+
[ 57.746951, 57.564205, 60.813841, 66.989435, 75.353368],
264+
[ 171.003315, 187.346924, 202.974357, 216.725599, 228.317233],
265+
[1414, 1414, 1414, 1414, 1414],
266+
[ 1.869315, 1.859981, 2.044429, 2.544943, 3.900136]]).T,
267+
columns=['dni', 'dhi', 'solar_zenith',
268+
'solar_azimuth', 'dni_extra', 'airmass'],
269+
index=times
270+
)
271+
272+
out = irradiance.perez(34, 180, inputs['dhi'], inputs['dni'],
273+
inputs['dni_extra'], inputs['solar_zenith'],
274+
inputs['solar_azimuth'], inputs['airmass'],
275+
model='allsitescomposite1990',
276+
return_components=True)
277+
278+
# sky_diffuse can be less than isotropic under certain conditions as
279+
# horizon goes negative
280+
expected = pd.DataFrame(np.array(
281+
[[281.410185, 152.20879, 123.867898, 82.836412, 43.517015],
282+
[166.785419, 142.24475, 119.173875, 83.525150, 45.725931],
283+
[113.548755, 16.09757, 9.956174, 3.142467, 0],
284+
[ 1.076010, -6.13353, -5.262151, -3.831230, -2.208923]]).T,
285+
columns=['sky_diffuse', 'isotropic', 'circumsolar', 'horizon'],
286+
index=times
287+
)
288+
289+
expected_for_sum = expected['sky_diffuse'].copy()
290+
sum_components = out.iloc[:, 1:].sum(axis=1)
291+
sum_components.name = 'sky_diffuse'
292+
293+
assert_frame_equal(out, expected, check_less_precise=2)
294+
assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
295+
296+
251297
def test_perez_arrays(irrad_data, ephem_data, dni_et, relative_airmass):
252298
dni = irrad_data['dni'].copy()
253299
dni.iloc[2] = np.nan
@@ -608,7 +654,7 @@ def test_gti_dirint():
608654
expected_col_order = ['ghi', 'dni', 'dhi']
609655
expected = pd.DataFrame(array(
610656
[[ 21.05796198, 0. , 21.05796198],
611-
[ 288.22574368, 60.59964218, 245.37532576],
657+
[ 291.40037163, 63.41290679, 246.56067523],
612658
[ 931.04078010, 695.94965324, 277.06172442]]),
613659
columns=expected_col_order, index=times)
614660

@@ -632,7 +678,7 @@ def test_gti_dirint():
632678

633679
expected = pd.DataFrame(array(
634680
[[ 21.05796198, 0. , 21.05796198],
635-
[ 289.81109139, 60.52460392, 247.01373353],
681+
[ 293.21310935, 63.27500913, 248.47092131],
636682
[ 932.46756378, 648.05001357, 323.49974813]]),
637683
columns=expected_col_order, index=times)
638684

@@ -646,8 +692,8 @@ def test_gti_dirint():
646692

647693
expected = pd.DataFrame(array(
648694
[[ 21.3592591, 0. , 21.3592591 ],
649-
[ 292.5162373, 64.42628826, 246.95997198],
650-
[ 941.6753031, 727.16311901, 258.36548605]]),
695+
[ 294.4985420, 66.25848451, 247.64671830],
696+
[ 941.7943404, 727.50552952, 258.16276278]]),
651697
columns=expected_col_order, index=times)
652698

653699
assert_frame_equal(output, expected)
@@ -659,8 +705,8 @@ def test_gti_dirint():
659705
temp_dew=temp_dew)
660706

661707
expected = pd.DataFrame(array(
662-
[[ 21.05796198, 0. , 21.05796198],
663-
[ 292.40468994, 36.79559287, 266.3862767 ],
708+
[[ 21.05796198, 0., 21.05796198],
709+
[ 295.06070190, 38.20346345, 268.0467738],
664710
[ 931.79627208, 689.81549269, 283.5817439]]),
665711
columns=expected_col_order, index=times)
666712

0 commit comments

Comments
 (0)