11
11
import requests
12
12
import pandas as pd
13
13
from json import JSONDecodeError
14
+ from pvlib import tools
14
15
15
16
NSRDB_API_BASE = "https://developer.nrel.gov/api/nsrdb/v2/solar/"
16
17
PSM4_AGG_ENDPOINT = "nsrdb-GOES-aggregated-v4-0-0-download.csv"
@@ -82,7 +83,7 @@ def get_nsrdb_psm4_aggregated(latitude, longitude, api_key, email,
82
83
Aggregated v4 API.
83
84
84
85
The NSRDB is described in [1]_ and the PSM4 NSRDB GOES Aggregated v4 API is
85
- described in [2]_, .
86
+ described in [2]_.
86
87
87
88
Parameters
88
89
----------
@@ -132,7 +133,7 @@ def get_nsrdb_psm4_aggregated(latitude, longitude, api_key, email,
132
133
timeseries data from NREL PSM4
133
134
metadata : dict
134
135
metadata from NREL PSM4 about the record, see
135
- :func:`pvlib.iotools.parse_nsrdb_psm4 ` for fields
136
+ :func:`pvlib.iotools.read_nsrdb_psm4 ` for fields
136
137
137
138
Raises
138
139
------
@@ -151,19 +152,15 @@ def get_nsrdb_psm4_aggregated(latitude, longitude, api_key, email,
151
152
result in rejected requests.
152
153
153
154
.. warning:: PSM4 is limited to data found in the NSRDB, please consult
154
- the references below for locations with available data. Additionally,
155
- querying data with < 30-minute resolution uses a different API endpoint
156
- with fewer available fields (see [4]_).
155
+ the references below for locations with available data.
157
156
158
157
See Also
159
158
--------
160
159
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus,
161
- pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.read_nsrdb_psm4,
162
- pvlib.iotools.parse_nsrdb_psm4
160
+ pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.read_nsrdb_psm4
163
161
164
162
References
165
163
----------
166
-
167
164
.. [1] `NREL National Solar Radiation Database (NSRDB)
168
165
<https://nsrdb.nrel.gov/>`_
169
166
.. [2] `NSRDB GOES Aggregated V4.0.0
@@ -213,7 +210,7 @@ def get_nsrdb_psm4_aggregated(latitude, longitude, api_key, email,
213
210
# the CSV is in the response content as a UTF-8 bytestring
214
211
# to use pandas we need to create a file buffer from the response
215
212
fbuf = io .StringIO (response .content .decode ('utf-8' ))
216
- return parse_nsrdb_psm4 (fbuf , map_variables )
213
+ return read_nsrdb_psm4 (fbuf , map_variables )
217
214
218
215
219
216
def get_nsrdb_psm4_tmy (latitude , longitude , api_key , email , year = 'tmy' ,
@@ -225,7 +222,7 @@ def get_nsrdb_psm4_tmy(latitude, longitude, api_key, email, year='tmy',
225
222
TMY v4 API.
226
223
227
224
The NSRDB is described in [1]_ and the PSM4 NSRDB GOES TMY v4 API is
228
- described in [2]_, .
225
+ described in [2]_.
229
226
230
227
Parameters
231
228
----------
@@ -276,7 +273,7 @@ def get_nsrdb_psm4_tmy(latitude, longitude, api_key, email, year='tmy',
276
273
timeseries data from NREL PSM4
277
274
metadata : dict
278
275
metadata from NREL PSM4 about the record, see
279
- :func:`pvlib.iotools.parse_nsrdb_psm4 ` for fields
276
+ :func:`pvlib.iotools.read_nsrdb_psm4 ` for fields
280
277
281
278
Raises
282
279
------
@@ -295,19 +292,16 @@ def get_nsrdb_psm4_tmy(latitude, longitude, api_key, email, year='tmy',
295
292
result in rejected requests.
296
293
297
294
.. warning:: PSM4 is limited to data found in the NSRDB, please consult
298
- the references below for locations with available data. Additionally,
299
- querying data with < 30-minute resolution uses a different API endpoint
300
- with fewer available fields (see [4]_).
295
+ the references below for locations with available data.
301
296
302
297
See Also
303
298
--------
304
299
pvlib.iotools.get_nsrdb_psm4_aggregated,
305
300
pvlib.iotools.get_nsrdb_psm4_conus, pvlib.iotools.get_nsrdb_psm4_full_disc,
306
- pvlib.iotools.read_nsrdb_psm4,pvlib.iotools.parse_nsrdb_psm4
301
+ pvlib.iotools.read_nsrdb_psm4
307
302
308
303
References
309
304
----------
310
-
311
305
.. [1] `NREL National Solar Radiation Database (NSRDB)
312
306
<https://nsrdb.nrel.gov/>`_
313
307
.. [2] `NSRDB GOES Tmy V4.0.0
@@ -357,7 +351,7 @@ def get_nsrdb_psm4_tmy(latitude, longitude, api_key, email, year='tmy',
357
351
# the CSV is in the response content as a UTF-8 bytestring
358
352
# to use pandas we need to create a file buffer from the response
359
353
fbuf = io .StringIO (response .content .decode ('utf-8' ))
360
- return parse_nsrdb_psm4 (fbuf , map_variables )
354
+ return read_nsrdb_psm4 (fbuf , map_variables )
361
355
362
356
363
357
def get_nsrdb_psm4_conus (latitude , longitude , api_key , email , year = '2023' ,
@@ -369,7 +363,7 @@ def get_nsrdb_psm4_conus(latitude, longitude, api_key, email, year='2023',
369
363
v4 API.
370
364
371
365
The NSRDB is described in [1]_ and the PSM4 NSRDB GOES CONUS v4 API is
372
- described in [2]_, .
366
+ described in [2]_.
373
367
374
368
Parameters
375
369
----------
@@ -418,7 +412,7 @@ def get_nsrdb_psm4_conus(latitude, longitude, api_key, email, year='2023',
418
412
timeseries data from NREL PSM4
419
413
metadata : dict
420
414
metadata from NREL PSM4 about the record, see
421
- :func:`pvlib.iotools.parse_nsrdb_psm4 ` for fields
415
+ :func:`pvlib.iotools.read_nsrdb_psm4 ` for fields
422
416
423
417
Raises
424
418
------
@@ -437,19 +431,16 @@ def get_nsrdb_psm4_conus(latitude, longitude, api_key, email, year='2023',
437
431
result in rejected requests.
438
432
439
433
.. warning:: PSM4 is limited to data found in the NSRDB, please consult
440
- the references below for locations with available data. Additionally,
441
- querying data with < 30-minute resolution uses a different API endpoint
442
- with fewer available fields (see [4]_).
434
+ the references below for locations with available data.
443
435
444
436
See Also
445
437
--------
446
438
pvlib.iotools.get_nsrdb_psm4_aggregated,
447
439
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_full_disc,
448
- pvlib.iotools.read_nsrdb_psm4, pvlib.iotools.parse_nsrdb_psm4
440
+ pvlib.iotools.read_nsrdb_psm4
449
441
450
442
References
451
443
----------
452
-
453
444
.. [1] `NREL National Solar Radiation Database (NSRDB)
454
445
<https://nsrdb.nrel.gov/>`_
455
446
.. [2] `NSRDB GOES Conus V4.0.0
@@ -499,7 +490,7 @@ def get_nsrdb_psm4_conus(latitude, longitude, api_key, email, year='2023',
499
490
# the CSV is in the response content as a UTF-8 bytestring
500
491
# to use pandas we need to create a file buffer from the response
501
492
fbuf = io .StringIO (response .content .decode ('utf-8' ))
502
- return parse_nsrdb_psm4 (fbuf , map_variables )
493
+ return read_nsrdb_psm4 (fbuf , map_variables )
503
494
504
495
505
496
def get_nsrdb_psm4_full_disc (latitude , longitude , api_key , email ,
@@ -513,7 +504,7 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email,
513
504
Disc v4 API.
514
505
515
506
The NSRDB is described in [1]_ and the PSM4 NSRDB GOES Full Disc v4 API is
516
- described in [2]_, .
507
+ described in [2]_.
517
508
518
509
Parameters
519
510
----------
@@ -563,7 +554,7 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email,
563
554
timeseries data from NREL PSM4
564
555
metadata : dict
565
556
metadata from NREL PSM4 about the record, see
566
- :func:`pvlib.iotools.parse_nsrdb_psm4 ` for fields
557
+ :func:`pvlib.iotools.read_nsrdb_psm4 ` for fields
567
558
568
559
Raises
569
560
------
@@ -582,19 +573,16 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email,
582
573
result in rejected requests.
583
574
584
575
.. warning:: PSM4 is limited to data found in the NSRDB, please consult
585
- the references below for locations with available data. Additionally,
586
- querying data with < 30-minute resolution uses a different API endpoint
587
- with fewer available fields (see [4]_).
576
+ the references below for locations with available data.
588
577
589
578
See Also
590
579
--------
591
580
pvlib.iotools.get_nsrdb_psm4_aggregated,
592
581
pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus,
593
- pvlib.iotools.read_nsrdb_psm4, pvlib.iotools.parse_nsrdb_psm4
582
+ pvlib.iotools.read_nsrdb_psm4
594
583
595
584
References
596
585
----------
597
-
598
586
.. [1] `NREL National Solar Radiation Database (NSRDB)
599
587
<https://nsrdb.nrel.gov/>`_
600
588
.. [2] `NSRDB GOES Full Disc V4.0.0
@@ -644,19 +632,19 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email,
644
632
# the CSV is in the response content as a UTF-8 bytestring
645
633
# to use pandas we need to create a file buffer from the response
646
634
fbuf = io .StringIO (response .content .decode ('utf-8' ))
647
- return parse_nsrdb_psm4 (fbuf , map_variables )
635
+ return read_nsrdb_psm4 (fbuf , map_variables )
648
636
649
637
650
- def parse_nsrdb_psm4 ( fbuf , map_variables = True ):
638
+ def read_nsrdb_psm4 ( filename , map_variables = True ):
651
639
"""
652
- Parse an NSRDB PSM4 weather file (formatted as SAM CSV).
640
+ Read an NSRDB PSM4 weather file (formatted as SAM CSV).
653
641
654
642
The NSRDB is described in [1]_ and the SAM CSV format is described in [2]_.
655
643
656
644
Parameters
657
645
----------
658
- fbuf: file -like object
659
- File-like object containing data to read.
646
+ filename: str, path -like, or buffer
647
+ Filename or in-memory buffer of a file containing data to read.
660
648
map_variables: bool, default True
661
649
When true, renames columns of the Dataframe to pvlib variable names
662
650
where applicable. See variable :const:`VARIABLE_MAP`.
@@ -726,12 +714,19 @@ def parse_nsrdb_psm4(fbuf, map_variables=True):
726
714
Examples
727
715
--------
728
716
>>> # Read a local PSM4 file:
717
+ >>> df, metadata = iotools.read_nsrdb_psm4("data.csv") # doctest: +SKIP
718
+
719
+ >>> # Read a file object or an in-memory buffer:
729
720
>>> with open(filename, 'r') as f: # doctest: +SKIP
730
- ... df, metadata = iotools.parse_nsrdb_psm4 (f) # doctest: +SKIP
721
+ ... df, metadata = iotools.read_nsrdb_psm4 (f) # doctest: +SKIP
731
722
732
723
See Also
733
724
--------
734
- pvlib.iotools.read_nsrdb_psm4, pvlib.iotools.get_psm4
725
+ pvlib.iotools.get_nsrdb_psm4_aggregated
726
+ pvlib.iotools.get_nsrdb_psm4_tmy
727
+ pvlib.iotools.get_nsrdb_psm4_conus
728
+ pvlib.iotools.get_nsrdb_psm4_full_disc
729
+ pvlib.iotools.read_psm3
735
730
736
731
References
737
732
----------
@@ -740,34 +735,36 @@ def parse_nsrdb_psm4(fbuf, map_variables=True):
740
735
.. [2] `Standard Time Series Data File Format
741
736
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
742
737
"""
743
- # The first 2 lines of the response are headers with metadata
744
- metadata_fields = fbuf .readline ().split (',' )
745
- metadata_fields [- 1 ] = metadata_fields [- 1 ].strip () # strip trailing newline
746
- metadata_values = fbuf .readline ().split (',' )
747
- metadata_values [- 1 ] = metadata_values [- 1 ].strip () # strip trailing newline
738
+ with tools ._file_context_manager (filename ) as fbuf :
739
+ # The first 2 lines of the response are headers with metadata
740
+ metadata_fields = fbuf .readline ().split (',' )
741
+ metadata_values = fbuf .readline ().split (',' )
742
+ # get the column names so we can set the dtypes
743
+ columns = fbuf .readline ().split (',' )
744
+ columns [- 1 ] = columns [- 1 ].strip () # strip trailing newline
745
+ # Since the header has so many columns, excel saves blank cols in the
746
+ # data below the header lines.
747
+ columns = [col for col in columns if col != '' ]
748
+ dtypes = dict .fromkeys (columns , float )
749
+ dtypes .update ({'Year' : int , 'Month' : int , 'Day' : int , 'Hour' : int ,
750
+ 'Minute' : int , 'Cloud Type' : int , 'Fill Flag' : int })
751
+
752
+ data = pd .read_csv (
753
+ fbuf , header = None , names = columns , usecols = columns , dtype = dtypes ,
754
+ delimiter = ',' , lineterminator = '\n ' ) # skip carriage returns \r
755
+
756
+ metadata_fields [- 1 ] = metadata_fields [- 1 ].strip () # trailing newline
757
+ metadata_values [- 1 ] = metadata_values [- 1 ].strip () # trailing newline
748
758
metadata = dict (zip (metadata_fields , metadata_values ))
749
759
# the response is all strings, so set some metadata types to numbers
750
760
metadata ['Local Time Zone' ] = int (metadata ['Local Time Zone' ])
751
761
metadata ['Time Zone' ] = int (metadata ['Time Zone' ])
752
762
metadata ['Latitude' ] = float (metadata ['Latitude' ])
753
763
metadata ['Longitude' ] = float (metadata ['Longitude' ])
754
764
metadata ['Elevation' ] = int (metadata ['Elevation' ])
755
- # get the column names so we can set the dtypes
756
- columns = fbuf .readline ().split (',' )
757
- columns [- 1 ] = columns [- 1 ].strip () # strip trailing newline
758
- # Since the header has so many columns, excel saves blank cols in the
759
- # data below the header lines.
760
- columns = [col for col in columns if col != '' ]
761
- dtypes = dict .fromkeys (columns , float ) # all floats except datevec
762
- dtypes .update (Year = int , Month = int , Day = int , Hour = int , Minute = int )
763
- dtypes ['Cloud Type' ] = int
764
- dtypes ['Fill Flag' ] = int
765
- data = pd .read_csv (
766
- fbuf , header = None , names = columns , usecols = columns , dtype = dtypes ,
767
- delimiter = ',' , lineterminator = '\n ' ) # skip carriage returns \r
765
+
768
766
# the response 1st 5 columns are a date vector, convert to datetime
769
- dtidx = pd .to_datetime (
770
- data [['Year' , 'Month' , 'Day' , 'Hour' , 'Minute' ]])
767
+ dtidx = pd .to_datetime (data [['Year' , 'Month' , 'Day' , 'Hour' , 'Minute' ]])
771
768
# in USA all timezones are integers
772
769
tz = 'Etc/GMT%+d' % - metadata ['Time Zone' ]
773
770
data .index = pd .DatetimeIndex (dtidx ).tz_localize (tz )
@@ -779,41 +776,3 @@ def parse_nsrdb_psm4(fbuf, map_variables=True):
779
776
metadata ['altitude' ] = metadata .pop ('Elevation' )
780
777
781
778
return data , metadata
782
-
783
-
784
- def read_nsrdb_psm4 (filename , map_variables = True ):
785
- """
786
- Read an NSRDB PSM4 weather file (formatted as SAM CSV).
787
-
788
- The NSRDB is described in [1]_ and the SAM CSV format is described in [2]_.
789
-
790
- Parameters
791
- ----------
792
- filename: str or path-like
793
- Filename of a file containing data to read.
794
- map_variables: bool, default True
795
- When true, renames columns of the Dataframe to pvlib variable names
796
- where applicable. See variable :const:`VARIABLE_MAP`.
797
-
798
- Returns
799
- -------
800
- data : pandas.DataFrame
801
- timeseries data from NREL PSM4
802
- metadata : dict
803
- metadata from NREL PSM4 about the record, see
804
- :func:`pvlib.iotools.parse_nsrdb_psm4` for fields
805
-
806
- See Also
807
- --------
808
- pvlib.iotools.parse_nsrdb_psm4, pvlib.iotools.get_psm4
809
-
810
- References
811
- ----------
812
- .. [1] `NREL National Solar Radiation Database (NSRDB)
813
- <https://nsrdb.nrel.gov/>`_
814
- .. [2] `Standard Time Series Data File Format
815
- <https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
816
- """
817
- with open (str (filename ), 'r' ) as fbuf :
818
- content = parse_nsrdb_psm4 (fbuf , map_variables )
819
- return content
0 commit comments