Skip to content

fix rounding issue in linke turbidity lookup function #755

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

Merged
merged 21 commits into from
Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c51a4d6
Resolve merge conflicts.
alexandermorgan Jul 12, 2019
0e9a985
Merge remote-tracking branch 'upstream/master'
alexandermorgan Jul 16, 2019
a603c2b
Copy whatsnew file from upstream.
alexandermorgan Jul 16, 2019
078146f
Remove unnecessary np.around().
alexandermorgan Jul 16, 2019
ee45949
Use <= .5 as comparisons in _linearly_scale.
alexandermorgan Jul 17, 2019
fba6d37
Correct previous commit, use <= .5.
alexandermorgan Jul 17, 2019
3e7a53d
Update what's new file.
alexandermorgan Jul 17, 2019
48f4d9c
Compare to 0.500001 for margin of error.
alexandermorgan Jul 20, 2019
b49e6b5
Rename _linearly_scale -> _degrees_to_index, refactor.
alexandermorgan Jul 21, 2019
5af90e6
Add test for clearsky._degrees_to_index().
alexandermorgan Jul 21, 2019
83f8b5d
Remove try/except/finally.
alexandermorgan Jul 21, 2019
4c855d0
Update parameter type description.
alexandermorgan Jul 21, 2019
5abb179
Fix linting errors.
alexandermorgan Jul 21, 2019
5d3033f
Fix typo.
alexandermorgan Jul 21, 2019
1e1b4b2
Give more detail in what's new description.
alexandermorgan Jul 22, 2019
6d087bd
Rename arg, use context manager, and add more tech. documentation.
alexandermorgan Jul 22, 2019
f2e3cd8
Add missing zero in documentation.
alexandermorgan Jul 22, 2019
dd432e4
Break up line so it's < 80 characters.
alexandermorgan Jul 22, 2019
2351bf4
Change arg type to float or int.
alexandermorgan Jul 22, 2019
ac8bb1d
Update argument name in test_degrees_to_index_1().
alexandermorgan Jul 22, 2019
8071296
Merge branch 'master' into clearsky_change
alexandermorgan Aug 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/sphinx/source/whatsnew/v0.7.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Bug fixes
* Fix handling of keyword arguments in `forecasts.get_processed_data`.
(:issue:`745`)
* Fix output as Series feature in :py:func:`pvlib.pvsystem.ashraeiam`.
* Fix rounding issue in `clearsky._linearly_scale`, a function that converts
longitude or latitude degree to an index number in a Linke turbidity lookup
table. Also rename the function to `clearsky._degrees_to_index`.
(:issue:`754`)

Testing
~~~~~~~
Expand Down
89 changes: 58 additions & 31 deletions pvlib/clearsky.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
----------
time : pandas.DatetimeIndex

latitude : float
latitude : float or int

longitude : float
longitude : float or int

filepath : None or string, default None
The path to the ``.h5`` file.
Expand Down Expand Up @@ -193,22 +193,12 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
pvlib_path = os.path.dirname(os.path.abspath(__file__))
filepath = os.path.join(pvlib_path, 'data', 'LinkeTurbidities.h5')

latitude_index = (
np.around(_linearly_scale(latitude, 90, -90, 0, 2160))
.astype(np.int64))
longitude_index = (
np.around(_linearly_scale(longitude, -180, 180, 0, 4320))
.astype(np.int64))
latitude_index = _degrees_to_index(latitude, coordinate='latitude')
longitude_index = _degrees_to_index(longitude, coordinate='longitude')

lt_h5_file = tables.open_file(filepath)
try:
with tables.open_file(filepath) as lt_h5_file:
lts = lt_h5_file.root.LinkeTurbidity[latitude_index,
longitude_index, :]
except IndexError:
raise IndexError('Latitude should be between 90 and -90, '
'longitude between -180 and 180.')
finally:
lt_h5_file.close()

if interp_turbidity:
linke_turbidity = _interpolate_turbidity(lts, time)
Expand Down Expand Up @@ -299,28 +289,65 @@ def _calendar_month_middles(year):
return middles


def _linearly_scale(inputmatrix, inputmin, inputmax, outputmin, outputmax):
"""linearly scale input to output, used by Linke turbidity lookup"""
def _degrees_to_index(degrees, coordinate):
"""Transform input degrees to an output index integer. The Linke
turbidity lookup tables have three dimensions, latitude, longitude, and
month. Specify a degree value and either 'latitude' or 'longitude' to get
the appropriate index number for the first two of these index numbers.

Parameters
----------
degrees : float or int
Degrees of either latitude or longitude.
coordinate : string
Specify whether degrees arg is latitude or longitude. Must be set to
either 'latitude' or 'longitude' or an error will be raised.

Returns
-------
index : np.int16
The latitude or longitude index number to use when looking up values
in the Linke turbidity lookup table.
"""
# Assign inputmin, inputmax, and outputmax based on degree type.
if coordinate == 'latitude':
inputmin = 90
inputmax = -90
outputmax = 2160
elif coordinate == 'longitude':
inputmin = -180
inputmax = 180
outputmax = 4320
else:
raise IndexError("coordinate must be 'latitude' or 'longitude'.")

inputrange = inputmax - inputmin
outputrange = outputmax - outputmin
delta = outputrange/inputrange # number of indices per input unit
inputmin = inputmin + 1.0 / delta / 2.0 # shift to center of index
outputmax = outputmax - 1 # shift index to zero indexing
outputmatrix = (inputmatrix - inputmin) * delta + outputmin
scale = outputmax/inputrange # number of indices per degree
center = inputmin + 1 / scale / 2 # shift to center of index
outputmax -= 1 # shift index to zero indexing
index = (degrees - center) * scale
err = IndexError('Input, %g, is out of range (%g, %g).' %
(inputmatrix, inputmax - inputrange, inputmax))
# round down if input is within half an index or else raise index error
if outputmatrix > outputmax:
if np.around(outputmatrix - outputmax, 1) <= 0.5:
outputmatrix = outputmax
(degrees, inputmin, inputmax))

# If the index is still out of bounds after rounding, raise an error.
# 0.500001 is used in comparisons instead of 0.5 to allow for a small
# margin of error which can occur when dealing with floating point numbers.
if index > outputmax:
if index - outputmax <= 0.500001:
index = outputmax
else:
raise err
elif outputmatrix < outputmin:
if np.around(outputmin - outputmatrix, 1) <= 0.5:
outputmatrix = outputmin
elif index < 0:
if -index <= 0.500001:
index = 0
else:
raise err
return outputmatrix
# If the index wasn't set to outputmax or 0, round it and cast it as an
# integer so it can be used in integer-based indexing.
else:
index = int(np.around(index))

return index


def haurwitz(apparent_zenith):
Expand Down
7 changes: 7 additions & 0 deletions pvlib/test/test_clearsky.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,13 @@ def monthly_lt_nointerp(lat, lon, time=months):
monthly_lt_nointerp(38.2, -181) # exceeds min longitude


def test_degrees_to_index_1():
"""Test that _degrees_to_index raises an error when something other than
'latitude' or 'longitude' is passed."""
with pytest.raises(IndexError): # invalid value for coordinate argument
clearsky._degrees_to_index(degrees=22.0, coordinate='width')


@pytest.fixture
def detect_clearsky_data():
test_dir = os.path.dirname(os.path.abspath(
Expand Down