Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

add linke turbidity formulas module to atmosphere #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Feb 6, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e9aaf0
add linke turbidity formulas module
mikofski Dec 3, 2016
4a2dde7
ignore venv, sublime
mikofski Jan 17, 2017
c492804
revert api changes from 6e9aaf0fce0214591225d1fa8aeafb8f5aa802cb
mikofski Jan 23, 2017
f0b5246
move demo to tests
mikofski Jan 24, 2017
17f3b9f
fix docstring
mikofski Jan 24, 2017
33f6374
test kaste96_lt against linke turbidity using tmy3 at 700nm
mikofski Jan 25, 2017
086b640
removing filters from kasten pyrhelometric formula
mikofski Jan 30, 2017
eda94b8
refactor kasten96_lt api simpler
mikofski Jan 31, 2017
02d1fe5
add angstrom_alpha() method in atmosphere to calculate alpha
mikofski Jan 31, 2017
a5221a4
simplify kasten96_lt API
mikofski Jan 31, 2017
645b2fb
Merge branch 'master' into linke_turb_forms
mikofski Jan 31, 2017
ec3521c
add new linke and angstrom functions to api.rst
mikofski Jan 31, 2017
1964e20
add doi to sphinx docs as extlink
mikofski Feb 2, 2017
6c3f380
make landscape happy and use r"""docstring with :math:`\alpha`"""
mikofski Feb 2, 2017
fd382bf
reformat long lines to make landscape happy :)
mikofski Feb 2, 2017
bbe2740
use broadband AOD arg instead of methods
mikofski Feb 3, 2017
8f667c2
use hard coded test values instead of TMY3
mikofski Feb 4, 2017
e64345e
remove unused imports
mikofski Feb 4, 2017
74524c1
fix test kasten
mikofski Feb 4, 2017
00166d0
remove clearsky import from test_atmosphere
mikofski Feb 4, 2017
59368c8
add missing assert statements for tests
mikofski Feb 6, 2017
13bb4cd
update hulstrom expected value
mikofski Feb 6, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions 3 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var/
Drafts/
*/build/
build/
venv/

*.egg-info/
.installed.cfg
Expand Down Expand Up @@ -58,6 +59,8 @@ coverage.xml
.pydevproject
.spyderproject
.idea/
*.sublime-project
*.sublime-workspace

# Rope
.ropeproject
Expand Down
167 changes: 167 additions & 0 deletions 167 pvlib/atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,170 @@ def first_solar_spectral_correction(pw, airmass_absolute, module_type=None,
coeff[4]*np.sqrt(pw) + coeff[5]*ama/np.sqrt(pw))

return modifier


def kasten96_lt(aod, am, pwat, alpha0=1.14, method='Molineaux'):
"""
Calculate Linke turbidity factor using Kasten pyrheliometric formula (1980).

Aerosol optical depth can be given as a list of tuples with wavelength in
nanometers as the first item in each tuple and values as AOD as the second
item. The list must be in ascending order by wavelength. If ``aod`` is given
as a sequence of floats or as a float then a wavelength of 500[nm] will be
used and alpha will default to 1.14, unless alpha is also given. Otherwise
alpha is calculated from the given wavelength and aod.

Method can be either ``'Molineaux'`` or ``'Bird-Huldstrom'``. Airmass less
than 1 or greater than 6 will return ``NaN``. Precipitable water less than
zero or greater than 5[cm] will also return ``NaN``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me that we need to set these limits. Garbage in, garbage out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, removed filters and put these limits as a .. warning::


Based on originam implementation by Armel Oumbe.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

original

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Parameters
----------
aod : numeric
aerosol optical depth table or value at 500
am : numeric
airmass, pressure corrected in atmospheres
pwat : numeric
precipitable water or total column water vapor in centimeters
alpha0 : numeric
Angstrom turbidity alpha exponent, default is 1.14
method : str
Molineaux (default) or Bird-Huldstrom

Returns
-------
Linke turbidity

References
----------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are a handful of typos in the references

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1-3 good references might be more useful than 8.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the references errors. Not sure I agree about the references. It's hard for me to tease out all of these pieces from just one or two references. I suppose we could just use the Ineichen references which include almost all of the other ones, although some are incorrect:

  • "A new airmass independent ..." (2002) includes: Kasten-1980, Kasten-1996, Linke-1922, Molineaux-1989
  • "Conversion function between Linke ..." (2008) includes: Berk-1989,1996, Bird-1980 (incorrect reference), Mueller and Mayer

What is your preference?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with a longer references section if that's your preference.

[1] F. Linke, "Transmissions-Koeffizient und Trubungsfaktor", Beitrage
zur Physik der Atmosphare, Vol 10, pp. 91-103 (1922)

[2] B. Molineaux, P. Ineichen, N. O'Neill, "Equivalence of pyrheliometric
and monochromatic aerosol optical depths at a single key wavelength,"
Appl.ied Optics 37, 7008-7018 (1998)
`DOI: 10.1364/AO.37.007008 <https://doi.org/10.1364/AO.37.007008>`_

[3] F. Kasten, "A simple parameterization of the pyrheliometric formula for
determining the Linke turbidity factor", Meteorologische Rundschau 33,
pp. 124-127(1980)

[4] P. Ineichen, "Conversion function between the Linke turbidity and the
atmospheric water vapor and aerosol content", Solar Energy 82,
pp. 1095-1097 (2008)
`DOI: 10.1016/j.solener.2008.04.010 <http://dx.doi.org/10.1016/j.solener.2008.04.010>`_

[5] Bird and Hulstrom, "Direct Insolation Models" (1980)
`SERI/TR-335-344 <http://www.nrel.gov/docs/legosti/old/344.pdf>`_

[6] R. E. Bird and R. L. Hulstrom, "Review, Evaluation, and Improvement of
Direct Irradiance Models" Journal of Solar Energy Engineering 103(3),
pp. 182-192 (1981)
`DOI: 10.1115/1.3266239 <https://doi.org/10.1115/1.3266239>`_

[7] Kasten, "The Linke turbidity factor based on improved valuse of the
integral Rayleigh optical thickness", Solar Energy, Vol. 56, No. 3,
pp. 239-244 (1996)
`DOI: 10.1016/0038-092X(95)00114-7 <http://dx.doi.org/10.1016/0038-092X(95)00114-7>`_

[8] P. Ineichen and R. Perez, "A new aiermass independent formulation for
the Linke Turbidity coefficient", Solar Energy, Vol. 73, no. 3, pp. 151-157
(2002)
`DOI: 10.1016/S0038-092X(02)00045-2 <http://dx.doi.org/10.1016/S0038-092X(02)00045-2>`_
"""
# calculate Angstrom turbidity alpha exponent if not known, from AOD at two
# wavelengths, lambda1 and lambda2
alpha = []
try:
# xrange(0) means iterate zero times, xrange(negative) == xrange(0)
# use `range` for Python 3 compatibility, small loop no Python 2 impact
for idx in range(len(aod) - 1):
lambda1, aod1 = aod[idx]
lambda2, aod2 = aod[idx + 1]
alpha.append(-np.log(aod1 / aod2) / np.log(lambda1 / lambda2))
except TypeError:
# case 1: aod is a float, so len(aod) raises TypeError
# case 2: aod is an array of float, so (lambda1, aod1) = aod[idx] raises
# TypeError
aod = [(500.0, aod)]
else:
# case 3: len(aod) == 1, then alpha == []
if len(alpha) > 1:
alpha0 = alpha
# make sure alpha can be indexed
try:
alpha = list(alpha0)
except TypeError:
alpha = [alpha0]
# make sure aod has lambda
try:
# case 3: len(aod) == 1 and aod == [aod]
_, _ = zip(*aod)
except TypeError:
aod = [(500.0, aod)]
# "From numerically integrated spectral simulations done with Modtran (Berk,
# 1989), Molineaux (1998) obtained for the broadband optical depth of a
# clean and dry atmospshere (fictitious atmosphere that comprises only the
# effects of Rayleigh scattering and absorption by the atmosphere gases
# other than the water vapor) the following expression" - P. Ineichen (2008)
delta_cda = -0.101 + 0.235 * am ** (-0.16)
# "and the broadband water vapor optical depth where pwat is the integrated
# precipitable water vapor content of the atmosphere expressed in cm and am
# the optical air mass. The precision of these fits is better than 1% when
# compared with Modtran simulations in the range 1 < am < 5 and
# 0 < pwat < 5 cm at sea level" - P. Ineichen (2008)
delta_w = 0.112 * am ** (-0.55) * pwat ** (0.34)
if method == 'Molineaux':
# get aod at 700[nm] from alpha for Molineaux (1998)
delta_a = angstrom_aod_at_lambda(aod, alpha)
else:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably best to elif method == 'bird-hulstrom' and then else: raise ValueError('invalid method')

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# using (Bird-Hulstrom 1980)
aod380 = angstrom_aod_at_lambda(aod, alpha, 380.0)
aod500 = angstrom_aod_at_lambda(aod, alpha, 500.0)
delta_a = 0.27583 * aod380 + 0.35 * aod500
# "Then using the Kasten pyrheliometric formula (1980, 1996), the Linke
# turbidity at am = 2 can be written. The extension of the Linke turbidity
# coefficient to other values of air mass was published by Ineichen and
# Perez (2002)" - P. Ineichen (2008)
lt = -(9.4 + 0.9 * am) * np.log(
np.exp(-am * (delta_cda + delta_w + delta_a))
) / am
# filter out of extrapolated values
filter = (am < 1.0) | (am > 6.0) | (pwat < 0) | (pwat > 5.0)
lt[filter] = np.nan # set out of range to NaN
return lt


def angstrom_aod_at_lambda(aod, alpha, lambda0=700.0):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function needs its own tests

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""
Get AOD at specified wavelength using Angstrom turbidity model.

Parameters
----------
aod : sequence
tuples of ``(wavelength[nm], aod)`` in ascending order by wavelength
alpha : sequence
Angstrom :math:`\\alpha` exponent corresponding to wavelength in ``aod``
lambda0 : numeric
desired wavelength in nanometers, defaults to 700[nm]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a Returns section

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

References
----------
[1] Anders Angstrom, "On the Atmospheric Transmission of Sun Radiation and
On Dust in the Air", Geografiska Annaler Vol. 11, pp. 156-166 (192) JSTOR
`DOI: 10.2307/519399 <http://dx.doi.org/10.2307/519399>`_

[2] Anders Angstrom, "Techniques of Determining the Turbidity of the
Atmosphere", Tellus 13:2, pp. 214-223 (1961) Taylor & Francis or Wiley
`DOI: 10.3402/tellusa.v13i2.9493 <http://dx.doi.org/10.3402/tellusa.v13i2.9493>`_
`DOI: 10.1111/j.2153-3490.1961.tb00078.x <http://dx.doi.org/10.1111/j.2153-3490.1961.tb00078.x>`_
"""
lambda1, aod = zip(*aod)
# lambda0 is between (idx - 1) and idx
idx = np.searchsorted(lambda1, lambda0)
# unless idx is zero
if idx == 0:
idx = 1
return aod[idx - 1] * ((lambda0 / lambda1[idx - 1]) ** (-alpha[idx - 1]))
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.