From 3ba597e92196b9f83f3b2a9ef6bcd604161b9239 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 02:00:50 -0700 Subject: [PATCH 1/9] DOC: add example for Kasten pyrheliometric formula * closes #302 * add references to Kasten 96 and Molineaux * discuss using Kasten and calculating broadband AOD usinge Angstrom turbidity model Signed-off-by: Mark Mikofski --- docs/sphinx/source/clearsky.rst | 75 ++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index 2f208fb3cb..f2fd783917 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -26,10 +26,6 @@ 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:: @@ -42,7 +38,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 +114,57 @@ 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. + +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 AOD which can +be approximated at 700-nm [Mol98]_ or from the function, +:py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb` which uses a combination of +AOD measured at two wavelengths. + +.. ipython:: + + In [1]: MBARS = 100 # conversion factor from mbars to Pa + + In [1]: URL = 'http://rredc.nrel.gov/solar/old_data/nsrdb/1991-2005/data/tmy3/722040TYA.CSV' + + In [1]: melbourne = tmy.readtmy3(URL) + + In [1]: dt = pd.DatetimeIndex(start='2000-01-01 01:00:00', end='2000-12-31', freq='H') + + In [1]: melbourne[0].index = dt + + In [1]: melbourne_tl = clearsky.lookup_linke_turbidity(time=melbourne[0].index, + ...: latitude=melbourne[1]['latitude'], longitude=melbourne[1]['longitude']) + + In [1]: melbourne_solpos = solarposition.get_solarposition(time=melbourne[0].index, + ...: latitude=melbourne[1]['latitude'], longitude=melbourne[1]['longitude'], + ...: altitude=melbourne[1]['altitude'], pressure=melbourne[0]['Pressure']*MBARS, + ...: temperature=melbourne[0]['DryBulb']) + + In [1]: am_rel = atmosphere.relativeairmass(melbourne_solpos.apparent_zenith) + + In [1]: am_abs = atmosphere.absoluteairmass(am_rel, melbourne[0]['Pressure']*MBARS) + + In [1]: melbourne_am = pd.DataFrame({'airmass_relative': am_rel, 'airmass_absolute': am_abs}, + ...: index=melbourne[0].index) + + In [1]: melbourne_tl_molineaux = atmosphere.kasten96_lt( + ...: melbourne_am.airmass_absolute, melbourne[0]['Pwat'], melbourne[0]['AOD']) + + In [1]: tl = pd.concat([melbourne_tl, melbourne_tl_molineaux], axis=1) + + In [1]: tl.rename(columns={0:'TL', 1:'Kasten'}).resample('W').mean().plot(); + + In [1]: plt.grid() + + In [1]: plt.title('\n'.join(['Comparison of Historic Linke Turbidity Factors vs.', + ...: 'Kasten Pyrheliometric Formula at Melbourne, FL (722040TYA)'])); + + @savefig kasten-tl.png width=10in + In [1]: plt.ylabel('Linke Turbidity Factor, TL'); + + Turbidity data ^^^^^^^^^^^^^^ @@ -327,8 +374,14 @@ from the `ECMWF `_. 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 +Solis model requires AOD at 700 nm. The function, +:py:func:`~pvlib.atmosphere.angstrom_aod_at_lambda`, is useful for converting +AOD between different wavelengths using the Angstrom turbidity model and given +the Angstrom exponent, :math:`\alpha`, which can be calculated from AOD at two +wavelengths with the :py:func:`~pvlib.atmosphere.angstrom_alpha` function. The +function, :py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb`, can be used to +approximate broadband AOD based on the Bird and Hulstrom model, but the +recommendation by Molineaux is to use AOD at 700-nm for broadband. [Ine08con]_, [Ine16]_. @@ -617,3 +670,11 @@ 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. From fffab3a6abd4910eab874577580bfa392525ee55 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 02:25:36 -0700 Subject: [PATCH 2/9] DOC: update what's new, add refs to Bird & Hulstrom and Angstrom --- docs/sphinx/source/clearsky.rst | 10 ++++++++-- docs/sphinx/source/whatsnew/v0.6.0.rst | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index f2fd783917..c05943f6bf 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -120,7 +120,7 @@ Linke turbidity [Kas96]_ as input to the clear sky Ineichen and Perez function. The Kasten formulation requires precipitable water and broadband AOD which can be approximated at 700-nm [Mol98]_ or from the function, :py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb` which uses a combination of -AOD measured at two wavelengths. +AOD measured at two wavelengths [Bir80]_. .. ipython:: @@ -382,7 +382,7 @@ wavelengths with the :py:func:`~pvlib.atmosphere.angstrom_alpha` function. The function, :py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb`, can be used to approximate broadband AOD based on the Bird and Hulstrom model, but the recommendation by Molineaux is to use AOD at 700-nm for broadband. -[Ine08con]_, [Ine16]_. +[Ine08con]_, [Ine16]_, [Ang61]_, [Bir80]_, [Mol98]_. Examples @@ -678,3 +678,9 @@ References .. [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 3e95eeb079..fbe015b2ed 100644 --- a/docs/sphinx/source/whatsnew/v0.6.0.rst +++ b/docs/sphinx/source/whatsnew/v0.6.0.rst @@ -152,6 +152,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 From e149e3ee2ceb94653bec40848d0ef4a1b534c6dd Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 11:05:45 -0700 Subject: [PATCH 3/9] DOC: split sentences, replace abbrev. AOD * use TMY in pvlib/data, lowercase MBARS, use non-specific variable names * split output from readtmy3 instead of using indexing for clarity --- docs/sphinx/source/clearsky.rst | 55 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index c05943f6bf..f4237595b7 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -30,6 +30,8 @@ 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 @@ -117,49 +119,54 @@ the :py:func:`pvlib.clearsky.ineichen` function. 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 AOD which can -be approximated at 700-nm [Mol98]_ or from the function, -:py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb` which uses a combination of -AOD measured at two wavelengths [Bir80]_. +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]: MBARS = 100 # conversion factor from mbars to Pa + 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]: URL = 'http://rredc.nrel.gov/solar/old_data/nsrdb/1991-2005/data/tmy3/722040TYA.CSV' + In [1]: tmy_file = os.path.join(pvlib_data, '703165TY.csv') # TMY file - In [1]: melbourne = tmy.readtmy3(URL) + In [1]: tmy_data, tmy_header = tmy.readtmy3(tmy_file) # read TMY data In [1]: dt = pd.DatetimeIndex(start='2000-01-01 01:00:00', end='2000-12-31', freq='H') - In [1]: melbourne[0].index = dt + In [1]: tmy_data.index = dt # replace TMY timestamps - In [1]: melbourne_tl = clearsky.lookup_linke_turbidity(time=melbourne[0].index, - ...: latitude=melbourne[1]['latitude'], longitude=melbourne[1]['longitude']) + In [1]: tl_historic = clearsky.lookup_linke_turbidity(time=tmy_data.index, + ...: latitude=tmy_header['latitude'], longitude=tmy_header['longitude']) - In [1]: melbourne_solpos = solarposition.get_solarposition(time=melbourne[0].index, - ...: latitude=melbourne[1]['latitude'], longitude=melbourne[1]['longitude'], - ...: altitude=melbourne[1]['altitude'], pressure=melbourne[0]['Pressure']*MBARS, - ...: temperature=melbourne[0]['DryBulb']) + 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.relativeairmass(melbourne_solpos.apparent_zenith) + In [1]: am_rel = atmosphere.relativeairmass(solpos.apparent_zenith) - In [1]: am_abs = atmosphere.absoluteairmass(am_rel, melbourne[0]['Pressure']*MBARS) + In [1]: am_abs = atmosphere.absoluteairmass(am_rel, tmy_data['Pressure']*MBARS) - In [1]: melbourne_am = pd.DataFrame({'airmass_relative': am_rel, 'airmass_absolute': am_abs}, - ...: index=melbourne[0].index) + In [1]: airmass = pd.DataFrame({'airmass_relative': am_rel, 'airmass_absolute': am_abs}, + ...: index=tmy_data.index) - In [1]: melbourne_tl_molineaux = atmosphere.kasten96_lt( - ...: melbourne_am.airmass_absolute, melbourne[0]['Pwat'], melbourne[0]['AOD']) + In [1]: tl_calculated = atmosphere.kasten96_lt( + ...: airmass.airmass_absolute, tmy_data['Pwat'], tmy_data['AOD']) - In [1]: tl = pd.concat([melbourne_tl, melbourne_tl_molineaux], axis=1) + In [1]: tl = pd.concat([tl_historic, tl_calculated], axis=1) - In [1]: tl.rename(columns={0:'TL', 1:'Kasten'}).resample('W').mean().plot(); + In [1]: tl.rename(columns={0:'Historic', 1:'Calculated'}).resample('W').mean().plot(); In [1]: plt.grid() - In [1]: plt.title('\n'.join(['Comparison of Historic Linke Turbidity Factors vs.', - ...: 'Kasten Pyrheliometric Formula at Melbourne, FL (722040TYA)'])); + 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'])); @savefig kasten-tl.png width=10in In [1]: plt.ylabel('Linke Turbidity Factor, TL'); From 4b93e22a2c2bf5a7c3be6c9865bc9581ebc46347 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 12:14:05 -0700 Subject: [PATCH 4/9] DOC: fix up ipython example --- docs/sphinx/source/clearsky.rst | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index f4237595b7..0d195af8fb 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -128,7 +128,7 @@ wavelengths [Bir80]_, and is implemented in .. ipython:: - In [1] pvlib_data = os.path.join(os.path.dirname(pvlib.__file__), 'data') + In [1]: pvlib_data = os.path.join(os.path.dirname(pvlib.__file__), 'data') In [1]: mbars = 100 # conversion factor from mbars to Pa @@ -136,31 +136,35 @@ wavelengths [Bir80]_, and is implemented in In [1]: tmy_data, tmy_header = tmy.readtmy3(tmy_file) # read TMY data - In [1]: dt = pd.DatetimeIndex(start='2000-01-01 01:00:00', end='2000-12-31', freq='H') + In [1]: dt = pd.DatetimeIndex(start='1999-01-01 00:00:00', end='1999-12-31 23:59:59', + ...: freq='H') - In [1]: tmy_data.index = dt # replace TMY timestamps + In [1]: tmy_data.index = dt.tz_localize(tz=tmy_data.index.tz) # replace timestamps 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, + ...: altitude=tmy_header['altitude'], pressure=tmy_data['Pressure']*mbars, ...: temperature=tmy_data['DryBulb']) In [1]: am_rel = atmosphere.relativeairmass(solpos.apparent_zenith) - In [1]: am_abs = atmosphere.absoluteairmass(am_rel, tmy_data['Pressure']*MBARS) + In [1]: am_abs = atmosphere.absoluteairmass(am_rel, tmy_data['Pressure']*mbars) - In [1]: airmass = pd.DataFrame({'airmass_relative': am_rel, 'airmass_absolute': am_abs}, - ...: index=tmy_data.index) + 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) + In [1]: tl = pd.concat([tl_historic, tl_calculated], axis=1).rename( + ...: columns={0:'Historic', 1:'Calculated'}) - In [1]: tl.rename(columns={0:'Historic', 1:'Calculated'}).resample('W').mean().plot(); + In [1]: tl.index = dt # remove timezone + + In [1]: tl.resample('W').mean().plot(); In [1]: plt.grid() From 8f3004e67f8d66e6f53290039cb8208fc5307093 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 12:54:40 -0700 Subject: [PATCH 5/9] DOC: split sentences, revise, add angstrom example --- docs/sphinx/source/clearsky.rst | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index 0d195af8fb..120bf6eb4a 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -385,15 +385,22 @@ from the `ECMWF `_. Aerosol optical depth is a function of wavelength, and the Simplified -Solis model requires AOD at 700 nm. The function, -:py:func:`~pvlib.atmosphere.angstrom_aod_at_lambda`, is useful for converting -AOD between different wavelengths using the Angstrom turbidity model and given -the Angstrom exponent, :math:`\alpha`, which can be calculated from AOD at two -wavelengths with the :py:func:`~pvlib.atmosphere.angstrom_alpha` function. The -function, :py:func:`~pvlib.atmosphere.bird_hulstrom80_aod_bb`, can be used to -approximate broadband AOD based on the Bird and Hulstrom model, but the -recommendation by Molineaux is to use AOD at 700-nm for broadband. -[Ine08con]_, [Ine16]_, [Ang61]_, [Bir80]_, [Mol98]_. +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 = 2.2 # AOD measured at 1240-nm + + In [1]: aod550nm = 3.3 # 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) Examples From daf04c5e77fe0d47a643044340b8023d3cdaf42e Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 13:54:17 -0700 Subject: [PATCH 6/9] ENH: set default alpha to 1.14, update what's new --- docs/sphinx/source/whatsnew/v0.6.0.rst | 1 + pvlib/atmosphere.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst index 5be39bee10..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 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 From f64f7189693d47ae7988eacf016817dc7abbb3a3 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 15:14:40 -0700 Subject: [PATCH 7/9] DOC: use coerce year, use v0.6.0 get_property() for airmass --- docs/sphinx/source/clearsky.rst | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index 120bf6eb4a..11fcf8ccb5 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -134,12 +134,7 @@ wavelengths [Bir80]_, and is implemented in In [1]: tmy_file = os.path.join(pvlib_data, '703165TY.csv') # TMY file - In [1]: tmy_data, tmy_header = tmy.readtmy3(tmy_file) # read TMY data - - In [1]: dt = pd.DatetimeIndex(start='1999-01-01 00:00:00', end='1999-12-31 23:59:59', - ...: freq='H') - - In [1]: tmy_data.index = dt.tz_localize(tz=tmy_data.index.tz) # replace timestamps + 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']) @@ -149,9 +144,9 @@ wavelengths [Bir80]_, and is implemented in ...: altitude=tmy_header['altitude'], pressure=tmy_data['Pressure']*mbars, ...: temperature=tmy_data['DryBulb']) - In [1]: am_rel = atmosphere.relativeairmass(solpos.apparent_zenith) + In [1]: am_rel = atmosphere.get_relative_airmass(solpos.apparent_zenith) - In [1]: am_abs = atmosphere.absoluteairmass(am_rel, tmy_data['Pressure']*mbars) + 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'}) @@ -162,7 +157,7 @@ wavelengths [Bir80]_, and is implemented in In [1]: tl = pd.concat([tl_historic, tl_calculated], axis=1).rename( ...: columns={0:'Historic', 1:'Calculated'}) - In [1]: tl.index = dt # remove timezone + In [1]: tl.index = tmy_data.index.tz_convert(None) # remove timezone In [1]: tl.resample('W').mean().plot(); @@ -172,9 +167,10 @@ wavelengths [Bir80]_, and is implemented in ...: 'Kasten Pyrheliometric Formula at {name:s}, {state:s} ({usaf:d}TY)'.format( ...: name=tmy_header['Name'], state=tmy_header['State'], usaf=tmy_header['USAF'])); - @savefig kasten-tl.png width=10in In [1]: plt.ylabel('Linke Turbidity Factor, TL'); + @savefig kasten-tl.png width=10in + In [1]: plt.tight_layout() Turbidity data ^^^^^^^^^^^^^^ From 70231ea74f9d1bfe01799decd25d87142ea6c772 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 15:30:36 -0700 Subject: [PATCH 8/9] DOC: print calculated AOD, move TL calculation after turbidity section --- docs/sphinx/source/clearsky.rst | 123 +++++++++++++++++--------------- 1 file changed, 66 insertions(+), 57 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index 11fcf8ccb5..a3c90f2003 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -117,61 +117,6 @@ of the Linke turbidity [Ine02]_. pvlib-python implements this model in the :py:func:`pvlib.clearsky.ineichen` function. -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() - Turbidity data ^^^^^^^^^^^^^^ @@ -252,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 ^^^^^^^^ @@ -390,14 +391,22 @@ wavelengths with :py:func:`~pvlib.atmosphere.angstrom_alpha`. .. ipython:: - In [1]: aod1240nm = 2.2 # AOD measured at 1240-nm + In [1]: aod1240nm = 1.2 # AOD measured at 1240-nm - In [1]: aod550nm = 3.3 # AOD measured at 550-nm + In [1]: aod550nm = 3.1 # 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 ^^^^^^^^ From 04fd379ddab729895eb0570bf9182a41717d2eb1 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 6 Sep 2018 15:43:32 -0700 Subject: [PATCH 9/9] DOC: wrap long lines, abbrev AOD, be explicit re: fictitious AOD --- docs/sphinx/source/clearsky.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sphinx/source/clearsky.rst b/docs/sphinx/source/clearsky.rst index a3c90f2003..ee2e781d00 100644 --- a/docs/sphinx/source/clearsky.rst +++ b/docs/sphinx/source/clearsky.rst @@ -381,7 +381,7 @@ 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 +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 @@ -391,9 +391,9 @@ wavelengths with :py:func:`~pvlib.atmosphere.angstrom_alpha`. .. ipython:: - In [1]: aod1240nm = 1.2 # AOD measured at 1240-nm + In [1]: aod1240nm = 1.2 # fictitious AOD measured at 1240-nm - In [1]: aod550nm = 3.1 # AOD measured at 550-nm + In [1]: aod550nm = 3.1 # fictitious AOD measured at 550-nm In [1]: alpha_exponent = atmosphere.angstrom_alpha(aod1240nm, 1240, aod550nm, 550) @@ -405,8 +405,8 @@ wavelengths with :py:func:`~pvlib.atmosphere.angstrom_alpha`. 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)) + In [1]: print('compare AOD at 700-nm = {:g}, to estimated broadband AOD = {:g}, ' + ...: 'with alpha = {:g}'.format(aod700nm, aod_bb, alpha_exponent)) Examples ^^^^^^^^