Skip to content

Commit d6b22c3

Browse files
wholmgrencwhanse
authored andcommitted
add max_airmass=12 kwarg to disc (#626)
* add max_airmass=12 kwarg to disc * more tests, clean up * fix bad whatsnew merge * more merge fixing * move limit so it helps in gti_dirint. reword whatsnew
1 parent ef82a39 commit d6b22c3

File tree

3 files changed

+78
-18
lines changed

3 files changed

+78
-18
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ API Changes
2121
* Added keyword argument ``horizon`` to :func:`~pvlib.solarposition.pyephem`
2222
and :func:`~pvlib.solarposition.calc_time` with default value ``'+0:00'``.
2323
(:issue:`588`)
24+
* Add `max_airmass` keyword argument to :py:func:`pvlib.irradiance.disc`.
25+
Default value (`max_airmass=12`) is consistent with polynomial fit in
26+
original paper describing the model. This change may result in different
27+
output of functions that use the `disc` *Kn* calculation for times when
28+
input zenith angles approach 90 degrees. This includes
29+
:py:func:`pvlib.irradiance.dirint` and :py:func:`pvlib.irradiance.dirindex`
30+
when `min_cos_zenith` and `max_zenith` kwargs are used, as well as
31+
:py:func:`pvlib.irradiance.gti_dirint`. (:issue:`450`)
2432
* Changed key names for `components` returned from
2533
:py:func:`pvlib.clearsky.detect_clearsky`. (:issue:`596`)
2634
* Changed function name from `pvlib.solarposition.get_rise_set_transit`

pvlib/irradiance.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ def _kt_kt_prime_factor(airmass):
12951295

12961296

12971297
def disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,
1298-
min_cos_zenith=0.065, max_zenith=87):
1298+
min_cos_zenith=0.065, max_zenith=87, max_airmass=12):
12991299
"""
13001300
Estimate Direct Normal Irradiance from Global Horizontal Irradiance
13011301
using the DISC model.
@@ -1338,6 +1338,11 @@ def disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,
13381338
Maximum value of zenith to allow in DNI calculation. DNI will be
13391339
set to 0 for times with zenith values greater than `max_zenith`.
13401340
1341+
max_airmass : numeric, default 12
1342+
Maximum value of the airmass to allow in Kn calculation.
1343+
Default value (12) comes from range over which Kn was fit
1344+
to airmass in the original paper.
1345+
13411346
Returns
13421347
-------
13431348
output : OrderedDict or DataFrame
@@ -1376,7 +1381,7 @@ def disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,
13761381
if pressure is not None:
13771382
am = atmosphere.get_absolute_airmass(am, pressure)
13781383

1379-
Kn = _disc_kn(kt, am)
1384+
Kn, am = _disc_kn(kt, am, max_airmass=max_airmass)
13801385
dni = Kn * I0
13811386

13821387
bad_values = (solar_zenith > max_zenith) | (ghi < 0) | (dni < 0)
@@ -1393,16 +1398,29 @@ def disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,
13931398
return output
13941399

13951400

1396-
def _disc_kn(clearness_index, airmass):
1401+
def _disc_kn(clearness_index, airmass, max_airmass=12):
13971402
"""
13981403
Calculate Kn for `disc`
1404+
1405+
Parameters
1406+
----------
1407+
clearness_index : numeric
1408+
airmass : numeric
1409+
max_airmass : float
1410+
airmass > max_airmass is set to max_airmass before being used
1411+
in calculating Kn.
1412+
1413+
Returns
1414+
-------
1415+
Kn : numeric
1416+
am : numeric
1417+
airmass used in the calculation of Kn. am <= max_airmass.
13991418
"""
14001419
# short names for equations
14011420
kt = clearness_index
14021421
am = airmass
14031422

1404-
# consider adding
1405-
# am = np.maximum(am, 12) # GH 450
1423+
am = np.minimum(am, max_airmass) # GH 450
14061424

14071425
# powers of kt will be used repeatedly, so compute only once
14081426
kt2 = kt * kt # about the same as kt ** 2
@@ -1423,7 +1441,7 @@ def _disc_kn(clearness_index, airmass):
14231441

14241442
Knc = 0.866 - 0.122*am + 0.0121*am**2 - 0.000653*am**3 + 1.4e-05*am**4
14251443
Kn = Knc - delta_kn
1426-
return Kn
1444+
return Kn, am
14271445

14281446

14291447
def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True,
@@ -1934,7 +1952,7 @@ def _gti_dirint_lt_90(poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth,
19341952

19351953
# calculate kt and DNI from GTI
19361954
kt = clearness_index(poa_global_i, aoi, I0) # kt from Marion eqn 2
1937-
disc_dni = np.maximum(_disc_kn(kt, airmass) * I0, 0)
1955+
disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)
19381956
kt_prime = clearness_index_zenith_independent(kt, airmass)
19391957
# dirint DNI in Marion eqn 3
19401958
dni = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,
@@ -2017,7 +2035,7 @@ def _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth,
20172035
airmass = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')
20182036
airmass = atmosphere.get_absolute_airmass(airmass, pressure)
20192037
kt = kt_prime_gte_90 * _kt_kt_prime_factor(airmass)
2020-
disc_dni = np.maximum(_disc_kn(kt, airmass) * I0, 0)
2038+
disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)
20212039

20222040
dni_gte_90 = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,
20232041
False, temp_dew)

pvlib/test/test_irradiance.py

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -404,28 +404,57 @@ def test_disc_min_cos_zenith_max_zenith():
404404
times = pd.DatetimeIndex(['2016-07-19 06:11:00'], tz='America/Phoenix')
405405
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times)
406406
expected = pd.DataFrame(np.array(
407-
[[0.00000000e+00, 1.16046346e-02, 3.63954476e+01]]),
407+
[[0.00000000e+00, 1.16046346e-02, 12.0]]),
408408
columns=columns, index=times)
409409
assert_frame_equal(out, expected)
410410

411+
# max_zenith and/or max_airmass keep these results reasonable
411412
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
412413
min_cos_zenith=0)
413414
expected = pd.DataFrame(np.array(
414-
[[0.00000000e+00, 1.0, 3.63954476e+01]]),
415+
[[0.00000000e+00, 1.0, 12.0]]),
415416
columns=columns, index=times)
416417
assert_frame_equal(out, expected)
417418

419+
# still get reasonable values because of max_airmass=12 limit
418420
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
419421
max_zenith=100)
420422
expected = pd.DataFrame(np.array(
421-
[[6.68577449e+03, 1.16046346e-02, 3.63954476e+01]]),
423+
[[0., 1.16046346e-02, 12.0]]),
422424
columns=columns, index=times)
423425
assert_frame_equal(out, expected)
424426

427+
# still get reasonable values because of max_airmass=12 limit
425428
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
426429
min_cos_zenith=0, max_zenith=100)
427430
expected = pd.DataFrame(np.array(
428-
[[7.21238390e+03, 1.00000000e+00, 3.63954476e+01]]),
431+
[[277.50185968, 1.0, 12.0]]),
432+
columns=columns, index=times)
433+
assert_frame_equal(out, expected)
434+
435+
# max_zenith keeps this result reasonable
436+
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
437+
min_cos_zenith=0, max_airmass=100)
438+
expected = pd.DataFrame(np.array(
439+
[[0.00000000e+00, 1.0, 36.39544757]]),
440+
columns=columns, index=times)
441+
assert_frame_equal(out, expected)
442+
443+
# allow zenith to be close to 90 and airmass to be infinite
444+
# and we get crazy values
445+
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
446+
max_zenith=100, max_airmass=100)
447+
expected = pd.DataFrame(np.array(
448+
[[6.68577449e+03, 1.16046346e-02, 3.63954476e+01]]),
449+
columns=columns, index=times)
450+
assert_frame_equal(out, expected)
451+
452+
# allow min cos zenith to be 0, zenith to be close to 90,
453+
# and airmass to be very big and we get even higher DNI values
454+
out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times,
455+
min_cos_zenith=0, max_zenith=100, max_airmass=100)
456+
expected = pd.DataFrame(np.array(
457+
[[7.21238390e+03, 1., 3.63954476e+01]]),
429458
columns=columns, index=times)
430459
assert_frame_equal(out, expected)
431460

@@ -497,13 +526,18 @@ def test_dirint_min_cos_zenith_max_zenith():
497526
expected = pd.Series([0.0, 0.0], index=times, name='dni')
498527
assert_series_equal(out, expected)
499528

500-
out = irradiance.dirint(ghi, solar_zenith, times, max_zenith=100)
501-
expected = pd.Series([862.198, 848.387], index=times, name='dni')
529+
out = irradiance.dirint(ghi, solar_zenith, times, max_zenith=90)
530+
expected = pd.Series([0.0, 0.0], index=times, name='dni')
531+
assert_series_equal(out, expected, check_less_precise=True)
532+
533+
out = irradiance.dirint(ghi, solar_zenith, times, min_cos_zenith=0,
534+
max_zenith=90)
535+
expected = pd.Series([0.0, 144.264507], index=times, name='dni')
502536
assert_series_equal(out, expected, check_less_precise=True)
503537

504538
out = irradiance.dirint(ghi, solar_zenith, times, min_cos_zenith=0,
505539
max_zenith=100)
506-
expected = pd.Series([147655.5994, 3749.8542], index=times, name='dni')
540+
expected = pd.Series([0.0, 144.264507], index=times, name='dni')
507541
assert_series_equal(out, expected, check_less_precise=True)
508542

509543

@@ -670,13 +704,13 @@ def test_dirindex_min_cos_zenith_max_zenith():
670704
assert_series_equal(out, expected)
671705

672706
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clearsky, solar_zenith,
673-
times, max_zenith=100)
674-
expected = pd.Series([0., 5.], index=times)
707+
times, max_zenith=90)
708+
expected = pd.Series([nan, nan], index=times)
675709
assert_series_equal(out, expected)
676710

677711
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clearsky, solar_zenith,
678712
times, min_cos_zenith=0, max_zenith=100)
679-
expected = pd.Series([0., 5.], index=times)
713+
expected = pd.Series([nan, 5.], index=times)
680714
assert_series_equal(out, expected)
681715

682716

0 commit comments

Comments
 (0)