Skip to content

Commit 29b2b0c

Browse files
kevinsa5cwhanse
authored andcommitted
Add irradiance.clearsky_index (#571)
* basic code for irradiance.clearsky_index, still needs full docstring and tests * Add a float conversion to irradiance.clearsky_index to allow integer inputs * added tests for irradiance.clearsky_index * fix typo in irradiance.clearsky_index test * fix typo in irradiance.clearsky_index test * Update pvlib/test/test_irradiance.py to remove extra spaces * fixed incorrect documentation for irradiance.clearsky_index * rename poorly-named variables in irradiance.clearsky_index * truncate nan/inf values to zero in irradiance.clearsky_index * update whatsnew and api.rst * improved formatting to satisfy stickler * preserve input nans for irradiance.clearsky_index * remove trailing whitespace * refactor irradiance.clearsky_index to simplify type-handling logic. also changed behavior for input inf values to set clearsky index to zero * revert change to inf/nan handling; input infs yield clearsky_index=nan
1 parent 9cec7ab commit 29b2b0c

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

docs/sphinx/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ Clearness index models
190190

191191
irradiance.clearness_index
192192
irradiance.clearness_index_zenith_independent
193+
irradiance.clearsky_index
193194

194195

195196
PV Modeling

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

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ Enhancements
6363
* Created :py:func:`pvlib.pvsystem.pvsyst_celltemp` to implement PVsyst's cell temperature model. (:issue:`552`)
6464
* Created :py:func:`pvlib.bifacial.pvfactors_timeseries` to use open-source `pvfactors` package to calculate back surface irradiance (:issue:`421`)
6565
* Add `PVSystem` class method :py:func:`~pvlib.pvsystem.PVSystem.pvsyst_celltemp` (:issue:`633`)
66+
* Add :py:func:`pvlib.irradiance.clearsky_index` to calculate clear-sky index
67+
from measured GHI and modeled clear-sky GHI. (:issue:`551`)
6668

6769

6870
Bug fixes
@@ -102,3 +104,4 @@ Contributors
102104
* Jonathan Gaffiot (:ghuser:`jgaffiot`)
103105
* Marc Anoma (:ghuser:`anomam`)
104106
* Anton Driesse (:ghuser:`adriesse`)
107+
* Kevin Anderson (:ghuser:`kevinsa5`)

pvlib/irradiance.py

+42
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,48 @@ def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
11981198
return sky_diffuse
11991199

12001200

1201+
def clearsky_index(ghi, clearsky_ghi, max_clearsky_index=2.0):
1202+
"""
1203+
Calculate the clearsky index.
1204+
1205+
The clearsky index is the ratio of global to clearsky global irradiance.
1206+
Negative and non-finite clearsky index values will be truncated to zero.
1207+
1208+
Parameters
1209+
----------
1210+
ghi : numeric
1211+
Global horizontal irradiance in W/m^2.
1212+
1213+
clearsky_ghi : numeric
1214+
Modeled clearsky GHI
1215+
1216+
max_clearsky_index : numeric, default 2.0
1217+
Maximum value of the clearsky index. The default, 2.0, allows
1218+
for over-irradiance events typically seen in sub-hourly data.
1219+
1220+
Returns
1221+
-------
1222+
clearsky_index : numeric
1223+
Clearsky index
1224+
"""
1225+
clearsky_index = ghi / clearsky_ghi
1226+
# set +inf, -inf, and nans to zero
1227+
clearsky_index = np.where(~np.isfinite(clearsky_index), 0,
1228+
clearsky_index)
1229+
# but preserve nans in the input arrays
1230+
input_is_nan = ~np.isfinite(ghi) | ~np.isfinite(clearsky_ghi)
1231+
clearsky_index = np.where(input_is_nan, np.nan, clearsky_index)
1232+
1233+
clearsky_index = np.maximum(clearsky_index, 0)
1234+
clearsky_index = np.minimum(clearsky_index, max_clearsky_index)
1235+
1236+
# preserve input type
1237+
if isinstance(ghi, pd.Series):
1238+
clearsky_index = pd.Series(clearsky_index, index=ghi.index)
1239+
1240+
return clearsky_index
1241+
1242+
12011243
def clearness_index(ghi, solar_zenith, extra_radiation, min_cos_zenith=0.065,
12021244
max_clearness_index=2.0):
12031245
"""

pvlib/test/test_irradiance.py

+39
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,45 @@ def test_kt_kt_prime_factor(airmass_kt):
766766
assert_allclose(out, expected, atol=1e-5)
767767

768768

769+
def test_clearsky_index():
770+
ghi = np.array([-1., 0., 1., 500., 1000., np.nan])
771+
ghi_measured, ghi_modeled = np.meshgrid(ghi, ghi)
772+
# default max_clearsky_index
773+
with np.errstate(invalid='ignore', divide='ignore'):
774+
out = irradiance.clearsky_index(ghi_measured, ghi_modeled)
775+
expected = np.array(
776+
[[1. , 0. , 0. , 0. , 0. , np.nan],
777+
[0. , 0. , 0. , 0. , 0. , np.nan],
778+
[0. , 0. , 1. , 2. , 2. , np.nan],
779+
[0. , 0. , 0.002 , 1. , 2. , np.nan],
780+
[0. , 0. , 0.001 , 0.5 , 1. , np.nan],
781+
[np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]])
782+
assert_allclose(out, expected, atol=0.001)
783+
# specify max_clearsky_index
784+
with np.errstate(invalid='ignore', divide='ignore'):
785+
out = irradiance.clearsky_index(ghi_measured, ghi_modeled,
786+
max_clearsky_index=1.5)
787+
expected = np.array(
788+
[[1. , 0. , 0. , 0. , 0. , np.nan],
789+
[0. , 0. , 0. , 0. , 0. , np.nan],
790+
[0. , 0. , 1. , 1.5 , 1.5 , np.nan],
791+
[0. , 0. , 0.002 , 1. , 1.5 , np.nan],
792+
[0. , 0. , 0.001 , 0.5 , 1. , np.nan],
793+
[np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]])
794+
assert_allclose(out, expected, atol=0.001)
795+
# scalars
796+
out = irradiance.clearsky_index(10, 1000)
797+
expected = 0.01
798+
assert_allclose(out, expected, atol=0.001)
799+
# series
800+
times = pd.DatetimeIndex(start='20180601', periods=2, freq='12H')
801+
ghi_measured = pd.Series([100, 500], index=times)
802+
ghi_modeled = pd.Series([500, 1000], index=times)
803+
out = irradiance.clearsky_index(ghi_measured, ghi_modeled)
804+
expected = pd.Series([0.2, 0.5], index=times)
805+
assert_series_equal(out, expected)
806+
807+
769808
def test_clearness_index():
770809
ghi = np.array([-1, 0, 1, 1000])
771810
solar_zenith = np.array([180, 90, 89.999, 0])

0 commit comments

Comments
 (0)