Skip to content

Commit 263dac2

Browse files
committed
add the new lookup code. add more tests
1 parent c2a94ae commit 263dac2

File tree

2 files changed

+145
-55
lines changed

2 files changed

+145
-55
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: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from nose.tools import raises
88
from numpy.testing import assert_almost_equal
9-
from pandas.util.testing import assert_frame_equal
9+
from pandas.util.testing import assert_frame_equal, assert_series_equal
1010

1111
from pvlib.location import Location
1212
from pvlib import clearsky
@@ -20,10 +20,8 @@
2020
ephem_data = solarposition.get_solarposition(times, tus)
2121

2222

23-
# test the ineichen clear sky model implementation in a few ways
24-
2523
def test_ineichen_required():
26-
# the clearsky function should lookup the linke turbidity on its own
24+
# the clearsky function should call lookup_linke_turbidity by default
2725
# will fail without scipy
2826
expected = pd.DataFrame(np.array([[0.,0.,0.],
2927
[0.,0.,0.],
@@ -39,6 +37,7 @@ def test_ineichen_required():
3937
out = clearsky.ineichen(times, tus)
4038
assert_frame_equal(expected, out)
4139

40+
4241
def test_ineichen_supply_linke():
4342
expected = pd.DataFrame(np.array([[0.,0.,0.],
4443
[0.,0.,0.],
@@ -54,10 +53,12 @@ def test_ineichen_supply_linke():
5453
out = clearsky.ineichen(times, tus, linke_turbidity=3)
5554
assert_frame_equal(expected, out)
5655

56+
5757
def test_ineichen_solpos():
5858
clearsky.ineichen(times, tus, linke_turbidity=3,
5959
solarposition_method='ephemeris')
6060

61+
6162
def test_ineichen_airmass():
6263
expected = pd.DataFrame(np.array([[0.,0.,0.],
6364
[0.,0.,0.],
@@ -74,19 +75,63 @@ def test_ineichen_airmass():
7475
airmass_model='simple')
7576
assert_frame_equal(expected, out)
7677

77-
def test_ineichen_keys():
78-
clearsky_data = clearsky.ineichen(times, tus, linke_turbidity=3)
79-
assert 'ghi' in clearsky_data.columns
80-
assert 'dni' in clearsky_data.columns
81-
assert 'dhi' in clearsky_data.columns
8278

8379
def test_lookup_linke_turbidity():
84-
raise Exception
80+
times = pd.date_range(start='2014-06-24', end='2014-06-25',
81+
freq='12h', tz=tus.tz)
82+
# expect same value on 2014-06-24 0000 and 1200, and
83+
# diff value on 2014-06-25
84+
expected = pd.Series(np.array([3.10126582, 3.10126582, 3.11443038]),
85+
index=times)
86+
out = clearsky.lookup_linke_turbidity(times, tus.latitude, tus.longitude)
87+
assert_series_equal(expected, out)
88+
89+
90+
def test_lookup_linke_turbidity_nointerp():
91+
times = pd.date_range(start='2014-06-24', end='2014-06-25',
92+
freq='12h', tz=tus.tz)
93+
# expect same value for all days
94+
expected = pd.Series(np.array([3., 3., 3.]), index=times)
95+
out = clearsky.lookup_linke_turbidity(times, tus.latitude, tus.longitude,
96+
interp_turbidity=False)
97+
assert_series_equal(expected, out)
8598

86-
# test the haurwitz clear sky implementation
87-
def test_haurwitz():
88-
clearsky.haurwitz(ephem_data['zenith'])
8999

90-
def test_haurwitz_keys():
91-
clearsky_data = clearsky.haurwitz(ephem_data['zenith'])
92-
assert 'ghi' in clearsky_data.columns
100+
def test_lookup_linke_turbidity_months():
101+
times = pd.date_range(start='2014-04-01', end='2014-07-01',
102+
freq='1M', tz=tus.tz)
103+
expected = pd.Series(np.array([2.8943038, 2.97316456, 3.18025316]),
104+
index=times)
105+
out = clearsky.lookup_linke_turbidity(times, tus.latitude,
106+
tus.longitude)
107+
assert_series_equal(expected, out)
108+
109+
110+
def test_lookup_linke_turbidity_nointerp_months():
111+
times = pd.date_range(start='2014-04-10', end='2014-07-10',
112+
freq='1M', tz=tus.tz)
113+
expected = pd.Series(np.array([2.85, 2.95, 3.]), index=times)
114+
out = clearsky.lookup_linke_turbidity(times, tus.latitude, tus.longitude,
115+
interp_turbidity=False)
116+
assert_series_equal(expected, out)
117+
# changing the dates shouldn't matter if interp=False
118+
times = pd.date_range(start='2014-04-05', end='2014-07-05',
119+
freq='1M', tz=tus.tz)
120+
out = clearsky.lookup_linke_turbidity(times, tus.latitude, tus.longitude,
121+
interp_turbidity=False)
122+
assert_series_equal(expected, out)
123+
124+
125+
def test_haurwitz():
126+
expected = pd.DataFrame(np.array([[0.],
127+
[0.],
128+
[82.85934048],
129+
[699.74514735],
130+
[1016.50198354],
131+
[838.32103769],
132+
[271.90853863],
133+
[0.],
134+
[0.]]),
135+
columns=['ghi'], index=times_localized)
136+
out = clearsky.haurwitz(ephem_data['zenith'])
137+
assert_frame_equal(expected, out)

0 commit comments

Comments
 (0)