Skip to content

Commit 616edc0

Browse files
committed
refactor lookup_linke_turbidity for speed
1 parent 39c0862 commit 616edc0

File tree

1 file changed

+72
-35
lines changed

1 file changed

+72
-35
lines changed

pvlib/clearsky.py

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
196196
try:
197197
import scipy.io
198198
except ImportError:
199-
raise ImportError('The Linke turbidity lookup table requires scipy. ' +
200-
'You can still use clearsky.ineichen if you ' +
199+
raise ImportError('The Linke turbidity lookup table requires scipy. '
200+
'You can still use clearsky.ineichen if you '
201201
'supply your own turbidities.')
202202

203203
if filepath is None:
@@ -214,54 +214,91 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
214214
np.around(_linearly_scale(longitude, -180, 180, 0, 4320))
215215
.astype(np.int64))
216216

217-
g = linke_turbidity_table[latitude_index][longitude_index]
217+
lts = linke_turbidity_table[latitude_index][longitude_index]
218218

219219
if interp_turbidity:
220-
# Data covers 1 year. Assume that data corresponds to the value at the
221-
# middle of each month. This means that we need to add previous Dec and
222-
# next Jan to the array so that the interpolation will work for
223-
# Jan 1 - Jan 15 and Dec 16 - Dec 31.
224-
g2 = np.concatenate([[g[-1]], g, [g[0]]])
225-
# Then we map the month value to the day of year value.
226-
isleap = [calendar.isleap(t.year) for t in time]
227-
if all(isleap):
228-
days = _calendar_month_middles(2016) # all years are leap
229-
elif not any(isleap):
230-
days = _calendar_month_middles(2015) # none of the years are leap
231-
else:
232-
days = None # some of the years are leap years and some are not
233-
if days is None:
234-
# Loop over different years, might be slow for large timeserires
235-
linke_turbidity = pd.Series([
236-
np.interp(t.dayofyear, _calendar_month_middles(t.year), g2)
237-
for t in time
238-
], index=time)
239-
else:
240-
linke_turbidity = pd.Series(np.interp(time.dayofyear, days, g2),
241-
index=time)
220+
linke_turbidity = _interpolate_turbidity(lts, time)
242221
else:
243-
linke_turbidity = pd.DataFrame(time.month, index=time)
244-
# apply monthly data
245-
linke_turbidity = linke_turbidity.apply(lambda x: g[x[0]-1], axis=1)
222+
months = time.month - 1
223+
linke_turbidity = pd.Series(lts[months], index=time)
246224

247225
linke_turbidity /= 20.
248226

249227
return linke_turbidity
250228

251229

230+
def _is_leap_year(year):
231+
"""Determine if a year is leap year.
232+
233+
Parameters
234+
----------
235+
year : numeric
236+
237+
Returns
238+
-------
239+
isleap : array of bools
240+
"""
241+
isleap = ((np.mod(year, 4) == 0) &
242+
((np.mod(year, 100) != 0) | (np.mod(year, 400) == 0)))
243+
return isleap
244+
245+
246+
def _interpolate_turbidity(lts, time):
247+
"""
248+
Interpolated monthly Linke turbidity onto daily values.
249+
250+
Parameters
251+
----------
252+
lts : np.array
253+
Monthly Linke turbidity values.
254+
time : pd.DatetimeIndex
255+
Times to be interpolated onto.
256+
257+
Returns
258+
-------
259+
linke_turbidity : pd.Series
260+
The interpolated turbidity.
261+
"""
262+
# Data covers 1 year. Assume that data corresponds to the value at the
263+
# middle of each month. This means that we need to add previous Dec and
264+
# next Jan to the array so that the interpolation will work for
265+
# Jan 1 - Jan 15 and Dec 16 - Dec 31.
266+
lts_concat = np.concatenate([[lts[-1]], lts, [lts[0]]])
267+
# Then we map the month value to the day of year value.
268+
269+
# use this for the real code
270+
try:
271+
isleap = time.is_leap_year
272+
except AttributeError:
273+
year = time.year
274+
isleap = _is_leap_year(time.year)
275+
276+
dayofyear = time.dayofyear
277+
days_leap = _calendar_month_middles(2016)
278+
days_no_leap = _calendar_month_middles(2015)
279+
lt_leap = np.interp(dayofyear, days_leap, lts_concat)
280+
lt_no_leap = np.interp(dayofyear, days_no_leap, lts_concat)
281+
linke_turbidity = np.where(isleap, lt_leap, lt_no_leap)
282+
linke_turbidity = pd.Series(linke_turbidity, index=time)
283+
return linke_turbidity
284+
285+
252286
def _calendar_month_middles(year):
253-
"""list of middle day of each month, used by Linke turbidity lookup"""
287+
"""List of middle day of each month, used by Linke turbidity lookup"""
254288
# remove mdays[0] since January starts at mdays[1]
255-
# make local copy of mdays since we need to change February for leap years
289+
# make local copy of mdays since we need to change
290+
# February for leap years
256291
mdays = np.array(calendar.mdays[1:])
257292
ydays = 365
258293
# handle leap years
259294
if calendar.isleap(year):
260295
mdays[1] = mdays[1] + 1
261296
ydays = 366
262-
return np.concatenate([[-calendar.mdays[-1] / 2.0], # Dec last year
263-
np.cumsum(mdays) - np.array(mdays) / 2., # this year
264-
[ydays + calendar.mdays[1] / 2.0]]) # Jan next year
297+
middles = np.concatenate(
298+
[[-calendar.mdays[-1] / 2.0], # Dec last year
299+
np.cumsum(mdays) - np.array(mdays) / 2., # this year
300+
[ydays + calendar.mdays[1] / 2.0]]) # Jan next year
301+
return middles
265302

266303

267304
def _linearly_scale(inputmatrix, inputmin, inputmax, outputmin, outputmax):
@@ -294,8 +331,8 @@ def haurwitz(apparent_zenith):
294331
295332
Implements the Haurwitz clear sky model for global horizontal
296333
irradiance (GHI) as presented in [1, 2]. A report on clear
297-
sky models found the Haurwitz model to have the best performance
298-
in terms of average monthly error among models which require only
334+
sky models found the Haurwitz model to have the best performance
335+
in terms of average monthly error among models which require only
299336
zenith angle [3].
300337
301338
Parameters

0 commit comments

Comments
 (0)