Skip to content
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

coerce and rotate pvgis TMY data to desired tz and year #2138

Merged
merged 26 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
883cfbe
coerce and rotate pvgis TMY data to desired tz and year
mikofski Jul 19, 2024
7e6e4c0
test get_pvgis_tmy_coerce_year
mikofski Jul 19, 2024
84d4695
fix flake8 in test_pvgis_coerce_year
mikofski Jul 19, 2024
3e42075
remove iloc for index in test pvgis coerce
mikofski Jul 19, 2024
d0bd0a0
deal with leap year in pvgis when coercing
mikofski Jul 19, 2024
ec482ac
fix space around operator in coerce pvgis
mikofski Jul 19, 2024
883ced8
fix pd.Timestamp in pvgis coerce year
mikofski Jul 19, 2024
dd2c85f
Update v0.11.1 what's new for coerce pvgis tmy
mikofski Jul 20, 2024
31800e9
replace year and tzinfo in pvgis_tmy coerce year
mikofski Jul 27, 2024
72c55f6
remove unused imports from pvgis.py for flake8
mikofski Jul 27, 2024
0735183
change private function name to _coerce_and_roll_pvgis_tmy
mikofski Jul 27, 2024
2059dc6
spot check rolled pvgis TMY values after converting tz
mikofski Jul 27, 2024
a38cf9a
Update utc_offset description
mikofski Jul 31, 2024
440e780
change coerce_year and utc_offset defaults to None in pvgis TMY
mikofski Jul 31, 2024
4fd05fb
rename roll_utc_offset in get_pvgis_tmy
mikofski Jul 31, 2024
1b92d40
Update pvlib/iotools/pvgis.py with suggestions
mikofski Aug 1, 2024
43ce3c4
Update docs/sphinx/source/whatsnew/v0.11.1.rst
mikofski Aug 1, 2024
76c8ec6
Merge branch 'main' into coerce-and-rotate-pvgis
AdamRJensen Aug 5, 2024
d77a3d3
Merge branch 'main' into coerce-and-rotate-pvgis
mikofski Aug 5, 2024
91c169e
rename _coerce_and_roll_tmy, remove 'pvgis'
mikofski Aug 6, 2024
1e9ee64
rename index with new tz in coerce pvgis tmy
mikofski Aug 6, 2024
d24e4f3
allow tz of None in _coerce_and_roll_tmy
mikofski Aug 6, 2024
f12571d
Merge branch 'main' into coerce-and-rotate-pvgis
mikofski Aug 13, 2024
fb2813d
clarify input tmy_data is UTC...
mikofski Aug 14, 2024
ac9dbb0
fix flake8 in _coerce_and_roll_tmy
mikofski Aug 14, 2024
9875521
Merge branch 'main' into coerce-and-rotate-pvgis
mikofski Aug 16, 2024
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
6 changes: 5 additions & 1 deletion docs/sphinx/source/whatsnew/v0.11.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Enhancements
* Add new parameters for min/max absolute air mass to
:py:func:`pvlib.spectrum.spectral_factor_firstsolar`.
(:issue:`2086`, :pull:`2100`)
* Add ``utc_offset`` and ``coerce_year`` arguments to
mikofski marked this conversation as resolved.
Show resolved Hide resolved
:py:func:`pvlib.iotools.get_pvgis_tmy` to allow user to specify time zone,
rotate indices of TMY to begin at midnight, and force indices to desired
year. (:issue:`2139`, :pull:`2138`)


Bug fixes
Expand Down Expand Up @@ -45,4 +49,4 @@ Contributors
* Leonardo Micheli (:ghuser:`lmicheli`)
* Echedey Luis (:ghuser:`echedey-ls`)
* Rajiv Daxini (:ghuser:`RDaxini`)

* Mark A. Mikofski (:ghuser:`mikofski`)
35 changes: 34 additions & 1 deletion pvlib/iotools/pvgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* `monthly radiation
<https://ec.europa.eu/jrc/en/PVGIS/tools/monthly-radiation>`_
"""
import calendar
import io
import json
from pathlib import Path
Expand Down Expand Up @@ -390,9 +391,32 @@ def read_pvgis_hourly(filename, pvgis_format=None, map_variables=True):
raise ValueError(err_msg)


def _coerce_and_rotate_pvgis(pvgis_data, tz, year):
adriesse marked this conversation as resolved.
Show resolved Hide resolved
"""
After converting TZ, rotate indices so timeseries starts at midnight
and force all indices to a common year. Only works for integer TZ.
"""
# assert tz//1 == tz
tzname = f'Etc/GMT{-tz:+d}'
# check if February is leap year
feb1 = pvgis_data[pvgis_data.index.month == 2].index.year[0]
if calendar.isleap(feb1):
# replace Feb year with a non-leap year
pvgis_data.index = [
ts.replace(year=1990) if ts.month == 2 else ts
for ts in pvgis_data.index]
adriesse marked this conversation as resolved.
Show resolved Hide resolved
pvgis_data = pd.concat(
[pvgis_data.iloc[-tz:], pvgis_data.iloc[:-tz]],
axis=0).tz_convert(tzname)
adriesse marked this conversation as resolved.
Show resolved Hide resolved
pvgis_data.index = [
timestamp.replace(year=year) for timestamp in pvgis_data.index]
return pvgis_data


def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
userhorizon=None, startyear=None, endyear=None,
map_variables=True, url=URL, timeout=30):
map_variables=True, url=URL, timeout=30,
utc_offset=0, coerce_year=1990):
"""
Get TMY data from PVGIS.

Expand Down Expand Up @@ -424,6 +448,12 @@ def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
base url of PVGIS API, append ``tmy`` to get TMY endpoint
timeout : int, default 30
time in seconds to wait for server response before timeout
utc_offset: int, default 0
Use to specify a timezone other than the default UTC zero. Will force
year to ``coerce_year`` if not zero.
adriesse marked this conversation as resolved.
Show resolved Hide resolved
mikofski marked this conversation as resolved.
Show resolved Hide resolved
coerce_year: int, default 1990
adriesse marked this conversation as resolved.
Show resolved Hide resolved
mikofski marked this conversation as resolved.
Show resolved Hide resolved
Use to force indices to desired year. Ignored if ``utc_offset`` is
zero.
adriesse marked this conversation as resolved.
Show resolved Hide resolved

Returns
-------
Expand Down Expand Up @@ -510,6 +540,9 @@ def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
if map_variables:
data = data.rename(columns=VARIABLE_MAP)

if utc_offset != 0:
data = _coerce_and_rotate_pvgis(data, utc_offset, coerce_year)

return data, months_selected, inputs, meta


Expand Down
16 changes: 16 additions & 0 deletions pvlib/tests/iotools/test_pvgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,22 @@ def _compare_pvgis_tmy_basic(expected, meta_expected, pvgis_data):
assert np.allclose(data[outvar], expected[outvar])


@pytest.mark.remote_data
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
def test_get_pvgis_tmy_coerce_year():
"""test utc_offset and coerce_year work as expected"""
pvgis_data = get_pvgis_tmy(45, 8, utc_offset=2) # Turin
jan1_midnight1990 = pd.Timestamp('1990-01-01 00:00:00', tz='Etc/GMT-2')
dec31_midnight1990 = pd.Timestamp('1990-12-31 23:00:00', tz='Etc/GMT-2')
assert pvgis_data[0].index[0] == jan1_midnight1990
assert pvgis_data[0].index[-1] == dec31_midnight1990
pvgis_data = get_pvgis_tmy(45, 8, utc_offset=2, coerce_year=2021) # Turin
jan1_midnight2021 = pd.Timestamp('2021-01-01 00:00:00', tz='Etc/GMT-2')
dec31_midnight2021 = pd.Timestamp('2021-12-31 23:00:00', tz='Etc/GMT-2')
assert pvgis_data[0].index[0] == jan1_midnight2021
assert pvgis_data[0].index[-1] == dec31_midnight2021
mikofski marked this conversation as resolved.
Show resolved Hide resolved


@pytest.mark.remote_data
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
def test_get_pvgis_tmy_csv(expected, month_year_expected, inputs_expected,
Expand Down
Loading