Skip to content

Commit 79454c4

Browse files
authored
Handle aoi>90 correctly in spectrum.spectrl2 (#1349)
* implement fix and add docstring note * add test * whatsnew
1 parent db7e5d8 commit 79454c4

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.. _whatsnew_0910:
22

3-
v0.9.1 (December 1, 2021)
3+
v0.9.1 (TBD)
44
--------------------------
55

66
Breaking changes
@@ -16,6 +16,9 @@ Bug fixes
1616
~~~~~~~~~
1717
* Address round-off effects in :py:func:`pvlib.ivtools.utils._schumaker_qspline`
1818
(:issue:`1311`, :pull:`1315`)
19+
* Fixed a bug in :py:func:`pvlib.spectrum.spectrl2` where negative spectral irradiance
20+
values were returned when the sun is behind the plane of array (:issue:`1348`, :pull:`1349`)
21+
1922

2023
Testing
2124
~~~~~~~
@@ -31,3 +34,5 @@ Contributors
3134
* Cliff Hansen (:ghuser:`cwhanse`)
3235
* :ghuser:`Antoine-0`
3336
* :ghuser:`Carlosbogo`
37+
* Christian Weickhmann (:ghuser:`cweickhmann`)
38+
* Kevin Anderson (:ghuser:`kanderso-nrel`)

pvlib/spectrum/spectrl2.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ def spectrl2(apparent_zenith, aoi, surface_tilt, ground_albedo,
260260
2-5 kasten1966 kasten1966 kastenyoung1989
261261
=================== ========== ========== ===============
262262
263+
This implementation also deviates from the reference by including a
264+
check for angles of incidence greater than 90 degrees; without this,
265+
the model might return negative spectral irradiance values when the
266+
sun is behind the plane of array.
267+
263268
References
264269
----------
265270
.. [1] Bird, R, and Riordan, C., 1984, "Simple solar spectral model for
@@ -357,10 +362,16 @@ def spectrl2(apparent_zenith, aoi, surface_tilt, ground_albedo,
357362
Is = (Ir + Ia + Ig) * Cs # Eq 3-1
358363

359364
# calculate spectral irradiance on a tilted surface, Eq 3-18
360-
Ibeam = Id * cosd(aoi)
361-
362-
# don't need surface_azimuth if we provide projection_ratio
363-
projection_ratio = cosd(aoi) / cosZ
365+
# Note: clipping cosd(aoi) to >=0 is not in the reference, but is necessary
366+
# to prevent nonsense values when the sun is behind the plane of array.
367+
# The same constraint is applied in irradiance.haydavies when not
368+
# supplying `projection_ratio`.
369+
aoi_projection_nn = np.maximum(cosd(aoi), 0) # GH 1348
370+
Ibeam = Id * aoi_projection_nn
371+
372+
# don't need surface_azimuth if we provide projection_ratio.
373+
# Also constrain cos zenith to avoid blowup, as in irradiance.haydavies
374+
projection_ratio = aoi_projection_nn / np.maximum(cosZ, 0.01745)
364375
Isky = pvlib.irradiance.haydavies(surface_tilt=surface_tilt,
365376
surface_azimuth=None,
366377
dhi=Is,

pvlib/tests/test_spectrum.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,17 @@ def test_dayofyear_missing(spectrl2_data):
9292
kwargs.pop('dayofyear')
9393
with pytest.raises(ValueError, match='dayofyear must be specified'):
9494
_ = spectrum.spectrl2(**kwargs)
95+
96+
97+
def test_aoi_gt_90(spectrl2_data):
98+
# test that returned irradiance values are non-negative when aoi > 90
99+
# see GH #1348
100+
kwargs, _ = spectrl2_data
101+
kwargs['apparent_zenith'] = 70
102+
kwargs['aoi'] = 130
103+
kwargs['surface_tilt'] = 60
104+
105+
spectra = spectrum.spectrl2(**kwargs)
106+
for key in ['poa_direct', 'poa_global']:
107+
message = f'{key} contains negative values for aoi>90'
108+
assert np.all(spectra[key] >= 0), message

0 commit comments

Comments
 (0)