Skip to content

Commit 35d37ca

Browse files
authored
Merge pull request #1 from wholmgren/int_indexing
make dirint work with nans again
2 parents c0cbf4c + 59b32a4 commit 35d37ca

File tree

2 files changed

+90
-71
lines changed

2 files changed

+90
-71
lines changed

pvlib/irradiance.py

Lines changed: 72 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,12 +1313,12 @@ def _get_perez_coefficients(perezmodelt):
13131313

13141314
def disc(ghi, zenith, times, pressure=101325):
13151315
'''
1316-
Estimate Direct Normal Irradiance from Global Horizontal Irradiance
1316+
Estimate Direct Normal Irradiance from Global Horizontal Irradiance
13171317
using the DISC model.
13181318
13191319
The DISC algorithm converts global horizontal irradiance to direct
13201320
normal irradiance through empirical relationships between the global
1321-
and direct clearness indices.
1321+
and direct clearness indices.
13221322
13231323
Parameters
13241324
----------
@@ -1327,62 +1327,62 @@ def disc(ghi, zenith, times, pressure=101325):
13271327
Global horizontal irradiance in W/m^2.
13281328
13291329
solar_zenith : Series
1330-
True (not refraction - corrected) solar zenith
1331-
angles in decimal degrees.
1330+
True (not refraction - corrected) solar zenith
1331+
angles in decimal degrees.
13321332
13331333
times : DatetimeIndex
13341334
13351335
pressure : float or Series
13361336
Site pressure in Pascal.
13371337
1338-
Returns
1338+
Returns
13391339
-------
13401340
DataFrame with the following keys:
1341-
* ``dni``: The modeled direct normal irradiance
1341+
* ``dni``: The modeled direct normal irradiance
13421342
in W/m^2 provided by the
1343-
Direct Insolation Simulation Code (DISC) model.
1344-
* ``kt``: Ratio of global to extraterrestrial
1343+
Direct Insolation Simulation Code (DISC) model.
1344+
* ``kt``: Ratio of global to extraterrestrial
13451345
irradiance on a horizontal plane.
13461346
* ``airmass``: Airmass
13471347
13481348
References
13491349
----------
13501350
1351-
[1] Maxwell, E. L., "A Quasi-Physical Model for Converting Hourly
1352-
Global Horizontal to Direct Normal Insolation", Technical
1353-
Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research
1351+
[1] Maxwell, E. L., "A Quasi-Physical Model for Converting Hourly
1352+
Global Horizontal to Direct Normal Insolation", Technical
1353+
Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research
13541354
Institute, 1987.
13551355
1356-
[2] J.W. "Fourier series representation of the position of the sun".
1356+
[2] J.W. "Fourier series representation of the position of the sun".
13571357
Found at:
13581358
http://www.mail-archive.com/[email protected]/msg01050.html on
13591359
January 12, 2012
13601360
1361-
See Also
1362-
--------
1363-
atmosphere.alt2pres
1361+
See Also
1362+
--------
1363+
atmosphere.alt2pres
13641364
dirint
13651365
'''
13661366

13671367
pvl_logger.debug('clearsky.disc')
1368-
1368+
13691369
temp = pd.DataFrame(index=times, columns=['A','B','C'], dtype=float)
13701370

13711371
doy = times.dayofyear
1372-
1372+
13731373
DayAngle = 2. * np.pi*(doy - 1) / 365
1374-
1374+
13751375
re = (1.00011 + 0.034221*np.cos(DayAngle) + 0.00128*np.sin(DayAngle)
13761376
+ 0.000719*np.cos(2.*DayAngle) + 7.7e-05*np.sin(2.*DayAngle) )
1377-
1377+
13781378
I0 = re * 1370.
13791379
I0h = I0 * np.cos(np.radians(zenith))
1380-
1380+
13811381
Ztemp = zenith.copy()
13821382
Ztemp[zenith > 87] = np.NaN
1383-
1383+
13841384
AM = 1.0 / ( np.cos(np.radians(Ztemp)) + 0.15*( (93.885 - Ztemp)**(-1.253) ) ) * (pressure / 101325)
1385-
1385+
13861386
Kt = ghi / I0h
13871387
Kt[Kt < 0] = 0
13881388
Kt[Kt > 2] = np.NaN
@@ -1395,10 +1395,10 @@ def disc(ghi, zenith, times, pressure=101325):
13951395
temp.C[Kt <= 0.6] = -0.28 + 0.932*(Kt[Kt <= 0.6]) - 2.048*(Kt[Kt <= 0.6] ** 2)
13961396

13971397
delKn = temp.A + temp.B * np.exp(temp.C*AM)
1398-
1398+
13991399
Knc = 0.866 - 0.122*(AM) + 0.0121*(AM ** 2) - 0.000653*(AM ** 3) + 1.4e-05*(AM ** 4)
14001400
Kn = Knc - delKn
1401-
1401+
14021402
dni = Kn * I0
14031403

14041404
dni[zenith > 87] = np.NaN
@@ -1409,14 +1409,14 @@ def disc(ghi, zenith, times, pressure=101325):
14091409
dfout['airmass'] = AM
14101410

14111411
return dfout
1412-
14131412

1414-
def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
1413+
1414+
def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
14151415
temp_dew=None):
14161416
"""
1417-
Determine DNI from GHI using the DIRINT modification
1417+
Determine DNI from GHI using the DIRINT modification
14181418
of the DISC model.
1419-
1419+
14201420
Implements the modified DISC model known as "DIRINT" introduced in [1].
14211421
DIRINT predicts direct normal irradiance (DNI) from measured global
14221422
horizontal irradiance (GHI). DIRINT improves upon the DISC model by
@@ -1425,22 +1425,22 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
14251425
information provided.
14261426
14271427
Parameters
1428-
----------
1428+
----------
14291429
ghi : pd.Series
1430-
Global horizontal irradiance in W/m^2.
1431-
1430+
Global horizontal irradiance in W/m^2.
1431+
14321432
zenith : pd.Series
14331433
True (not refraction-corrected) zenith
14341434
angles in decimal degrees. If Z is a vector it must be of the
14351435
same size as all other vector inputs. Z must be >=0 and <=180.
1436-
1436+
14371437
times : DatetimeIndex
1438-
1438+
14391439
pressure : float or pd.Series
1440-
The site pressure in Pascal.
1441-
Pressure may be measured or an average pressure may be
1440+
The site pressure in Pascal.
1441+
Pressure may be measured or an average pressure may be
14421442
calculated from site altitude.
1443-
1443+
14441444
use_delta_kt_prime : bool
14451445
Indicates if the user would like to
14461446
utilize the time-series nature of the GHI measurements. A value of ``False``
@@ -1450,13 +1450,13 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
14501450
than 1.5 hours. If none of the input arguments are
14511451
vectors, then time-series improvements are not used (because it's not
14521452
a time-series).
1453-
1454-
temp_dew : None, float, or pd.Series
1455-
Surface dew point temperatures, in degrees C.
1453+
1454+
temp_dew : None, float, or pd.Series
1455+
Surface dew point temperatures, in degrees C.
14561456
Values of temp_dew may be numeric or NaN. Any
14571457
single time period point with a DewPtTemp=NaN does not have dew point
1458-
improvements applied. If DewPtTemp is not provided, then dew point
1459-
improvements are not applied.
1458+
improvements applied. If DewPtTemp is not provided, then dew point
1459+
improvements are not applied.
14601460
14611461
Returns
14621462
-------
@@ -1467,57 +1467,58 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
14671467
References
14681468
----------
14691469
[1] Perez, R., P. Ineichen, E. Maxwell, R. Seals and A. Zelenka, (1992).
1470-
"Dynamic Global-to-Direct Irradiance Conversion Models". ASHRAE
1470+
"Dynamic Global-to-Direct Irradiance Conversion Models". ASHRAE
14711471
Transactions-Research Series, pp. 354-369
14721472
1473-
[2] Maxwell, E. L., "A Quasi-Physical Model for Converting Hourly
1474-
Global Horizontal to Direct Normal Insolation", Technical
1475-
Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research
1473+
[2] Maxwell, E. L., "A Quasi-Physical Model for Converting Hourly
1474+
Global Horizontal to Direct Normal Insolation", Technical
1475+
Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research
14761476
Institute, 1987.
14771477
14781478
DIRINT model requires time series data (ie. one of the inputs must be a
14791479
vector of length >2.
14801480
"""
1481-
1481+
14821482
pvl_logger.debug('clearsky.dirint')
1483-
1483+
14841484
disc_out = disc(ghi, zenith, times)
14851485
kt = disc_out['kt']
1486-
1486+
14871487
# Absolute Airmass, per the DISC model
14881488
# Note that we calculate the AM pressure correction slightly differently
14891489
# than Perez. He uses altitude, we use pressure (which we calculate
14901490
# slightly differently)
1491-
airmass = (1./(tools.cosd(zenith) + 0.15*((93.885-zenith)**(-1.253))) *
1491+
airmass = (1./(tools.cosd(zenith) + 0.15*((93.885-zenith)**(-1.253))) *
14921492
pressure/101325)
1493-
1493+
14941494
coeffs = _get_dirint_coeffs()
1495-
1495+
14961496
kt_prime = kt / (1.031 * np.exp(-1.4/(0.9+9.4/airmass)) + 0.1)
14971497
kt_prime[kt_prime > 0.82] = 0.82 # From SRRL code. consider np.NaN
1498-
kt_prime.fillna(0, inplace=True)
14991498
pvl_logger.debug('kt_prime:\n%s', kt_prime)
1500-
1501-
# wholmgren:
1499+
1500+
# wholmgren:
15021501
# the use_delta_kt_prime statement is a port of the MATLAB code.
15031502
# I am confused by the abs() in the delta_kt_prime calculation.
15041503
# It is not the absolute value of the central difference.
15051504
if use_delta_kt_prime:
15061505
delta_kt_prime = 0.5*( (kt_prime - kt_prime.shift(1)).abs()
15071506
.add(
1508-
(kt_prime - kt_prime.shift(-1)).abs(),
1507+
(kt_prime - kt_prime.shift(-1)).abs(),
15091508
fill_value=0))
15101509
else:
15111510
delta_kt_prime = pd.Series(-1, index=times)
1512-
1511+
15131512
if temp_dew is not None:
15141513
w = pd.Series(np.exp(0.07 * temp_dew - 0.075), index=times)
15151514
else:
15161515
w = pd.Series(-1, index=times)
1517-
1516+
15181517
# @wholmgren: the following bin assignments use MATLAB's 1-indexing.
15191518
# Later, we'll subtract 1 to conform to Python's 0-indexing.
1520-
1519+
# The initial filled 0s will result in nans.
1520+
# see discussion at https://github.com/pvlib/pvlib-python/pull/164
1521+
15211522
# Create kt_prime bins
15221523
kt_prime_bin = pd.Series(0, index=times, dtype=np.int64)
15231524
kt_prime_bin[(kt_prime>=0) & (kt_prime<0.24)] = 1
@@ -1527,7 +1528,7 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
15271528
kt_prime_bin[(kt_prime>=0.7) & (kt_prime<0.8)] = 5
15281529
kt_prime_bin[(kt_prime>=0.8) & (kt_prime<=1)] = 6
15291530
pvl_logger.debug('kt_prime_bin:\n%s', kt_prime_bin)
1530-
1531+
15311532
# Create zenith angle bins
15321533
zenith_bin = pd.Series(0, index=times, dtype=np.int64)
15331534
zenith_bin[(zenith>=0) & (zenith<25)] = 1
@@ -1537,7 +1538,7 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
15371538
zenith_bin[(zenith>=70) & (zenith<80)] = 5
15381539
zenith_bin[(zenith>=80)] = 6
15391540
pvl_logger.debug('zenith_bin:\n%s', zenith_bin)
1540-
1541+
15411542
# Create the bins for w based on dew point temperature
15421543
w_bin = pd.Series(0, index=times, dtype=np.int64)
15431544
w_bin[(w>=0) & (w<1)] = 1
@@ -1557,11 +1558,16 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
15571558
delta_kt_prime_bin[(delta_kt_prime>=0.3) & (delta_kt_prime<=1)] = 6
15581559
delta_kt_prime_bin[delta_kt_prime == -1] = 7
15591560
pvl_logger.debug('delta_kt_prime_bin:\n%s', delta_kt_prime_bin)
1560-
1561+
15611562
# subtract 1 to account for difference between MATLAB-style bin
15621563
# assignment and Python-style array lookup.
15631564
dirint_coeffs = coeffs[kt_prime_bin-1, zenith_bin-1,
15641565
delta_kt_prime_bin-1, w_bin-1]
1566+
# convert unassigned bins to nan
1567+
# use where to avoid boolean indexing deprecation
1568+
dirint_coeffs[np.where((kt_prime_bin == 0) | (zenith_bin == 0) |
1569+
(w_bin == 0) | (delta_kt_prime_bin == 0))] = np.nan
1570+
15651571
dni = disc_out['dni'] * dirint_coeffs
15661572

15671573
dni.name = 'dni'
@@ -1572,19 +1578,19 @@ def dirint(ghi, zenith, times, pressure=101325, use_delta_kt_prime=True,
15721578
def _get_dirint_coeffs():
15731579
"""
15741580
A place to stash the dirint coefficients.
1575-
1581+
15761582
Returns
15771583
-------
15781584
np.array with shape ``(6, 6, 7, 5)``.
15791585
Ordering is ``[kt_prime_bin, zenith_bin, delta_kt_prime_bin, w_bin]``
15801586
"""
15811587

1582-
# To allow for maximum copy/paste from the MATLAB 1-indexed code,
1588+
# To allow for maximum copy/paste from the MATLAB 1-indexed code,
15831589
# we create and assign values to an oversized array.
15841590
# Then, we return the [1:, 1:, :, :] slice.
1585-
1591+
15861592
coeffs = np.zeros((7,7,7,5))
1587-
1593+
15881594
coeffs[1,1,:,:] = [
15891595
[0.385230, 0.385230, 0.385230, 0.462880, 0.317440],
15901596
[0.338390, 0.338390, 0.221270, 0.316730, 0.503650],
@@ -1908,6 +1914,6 @@ def _get_dirint_coeffs():
19081914
[0.570000, 0.550000, 0.598800, 0.400000, 0.560150],
19091915
[0.475230, 0.500000, 0.518640, 0.339970, 0.520230],
19101916
[0.743440, 0.592190, 0.603060, 0.316930, 0.794390 ]]
1911-
1917+
19121918
return coeffs[1:,1:,:,:]
19131919

pvlib/test/test_irradiance.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,14 @@ def test_total_irrad():
152152

153153
for model in models:
154154
total = irradiance.total_irrad(
155-
32, 180,
155+
32, 180,
156156
ephem_data['apparent_zenith'], ephem_data['azimuth'],
157157
dni=irrad_data['dni'], ghi=irrad_data['ghi'],
158158
dhi=irrad_data['dhi'],
159159
dni_extra=dni_et, airmass=AM,
160160
model=model,
161161
surface_type='urban')
162-
162+
163163
assert total.columns.tolist() == ['poa_global', 'poa_direct',
164164
'poa_diffuse', 'poa_sky_diffuse',
165165
'poa_ground_diffuse']
@@ -181,7 +181,7 @@ def test_globalinplane():
181181
def test_disc_keys():
182182
clearsky_data = clearsky.ineichen(times, tus.latitude, tus.longitude,
183183
linke_turbidity=3)
184-
disc_data = irradiance.disc(clearsky_data['ghi'], ephem_data['zenith'],
184+
disc_data = irradiance.disc(clearsky_data['ghi'], ephem_data['zenith'],
185185
ephem_data.index)
186186
assert 'dni' in disc_data.columns
187187
assert 'kt' in disc_data.columns
@@ -202,7 +202,7 @@ def test_dirint():
202202
clearsky_data = clearsky.ineichen(times, tus.latitude, tus.longitude,
203203
linke_turbidity=3)
204204
pressure = 93193.
205-
dirint_data = irradiance.dirint(clearsky_data['ghi'], ephem_data['zenith'],
205+
dirint_data = irradiance.dirint(clearsky_data['ghi'], ephem_data['zenith'],
206206
ephem_data.index, pressure=pressure)
207207

208208
def test_dirint_value():
@@ -214,6 +214,19 @@ def test_dirint_value():
214214
assert_almost_equal(dirint_data.values,
215215
np.array([928.85, 688.26]), 1)
216216

217+
218+
def test_dirint_nans():
219+
times = pd.DatetimeIndex(start='2014-06-24T12-0700', periods=5, freq='6H')
220+
ghi = pd.Series([np.nan, 1038.62, 1038.62, 1038.62, 1038.62], index=times)
221+
zenith = pd.Series([10.567, np.nan, 10.567, 10.567, 10.567,], index=times)
222+
pressure = pd.Series([93193., 93193., np.nan, 93193., 93193.], index=times)
223+
temp_dew = pd.Series([10, 10, 10, np.nan, 10], index=times)
224+
dirint_data = irradiance.dirint(ghi, zenith, times, pressure=pressure,
225+
temp_dew=temp_dew)
226+
assert_almost_equal(dirint_data.values,
227+
np.array([np.nan, np.nan, np.nan, np.nan, 934.2]), 1)
228+
229+
217230
def test_dirint_tdew():
218231
times = pd.DatetimeIndex(['2014-06-24T12-0700','2014-06-24T18-0700'])
219232
ghi = pd.Series([1038.62, 254.53], index=times)
@@ -238,4 +251,4 @@ def test_dirint_coeffs():
238251
coeffs = irradiance._get_dirint_coeffs()
239252
assert coeffs[0,0,0,0] == 0.385230
240253
assert coeffs[0,1,2,1] == 0.229970
241-
assert coeffs[3,2,6,3] == 1.032260
254+
assert coeffs[3,2,6,3] == 1.032260

0 commit comments

Comments
 (0)