Skip to content

Commit b901e31

Browse files
committed
Add get_nsrdb_psm4_polar_tmy
1 parent 29ed259 commit b901e31

5 files changed

Lines changed: 8942 additions & 8 deletions

File tree

docs/sphinx/source/reference/iotools.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Satellite-derived irradiance and weather data for the Americas.
8181
iotools.get_nsrdb_psm4_conus
8282
iotools.get_nsrdb_psm4_full_disc
8383
iotools.get_nsrdb_psm4_polar
84+
iotools.get_nsrdb_psm4_polar_tmy
8485
iotools.read_nsrdb_psm4
8586

8687

pvlib/iotools/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pvlib.iotools.psm4 import get_nsrdb_psm4_conus # noqa: F401
1414
from pvlib.iotools.psm4 import get_nsrdb_psm4_full_disc # noqa: F401
1515
from pvlib.iotools.psm4 import get_nsrdb_psm4_polar # noqa: F401
16+
from pvlib.iotools.psm4 import get_nsrdb_psm4_polar_tmy # noqa: F401
1617
from pvlib.iotools.psm4 import read_nsrdb_psm4 # noqa: F401
1718
from pvlib.iotools.pvgis import get_pvgis_tmy, read_pvgis_tmy # noqa: F401
1819
from pvlib.iotools.pvgis import read_pvgis_hourly # noqa: F401

pvlib/iotools/psm4.py

Lines changed: 160 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ def get_nsrdb_psm4_aggregated(latitude, longitude, api_key, email,
164164
See Also
165165
--------
166166
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus,
167-
pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.read_nsrdb_psm4
167+
pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.get_nsrdb_psm4_polar,
168+
pvlib.iotools.get_nsrdb_psm4_polar_tmy, pvlib.iotools.read_nsrdb_psm4
168169
169170
References
170171
----------
@@ -300,8 +301,10 @@ def get_nsrdb_psm4_tmy(latitude, longitude, api_key, email, year='tmy',
300301
301302
See Also
302303
--------
304+
pvlib.iotools.get_nsrdb_psm4_polar_tmy,
303305
pvlib.iotools.get_nsrdb_psm4_aggregated,
304306
pvlib.iotools.get_nsrdb_psm4_conus, pvlib.iotools.get_nsrdb_psm4_full_disc,
307+
pvlib.iotools.get_nsrdb_psm4_polar,
305308
pvlib.iotools.read_nsrdb_psm4
306309
307310
References
@@ -436,9 +439,9 @@ def get_nsrdb_psm4_conus(latitude, longitude, api_key, email, year,
436439
437440
See Also
438441
--------
439-
pvlib.iotools.get_nsrdb_psm4_aggregated,
440-
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_full_disc,
441-
pvlib.iotools.read_nsrdb_psm4
442+
pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_tmy,
443+
pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.get_nsrdb_psm4_polar,
444+
pvlib.iotools.get_nsrdb_psm4_polar_tmy, pvlib.iotools.read_nsrdb_psm4
442445
443446
References
444447
----------
@@ -575,9 +578,9 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email,
575578
576579
See Also
577580
--------
578-
pvlib.iotools.get_nsrdb_psm4_aggregated,
579-
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus,
580-
pvlib.iotools.read_nsrdb_psm4
581+
pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_tmy,
582+
pvlib.iotools.get_nsrdb_psm4_conus, pvlib.iotools.get_nsrdb_psm4_polar,
583+
pvlib.iotools.get_nsrdb_psm4_polar_tmy, pvlib.iotools.read_nsrdb_psm4
581584
582585
References
583586
----------
@@ -640,7 +643,7 @@ def get_nsrdb_psm4_polar(latitude, longitude, api_key, email,
640643
Retrieve timeseries weather data from the PSM4 NSRDB Polar API.
641644
642645
The NSRDB is described in [1]_ and the NSRDB PSM4 NSRDB Polar v4 dataset
643-
is described in [2]_, [3]_. The Polar dataset extends NSRDB coverage to
646+
is described in [2]_, [3]_. The polar dataset extends NSRDB coverage to
644647
high latitude regions, that are outside the field of view of the
645648
geostationary satellites.
646649
@@ -721,6 +724,7 @@ def get_nsrdb_psm4_polar(latitude, longitude, api_key, email,
721724
--------
722725
pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_tmy,
723726
pvlib.iotools.get_nsrdb_psm4_conus, pvlib.iotools.get_nsrdb_psm4_full_disc,
727+
pvlib.iotools.get_nsrdb_psm4_polar, pvlib.iotools.get_nsrdb_psm4_polar_tmy,
724728
pvlib.iotools.read_nsrdb_psm4
725729
726730
References
@@ -776,6 +780,152 @@ def get_nsrdb_psm4_polar(latitude, longitude, api_key, email,
776780
return read_nsrdb_psm4(fbuf, map_variables)
777781

778782

783+
def get_nsrdb_psm4_polar_tmy(latitude, longitude, api_key, email, year='tmy',
784+
time_step=60, parameters=PARAMETERS,
785+
leap_day=False, full_name=PVLIB_PYTHON,
786+
affiliation=PVLIB_PYTHON, utc=False,
787+
map_variables=True, url=None, timeout=30):
788+
"""
789+
Retrieve timeseries weather data from the PSM4 NSRDB Polar TMY v4 API.
790+
791+
The NSRDB is described in [1]_ and the NSRDB PSM4 Polar TMY v4 dataset is
792+
described in [2]_, [3]_. The polar dataset extends NSRDB coverage to high
793+
latitude polar regions, that are outside the field of view of the
794+
geostationary satellites.
795+
796+
The dataset provides typical year data over the exclusive economic zone
797+
above 60 degrees north. The data have a spatial resolution of 4 km and a
798+
temporal resolution of 1 hour.
799+
800+
Parameters
801+
----------
802+
latitude : float or int
803+
in decimal degrees, between 60 and 90 degrees north
804+
longitude : float or int
805+
in decimal degrees, between -180 and 180, east is positive
806+
api_key : str
807+
NLR Developer Network API key
808+
email : str
809+
NLR API uses this to automatically communicate messages back
810+
to the user only if necessary
811+
year : str, default 'tmy'
812+
PSM4 API parameter specifing TMY variant to download (e.g. ``'tmy'``
813+
or ``'tgy-2023'``). The allowed values update periodically, so
814+
consult the NSRDB references below for the current set of options.
815+
Called ``names`` in NSRDB API.
816+
time_step : int, {60}
817+
time step in minutes. Must be 60 for typical year requests. Called
818+
``interval`` in NSRDB API.
819+
parameters : list of str, optional
820+
meteorological fields to fetch. If not specified, defaults to
821+
``pvlib.iotools.psm4.PARAMETERS``. See reference [2]_ for a list of
822+
available fields. Alternatively, pvlib names may also be used (e.g.
823+
'ghi' rather than 'GHI'); see :const:`REQUEST_VARIABLE_MAP`. To
824+
retrieve all available fields, set ``parameters=[]``.
825+
leap_day : bool, default : False
826+
Include leap day in the results. Ignored for tmy/tgy/tdy requests.
827+
full_name : str, default 'pvlib python'
828+
optional
829+
affiliation : str, default 'pvlib python'
830+
optional
831+
utc: bool, default : False
832+
retrieve data with timestamps converted to UTC. False returns
833+
timestamps in local standard time of the selected location
834+
map_variables : bool, default True
835+
When true, renames columns of the Dataframe to pvlib variable names
836+
where applicable. See variable :const:`VARIABLE_MAP`.
837+
url : str, optional
838+
Full API endpoint URL. If not specified, the PSM4 Polar TMY v4 URL
839+
is used.
840+
timeout : int, default 30
841+
time in seconds to wait for server response before timeout
842+
843+
Returns
844+
-------
845+
data : pandas.DataFrame
846+
timeseries data from NLR PSM4
847+
metadata : dict
848+
metadata from NLR PSM4 about the record, see
849+
:func:`pvlib.iotools.read_nsrdb_psm4` for fields
850+
851+
Raises
852+
------
853+
requests.HTTPError
854+
if the request response status is not ok, then the ``'errors'`` field
855+
from the JSON response or any error message in the content will be
856+
raised as an exception, for example if the `api_key` was rejected or if
857+
the coordinates were not found in the NSRDB
858+
859+
Notes
860+
-----
861+
The required NLR developer key, `api_key`, is available for free by
862+
registering at the `NLR Developer Network <https://developer.nlr.gov/>`_.
863+
864+
.. warning:: The "DEMO_KEY" `api_key` is severely rate limited and may
865+
result in rejected requests.
866+
867+
.. warning:: PSM4 is limited to data found in the NSRDB, please consult
868+
the references below for locations with available data.
869+
870+
See Also
871+
--------
872+
pvlib.iotools.get_nsrdb_psm4_polar, pvlib.iotools.get_nsrdb_psm4_tmy,
873+
pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_conus,
874+
pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.read_nsrdb_psm4
875+
876+
References
877+
----------
878+
.. [1] `NLR National Solar Radiation Database (NSRDB)
879+
<https://developer.nlr.gov/docs/solar/nsrdb/>`_
880+
.. [2] `NLR NSRDB Polar Data
881+
<https://nsrdb.nlr.gov/data-sets/polar-data/>`_
882+
.. [3] `NSRDB Polar Tmy V4.0.0
883+
<https://developer.nlr.gov/docs/solar/nsrdb/nsrdb-polar-tmy-v4-0-0-download/>`_
884+
"""
885+
# The well know text (WKT) representation of geometry notation is strict.
886+
# A POINT object is a string with longitude first, then the latitude, with
887+
# four decimals each, and exactly one space between them.
888+
longitude = ('%9.4f' % longitude).strip()
889+
latitude = ('%8.4f' % latitude).strip()
890+
# TODO: make format_WKT(object_type, *args) in tools.py
891+
892+
# convert pvlib names in parameters to PSM4 convention
893+
parameters = [REQUEST_VARIABLE_MAP.get(a, a) for a in parameters]
894+
895+
# required query-string parameters for request to PSM4 API
896+
params = {
897+
'api_key': api_key,
898+
'full_name': full_name,
899+
'email': email,
900+
'affiliation': affiliation,
901+
'reason': PVLIB_PYTHON,
902+
'mailing_list': 'false',
903+
'wkt': 'POINT(%s %s)' % (longitude, latitude),
904+
'names': year,
905+
'attributes': ','.join(parameters),
906+
'leap_day': str(leap_day).lower(),
907+
'utc': str(utc).lower(),
908+
'interval': time_step
909+
}
910+
# request CSV download from NLR PSM4
911+
if url is None:
912+
url = PSM4_POLAR_TMY_URL
913+
914+
response = requests.get(url, params=params, timeout=timeout)
915+
if not response.ok:
916+
# if the API key is rejected, then the response status will be 403
917+
# Forbidden, and then the error is in the content and there is no JSON
918+
try:
919+
errors = response.json()['errors']
920+
except JSONDecodeError:
921+
errors = response.content.decode('utf-8')
922+
raise requests.HTTPError(errors, response=response)
923+
# the CSV is in the response content as a UTF-8 bytestring
924+
# to use pandas we need to create a file buffer from the response
925+
fbuf = io.StringIO(response.content.decode('utf-8'))
926+
return read_nsrdb_psm4(fbuf, map_variables)
927+
928+
779929
def read_nsrdb_psm4(filename, map_variables=True):
780930
"""
781931
Read an NSRDB PSM4 weather file (formatted as SAM CSV).
@@ -867,6 +1017,8 @@ def read_nsrdb_psm4(filename, map_variables=True):
8671017
pvlib.iotools.get_nsrdb_psm4_tmy
8681018
pvlib.iotools.get_nsrdb_psm4_conus
8691019
pvlib.iotools.get_nsrdb_psm4_full_disc
1020+
pvlib.iotools.get_nsrdb_psm4_polar
1021+
pvlib.iotools.get_nsrdb_psm4_polar_tmy
8701022
8711023
References
8721024
----------

0 commit comments

Comments
 (0)