1
-
2
1
"""
3
2
Get PSM3 TMY
4
3
see https://developer.nrel.gov/docs/solar/nsrdb/psm3_data_download/
8
7
import requests
9
8
import pandas as pd
10
9
from json import JSONDecodeError
10
+ import warnings
11
+ from pvlib ._deprecation import pvlibDeprecationWarning
11
12
12
13
NSRDB_API_BASE = "https://developer.nrel.gov"
13
14
PSM_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-download.csv"
20
21
'surface_pressure' , 'wind_direction' , 'wind_speed' )
21
22
PVLIB_PYTHON = 'pvlib python'
22
23
24
+ # Dictionary mapping PSM3 names to pvlib names
25
+ VARIABLE_MAP = {
26
+ 'GHI' : 'ghi' ,
27
+ 'DHI' : 'dhi' ,
28
+ 'DNI' : 'dni' ,
29
+ 'Clearsky GHI' : 'ghi_clear' ,
30
+ 'Clearsky DHI' : 'dhi_clear' ,
31
+ 'Clearsky DNI' : 'dni_clear' ,
32
+ 'Solar Zenith Angle' : 'solar_zenith' ,
33
+ 'Temperature' : 'temp_air' ,
34
+ 'Relative Humidity' : 'relative_humidity' ,
35
+ 'Dew point' : 'temp_dew' ,
36
+ 'Pressure' : 'pressure' ,
37
+ 'Wind Direction' : 'wind_direction' ,
38
+ 'Wind Speed' : 'wind_speed' ,
39
+ 'Surface Albedo' : 'albedo' ,
40
+ 'Precipitable Water' : 'precipitable_water' ,
41
+ }
42
+
23
43
24
44
def get_psm3 (latitude , longitude , api_key , email , names = 'tmy' , interval = 60 ,
25
45
attributes = ATTRIBUTES , leap_day = False , full_name = PVLIB_PYTHON ,
26
- affiliation = PVLIB_PYTHON , timeout = 30 ):
46
+ affiliation = PVLIB_PYTHON , map_variables = None , timeout = 30 ):
27
47
"""
28
- Retrieve NSRDB PSM3 timeseries weather data from the PSM3 API. The NSRDB
48
+ Retrieve NSRDB PSM3 timeseries weather data from the PSM3 API. The NSRDB
29
49
is described in [1]_ and the PSM3 API is described in [2]_, [3]_, and [4]_.
30
50
31
51
.. versionchanged:: 0.9.0
@@ -48,19 +68,23 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
48
68
PSM3 API parameter specifing year or TMY variant to download, see notes
49
69
below for options
50
70
interval : int, {60, 5, 15, 30}
51
- interval size in minutes, must be 5, 15, 30 or 60. Only used for
71
+ interval size in minutes, must be 5, 15, 30 or 60. Only used for
52
72
single-year requests (i.e., it is ignored for tmy/tgy/tdy requests).
53
73
attributes : list of str, optional
54
74
meteorological fields to fetch. If not specified, defaults to
55
75
``pvlib.iotools.psm3.ATTRIBUTES``. See references [2]_, [3]_, and [4]_
56
- for lists of available fields.
76
+ for lists of available fields. Alternatively, pvlib names may also be
77
+ used (e.g. 'ghi' rather than 'GHI'); see :const:`VARIABLE_MAP`.
57
78
leap_day : boolean, default False
58
- include leap day in the results. Only used for single-year requests
79
+ include leap day in the results. Only used for single-year requests
59
80
(i.e., it is ignored for tmy/tgy/tdy requests).
60
81
full_name : str, default 'pvlib python'
61
82
optional
62
83
affiliation : str, default 'pvlib python'
63
84
optional
85
+ map_variables: boolean, optional
86
+ When true, renames columns of the Dataframe to pvlib variable names
87
+ where applicable. See variable :const:`VARIABLE_MAP`.
64
88
timeout : int, default 30
65
89
time in seconds to wait for server response before timeout
66
90
@@ -96,14 +120,15 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
96
120
+===========+=============================================================+
97
121
| Year | 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
98
122
| | 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, |
99
- | | 2018, 2019 |
123
+ | | 2018, 2019, 2020 |
100
124
+-----------+-------------------------------------------------------------+
101
125
| TMY | tmy, tmy-2016, tmy-2017, tdy-2017, tgy-2017, |
102
126
| | tmy-2018, tdy-2018, tgy-2018, tmy-2019, tdy-2019, tgy-2019 |
127
+ | | tmy-2020, tdy-2020, tgy-2020 |
103
128
+-----------+-------------------------------------------------------------+
104
129
105
130
.. warning:: PSM3 is limited to data found in the NSRDB, please consult the
106
- references below for locations with available data. Additionally,
131
+ references below for locations with available data. Additionally,
107
132
querying data with < 30-minute resolution uses a different API endpoint
108
133
with fewer available fields (see [4]_).
109
134
@@ -133,6 +158,13 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
133
158
# convert to string to accomodate integer years being passed in
134
159
names = str (names )
135
160
161
+ # convert pvlib names in attributes to psm3 convention (reverse mapping)
162
+ # unlike psm3 columns, attributes are lower case and with underscores
163
+ amap = {value : key .lower ().replace (' ' , '_' ) for (key , value ) in
164
+ VARIABLE_MAP .items ()}
165
+ attributes = [amap .get (a , a ) for a in attributes ]
166
+ attributes = list (set (attributes )) # remove duplicate values
167
+
136
168
# required query-string parameters for request to PSM3 API
137
169
params = {
138
170
'api_key' : api_key ,
@@ -167,12 +199,12 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
167
199
# the CSV is in the response content as a UTF-8 bytestring
168
200
# to use pandas we need to create a file buffer from the response
169
201
fbuf = io .StringIO (response .content .decode ('utf-8' ))
170
- return parse_psm3 (fbuf )
202
+ return parse_psm3 (fbuf , map_variables )
171
203
172
204
173
- def parse_psm3 (fbuf ):
205
+ def parse_psm3 (fbuf , map_variables = None ):
174
206
"""
175
- Parse an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
207
+ Parse an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
176
208
is described in [1]_ and the SAM CSV format is described in [2]_.
177
209
178
210
.. versionchanged:: 0.9.0
@@ -184,6 +216,9 @@ def parse_psm3(fbuf):
184
216
----------
185
217
fbuf: file-like object
186
218
File-like object containing data to read.
219
+ map_variables: bool
220
+ When true, renames columns of the Dataframe to pvlib variable names
221
+ where applicable. See variable VARIABLE_MAP.
187
222
188
223
Returns
189
224
-------
@@ -296,12 +331,25 @@ def parse_psm3(fbuf):
296
331
tz = 'Etc/GMT%+d' % - metadata ['Time Zone' ]
297
332
data .index = pd .DatetimeIndex (dtidx ).tz_localize (tz )
298
333
334
+ if map_variables is None :
335
+ warnings .warn (
336
+ 'PSM3 variable names will be renamed to pvlib conventions by '
337
+ 'default starting in pvlib 0.11.0. Specify map_variables=True '
338
+ 'to enable that behavior now, or specify map_variables=False '
339
+ 'to hide this warning.' , pvlibDeprecationWarning )
340
+ map_variables = False
341
+ if map_variables :
342
+ data = data .rename (columns = VARIABLE_MAP )
343
+ metadata ['latitude' ] = metadata .pop ('Latitude' )
344
+ metadata ['longitude' ] = metadata .pop ('Longitude' )
345
+ metadata ['altitude' ] = metadata .pop ('Elevation' )
346
+
299
347
return data , metadata
300
348
301
349
302
- def read_psm3 (filename ):
350
+ def read_psm3 (filename , map_variables = None ):
303
351
"""
304
- Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
352
+ Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
305
353
is described in [1]_ and the SAM CSV format is described in [2]_.
306
354
307
355
.. versionchanged:: 0.9.0
@@ -313,6 +361,9 @@ def read_psm3(filename):
313
361
----------
314
362
filename: str
315
363
Filename of a file containing data to read.
364
+ map_variables: bool
365
+ When true, renames columns of the Dataframe to pvlib variable names
366
+ where applicable. See variable VARIABLE_MAP.
316
367
317
368
Returns
318
369
-------
@@ -334,5 +385,5 @@ def read_psm3(filename):
334
385
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
335
386
"""
336
387
with open (str (filename ), 'r' ) as fbuf :
337
- content = parse_psm3 (fbuf )
388
+ content = parse_psm3 (fbuf , map_variables )
338
389
return content
0 commit comments