irradiance.py tutorial

This tutorial explores some of the functions available in the pvlib module irradiance.py.

This tutorial is known to work with the following package versions:

  • pvlib 0.4.4
  • Python 3.5.1
  • IPython 5.1
  • pandas 0.19.0

It should work with other Python and Pandas versions. It requires pvlib >= 0.4.0 and IPython >= 3.0.

Authors:

  • Will Holmgren (@wholmgren), University of Arizona. July 2014, April 2015, July 2015, March 2016, July 2016, February 2017.

In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
try:
    import seaborn as sns
    sns.set(rc={'figure.figsize':(12,6)})
except ImportError:
    pass
    
# built in python modules
import datetime

# python add-ons
import numpy as np
import pandas as pd

import pvlib

Extraterrestrial radiation

Many solar power algorithms start with the irradiance incident on the top of the Earth's atmosphere, often known as the extraterrestrial radiation. pvlib has four different algorithms to calculate the yearly cycle of the extraterrestrial radiation given the solar constant. As of pvlib 0.4, each method can accept many different input types (day of year, arrays of day of year, datetimes, DatetimeIndex, etc.) and will consistently return the appropriate output type.


In [2]:
# DatetimeIndex in yields a TimeSeries out
times = pd.date_range('2014-01-01', '2015-01-01', freq='1h')

spencer = pvlib.irradiance.extraradiation(times, method='spencer')
asce = pvlib.irradiance.extraradiation(times, method='asce')
ephem = pvlib.irradiance.extraradiation(times, method='pyephem') 
nrel = pvlib.irradiance.extraradiation(times, method='nrel')

In [3]:
spencer.plot(label='spencer')
asce.plot(label='asce')
ephem.plot(label='pyephem')
nrel.plot(label='nrel')
plt.legend()
plt.ylabel('Extraterrestrial radiation (W/m^2)')


Out[3]:
<matplotlib.text.Text at 0x111b0eeb8>

The pyephem and nrel methods are the most accurate. However, as shown in the plot below, the difference between them and the spencer method is only +/-2 W/m^2 over the entire year.


In [4]:
et_diff = spencer - ephem
et_diff.plot()
plt.ylabel('spencer-ephem (W/m**2)')


Out[4]:
<matplotlib.text.Text at 0x111db46d8>

The intraday squiggles are due to the fact that the asce and spencer methods will cast a DatetimeIndex into integer days of year, while the pyephem and nrel methods also use the time of day.

The difference between the nrel and pyephem methods is negligible.


In [5]:
et_diff = nrel - ephem
et_diff.plot()
plt.ylabel('nrel-ephem (W/m**2)')


Out[5]:
<matplotlib.text.Text at 0x11453c7b8>

You can also control the solar constant. Recent literature suggests that the solar constant is 1361 $W/m^2$ rather than the commonly accepted 1367 $W/m^2$.


In [6]:
spencer_1361 = pd.Series(pvlib.irradiance.extraradiation(times, method='spencer', solar_constant=1361), times)

spencer.plot(label='default 1366.7')
spencer_1361.plot(label='1361')
plt.legend()
plt.title('Impact of solar constant')
plt.ylabel('ET Irradiance (W/m^2)')


Out[6]:
<matplotlib.text.Text at 0x1146bf0b8>

Compare the time it takes to do the calculations.


In [7]:
times = pd.DatetimeIndex(start='2015', end='2016', freq='1min')

In [8]:
%timeit spencer = pvlib.irradiance.extraradiation(times, method='spencer')
%timeit asce = pvlib.irradiance.extraradiation(times, method='asce')
%timeit ephem = pvlib.irradiance.extraradiation(times, method='pyephem')
%timeit nrel = pvlib.irradiance.extraradiation(times, method='nrel')
%timeit nrel = pvlib.irradiance.extraradiation(times, method='nrel', how='numba')


10 loops, best of 3: 60.2 ms per loop
10 loops, best of 3: 38.8 ms per loop
1 loop, best of 3: 9.41 s per loop
1 loop, best of 3: 1.01 s per loop
The slowest run took 13.23 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 210 ms per loop

In addition to DatetimeIndex input, the methods also work for various scalar datetime-like formats as well as scalar and array day of year input.


In [9]:
methods = ['spencer', 'asce', 'pyephem', 'nrel']

# pandas timestamp input
times = pd.Timestamp('20161026')
for method in methods:
    dni_extra = pvlib.irradiance.extraradiation(times, method=method)
    assert isinstance(dni_extra, float)
    print(times, method, dni_extra)
    
    
# date input
times = datetime.date(2016, 10, 26)
for method in methods:
    dni_extra = pvlib.irradiance.extraradiation(times, method=method)
    assert isinstance(dni_extra, float)
    print(times, method, dni_extra)
    
    
# integer doy input
times = 300
for method in methods:
    dni_extra = pvlib.irradiance.extraradiation(times, method=method)
    assert isinstance(dni_extra, float)
    print(times, method, dni_extra)
    
    
# array doy input
times = np.arange(1, 366)
for method in methods:
    dni_extra = pvlib.irradiance.extraradiation(times, method=method)
    assert isinstance(dni_extra, np.ndarray)
    plt.plot(times, dni_extra, label=method)
    
plt.legend()
plt.ylabel('Extraterrestrial radiation (W/m^2)')


2016-10-26 00:00:00 spencer 1383.6362029
2016-10-26 00:00:00 asce 1385.08377469
2016-10-26 00:00:00 pyephem 1382.3920240844304
2016-10-26 00:00:00 nrel 1382.3912017480877
2016-10-26 spencer 1383.6362028955045
2016-10-26 asce 1385.0837746866198
2016-10-26 pyephem 1382.3920240844304
2016-10-26 nrel 1382.3912017480877
300 spencer 1383.6362029
300 asce 1385.08377469
300 pyephem 1382.618664623793
300 nrel 1382.6174658748046
Out[9]:
<matplotlib.text.Text at 0x11a4706d8>

Clear sky models

See the online documentation for clear sky modeling examples.

http://pvlib-python.readthedocs.io/en/latest/clearsky.html

Here we only generate data for the functions below.


In [10]:
tus = pvlib.location.Location(32.2, -111, 'US/Arizona', 700, 'Tucson')
times = pd.DatetimeIndex(start='2016-01-01', end='2016-01-02', freq='1min', tz=tus.tz)
ephem_data = tus.get_solarposition(times)
irrad_data = tus.get_clearsky(times)
irrad_data.plot()
plt.ylabel('Irradiance $W/m^2$')
plt.title('Ineichen, climatological turbidity')


Out[10]:
<matplotlib.text.Text at 0x118fd5a58>

Diffuse ground

The grounddiffuse function has a few different ways to obtain the diffuse light reflected from the ground given an surface tilt and the GHI.

First, you can specify the albedo of ground.


In [11]:
ground_irrad = pvlib.irradiance.grounddiffuse(40, irrad_data['ghi'], albedo=.25)
ground_irrad.plot()
plt.ylabel('Diffuse ground irradiance (W/m^2)')


Out[11]:
<matplotlib.text.Text at 0x11ce9c208>

Alternatively, you can specify the surface type with a string such as 'concrete' or 'snow'. All of the available surface_type options are show in the plot below.


In [12]:
try:
    sns.set_palette('husl', len(pvlib.irradiance.SURFACE_ALBEDOS.items()))
except:
    pass
    
for surface, albedo in sorted(pvlib.irradiance.SURFACE_ALBEDOS.items(), key=lambda x: x[1], reverse=True):
    ground_irrad = pvlib.irradiance.grounddiffuse(40, irrad_data['ghi'], surface_type=surface)
    ground_irrad.plot(label='{}: {}'.format(surface, albedo))

plt.legend()
plt.ylabel('Diffuse ground irradiance (W/m^2)')
plt.title('Surface types')


Out[12]:
<matplotlib.text.Text at 0x11cef7ac8>

Next, vary the tilt angle. We expect to see maximum ground diffuse irradiance at a 90 deg tilt, and no ground diffuse irradiance at 0 tilt.


In [13]:
for surf_tilt in np.linspace(0, 90, 5):
    ground_irrad = pvlib.irradiance.grounddiffuse(surf_tilt, irrad_data['ghi'])
    ground_irrad.plot(label=surf_tilt)

plt.legend()
plt.ylabel('Diffuse ground irradiance (W/m^2)')
plt.title('Ground diffuse as a function of tilt')


Out[13]:
<matplotlib.text.Text at 0x11c9f4668>

In [14]:
try:
    sns.set_palette('deep')
except:
    pass

Diffuse sky

pvlib has many different ways to calculate the diffuse sky component of GHI.

The API for some of these functions needs some work.

  1. Isotropic
  2. Klucher
  3. Reindl
  4. Hay-Davies
  5. Perez

Isotropic model

The isotropic model is the simplest model.


In [15]:
sky_diffuse = pvlib.irradiance.isotropic(40, irrad_data['dhi'])
sky_diffuse.plot(label='isotropic diffuse')
irrad_data['dhi'].plot()
irrad_data['ghi'].plot()
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


Out[15]:
<matplotlib.text.Text at 0x11bfa6cc0>

Compare just the POA diffuse to the input DHI.


In [16]:
sky_diffuse = pvlib.irradiance.isotropic(40, irrad_data['dhi'])
sky_diffuse.plot(label='isotropic diffuse')
irrad_data['dhi'].plot()
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


Out[16]:
<matplotlib.text.Text at 0x11a2aacf8>

Klucher model


In [17]:
surf_tilt = 40
surf_az = 180

sky_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, irrad_data['dhi'], irrad_data['ghi'], 
                                       ephem_data['apparent_zenith'], ephem_data['azimuth'])
sky_diffuse.plot(label='klucher diffuse')
irrad_data['dhi'].plot()
#irrad_data['ghi'].plot()
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


Out[17]:
<matplotlib.text.Text at 0x118f563c8>

In [18]:
surf_tilt = 40
surf_az = 180 # south facing

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, irrad_data['dhi'], irrad_data['ghi'], 
                                        ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

irrad_data['dhi'].plot()

plt.legend()
plt.ylabel('Irradiance (W/m^2)')


Out[18]:
<matplotlib.text.Text at 0x118d5b7f0>

Klucher as a function of surface azimuth.


In [19]:
surf_tilt = 40

irrad_data['dhi'].plot()

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic')

for surf_az in np.linspace(0, 270, 4):
    klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
    klucher_diffuse.plot(label='klucher: {}'.format(surf_az))

plt.legend()


Out[19]:
<matplotlib.legend.Legend at 0x11cc91dd8>

Surface azimuth should not matter if tilt is 0.


In [20]:
surf_tilt = 0

irrad_data['dhi'].plot()

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic')

for surf_az in np.linspace(0, 270, 4):
    klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, irrad_data['dhi'], irrad_data['ghi'], 
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
    klucher_diffuse.plot(label='klucher: {}'.format(surf_az))

plt.legend()


Out[20]:
<matplotlib.legend.Legend at 0x11a16aeb8>

Reindl model

South facing at latitude.


In [21]:
surf_tilt = 32
surf_az = 180 # south facing

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)
reindl_diffuse = pvlib.irradiance.reindl(surf_tilt, surf_az, 
                                          irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'], dni_et,
                                          ephem_data['apparent_zenith'], ephem_data['azimuth'])
reindl_diffuse.plot(label='reindl diffuse')

irrad_data['dhi'].plot()

plt.legend()


Out[21]:
<matplotlib.legend.Legend at 0x11cc9f240>

East facing


In [22]:
surf_tilt = 32
surf_az = 90 

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)
reindl_diffuse = pvlib.irradiance.reindl(surf_tilt, surf_az, 
                                          irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'], dni_et,
                                          ephem_data['apparent_zenith'], ephem_data['azimuth'])
reindl_diffuse.plot(label='reindl diffuse')

irrad_data['dhi'].plot()

plt.legend()


Out[22]:
<matplotlib.legend.Legend at 0x11bf9c358>

Hay-Davies model

Hay-Davies facing south.


In [23]:
surf_tilt = 32
surf_az = 180 

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)

haydavies_diffuse = pvlib.irradiance.haydavies(surf_tilt, surf_az, 
                                                irrad_data['dhi'], irrad_data['dni'], dni_et,
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
haydavies_diffuse.plot(label='haydavies diffuse')

reindl_diffuse = pvlib.irradiance.reindl(surf_tilt, surf_az, 
                                          irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'], dni_et,
                                          ephem_data['apparent_zenith'], ephem_data['azimuth'])
reindl_diffuse.plot(label='reindl diffuse')

irrad_data['dhi'].plot()

plt.legend()


Out[23]:
<matplotlib.legend.Legend at 0x117fac668>

Facing east.


In [24]:
surf_tilt = 32
surf_az = 90 

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)

haydavies_diffuse = pvlib.irradiance.haydavies(surf_tilt, surf_az, 
                                                irrad_data['dhi'], irrad_data['dni'], dni_et,
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
haydavies_diffuse.plot(label='haydavies diffuse')

reindl_diffuse = pvlib.irradiance.reindl(surf_tilt, surf_az, 
                                          irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'], dni_et,
                                          ephem_data['apparent_zenith'], ephem_data['azimuth'])
reindl_diffuse.plot(label='reindl diffuse')

irrad_data['dhi'].plot()

plt.legend()


Out[24]:
<matplotlib.legend.Legend at 0x11bfc67f0>

Hay-Davies appears to be very similar to Reindl. Too similar?

King model


In [25]:
surf_tilt = 32
surf_az = 90 

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)

haydavies_diffuse = pvlib.irradiance.haydavies(surf_tilt, surf_az, 
                                                irrad_data['dhi'], irrad_data['dni'], dni_et,
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
haydavies_diffuse.plot(label='haydavies diffuse')

king_diffuse = pvlib.irradiance.king(surf_tilt,irrad_data['dhi'], irrad_data['ghi'], ephem_data['azimuth'])
king_diffuse.plot(label='king diffuse')

irrad_data['dhi'].plot()

plt.legend()


Out[25]:
<matplotlib.legend.Legend at 0x114636a20>

Perez model

This section walks through the Perez algorithm.


In [26]:
sun_zen = ephem_data['apparent_zenith']
sun_az = ephem_data['azimuth']
DNI = irrad_data['dni']
DHI = irrad_data['dhi']
DNI_ET = pvlib.irradiance.extraradiation(times.dayofyear)
AM = pvlib.atmosphere.relativeairmass(sun_zen)

surf_tilt = 32
surf_az = 180

kappa = 1.041 #for sun_zen in radians
z = np.radians(sun_zen) # convert to radians

#Dhfilter = DHI > 0

# epsilon is the sky's clearness
eps = ( (DHI + DNI)/DHI + kappa*(z**3) ) / ( 1 + kappa*(z**3) )

In [27]:
eps.plot()


Out[27]:
<matplotlib.axes._subplots.AxesSubplot at 0x11ce5ef98>

In [28]:
ebin = eps.copy()
ebin[(eps<1.065)] = 1
ebin[(eps>=1.065) & (eps<1.23)] = 2
ebin[(eps>=1.23) & (eps<1.5)] = 3
ebin[(eps>=1.5) & (eps<1.95)] = 4
ebin[(eps>=1.95) & (eps<2.8)] = 5
ebin[(eps>=2.8) & (eps<4.5)] = 6
ebin[(eps>=4.5) & (eps<6.2)] = 7
ebin[eps>=6.2] = 8

ebin.plot()
plt.ylim(0,9)


Out[28]:
(0, 9)

In [29]:
ebin = ebin - 1
ebin = ebin.dropna().astype(int)
ebin.plot()


Out[29]:
<matplotlib.axes._subplots.AxesSubplot at 0x116e26940>

In [30]:
delta = DHI * AM / DNI_ET
delta.plot()


Out[30]:
<matplotlib.axes._subplots.AxesSubplot at 0x1191be710>

In [31]:
modelt = 'allsitescomposite1990'

F1c, F2c = pvlib.irradiance._get_perez_coefficients(modelt)

F1 = F1c[ebin,0] + F1c[ebin,1]*delta[ebin.index] + F1c[ebin,2]*z[ebin.index]
F1[F1<0]=0;
F1=F1.astype(float)

#F2= F2c[ebin,0] + F2c[ebin,1]*delta[ebinfilter] + F2c[ebin,2]*z[ebinfilter]
F2= F2c[ebin,0] + F2c[ebin,1]*delta[ebin.index] + F2c[ebin,2]*z[ebin.index]
F2[F2<0]=0
F2=F2.astype(float)

F1.plot(label='F1')
F2.plot(label='F2')
plt.legend()


Out[31]:
<matplotlib.legend.Legend at 0x118079198>

In [32]:
from pvlib import tools

In [33]:
A = tools.cosd(surf_tilt)*tools.cosd(sun_zen) + tools.sind(surf_tilt)*tools.sind(sun_zen)*tools.cosd(sun_az-surf_az) #removed +180 from azimuth modifier: Rob Andrews October 19th 2012
#A[A < 0] = 0

B = tools.cosd(sun_zen);
#B[B < pvl_tools.cosd(85)] = pvl_tools.cosd(85)

A.plot(label='A')
B.plot(label='B')
plt.legend()


Out[33]:
<matplotlib.legend.Legend at 0x11a49d518>

In [34]:
sky_diffuse = DHI*( 0.5* (1-F1)*(1+tools.cosd(surf_tilt))+F1 * A[ebin.index]/ B[ebin.index] + F2*tools.sind(surf_tilt))
sky_diffuse[sky_diffuse < 0] = 0
sky_diffuse[AM.isnull()] = 0

sky_diffuse.plot()


Out[34]:
<matplotlib.axes._subplots.AxesSubplot at 0x11bc494a8>

Compare the Perez model to others.


In [35]:
sun_zen = ephem_data['apparent_zenith']
sun_az = ephem_data['azimuth']
DNI = irrad_data['dni']
DHI = irrad_data['dhi']
DNI_ET = pvlib.irradiance.extraradiation(times.dayofyear)
AM = pvlib.atmosphere.relativeairmass(sun_zen)

surf_tilt = 32
surf_az = 180

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)

haydavies_diffuse = pvlib.irradiance.haydavies(surf_tilt, surf_az, 
                                                irrad_data['dhi'], irrad_data['dni'], dni_et,
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
haydavies_diffuse.plot(label='haydavies diffuse')

perez_diffuse = pvlib.irradiance.perez(surf_tilt, surf_az, 
                                        irrad_data['dhi'], irrad_data['dni'], dni_et,
                                        ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                        AM)
perez_diffuse.plot(label='perez diffuse')

irrad_data['dhi'].plot()

plt.legend()


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[35]:
<matplotlib.legend.Legend at 0x11bfbeb00>

In [36]:
sun_zen = ephem_data['apparent_zenith']
sun_az = ephem_data['azimuth']
DNI = irrad_data['dni']
DHI = irrad_data['dhi']
DNI_ET = pvlib.irradiance.extraradiation(times.dayofyear)
AM = pvlib.atmosphere.relativeairmass(sun_zen)

surf_tilt = 32
surf_az = 90

iso_diffuse = pvlib.irradiance.isotropic(surf_tilt, irrad_data['dhi'])
iso_diffuse.plot(label='isotropic diffuse')

klucher_diffuse = pvlib.irradiance.klucher(surf_tilt, surf_az, 
                                            irrad_data['dhi'], irrad_data['ghi'], 
                                            ephem_data['apparent_zenith'], ephem_data['azimuth'])
klucher_diffuse.plot(label='klucher diffuse')

dni_et = pvlib.irradiance.extraradiation(times.dayofyear)

haydavies_diffuse = pvlib.irradiance.haydavies(surf_tilt, surf_az, 
                                                irrad_data['dhi'], irrad_data['dni'], dni_et,
                                                ephem_data['apparent_zenith'], ephem_data['azimuth'])
haydavies_diffuse.plot(label='haydavies diffuse')

perez_diffuse = pvlib.irradiance.perez(surf_tilt, surf_az, 
                                        irrad_data['dhi'], irrad_data['dni'], dni_et,
                                        ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                        AM)
perez_diffuse.plot(label='perez diffuse')

irrad_data['dhi'].plot()

plt.legend()


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[36]:
<matplotlib.legend.Legend at 0x11d146390>

Examine the impact of the coeffecient selection.


In [37]:
perez_diffuse = pvlib.irradiance.perez(surf_tilt, surf_az, 
                                        irrad_data['dhi'], irrad_data['dni'], dni_et,
                                        ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                        AM, model='allsitescomposite1990')
perez_diffuse.plot(label='allsitescomposite1990')

perez_diffuse = pvlib.irradiance.perez(surf_tilt, surf_az, 
                                        irrad_data['dhi'], irrad_data['dni'], dni_et,
                                        ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                        AM, model='phoenix1988')
perez_diffuse.plot(label='phoenix1988')

plt.legend()


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[37]:
<matplotlib.legend.Legend at 0x11d12fc50>

Angle of incidence functions

The irradiance module has some convenience functions to help calculate the angle of incidence.

First, the angle of incidence.


In [38]:
proj = pvlib.irradiance.aoi(32, 180, ephem_data['apparent_zenith'], ephem_data['azimuth'])
proj.plot()

#plt.ylim(-1.1,1.1)
plt.legend()


Out[38]:
<matplotlib.legend.Legend at 0x11cc13cf8>

AOI projection: the dot production of the surface normal and the vector to the sun.


In [39]:
proj = pvlib.irradiance.aoi_projection(32, 180, ephem_data['apparent_zenith'], ephem_data['azimuth'])
proj.plot()

plt.ylim(-1.1,1.1)
plt.legend()


Out[39]:
<matplotlib.legend.Legend at 0x1179fee10>

The ratio between POA projection and the horizontal projection.


In [40]:
ratio = pvlib.irradiance.poa_horizontal_ratio(32, 180, ephem_data['apparent_zenith'], ephem_data['azimuth'])
ratio.plot()
plt.ylim(-4,4)


Out[40]:
(-4, 4)

This plot shows that an explicit dot product calculation gives the same result as aoi_projection.


In [41]:
surf_tilt = 90
surf_az = 90

sen_alt_rad = np.radians(90 - surf_tilt)
sen_azi_rad = np.radians(surf_az)

alts = np.radians(90 - ephem_data['apparent_zenith'])
azis = np.radians(ephem_data['azimuth'])

dotprod = np.cos(sen_alt_rad)*np.cos(alts)*np.cos(sen_azi_rad-azis) + np.sin(sen_alt_rad)*np.sin(alts)
dotprod.plot(label='dotprod')

proj = pvlib.irradiance.aoi_projection(surf_tilt, surf_az, ephem_data['apparent_zenith'], ephem_data['azimuth'])
proj.plot()

plt.ylim(-1.1,1.1)
plt.legend()


Out[41]:
<matplotlib.legend.Legend at 0x117f7aa58>

total_irrad

There is an experimental convenience function total_irrad that aims to make it easier to play with different models. For now, we use it to make summary plots of the models explored above.

South facing with latitude tilt.


In [42]:
models = ['isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez']
totals = {}

for model in models:
    total = pvlib.irradiance.total_irrad(32, 180, 
                                           ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                           dni=irrad_data['dni'], ghi=irrad_data['ghi'], dhi=irrad_data['dhi'],
                                           dni_extra=dni_et, airmass=AM,
                                           model=model,
                                           surface_type='urban')
    totals[model] = total
    total.plot()
    plt.title(model)
    plt.ylabel('Irradiance (W/m^2)')
    
    
plt.figure()
for model, total in totals.items():
    total['poa_global'].plot(lw=.5, label=model)
    
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[42]:
<matplotlib.text.Text at 0x11d0fdeb8>

tilt = 0


In [43]:
models = ['isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez']
totals = {}

for model in models:
    total = pvlib.irradiance.total_irrad(0, 180, 
                                           ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                           dni=irrad_data['dni'], ghi=irrad_data['ghi'], dhi=irrad_data['dhi'],
                                           dni_extra=dni_et, airmass=AM,
                                           model=model,
                                           surface_type='urban')
    totals[model] = total
    total.plot()
    plt.title(model)
    plt.ylabel('Irradiance (W/m^2)')
    
    
plt.figure()
for model, total in totals.items():
    total['poa_global'].plot(lw=.5, label=model)
    
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[43]:
<matplotlib.text.Text at 0x127aad2b0>

East facing with latitude tilt.


In [44]:
models = ['isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez']
totals = {}

for model in models:
    total = pvlib.irradiance.total_irrad(32, 90, 
                                           ephem_data['apparent_zenith'], ephem_data['azimuth'],
                                           dni=irrad_data['dni'], ghi=irrad_data['ghi'], dhi=irrad_data['dhi'],
                                           dni_extra=dni_et, airmass=AM,
                                           model=model,
                                           surface_type='urban')
    totals[model] = total
    total.plot()
    plt.title(model)
    plt.ylabel('Irradiance (W/m^2)')
    
    
plt.figure()
for model, total in totals.items():
    total['poa_global'].plot(lw=.5, label=model)
    
plt.legend()
plt.ylabel('Irradiance (W/m^2)')


/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1002: RuntimeWarning: invalid value encountered in less
  ebin[eps < 1.065] = 1
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1003: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.065) & (eps < 1.23)] = 2
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1004: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.23) & (eps < 1.5)] = 3
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1005: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.5) & (eps < 1.95)] = 4
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1006: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 1.95) & (eps < 2.8)] = 5
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1007: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 2.8) & (eps < 4.5)] = 6
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in greater_equal
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1008: RuntimeWarning: invalid value encountered in less
  ebin[(eps >= 4.5) & (eps < 6.2)] = 7
/Users/holmgren/git_repos/pvlib-python/pvlib/irradiance.py:1009: RuntimeWarning: invalid value encountered in greater_equal
  ebin[eps >= 6.2] = 8
Out[44]:
<matplotlib.text.Text at 0x1247f3cf8>

In [ ]: