diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index 2f208fb3cb..ee2e781d00 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -26,14 +26,12 @@ time series of clear sky data for a location. The :ref:`ineichen` and input data. The :ref:`detect_clearsky` subsection demonstrates the use of the clear sky detection algorithm. -The :py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb`, and -:py:func:`~pvlib.atmosphere.kasten96_lt` functions are useful for -calculating inputs to the clear sky functions. - We'll need these imports for the examples below. .. ipython:: + In [1]: import os + In [1]: import itertools In [1]: import matplotlib.pyplot as plt @@ -42,7 +40,7 @@ We'll need these imports for the examples below. In [1]: import pvlib - In [1]: from pvlib import clearsky, atmosphere + In [1]: from pvlib import clearsky, atmosphere, tmy, solarposition In [1]: from pvlib.location import Location @@ -118,6 +116,7 @@ The Ineichen and Perez clear sky model parameterizes irradiance in terms of the Linke turbidity [Ine02]_. pvlib-python implements this model in the :py:func:`pvlib.clearsky.ineichen` function. + Turbidity data ^^^^^^^^^^^^^^ @@ -198,6 +197,62 @@ varies from 300 m to 1500 m. @savefig turbidity-yes-interp.png width=6in In [1]: plt.ylabel('Linke Turbidity'); +The :py:func:`~pvlib.atmosphere.kasten96_lt` function can be used to calculate +Linke turbidity [Kas96]_ as input to the clear sky Ineichen and Perez function. +The Kasten formulation requires precipitable water and broadband aerosol +optical depth (AOD). According to Molineaux, broadband AOD can be approximated +by a single measurement at 700-nm [Mol98]_. An alternate broadband AOD +approximation from Bird and Hulstrom combines AOD measured at two +wavelengths [Bir80]_, and is implemented in +:py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb`. + +.. ipython:: + + In [1]: pvlib_data = os.path.join(os.path.dirname(pvlib.__file__), 'data') + + In [1]: mbars = 100 # conversion factor from mbars to Pa + + In [1]: tmy_file = os.path.join(pvlib_data, '703165TY.csv') # TMY file + + In [1]: tmy_data, tmy_header = tmy.readtmy3(tmy_file, coerce_year=1999) # read TMY data + + In [1]: tl_historic = clearsky.lookup_linke_turbidity(time=tmy_data.index, + ...: latitude=tmy_header['latitude'], longitude=tmy_header['longitude']) + + In [1]: solpos = solarposition.get_solarposition(time=tmy_data.index, + ...: latitude=tmy_header['latitude'], longitude=tmy_header['longitude'], + ...: altitude=tmy_header['altitude'], pressure=tmy_data['Pressure']*mbars, + ...: temperature=tmy_data['DryBulb']) + + In [1]: am_rel = atmosphere.get_relative_airmass(solpos.apparent_zenith) + + In [1]: am_abs = atmosphere.get_absolute_airmass(am_rel, tmy_data['Pressure']*mbars) + + In [1]: airmass = pd.concat([am_rel, am_abs], axis=1).rename( + ...: columns={0: 'airmass_relative', 1: 'airmass_absolute'}) + + In [1]: tl_calculated = atmosphere.kasten96_lt( + ...: airmass.airmass_absolute, tmy_data['Pwat'], tmy_data['AOD']) + + In [1]: tl = pd.concat([tl_historic, tl_calculated], axis=1).rename( + ...: columns={0:'Historic', 1:'Calculated'}) + + In [1]: tl.index = tmy_data.index.tz_convert(None) # remove timezone + + In [1]: tl.resample('W').mean().plot(); + + In [1]: plt.grid() + + In [1]: plt.title('Comparison of Historic Linke Turbidity Factors vs. \n' + ...: 'Kasten Pyrheliometric Formula at {name:s}, {state:s} ({usaf:d}TY)'.format( + ...: name=tmy_header['Name'], state=tmy_header['State'], usaf=tmy_header['USAF'])); + + In [1]: plt.ylabel('Linke Turbidity Factor, TL'); + + @savefig kasten-tl.png width=10in + In [1]: plt.tight_layout() + + Examples ^^^^^^^^ @@ -326,11 +381,32 @@ contain one or both of aerosols and precipitable water. Consider data from the `ECMWF `_ and `SoDa `_. -Aerosol optical depth is a function of wavelength, and the Simplified -Solis model requires AOD at 700 nm. Models exist to convert AOD between -different wavelengths, as well as convert Linke turbidity to AOD and PW -[Ine08con]_, [Ine16]_. +Aerosol optical depth (AOD) is a function of wavelength, and the Simplified +Solis model requires AOD at 700 nm. +:py:func:`~pvlib.atmosphere.angstrom_aod_at_lambda` is useful for converting +AOD between different wavelengths using the Angstrom turbidity model. The +Angstrom exponent, :math:`\alpha`, can be calculated from AOD at two +wavelengths with :py:func:`~pvlib.atmosphere.angstrom_alpha`. +[Ine08con]_, [Ine16]_, [Ang61]_. + +.. ipython:: + + In [1]: aod1240nm = 1.2 # fictitious AOD measured at 1240-nm + + In [1]: aod550nm = 3.1 # fictitious AOD measured at 550-nm + In [1]: alpha_exponent = atmosphere.angstrom_alpha(aod1240nm, 1240, aod550nm, 550) + + In [1]: aod700nm = atmosphere.angstrom_aod_at_lambda(aod1240nm, 1240, alpha_exponent, 700) + + In [1]: aod380nm = atmosphere.angstrom_aod_at_lambda(aod550nm, 550, alpha_exponent, 380) + + In [1]: aod500nm = atmosphere.angstrom_aod_at_lambda(aod550nm, 550, alpha_exponent, 500) + + In [1]: aod_bb = atmosphere.bird_hulstrom80_aod_bb(aod380nm, aod500nm) + + In [1]: print('compare AOD at 700-nm = {:g}, to estimated broadband AOD = {:g}, ' + ...: 'with alpha = {:g}'.format(aod700nm, aod_bb, alpha_exponent)) Examples ^^^^^^^^ @@ -617,3 +693,17 @@ References .. [Ren16] Reno, M.J. and C.W. Hansen, "Identification of periods of clear sky irradiance in time series of GHI measurements" Renewable Energy, v90, p. 520-531, 2016. + +.. [Mol98] B. Molineaux, P. Ineichen, and N. O’Neill, “Equivalence of + pyrheliometric and monochromatic aerosol optical depths at a single key + wavelength.,” Appl. Opt., vol. 37, no. 30, pp. 7008–18, Oct. 1998. + +.. [Kas96] F. Kasten, “The linke turbidity factor based on improved values + of the integral Rayleigh optical thickness,” Sol. Energy, vol. 56, no. 3, + pp. 239–244, Mar. 1996. + +.. [Bir80] R. E. Bird and R. L. Hulstrom, “Direct Insolation Models,” + 1980. + +.. [Ang61] A. ÅNGSTRÖM, “Techniques of Determinig the Turbidity of the + Atmosphere,” Tellus A, vol. 13, no. 2, pp. 214–223, 1961. diff --git a/docs/sphinx/source/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst index f534fd6213..154495713d 100644 --- a/docs/sphinx/source/whatsnew/v0.6.0.rst +++ b/docs/sphinx/source/whatsnew/v0.6.0.rst @@ -107,6 +107,7 @@ Enhancements * Add irradiance.clearness_index_zenith_independent function. (:issue:`396`) * Add checking for consistency between module_parameters and dc_model. (:issue:`417`) * Add DC model methods desoto and pvsyst to ModelChain (:issue:`487`) +* Set default alpha to 1.14 in :func:`~pvlib.atmosphere.angstrom_aod_at_lambda` (:issue:`563`) Bug fixes @@ -152,6 +153,8 @@ Documentation top-level "Intro Examples" page. * Copy pvlib documentation's "Getting support" section to README.md. * Add PVSystem documentation page. (:issue:`514`, :issue:`319`) +* Add example of Kasten Linke Turbidity calculation, discuss broadband AOD and + Angstrom Turbidity Model. (:issue:`302`) Testing diff --git a/pvlib/atmosphere.py b/pvlib/atmosphere.py index 46cbd2a110..ab4446a9c3 100644 --- a/pvlib/atmosphere.py +++ b/pvlib/atmosphere.py @@ -621,7 +621,7 @@ def kasten96_lt(airmass_absolute, precipitable_water, aod_bb): return lt -def angstrom_aod_at_lambda(aod0, lambda0, alpha, lambda1=700.0): +def angstrom_aod_at_lambda(aod0, lambda0, alpha=1.14, lambda1=700.0): r""" Get AOD at specified wavelength using Angstrom turbidity model. @@ -631,7 +631,7 @@ def angstrom_aod_at_lambda(aod0, lambda0, alpha, lambda1=700.0): aerosol optical depth (AOD) measured at known wavelength lambda0 : numeric wavelength in nanometers corresponding to ``aod0`` - alpha : numeric + alpha : numeric, default 1.14 Angstrom :math:`\alpha` exponent corresponding to ``aod0`` lambda1 : numeric, default 700 desired wavelength in nanometers