Skip to content

Commit dca5574

Browse files
committed
Revert "Make tables a required dependency (pvlib#1287)"
This reverts commit 65782fd
1 parent 22364d8 commit dca5574

File tree

6 files changed

+160
-5
lines changed

6 files changed

+160
-5
lines changed

docs/sphinx/source/whatsnew/v0.9.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ Requirements
235235
* ``dataclasses`` is required for python 3.6 (:pull:`1076`)
236236
* ``h5py`` is now a required dependency. This replaces ``tables``, which was formerly
237237
an optional dependency. (:pull:`1299`, :issue:`1252`, :issue:`1286`)
238+
* ``dataclasses`` is required for python 3.6
238239

239240
Contributors
240241
~~~~~~~~~~~~

pvlib/clearsky.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,23 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
194194
# 1st row: 89.9583 S, 2nd row: 89.875 S
195195
# 1st column: 179.9583 W, 2nd column: 179.875 W
196196

197+
try:
198+
import tables
199+
except ImportError:
200+
raise ImportError('The Linke turbidity lookup table requires tables. '
201+
'You can still use clearsky.ineichen if you '
202+
'supply your own turbidities.')
203+
197204
if filepath is None:
198205
pvlib_path = os.path.dirname(os.path.abspath(__file__))
199206
filepath = os.path.join(pvlib_path, 'data', 'LinkeTurbidities.h5')
200207

201208
latitude_index = _degrees_to_index(latitude, coordinate='latitude')
202209
longitude_index = _degrees_to_index(longitude, coordinate='longitude')
203210

204-
with h5py.File(filepath, 'r') as lt_h5_file:
205-
lts = lt_h5_file['LinkeTurbidity'][latitude_index, longitude_index]
211+
with tables.open_file(filepath) as lt_h5_file:
212+
lts = lt_h5_file.root.LinkeTurbidity[latitude_index,
213+
longitude_index, :]
206214

207215
if interp_turbidity:
208216
linke_turbidity = _interpolate_turbidity(lts, time)
@@ -290,6 +298,67 @@ def _calendar_month_middles(year):
290298
return middles
291299

292300

301+
def _degrees_to_index(degrees, coordinate):
302+
"""Transform input degrees to an output index integer. The Linke
303+
turbidity lookup tables have three dimensions, latitude, longitude, and
304+
month. Specify a degree value and either 'latitude' or 'longitude' to get
305+
the appropriate index number for the first two of these index numbers.
306+
307+
Parameters
308+
----------
309+
degrees : float or int
310+
Degrees of either latitude or longitude.
311+
coordinate : string
312+
Specify whether degrees arg is latitude or longitude. Must be set to
313+
either 'latitude' or 'longitude' or an error will be raised.
314+
315+
Returns
316+
-------
317+
index : np.int16
318+
The latitude or longitude index number to use when looking up values
319+
in the Linke turbidity lookup table.
320+
"""
321+
# Assign inputmin, inputmax, and outputmax based on degree type.
322+
if coordinate == 'latitude':
323+
inputmin = 90
324+
inputmax = -90
325+
outputmax = 2160
326+
elif coordinate == 'longitude':
327+
inputmin = -180
328+
inputmax = 180
329+
outputmax = 4320
330+
else:
331+
raise IndexError("coordinate must be 'latitude' or 'longitude'.")
332+
333+
inputrange = inputmax - inputmin
334+
scale = outputmax/inputrange # number of indices per degree
335+
center = inputmin + 1 / scale / 2 # shift to center of index
336+
outputmax -= 1 # shift index to zero indexing
337+
index = (degrees - center) * scale
338+
err = IndexError('Input, %g, is out of range (%g, %g).' %
339+
(degrees, inputmin, inputmax))
340+
341+
# If the index is still out of bounds after rounding, raise an error.
342+
# 0.500001 is used in comparisons instead of 0.5 to allow for a small
343+
# margin of error which can occur when dealing with floating point numbers.
344+
if index > outputmax:
345+
if index - outputmax <= 0.500001:
346+
index = outputmax
347+
else:
348+
raise err
349+
elif index < 0:
350+
if -index <= 0.500001:
351+
index = 0
352+
else:
353+
raise err
354+
# If the index wasn't set to outputmax or 0, round it and cast it as an
355+
# integer so it can be used in integer-based indexing.
356+
else:
357+
index = int(np.around(index))
358+
359+
return index
360+
361+
293362
def haurwitz(apparent_zenith):
294363
'''
295364
Determine clear sky GHI using the Haurwitz model.

pvlib/tests/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ def assert_frame_equal(left, right, **kwargs):
118118
not has_statsmodels, reason='requires statsmodels')
119119

120120

121+
try:
122+
import tables
123+
has_tables = True
124+
except ImportError:
125+
has_tables = False
126+
127+
requires_tables = pytest.mark.skipif(not has_tables, reason='requires tables')
128+
129+
121130
try:
122131
import ephem # noqa: F401
123132
has_ephem = True

pvlib/tests/test_clearsky.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from pvlib import atmosphere
1717
from pvlib import irradiance
1818

19-
from .conftest import DATA_DIR
19+
from .conftest import requires_tables, DATA_DIR
2020

2121

2222
def test_ineichen_series():
@@ -189,6 +189,7 @@ def test_ineichen_altitude():
189189
assert_frame_equal(expected, out)
190190

191191

192+
@requires_tables
192193
def test_lookup_linke_turbidity():
193194
times = pd.date_range(start='2014-06-24', end='2014-06-25',
194195
freq='12h', tz='America/Phoenix')
@@ -201,6 +202,7 @@ def test_lookup_linke_turbidity():
201202
assert_series_equal(expected, out)
202203

203204

205+
@requires_tables
204206
def test_lookup_linke_turbidity_leapyear():
205207
times = pd.date_range(start='2016-06-24', end='2016-06-25',
206208
freq='12h', tz='America/Phoenix')
@@ -213,6 +215,7 @@ def test_lookup_linke_turbidity_leapyear():
213215
assert_series_equal(expected, out)
214216

215217

218+
@requires_tables
216219
def test_lookup_linke_turbidity_nointerp():
217220
times = pd.date_range(start='2014-06-24', end='2014-06-25',
218221
freq='12h', tz='America/Phoenix')
@@ -223,6 +226,7 @@ def test_lookup_linke_turbidity_nointerp():
223226
assert_series_equal(expected, out)
224227

225228

229+
@requires_tables
226230
def test_lookup_linke_turbidity_months():
227231
times = pd.date_range(start='2014-04-01', end='2014-07-01',
228232
freq='1M', tz='America/Phoenix')
@@ -233,6 +237,7 @@ def test_lookup_linke_turbidity_months():
233237
assert_series_equal(expected, out)
234238

235239

240+
@requires_tables
236241
def test_lookup_linke_turbidity_months_leapyear():
237242
times = pd.date_range(start='2016-04-01', end='2016-07-01',
238243
freq='1M', tz='America/Phoenix')
@@ -243,6 +248,7 @@ def test_lookup_linke_turbidity_months_leapyear():
243248
assert_series_equal(expected, out)
244249

245250

251+
@requires_tables
246252
def test_lookup_linke_turbidity_nointerp_months():
247253
times = pd.date_range(start='2014-04-10', end='2014-07-10',
248254
freq='1M', tz='America/Phoenix')
@@ -474,6 +480,7 @@ def test_simplified_solis_nans_series():
474480
assert_frame_equal(expected, out)
475481

476482

483+
@requires_tables
477484
def test_linke_turbidity_corners():
478485
"""Test Linke turbidity corners out of bounds."""
479486
months = pd.DatetimeIndex('%d/1/2016' % (m + 1) for m in range(12))

pvlib/tests/test_location.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from pvlib.location import Location, lookup_altitude
1717
from pvlib.solarposition import declination_spencer71
1818
from pvlib.solarposition import equation_of_time_spencer71
19-
from .conftest import requires_ephem
19+
from .conftest import requires_ephem, requires_tables
2020

2121

2222
def test_location_required():
@@ -78,6 +78,7 @@ def times():
7878
freq='3h')
7979

8080

81+
@requires_tables
8182
def test_get_clearsky(mocker, times):
8283
tus = Location(32.2, -111, 'US/Arizona', 700, 'Tucson')
8384
m = mocker.spy(pvlib.clearsky, 'ineichen')

pvlib/tests/test_modelchain.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from .conftest import assert_series_equal, assert_frame_equal
1313
import pytest
1414

15-
from .conftest import fail_on_pvlib_version
15+
from .conftest import fail_on_pvlib_version, requires_tables
1616

1717

1818
@pytest.fixture(scope='function')
@@ -1787,6 +1787,72 @@ def test_ModelChain_no_extra_kwargs(sapm_dc_snl_ac_system, location):
17871787
ModelChain(sapm_dc_snl_ac_system, location, arbitrary_kwarg='value')
17881788

17891789

1790+
@fail_on_pvlib_version('0.10')
1791+
def test_ModelChain_attributes_deprecated_10(sapm_dc_snl_ac_system, location):
1792+
match = 'Use ModelChain.results'
1793+
mc = ModelChain(sapm_dc_snl_ac_system, location)
1794+
with pytest.warns(pvlibDeprecationWarning, match=match):
1795+
mc.aoi
1796+
with pytest.warns(pvlibDeprecationWarning, match=match):
1797+
mc.aoi = 5
1798+
1799+
1800+
@requires_tables
1801+
def test_basic_chain_alt_az(sam_data, cec_inverter_parameters,
1802+
sapm_temperature_cs5p_220m):
1803+
times = pd.date_range(start='20160101 1200-0700',
1804+
end='20160101 1800-0700', freq='6H')
1805+
latitude = 32.2
1806+
longitude = -111
1807+
surface_tilt = 0
1808+
surface_azimuth = 0
1809+
modules = sam_data['sandiamod']
1810+
module_parameters = modules['Canadian_Solar_CS5P_220M___2009_']
1811+
temp_model_params = sapm_temperature_cs5p_220m.copy()
1812+
dc, ac = modelchain.basic_chain(times, latitude, longitude,
1813+
surface_tilt, surface_azimuth,
1814+
module_parameters, temp_model_params,
1815+
cec_inverter_parameters)
1816+
1817+
expected = pd.Series(np.array([111.621405, -2.00000000e-02]),
1818+
index=times)
1819+
assert_series_equal(ac, expected)
1820+
1821+
1822+
@requires_tables
1823+
def test_basic_chain_altitude_pressure(sam_data, cec_inverter_parameters,
1824+
sapm_temperature_cs5p_220m):
1825+
times = pd.date_range(start='20160101 1200-0700',
1826+
end='20160101 1800-0700', freq='6H')
1827+
latitude = 32.2
1828+
longitude = -111
1829+
altitude = 700
1830+
surface_tilt = 0
1831+
surface_azimuth = 0
1832+
modules = sam_data['sandiamod']
1833+
module_parameters = modules['Canadian_Solar_CS5P_220M___2009_']
1834+
temp_model_params = sapm_temperature_cs5p_220m.copy()
1835+
dc, ac = modelchain.basic_chain(times, latitude, longitude,
1836+
surface_tilt, surface_azimuth,
1837+
module_parameters, temp_model_params,
1838+
cec_inverter_parameters,
1839+
pressure=93194)
1840+
1841+
expected = pd.Series(np.array([113.190045, -2.00000000e-02]),
1842+
index=times)
1843+
assert_series_equal(ac, expected)
1844+
1845+
dc, ac = modelchain.basic_chain(times, latitude, longitude,
1846+
surface_tilt, surface_azimuth,
1847+
module_parameters, temp_model_params,
1848+
cec_inverter_parameters,
1849+
altitude=altitude)
1850+
1851+
expected = pd.Series(np.array([113.189814, -2.00000000e-02]),
1852+
index=times)
1853+
assert_series_equal(ac, expected)
1854+
1855+
17901856
def test_complete_irradiance_clean_run(sapm_dc_snl_ac_system, location):
17911857
"""The DataFrame should not change if all columns are passed"""
17921858
mc = ModelChain(sapm_dc_snl_ac_system, location)
@@ -1804,6 +1870,7 @@ def test_complete_irradiance_clean_run(sapm_dc_snl_ac_system, location):
18041870
pd.Series([9, 5], index=times, name='ghi'))
18051871

18061872

1873+
@requires_tables
18071874
def test_complete_irradiance(sapm_dc_snl_ac_system, location, mocker):
18081875
"""Check calculations"""
18091876
mc = ModelChain(sapm_dc_snl_ac_system, location)
@@ -1836,6 +1903,7 @@ def test_complete_irradiance(sapm_dc_snl_ac_system, location, mocker):
18361903

18371904
@pytest.mark.filterwarnings("ignore:This function is not safe at the moment")
18381905
@pytest.mark.parametrize("input_type", [tuple, list])
1906+
@requires_tables
18391907
def test_complete_irradiance_arrays(
18401908
sapm_dc_snl_ac_system_same_arrays, location, input_type):
18411909
"""ModelChain.complete_irradiance can accept a tuple of weather

0 commit comments

Comments
 (0)