From f2b0b1c23bf24205745a2965a10354b400ea6131 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 17:44:23 -0400 Subject: [PATCH 01/12] Using pathlib for path operations --- pvlib/location.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/location.py b/pvlib/location.py index 0fb3b42a04..277a6db460 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -4,7 +4,7 @@ # Will Holmgren, University of Arizona, 2014-2016. -import os +import pathlib import datetime import warnings @@ -427,8 +427,8 @@ def lookup_altitude(latitude, longitude): """ - pvlib_path = os.path.dirname(os.path.abspath(__file__)) - filepath = os.path.join(pvlib_path, 'data', 'Altitude.h5') + pvlib_path = pathlib.Path(__file__).parent + filepath = pvlib_path / 'data' / 'Altitude.h5' latitude_index = _degrees_to_index(latitude, coordinate='latitude') longitude_index = _degrees_to_index(longitude, coordinate='longitude') From 64b1de2f2d6cb1eac5c827fcdee9838e5c9b1859 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 17:45:04 -0400 Subject: [PATCH 02/12] Pytest fixture for test_lookup_altitude --- pvlib/tests/test_location.py | 49 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/pvlib/tests/test_location.py b/pvlib/tests/test_location.py index b3c1576bdf..ff2c1dc56c 100644 --- a/pvlib/tests/test_location.py +++ b/pvlib/tests/test_location.py @@ -18,6 +18,33 @@ from .conftest import requires_ephem +@pytest.fixture( + # latitude, longitude, altitude + params=[ + (32.2540, -110.9742, 724), + (-15.3875, 28.3228, 1253), + (35.6762, 139.6503, 40), + (-35.2802, 149.1310, 566), + (4.7110, -74.0721, 2555), + (31.525849, 35.449214, -415), + (28.6139, 77.2090, 214), + (0, 0, 0) + ], + ids=[ + 'Tucson, USA', + 'Lusaka, Zambia', + 'Tokyo, Japan', + 'Canberra, Australia', + 'Bogota, Colombia', + 'Dead Sea, West Bank', + 'New Delhi, India', + 'Null Island, Atlantic Ocean' + ] +) +def location_altitude(request): + return request.param + + def test_location_required(): Location(32.2, -111) @@ -328,21 +355,7 @@ def test_extra_kwargs(): Location(32.2, -111, arbitrary_kwarg='value') -def test_lookup_altitude(): - max_alt_error = 125 - # location name, latitude, longitude, altitude - test_locations = [ - ('Tucson, USA', 32.2540, -110.9742, 724), - ('Lusaka, Zambia', -15.3875, 28.3228, 1253), - ('Tokio, Japan', 35.6762, 139.6503, 40), - ('Canberra, Australia', -35.2802, 149.1310, 566), - ('Bogota, Colombia', 4.7110, -74.0721, 2555), - ('Dead Sea, West Bank', 31.525849, 35.449214, -415), - ('New Delhi, India', 28.6139, 77.2090, 214), - ('Null Island, Atlantic Ocean', 0, 0, 0), - ] - - for name, lat, lon, expected_alt in test_locations: - alt_found = lookup_altitude(lat, lon) - assert abs(alt_found - expected_alt) < max_alt_error, \ - f'Max error exceded for {name} - e: {expected_alt} f: {alt_found}' +def test_lookup_altitude(location_altitude): + lat, lon, expected_alt = location_altitude + alt_found = lookup_altitude(lat, lon) + assert alt_found == pytest.approx(expected_alt, abs=125) From e9a5997812aba717b1355fa88499970787d217a8 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:30:19 -0400 Subject: [PATCH 03/12] Using lookup_altitude as the default altitude --- pvlib/clearsky.py | 13 +++-- pvlib/location.py | 9 +++- pvlib/solarposition.py | 110 ++++++++++++++++++++++++++++------------- 3 files changed, 91 insertions(+), 41 deletions(-) diff --git a/pvlib/clearsky.py b/pvlib/clearsky.py index ffc7ac9b55..f5f1059957 100644 --- a/pvlib/clearsky.py +++ b/pvlib/clearsky.py @@ -13,12 +13,12 @@ from scipy.linalg import hankel import h5py -from pvlib import atmosphere, tools +from pvlib import atmosphere, tools, location from pvlib.tools import _degrees_to_index def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, - altitude=0, dni_extra=1364., perez_enhancement=False): + altitude=None, dni_extra=1364., perez_enhancement=False): ''' Determine clear sky GHI, DNI, and DHI from Ineichen/Perez model. @@ -42,8 +42,10 @@ def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, linke_turbidity : numeric Linke Turbidity. - altitude : numeric, default 0 - Altitude above sea level in meters. + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. dni_extra : numeric, default 1364 Extraterrestrial irradiance. The units of ``dni_extra`` @@ -87,6 +89,9 @@ def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, ISES Solar World Congress, June 2003. Goteborg, Sweden. ''' + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + # ghi is calculated using either the equations in [1] by setting # perez_enhancement=False (default behavior) or using the model # in [2] by setting perez_enhancement=True. diff --git a/pvlib/location.py b/pvlib/location.py index 277a6db460..7c269938bc 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -45,8 +45,10 @@ class Location: pytz.timezone objects will be converted to strings. ints and floats must be in hours from UTC. - altitude : float, default 0. + altitude : None or float, default None Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. name : None or string, default None. Sets the name attribute of the Location object. @@ -56,7 +58,7 @@ class Location: pvlib.pvsystem.PVSystem """ - def __init__(self, latitude, longitude, tz='UTC', altitude=0, name=None): + def __init__(self, latitude, longitude, tz='UTC', altitude=None, name=None): self.latitude = latitude self.longitude = longitude @@ -76,6 +78,9 @@ def __init__(self, latitude, longitude, tz='UTC', altitude=0, name=None): else: raise TypeError('Invalid tz specification') + if altitude is None: + altitude = lookup_altitude(latitude, longitude) + self.altitude = altitude self.name = name diff --git a/pvlib/solarposition.py b/pvlib/solarposition.py index cdcacd7ec6..558458fa89 100644 --- a/pvlib/solarposition.py +++ b/pvlib/solarposition.py @@ -24,7 +24,7 @@ import warnings import datetime -from pvlib import atmosphere +from pvlib import atmosphere, location from pvlib.tools import datetime_to_djd, djd_to_datetime @@ -52,12 +52,13 @@ def get_solarposition(time, latitude, longitude, negative to west. altitude : None or float, default None - If None, computed from pressure. Assumed to be 0 m - if pressure is also None. + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. pressure : None or float, default None - If None, computed from altitude. Assumed to be 101325 Pa - if altitude is also None. + Air pressure in Pascals. + If None, computed from altitude. method : string, default 'nrel_numpy' 'nrel_numpy' uses an implementation of the NREL SPA algorithm @@ -92,12 +93,10 @@ def get_solarposition(time, latitude, longitude, .. [3] NREL SPA code: http://rredc.nrel.gov/solar/codesandalgorithms/spa/ """ - if altitude is None and pressure is None: - altitude = 0. - pressure = 101325. - elif altitude is None: - altitude = atmosphere.pres2alt(pressure) - elif pressure is None: + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + + if pressure is None: pressure = atmosphere.alt2pres(altitude) method = method.lower() @@ -129,7 +128,7 @@ def get_solarposition(time, latitude, longitude, return ephem_df -def spa_c(time, latitude, longitude, pressure=101325, altitude=0, +def spa_c(time, latitude, longitude, pressure=None, altitude=None, temperature=12, delta_t=67.0, raw_spa_output=False): """ @@ -153,10 +152,13 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0, longitude : float Longitude in decimal degrees. Positive east of prime meridian, negative to west. - pressure : float, default 101325 - Pressure in Pascals - altitude : float, default 0 - Height above sea level. [m] + pressure : None or float, default None + Air pressure in Pascals. + If None, computed from altitude. + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. temperature : float, default 12 Temperature in C delta_t : float, default 67.0 @@ -210,6 +212,11 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0, except TypeError: time_utc = time + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + spa_out = [] for date in time_utc: @@ -275,7 +282,7 @@ def _spa_python_import(how): def spa_python(time, latitude, longitude, - altitude=0, pressure=101325, temperature=12, delta_t=67.0, + altitude=None, pressure=None, temperature=12, delta_t=67.0, atmos_refract=None, how='numpy', numthreads=4): """ Calculate the solar position using a python implementation of the @@ -298,10 +305,13 @@ def spa_python(time, latitude, longitude, longitude : float Longitude in decimal degrees. Positive east of prime meridian, negative to west. - altitude : float, default 0 - Distance above sea level. - pressure : int or float, optional, default 101325 + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. + pressure : int or float, optional, default None avg. yearly air pressure in Pascals. + If None, computed from altitude. temperature : int or float, optional, default 12 avg. yearly air temperature in degrees C. delta_t : float, optional, default 67.0 @@ -351,6 +361,11 @@ def spa_python(time, latitude, longitude, pyephem, spa_c, ephemeris """ + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + # Added by Tony Lorenzo (@alorenzo175), University of Arizona, 2015 lat = latitude @@ -504,8 +519,8 @@ def _ephem_setup(latitude, longitude, altitude, pressure, temperature, def sun_rise_set_transit_ephem(times, latitude, longitude, next_or_previous='next', - altitude=0, - pressure=101325, + altitude=None, + pressure=None, temperature=12, horizon='0:00'): """ Calculate the next sunrise and sunset times using the PyEphem package. @@ -520,10 +535,13 @@ def sun_rise_set_transit_ephem(times, latitude, longitude, Longitude in degrees, positive east of prime meridian, negative to west next_or_previous : str 'next' or 'previous' sunrise and sunset relative to time - altitude : float, default 0 - distance above sea level in meters. - pressure : int or float, optional, default 101325 - air pressure in Pascals. + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. + pressure : None or float, default None + Air pressure in Pascals. + If None, computed from altitude. temperature : int or float, optional, default 12 air temperature in degrees C. horizon : string, format +/-X:YY @@ -555,6 +573,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude, else: raise ValueError('times must be localized') + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + obs, sun = _ephem_setup(latitude, longitude, altitude, pressure, temperature, horizon) # create lists of sunrise and sunset time localized to time.tz @@ -588,7 +611,7 @@ def sun_rise_set_transit_ephem(times, latitude, longitude, 'transit': trans}) -def pyephem(time, latitude, longitude, altitude=0, pressure=101325, +def pyephem(time, latitude, longitude, altitude=None, pressure=None, temperature=12, horizon='+0:00'): """ Calculate the solar position using the PyEphem package. @@ -603,10 +626,13 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325, longitude : float Longitude in decimal degrees. Positive east of prime meridian, negative to west. - altitude : float, default 0 - Height above sea level in meters. [m] - pressure : int or float, optional, default 101325 - air pressure in Pascals. + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. + pressure : None or float, default None + Air pressure in Pascals. + If None, computed from altitude. temperature : int or float, optional, default 12 air temperature in degrees C. horizon : string, optional, default '+0:00' @@ -642,6 +668,11 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325, except TypeError: time_utc = time + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + sun_coords = pd.DataFrame(index=time) obs, sun = _ephem_setup(latitude, longitude, altitude, @@ -862,7 +893,7 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12): def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value, - altitude=0, pressure=101325, temperature=12, horizon='+0:00', + altitude=None, pressure=None, temperature=12, horizon='+0:00', xtol=1.0e-12): """ Calculate the time between lower_bound and upper_bound @@ -885,11 +916,14 @@ def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value, and 'az' (which must be given in radians). value : int or float The value of the attribute to solve for - altitude : float, default 0 - Distance above sea level. - pressure : int or float, optional, default 101325 + altitude : None or float, default None + Altitude from sea level in meters. + If None, the altitude will be fetched from + :py:func:`pvlib.location.lookup_altitude`. + pressure : int or float, optional, default None Air pressure in Pascals. Set to 0 for no atmospheric correction. + If None, computed from altitude. temperature : int or float, optional, default 12 Air temperature in degrees C. horizon : string, optional, default '+0:00' @@ -913,6 +947,12 @@ def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value, If the given attribute is not an attribute of a PyEphem.Sun object. """ + + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + obs, sun = _ephem_setup(latitude, longitude, altitude, pressure, temperature, horizon) From 156ee381567200357694d59531e6b6e682fc16af Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:40:24 -0400 Subject: [PATCH 04/12] Reverting invalid change to clearsky --- pvlib/clearsky.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pvlib/clearsky.py b/pvlib/clearsky.py index f5f1059957..c6a8695037 100644 --- a/pvlib/clearsky.py +++ b/pvlib/clearsky.py @@ -18,7 +18,7 @@ def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, - altitude=None, dni_extra=1364., perez_enhancement=False): + altitude=0, dni_extra=1364., perez_enhancement=False): ''' Determine clear sky GHI, DNI, and DHI from Ineichen/Perez model. @@ -42,10 +42,8 @@ def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, linke_turbidity : numeric Linke Turbidity. - altitude : None or float, default None - Altitude from sea level in meters. - If None, the altitude will be fetched from - :py:func:`pvlib.location.lookup_altitude`. + altitude : numeric, default 0 + Altitude above sea level in meters. dni_extra : numeric, default 1364 Extraterrestrial irradiance. The units of ``dni_extra`` @@ -89,9 +87,6 @@ def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, ISES Solar World Congress, June 2003. Goteborg, Sweden. ''' - if altitude is None: - altitude = location.lookup_altitude(latitude, longitude) - # ghi is calculated using either the equations in [1] by setting # perez_enhancement=False (default behavior) or using the model # in [2] by setting perez_enhancement=True. From 53aaeb2314660127f423e7e586f02488cf508fba Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:43:16 -0400 Subject: [PATCH 05/12] Fix for linting issue --- pvlib/location.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pvlib/location.py b/pvlib/location.py index 7c269938bc..7cef02bec7 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -58,7 +58,8 @@ class Location: pvlib.pvsystem.PVSystem """ - def __init__(self, latitude, longitude, tz='UTC', altitude=None, name=None): + def __init__(self, latitude, longitude, tz='UTC', altitude=None, + name=None): self.latitude = latitude self.longitude = longitude From ff30962c19559a5acd02f4b1bde8efa911e5aeb8 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:48:08 -0400 Subject: [PATCH 06/12] Reverting dead code --- pvlib/clearsky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/clearsky.py b/pvlib/clearsky.py index c6a8695037..ffc7ac9b55 100644 --- a/pvlib/clearsky.py +++ b/pvlib/clearsky.py @@ -13,7 +13,7 @@ from scipy.linalg import hankel import h5py -from pvlib import atmosphere, tools, location +from pvlib import atmosphere, tools from pvlib.tools import _degrees_to_index From 62762db2af46f44d084c338549a1e949e63af05e Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:56:55 -0400 Subject: [PATCH 07/12] fix for test_tracking after lookup_altitude change --- pvlib/tests/test_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_tracking.py b/pvlib/tests/test_tracking.py index 87452939f5..7987dacf8a 100644 --- a/pvlib/tests/test_tracking.py +++ b/pvlib/tests/test_tracking.py @@ -450,7 +450,7 @@ def test_calc_axis_tilt(): stoptime = '2017-12-31T23:59:59-0300' lat, lon = -27.597300, -48.549610 times = pd.DatetimeIndex(pd.date_range(starttime, stoptime, freq='H')) - solpos = pvlib.solarposition.get_solarposition(times, lat, lon) + solpos = pvlib.solarposition.get_solarposition(times, lat, lon, altitude=0) # singleaxis tracker w/slope data slope_azimuth, slope_tilt = 77.34, 10.1149 axis_azimuth = 0.0 From b06b72348f6690a734fbd83c4f3fd96b5bcd3722 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:25:15 -0400 Subject: [PATCH 08/12] Adding lookup_altitude solarposition test --- pvlib/tests/test_solarposition.py | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_solarposition.py b/pvlib/tests/test_solarposition.py index 7578506561..2d9f1762a4 100644 --- a/pvlib/tests/test_solarposition.py +++ b/pvlib/tests/test_solarposition.py @@ -10,7 +10,7 @@ import pytest from pvlib.location import Location -from pvlib import solarposition, spa +from pvlib import solarposition, spa, location, atmosphere from .conftest import requires_ephem, requires_spa_c, requires_numba @@ -769,3 +769,37 @@ def test_spa_python_numba_physical_dst(expected_solpos, golden): temperature=11, delta_t=67, atmos_refract=0.5667, how='numpy', numthreads=1) + + +@pytest.mark.parametrize( + 'method', + [ + solarposition.get_solarposition, + pytest.param(solarposition.spa_c, marks=requires_spa_c), + pytest.param(solarposition.spa_python, marks=requires_numba), + pytest.param(solarposition.pyephem, marks=requires_ephem), + ] +) +def test_solarposition_lookup_altitude(mocker, method): + lat, lon = 32.2, -111 + times = pd.date_range(datetime.datetime(2003, 10, 17, 12, 30, 30), + periods=1, freq='D') + mocker.spy(location, 'lookup_altitude') + mocker.spy(atmosphere, 'alt2pres') + + method(times, lat, lon, altitude=0, pressure=0) + location.lookup_altitude.assert_not_called() + atmosphere.alt2pres.assert_not_called() + location.lookup_altitude.reset_mock() + atmosphere.alt2pres.reset_mock() + + method(times, lat, lon, altitude=0) + location.lookup_altitude.assert_not_called() + atmosphere.alt2pres.assert_called_once_with(0) + location.lookup_altitude.reset_mock() + atmosphere.alt2pres.reset_mock() + + method(times, lat, lon) + location.lookup_altitude.assert_called_once_with(lat, lon) + atmosphere.alt2pres.assert_called_once_with( + location.lookup_altitude(lat, lon)) From 8cbccfb4fc8faa28e71ded9d96cfab1112510b0b Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:31:35 -0400 Subject: [PATCH 09/12] Test location lookup_altitude Changing fixture to parametrize because is not reused --- pvlib/tests/test_location.py | 40 ++++++++++-------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/pvlib/tests/test_location.py b/pvlib/tests/test_location.py index ff2c1dc56c..f13e6a8e4f 100644 --- a/pvlib/tests/test_location.py +++ b/pvlib/tests/test_location.py @@ -18,33 +18,6 @@ from .conftest import requires_ephem -@pytest.fixture( - # latitude, longitude, altitude - params=[ - (32.2540, -110.9742, 724), - (-15.3875, 28.3228, 1253), - (35.6762, 139.6503, 40), - (-35.2802, 149.1310, 566), - (4.7110, -74.0721, 2555), - (31.525849, 35.449214, -415), - (28.6139, 77.2090, 214), - (0, 0, 0) - ], - ids=[ - 'Tucson, USA', - 'Lusaka, Zambia', - 'Tokyo, Japan', - 'Canberra, Australia', - 'Bogota, Colombia', - 'Dead Sea, West Bank', - 'New Delhi, India', - 'Null Island, Atlantic Ocean' - ] -) -def location_altitude(request): - return request.param - - def test_location_required(): Location(32.2, -111) @@ -355,7 +328,16 @@ def test_extra_kwargs(): Location(32.2, -111, arbitrary_kwarg='value') -def test_lookup_altitude(location_altitude): - lat, lon, expected_alt = location_altitude +@pytest.mark.parametrize('lat,lon,expected_alt', [ + pytest.param(32.2540, -110.9742, 724, id='Tucson, USA'), + pytest.param(-15.3875, 28.3228, 1253, id='Lusaka, Zambia'), + pytest.param(35.6762, 139.6503, 40, id='Tokyo, Japan'), + pytest.param(-35.2802, 149.1310, 566, id='Canberra, Australia'), + pytest.param(4.7110, -74.0721, 2555, id='Bogota, Colombia'), + pytest.param(31.525849, 35.449214, -415, id='Dead Sea, West Bank'), + pytest.param(28.6139, 77.2090, 214, id='New Delhi, India'), + pytest.param(0, 0, 0, id='Null Island, Atlantic Ocean'), +]) +def test_lookup_altitude(lat, lon, expected_alt): alt_found = lookup_altitude(lat, lon) assert alt_found == pytest.approx(expected_alt, abs=125) From 47271310b91e09fa3bf8a69100d18ec83283cfc3 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:39:28 -0400 Subject: [PATCH 10/12] Adding Location look_up altitude fallback test --- pvlib/tests/test_location.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pvlib/tests/test_location.py b/pvlib/tests/test_location.py index f13e6a8e4f..8d52f65a54 100644 --- a/pvlib/tests/test_location.py +++ b/pvlib/tests/test_location.py @@ -12,6 +12,7 @@ from pytz.exceptions import UnknownTimeZoneError import pvlib +from pvlib import location from pvlib.location import Location, lookup_altitude from pvlib.solarposition import declination_spencer71 from pvlib.solarposition import equation_of_time_spencer71 @@ -341,3 +342,15 @@ def test_extra_kwargs(): def test_lookup_altitude(lat, lon, expected_alt): alt_found = lookup_altitude(lat, lon) assert alt_found == pytest.approx(expected_alt, abs=125) + + +def test_location_lookup_altitude(mocker): + mocker.spy(location, 'lookup_altitude') + tus = Location(32.2, -111, 'US/Arizona', 700, 'Tucson') + location.lookup_altitude.assert_not_called() + assert tus.altitude == 700 + location.lookup_altitude.reset_mock() + + tus = Location(32.2, -111, 'US/Arizona') + location.lookup_altitude.assert_called_once_with(32.2, -111) + assert tus.altitude == location.lookup_altitude(32.2, -111) From b1fd173f1ab3eb9949565a6e5f2418948d11f2ee Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:44:00 -0400 Subject: [PATCH 11/12] Fix for existing pvsystem test --- pvlib/tests/test_pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 7fa013d0dc..5c78d95d8a 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1678,7 +1678,7 @@ def test_PVSystem_multiple_array_get_aoi(): def solar_pos(): times = pd.date_range(start='20160101 1200-0700', end='20160101 1800-0700', freq='6H') - location = Location(latitude=32, longitude=-111) + location = Location(latitude=32, longitude=-111, altitude=0) return location.get_solarposition(times) From 8c65ed08a72563b0e449b8a67d1c093345916410 Mon Sep 17 00:00:00 2001 From: Nicolas Martinez <17040442+nicomt@users.noreply.github.com> Date: Tue, 13 Sep 2022 01:08:44 -0400 Subject: [PATCH 12/12] Moving lookup_altitude up spa_c Moving lookup_altitude up to prevent confusion in code And credits --- pvlib/solarposition.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/solarposition.py b/pvlib/solarposition.py index 558458fa89..1aa3f10442 100644 --- a/pvlib/solarposition.py +++ b/pvlib/solarposition.py @@ -196,6 +196,11 @@ def spa_c(time, latitude, longitude, pressure=None, altitude=None, pyephem, spa_python, ephemeris """ + if altitude is None: + altitude = location.lookup_altitude(latitude, longitude) + if pressure is None: + pressure = atmosphere.alt2pres(altitude) + # Added by Rob Andrews (@Calama-Consulting), Calama Consulting, 2014 # Edited by Will Holmgren (@wholmgren), University of Arizona, 2014 # Edited by Tony Lorenzo (@alorenzo175), University of Arizona, 2015 @@ -212,11 +217,6 @@ def spa_c(time, latitude, longitude, pressure=None, altitude=None, except TypeError: time_utc = time - if altitude is None: - altitude = location.lookup_altitude(latitude, longitude) - if pressure is None: - pressure = atmosphere.alt2pres(altitude) - spa_out = [] for date in time_utc: