Skip to content

Commit 1c66a05

Browse files
committed
refactor linke turbidity lookup
1 parent f435b6e commit 1c66a05

File tree

2 files changed

+89
-48
lines changed

2 files changed

+89
-48
lines changed

pvlib/clearsky.py

Lines changed: 84 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -115,45 +115,9 @@ def ineichen(time, location, linke_turbidity=None,
115115

116116

117117
if linke_turbidity is None:
118-
# The .mat file 'LinkeTurbidities.mat' contains a single 2160 x 4320 x 12
119-
# matrix of type uint8 called 'LinkeTurbidity'. The rows represent global
120-
# latitudes from 90 to -90 degrees; the columns represent global longitudes
121-
# from -180 to 180; and the depth (third dimension) represents months of
122-
# the year from January (1) to December (12). To determine the Linke
123-
# turbidity for a position on the Earth's surface for a given month do the
124-
# following: LT = LinkeTurbidity(LatitudeIndex, LongitudeIndex, month).
125-
# Note that the numbers within the matrix are 20 * Linke Turbidity,
126-
# so divide the number from the file by 20 to get the
127-
# turbidity.
128-
129-
try:
130-
import scipy.io
131-
except ImportError:
132-
raise ImportError('The Linke turbidity lookup table requires scipy. ' +
133-
'You can still use clearsky.ineichen if you ' +
134-
'supply your own turbidities.')
135-
136-
# consider putting this code at module level
137-
this_path = os.path.dirname(os.path.abspath(__file__))
138-
logger.debug('this_path=%s', this_path)
139-
140-
mat = scipy.io.loadmat(os.path.join(this_path, 'data', 'LinkeTurbidities.mat'))
141-
linke_turbidity = mat['LinkeTurbidity']
142-
LatitudeIndex = np.round_(_linearly_scale(location.latitude,90,- 90,1,2160))
143-
LongitudeIndex = np.round_(_linearly_scale(location.longitude,- 180,180,1,4320))
144-
g = linke_turbidity[LatitudeIndex][LongitudeIndex]
145-
if interp_turbidity:
146-
logger.info('interpolating turbidity to the day')
147-
g2 = np.concatenate([[g[-1]], g, [g[0]]]) # wrap ends around
148-
days = np.linspace(-15, 380, num=14) # map day of year onto month (approximate)
149-
LT = pd.Series(np.interp(time.dayofyear, days, g2), index=time)
150-
else:
151-
logger.info('using monthly turbidity')
152-
ApplyMonth = lambda x:g[x[0]-1]
153-
LT = pd.DataFrame(time.month, index=time)
154-
LT = LT.apply(ApplyMonth, axis=1)
155-
TL = LT / 20.
156-
logger.info('using TL=\n%s', TL)
118+
TL = lookup_linke_turbidity(time, location.latitude,
119+
location.longitude,
120+
interp_turbidity=interp_turbidity)
157121
else:
158122
TL = linke_turbidity
159123

@@ -221,6 +185,87 @@ def ineichen(time, location, linke_turbidity=None,
221185
return df_out
222186

223187

188+
def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
189+
interp_turbidity=True):
190+
"""
191+
Look up the Linke Turibidity from the ``LinkeTurbidities.mat``
192+
data file supplied with pvlib.
193+
194+
Parameters
195+
----------
196+
time : pandas.DatetimeIndex
197+
198+
latitude : float
199+
200+
longitude : float
201+
202+
filepath : string
203+
The path to the ``.mat`` file.
204+
205+
interp_turbidity : bool
206+
If ``True``, interpolates the monthly Linke turbidity values
207+
found in ``LinkeTurbidities.mat`` to daily values.
208+
209+
Returns
210+
-------
211+
turbidity : Series
212+
"""
213+
214+
# The .mat file 'LinkeTurbidities.mat' contains a single 2160 x 4320 x 12
215+
# matrix of type uint8 called 'LinkeTurbidity'. The rows represent global
216+
# latitudes from 90 to -90 degrees; the columns represent global longitudes
217+
# from -180 to 180; and the depth (third dimension) represents months of
218+
# the year from January (1) to December (12). To determine the Linke
219+
# turbidity for a position on the Earth's surface for a given month do the
220+
# following: LT = LinkeTurbidity(LatitudeIndex, LongitudeIndex, month).
221+
# Note that the numbers within the matrix are 20 * Linke Turbidity,
222+
# so divide the number from the file by 20 to get the
223+
# turbidity.
224+
225+
try:
226+
import scipy.io
227+
except ImportError:
228+
raise ImportError('The Linke turbidity lookup table requires scipy. ' +
229+
'You can still use clearsky.ineichen if you ' +
230+
'supply your own turbidities.')
231+
232+
if filepath is None:
233+
pvlib_path = os.path.dirname(os.path.abspath(__file__))
234+
filepath = os.path.join(pvlib_path, 'data', 'LinkeTurbidities.mat')
235+
236+
mat = scipy.io.loadmat(filepath)
237+
linke_turbidity_table = mat['LinkeTurbidity']
238+
239+
latitude_index = np.around(_linearly_scale(latitude, 90, -90, 1, 2160))
240+
longitude_index = np.around(_linearly_scale(longitude, -180, 180, 1, 4320))
241+
242+
g = linke_turbidity_table[latitude_index][longitude_index]
243+
244+
if interp_turbidity:
245+
logger.info('interpolating turbidity to the day')
246+
# Cata covers 1 year.
247+
# Assume that data corresponds to the value at
248+
# the middle of each month.
249+
# This means that we need to add previous Dec and next Jan
250+
# to the array so that the interpolation will work for
251+
# Jan 1 - Jan 15 and Dec 16 - Dec 31.
252+
# Then we map the month value to the day of year value.
253+
# This is approximate and could be made more accurate.
254+
g2 = np.concatenate([[g[-1]], g, [g[0]]])
255+
days = np.linspace(-15, 380, num=14)
256+
linke_turbidity = pd.Series(np.interp(time.dayofyear, days, g2),
257+
index=time)
258+
else:
259+
logger.info('using monthly turbidity')
260+
apply_month = lambda x: g[x[0]-1]
261+
linke_turbidity = pd.DataFrame(time.month, index=time)
262+
linke_turbidity = linke_turbidity.apply(apply_month, axis=1)
263+
264+
linke_turbidity /= 20.
265+
266+
return linke_turbidity
267+
268+
224269
def haurwitz(apparent_zenith):
225270
'''
226271
Determine clear sky GHI from Haurwitz model.

pvlib/test/test_clearsky.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import logging
22
pvl_logger = logging.getLogger('pvlib')
33

4-
import datetime
5-
64
import numpy as np
75
import pandas as pd
86

@@ -15,17 +13,12 @@
1513
from pvlib import solarposition
1614

1715
# setup times and location to be tested.
18-
times = pd.date_range(start=datetime.datetime(2014,6,24),
19-
end=datetime.datetime(2014,6,26), freq='1Min')
20-
2116
tus = Location(32.2, -111, 'US/Arizona', 700)
22-
17+
times = pd.date_range(start='2014-06-24', end='2014-06-25', freq='3h')
2318
times_localized = times.tz_localize(tus.tz)
2419

2520
ephem_data = solarposition.get_solarposition(times, tus)
2621

27-
28-
2922
# test the ineichen clear sky model implementation in a few ways
3023

3124
def test_ineichen_required():
@@ -38,7 +31,7 @@ def test_ineichen_supply_linke():
3831

3932
def test_ineichen_solpos():
4033
clearsky.ineichen(times, tus, linke_turbidity=3,
41-
solarposition_method='pyephem')
34+
solarposition_method='nrel_numpy')
4235

4336
def test_ineichen_airmass():
4437
clearsky.ineichen(times, tus, linke_turbidity=3,
@@ -50,6 +43,9 @@ def test_ineichen_keys():
5043
assert 'dni' in clearsky_data.columns
5144
assert 'dhi' in clearsky_data.columns
5245

46+
def test_lookup_linke_turbidity():
47+
raise Exception
48+
5349
# test the haurwitz clear sky implementation
5450
def test_haurwitz():
5551
clearsky.haurwitz(ephem_data['zenith'])

0 commit comments

Comments
 (0)