-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Changes from 6 commits
6e9aaf0
4a2dde7
c492804
f0b5246
17f3b9f
33f6374
086b640
eda94b8
02d1fe5
a5221a4
645b2fb
ec3521c
1964e20
6c3f380
fd382bf
bbe2740
8f667c2
e64345e
74524c1
00166d0
59368c8
13bb4cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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``. | ||
|
||
Based on originam implementation by Armel Oumbe. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. original There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
---------- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there are a handful of typos in the references There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1-3 good references might be more useful than 8. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
What is your preference? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably best to There was a problem hiding this comment. Choose a reason for hiding this commentThe 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): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this function needs its own tests There was a problem hiding this comment. Choose a reason for hiding this commentThe 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] | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need a Returns section There was a problem hiding this comment. Choose a reason for hiding this commentThe 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])) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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::