Skip to content

Commit c6547b5

Browse files
nicomtkandersolar
andauthored
Adding altitude lookup for Location class (#1850)
* Adding altitude lookup for location class Set altitude automatically from built-in map when not specified. See #1547 * Readding change removed by accident by patch * Note about fallback to zero when there is no data * Adding description to "what's new" * Update pvlib/location.py Better type definition Co-authored-by: Kevin Anderson <[email protected]> * Fix wording for altitude param * move whatsnew entry to 0.11.0 * docstring tweak * fix 0.10.2 whatsnew file --------- Co-authored-by: Kevin Anderson <[email protected]>
1 parent 3d778ea commit c6547b5

File tree

3 files changed

+43
-23
lines changed

3 files changed

+43
-23
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ Enhancements
6464
diffuse fraction of Photosynthetically Active Radiation (PAR) from the
6565
global diffuse fraction and the solar zenith.
6666
(:issue:`2047`, :pull:`2048`)
67+
* Default altitude in :py:class:`pvlib.location.Location`
68+
now comes from :py:func:`~pvlib.location.lookup_altitude` (:issue:`1516`, :pull:`1850`)
69+
6770

6871
Bug fixes
6972
~~~~~~~~~
@@ -90,4 +93,5 @@ Contributors
9093
* Ioannis Sifnaios (:ghuser:`IoannisSifnaios`)
9194
* Mark Campanelli (:ghuser:`markcampanelli`)
9295
* Rajiv Daxini (:ghuser:`RDaxini`)
96+
* Nicolas Martinez (:ghuser:`nicomt`)
9397
* :ghuser:`PhilBrk8`

pvlib/location.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Will Holmgren, University of Arizona, 2014-2016.
66

7-
import os
7+
import pathlib
88
import datetime
99

1010
import pandas as pd
@@ -14,6 +14,7 @@
1414
from pvlib import solarposition, clearsky, atmosphere, irradiance
1515
from pvlib.tools import _degrees_to_index
1616

17+
1718
class Location:
1819
"""
1920
Location objects are convenient containers for latitude, longitude,
@@ -44,8 +45,11 @@ class Location:
4445
pytz.timezone objects will be converted to strings.
4546
ints and floats must be in hours from UTC.
4647
47-
altitude : float, default 0.
48+
altitude : float, optional
4849
Altitude from sea level in meters.
50+
If not specified, the altitude will be fetched from
51+
:py:func:`pvlib.location.lookup_altitude`.
52+
If no data is available for the location, the altitude is set to 0.
4953
5054
name : string, optional
5155
Sets the name attribute of the Location object.
@@ -55,7 +59,8 @@ class Location:
5559
pvlib.pvsystem.PVSystem
5660
"""
5761

58-
def __init__(self, latitude, longitude, tz='UTC', altitude=0, name=None):
62+
def __init__(self, latitude, longitude, tz='UTC', altitude=None,
63+
name=None):
5964

6065
self.latitude = latitude
6166
self.longitude = longitude
@@ -75,6 +80,9 @@ def __init__(self, latitude, longitude, tz='UTC', altitude=0, name=None):
7580
else:
7681
raise TypeError('Invalid tz specification')
7782

83+
if altitude is None:
84+
altitude = lookup_altitude(latitude, longitude)
85+
7886
self.altitude = altitude
7987

8088
self.name = name
@@ -427,8 +435,8 @@ def lookup_altitude(latitude, longitude):
427435
428436
"""
429437

430-
pvlib_path = os.path.dirname(os.path.abspath(__file__))
431-
filepath = os.path.join(pvlib_path, 'data', 'Altitude.h5')
438+
pvlib_path = pathlib.Path(__file__).parent
439+
filepath = pvlib_path / 'data' / 'Altitude.h5'
432440

433441
latitude_index = _degrees_to_index(latitude, coordinate='latitude')
434442
longitude_index = _degrees_to_index(longitude, coordinate='longitude')

pvlib/tests/test_location.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from pytz.exceptions import UnknownTimeZoneError
1313

1414
import pvlib
15+
from pvlib import location
1516
from pvlib.location import Location, lookup_altitude
1617
from pvlib.solarposition import declination_spencer71
1718
from pvlib.solarposition import equation_of_time_spencer71
@@ -328,21 +329,28 @@ def test_extra_kwargs():
328329
Location(32.2, -111, arbitrary_kwarg='value')
329330

330331

331-
def test_lookup_altitude():
332-
max_alt_error = 125
333-
# location name, latitude, longitude, altitude
334-
test_locations = [
335-
('Tucson, USA', 32.2540, -110.9742, 724),
336-
('Lusaka, Zambia', -15.3875, 28.3228, 1253),
337-
('Tokio, Japan', 35.6762, 139.6503, 40),
338-
('Canberra, Australia', -35.2802, 149.1310, 566),
339-
('Bogota, Colombia', 4.7110, -74.0721, 2555),
340-
('Dead Sea, West Bank', 31.525849, 35.449214, -415),
341-
('New Delhi, India', 28.6139, 77.2090, 214),
342-
('Null Island, Atlantic Ocean', 0, 0, 0),
343-
]
344-
345-
for name, lat, lon, expected_alt in test_locations:
346-
alt_found = lookup_altitude(lat, lon)
347-
assert abs(alt_found - expected_alt) < max_alt_error, \
348-
f'Max error exceded for {name} - e: {expected_alt} f: {alt_found}'
332+
@pytest.mark.parametrize('lat,lon,expected_alt', [
333+
pytest.param(32.2540, -110.9742, 724, id='Tucson, USA'),
334+
pytest.param(-15.3875, 28.3228, 1253, id='Lusaka, Zambia'),
335+
pytest.param(35.6762, 139.6503, 40, id='Tokyo, Japan'),
336+
pytest.param(-35.2802, 149.1310, 566, id='Canberra, Australia'),
337+
pytest.param(4.7110, -74.0721, 2555, id='Bogota, Colombia'),
338+
pytest.param(31.525849, 35.449214, -415, id='Dead Sea, West Bank'),
339+
pytest.param(28.6139, 77.2090, 214, id='New Delhi, India'),
340+
pytest.param(0, 0, 0, id='Null Island, Atlantic Ocean'),
341+
])
342+
def test_lookup_altitude(lat, lon, expected_alt):
343+
alt_found = lookup_altitude(lat, lon)
344+
assert alt_found == pytest.approx(expected_alt, abs=125)
345+
346+
347+
def test_location_lookup_altitude(mocker):
348+
mocker.spy(location, 'lookup_altitude')
349+
tus = Location(32.2, -111, 'US/Arizona', 700, 'Tucson')
350+
location.lookup_altitude.assert_not_called()
351+
assert tus.altitude == 700
352+
location.lookup_altitude.reset_mock()
353+
354+
tus = Location(32.2, -111, 'US/Arizona')
355+
location.lookup_altitude.assert_called_once_with(32.2, -111)
356+
assert tus.altitude == location.lookup_altitude(32.2, -111)

0 commit comments

Comments
 (0)