pvlib 0.12.0__py3-none-any.whl → 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvlib/atmosphere.py +40 -31
- pvlib/bifacial/infinite_sheds.py +11 -16
- pvlib/iotools/__init__.py +5 -0
- pvlib/iotools/bsrn.py +16 -10
- pvlib/iotools/epw.py +14 -11
- pvlib/iotools/psm3.py +37 -71
- pvlib/iotools/psm4.py +766 -0
- pvlib/iotools/pvgis.py +116 -101
- pvlib/iotools/sodapro.py +54 -69
- pvlib/iotools/srml.py +1 -2
- pvlib/irradiance.py +28 -19
- pvlib/ivtools/sdm/__init__.py +20 -0
- pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
- pvlib/ivtools/sdm/cec.py +93 -0
- pvlib/ivtools/sdm/desoto.py +401 -0
- pvlib/ivtools/sdm/pvsyst.py +630 -0
- pvlib/modelchain.py +1 -1
- pvlib/pvsystem.py +130 -69
- pvlib/solarposition.py +1 -1
- pvlib/spectrum/irradiance.py +2 -1
- pvlib/temperature.py +13 -10
- pvlib/tools.py +27 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/METADATA +2 -3
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/RECORD +28 -23
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/WHEEL +1 -1
- pvlib/ivtools/sdm.py +0 -1379
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/licenses/AUTHORS.md +0 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/licenses/LICENSE +0 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/top_level.txt +0 -0
pvlib/atmosphere.py
CHANGED
|
@@ -147,20 +147,13 @@ def get_relative_airmass(zenith, model='kastenyoung1989'):
|
|
|
147
147
|
|
|
148
148
|
* 'simple' - secant(apparent zenith angle) -
|
|
149
149
|
Note that this gives -Inf at zenith=90
|
|
150
|
-
* 'kasten1966' - See
|
|
151
|
-
|
|
152
|
-
* '
|
|
153
|
-
|
|
154
|
-
* '
|
|
155
|
-
|
|
156
|
-
* '
|
|
157
|
-
requires apparent sun zenith
|
|
158
|
-
* 'young1994' - See reference [5] -
|
|
159
|
-
requires true sun zenith
|
|
160
|
-
* 'pickering2002' - See reference [6] -
|
|
161
|
-
requires apparent sun zenith
|
|
162
|
-
* 'gueymard2003' - See references [7] and [8] -
|
|
163
|
-
requires apparent sun zenith
|
|
150
|
+
* 'kasten1966' - See [1]_ - requires apparent sun zenith
|
|
151
|
+
* 'youngirvine1967' - See [2]_ - requires true sun zenith
|
|
152
|
+
* 'kastenyoung1989' (default) - See [3]_ - requires apparent sun zenith
|
|
153
|
+
* 'gueymard1993' - See [4]_, [5]_ - requires apparent sun zenith
|
|
154
|
+
* 'young1994' - See [6]_ - requires true sun zenith
|
|
155
|
+
* 'pickering2002' - See [7]_ - requires apparent sun zenith
|
|
156
|
+
* 'gueymard2003' - See [8]_, [9]_ - requires apparent sun zenith
|
|
164
157
|
|
|
165
158
|
Returns
|
|
166
159
|
-------
|
|
@@ -174,41 +167,57 @@ def get_relative_airmass(zenith, model='kastenyoung1989'):
|
|
|
174
167
|
other models use true (not refraction-adjusted) zenith angle. Apparent
|
|
175
168
|
zenith angles should be calculated at sea level.
|
|
176
169
|
|
|
170
|
+
Comparison among several models is reported in [10]_.
|
|
171
|
+
|
|
177
172
|
References
|
|
178
173
|
----------
|
|
179
|
-
.. [1] Fritz Kasten
|
|
180
|
-
Relative Optical Air Mass"
|
|
181
|
-
|
|
174
|
+
.. [1] Fritz Kasten, "A New Table and Approximation Formula for the
|
|
175
|
+
Relative Optical Air Mass," CRREL (U.S. Army), Hanover, NH, USA,
|
|
176
|
+
Technical Report 136, 1965.
|
|
177
|
+
:doi:`11681/5671`
|
|
182
178
|
|
|
183
179
|
.. [2] A. T. Young and W. M. Irvine, "Multicolor Photoelectric
|
|
184
|
-
Photometry of the Brighter Planets
|
|
185
|
-
72, pp. 945-950, 1967.
|
|
180
|
+
Photometry of the Brighter Planets. I. Program and Procedure,"
|
|
181
|
+
The Astronomical Journal, vol. 72, pp. 945-950, 1967.
|
|
182
|
+
:doi:`10.1086/110366`
|
|
186
183
|
|
|
187
|
-
.. [3] Fritz Kasten and Andrew Young
|
|
188
|
-
and approximation formula"
|
|
184
|
+
.. [3] Fritz Kasten and Andrew Young, "Revised optical air mass tables
|
|
185
|
+
and approximation formula," Applied Optics 28:4735-4738, 1989.
|
|
186
|
+
:doi:`10.1364/AO.28.004735`
|
|
189
187
|
|
|
190
188
|
.. [4] C. Gueymard, "Critical analysis and performance assessment of
|
|
191
189
|
clear sky solar irradiance models using theoretical and measured
|
|
192
190
|
data," Solar Energy, vol. 51, pp. 121-138, 1993.
|
|
191
|
+
:doi:`10.1016/0038-092X(93)90074-X`
|
|
192
|
+
|
|
193
|
+
.. [5] C. Gueymard, "Development and performance assessment of a clear
|
|
194
|
+
sky spectral radiation model,” in Proc. of the 22nd ASES Conference,
|
|
195
|
+
Solar ’93, 1993, pp. 433–438.
|
|
193
196
|
|
|
194
|
-
.. [
|
|
195
|
-
pp. 1108-1110, Feb 1994.
|
|
197
|
+
.. [6] A. T. Young, "Air-Mass and Refraction," Applied Optics, vol. 33,
|
|
198
|
+
pp. 1108-1110, Feb. 1994.
|
|
199
|
+
:doi:`10.1364/AO.33.001108`
|
|
196
200
|
|
|
197
|
-
.. [
|
|
201
|
+
.. [7] Keith A. Pickering, "The Southern Limits of the Ancient Star Catalog
|
|
202
|
+
and the Commentary of Hipparchos," DIO, vol. 12, pp. 3-27, Sept. 2002.
|
|
203
|
+
Available at `DIO <http://dioi.org/jc01.pdf>`_
|
|
198
204
|
|
|
199
|
-
.. [
|
|
205
|
+
.. [8] C. Gueymard, "Direct solar transmittance and irradiance
|
|
200
206
|
predictions with broadband models. Part I: detailed theoretical
|
|
201
207
|
performance assessment". Solar Energy, vol 74, pp. 355-379, 2003.
|
|
202
208
|
:doi:`10.1016/S0038-092X(03)00195-6`
|
|
203
209
|
|
|
204
|
-
.. [
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
.. [9] C. Gueymard, "Clear-Sky Radiation Models and Aerosol Effects", in
|
|
211
|
+
Solar Resources Mapping: Fundamentals and Applications,
|
|
212
|
+
Polo, J., Martín-Pomares, L., Sanfilippo, A. (Eds), Cham, CH: Springer,
|
|
213
|
+
2019, pp. 137-182.
|
|
207
214
|
:doi:`10.1007/978-3-319-97484-2_5`
|
|
208
215
|
|
|
209
|
-
.. [
|
|
216
|
+
.. [10] Matthew J. Reno, Clifford W. Hansen and Joshua S. Stein, "Global
|
|
210
217
|
Horizontal Irradiance Clear Sky Models: Implementation and Analysis"
|
|
211
|
-
Sandia
|
|
218
|
+
Sandia National Laboratories, Albuquerque, NM, USA, SAND2012-2389, 2012.
|
|
219
|
+
:doi:`10.2172/1039404`
|
|
220
|
+
|
|
212
221
|
'''
|
|
213
222
|
|
|
214
223
|
# set zenith values greater than 90 to nans
|
|
@@ -236,7 +245,7 @@ def get_relative_airmass(zenith, model='kastenyoung1989'):
|
|
|
236
245
|
(np.cos(zenith_rad) ** 3 +
|
|
237
246
|
0.149864*(np.cos(zenith_rad) ** 2) +
|
|
238
247
|
0.0102963*(np.cos(zenith_rad)) + 0.000303978))
|
|
239
|
-
elif 'gueymard1993' == model:
|
|
248
|
+
elif 'gueymard1993' == model: # [4], Eq. 22 and [5], Eq. 3b
|
|
240
249
|
am = (1.0 / (np.cos(zenith_rad) +
|
|
241
250
|
0.00176759*(z)*((94.37515 - z) ** - 1.21563)))
|
|
242
251
|
elif 'gueymard2003' == model:
|
pvlib/bifacial/infinite_sheds.py
CHANGED
|
@@ -9,21 +9,23 @@ from pvlib.bifacial import utils
|
|
|
9
9
|
from pvlib.irradiance import beam_component, aoi, haydavies
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def _poa_ground_shadows(
|
|
12
|
+
def _poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam, vf_gnd_sky):
|
|
13
13
|
"""
|
|
14
14
|
Reduce ground-reflected irradiance to the tilted plane (poa_ground) to
|
|
15
15
|
account for shadows on the ground.
|
|
16
16
|
|
|
17
17
|
Parameters
|
|
18
18
|
----------
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
ghi : numeric
|
|
20
|
+
Global horizontal irradiance, with no adjustments. [W/m^2]
|
|
21
|
+
dhi : numeric
|
|
22
|
+
Diffuse horizontal irradiance, with no adjustments. [W/m^2]
|
|
23
|
+
albedo : numeric
|
|
24
|
+
Ground albedo, the ratio of reflected to incident irradiance of the
|
|
25
|
+
ground surface. [W/m^2]
|
|
22
26
|
f_gnd_beam : numeric
|
|
23
27
|
Fraction of the distance between rows that is illuminated (unshaded).
|
|
24
28
|
[unitless]
|
|
25
|
-
df : numeric
|
|
26
|
-
Diffuse fraction, the ratio of DHI to GHI. [unitless]
|
|
27
29
|
vf_gnd_sky : numeric
|
|
28
30
|
View factor from the ground to the sky, integrated along the distance
|
|
29
31
|
between rows. [unitless]
|
|
@@ -35,7 +37,7 @@ def _poa_ground_shadows(poa_ground, f_gnd_beam, df, vf_gnd_sky):
|
|
|
35
37
|
ground. [W/m^2]
|
|
36
38
|
|
|
37
39
|
"""
|
|
38
|
-
return
|
|
40
|
+
return albedo * (f_gnd_beam * (ghi - dhi) + vf_gnd_sky * dhi)
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
def _poa_sky_diffuse_pv(dhi, gcr, surface_tilt):
|
|
@@ -339,18 +341,11 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
|
|
|
339
341
|
# and restricted views
|
|
340
342
|
# this is a deviation from [1], because the row to ground view factor
|
|
341
343
|
# is accounted for in a different manner
|
|
342
|
-
ground_diffuse = ghi * albedo
|
|
343
|
-
|
|
344
|
-
# diffuse fraction
|
|
345
|
-
diffuse_fraction = np.clip(dhi / ghi, 0., 1.)
|
|
346
|
-
# make diffuse fraction 0 when ghi is small
|
|
347
|
-
diffuse_fraction = np.where(ghi < 0.0001, 0., diffuse_fraction)
|
|
348
|
-
|
|
349
344
|
# Reduce ground-reflected irradiance because other rows in the array
|
|
350
345
|
# block irradiance from reaching the ground.
|
|
351
346
|
# [2], Eq. 9
|
|
352
|
-
ground_diffuse = _poa_ground_shadows(
|
|
353
|
-
|
|
347
|
+
ground_diffuse = _poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam,
|
|
348
|
+
vf_gnd_sky)
|
|
354
349
|
|
|
355
350
|
# Ground-reflected irradiance on the row surface accounting for
|
|
356
351
|
# the view to the ground. This deviates from [1], Eq. 10, 11 and
|
pvlib/iotools/__init__.py
CHANGED
|
@@ -11,6 +11,11 @@ from pvlib.iotools.solrad import get_solrad # noqa: F401
|
|
|
11
11
|
from pvlib.iotools.psm3 import get_psm3 # noqa: F401
|
|
12
12
|
from pvlib.iotools.psm3 import read_psm3 # noqa: F401
|
|
13
13
|
from pvlib.iotools.psm3 import parse_psm3 # noqa: F401
|
|
14
|
+
from pvlib.iotools.psm4 import get_nsrdb_psm4_aggregated # noqa: F401
|
|
15
|
+
from pvlib.iotools.psm4 import get_nsrdb_psm4_tmy # noqa: F401
|
|
16
|
+
from pvlib.iotools.psm4 import get_nsrdb_psm4_conus # noqa: F401
|
|
17
|
+
from pvlib.iotools.psm4 import get_nsrdb_psm4_full_disc # noqa: F401
|
|
18
|
+
from pvlib.iotools.psm4 import read_nsrdb_psm4 # noqa: F401
|
|
14
19
|
from pvlib.iotools.pvgis import get_pvgis_tmy, read_pvgis_tmy # noqa: F401
|
|
15
20
|
from pvlib.iotools.pvgis import read_pvgis_hourly # noqa: F401
|
|
16
21
|
from pvlib.iotools.pvgis import get_pvgis_hourly # noqa: F401
|
pvlib/iotools/bsrn.py
CHANGED
|
@@ -9,6 +9,9 @@ import warnings
|
|
|
9
9
|
import io
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
|
+
from pvlib.tools import _file_context_manager
|
|
13
|
+
from pvlib._deprecation import deprecated
|
|
14
|
+
|
|
12
15
|
BSRN_FTP_URL = "ftp.bsrn.awi.de"
|
|
13
16
|
|
|
14
17
|
BSRN_LR0100_COL_SPECS = [(0, 3), (4, 9), (10, 16), (16, 22), (22, 27),
|
|
@@ -109,7 +112,7 @@ def get_bsrn(station, start, end, username, password,
|
|
|
109
112
|
UserWarning
|
|
110
113
|
If one or more requested files are missing a UserWarning is returned
|
|
111
114
|
with a list of the filenames missing. If no files match the specified
|
|
112
|
-
station and timeframe a
|
|
115
|
+
station and timeframe a separate UserWarning is given.
|
|
113
116
|
|
|
114
117
|
Notes
|
|
115
118
|
-----
|
|
@@ -136,7 +139,7 @@ def get_bsrn(station, start, end, username, password,
|
|
|
136
139
|
|
|
137
140
|
See Also
|
|
138
141
|
--------
|
|
139
|
-
pvlib.iotools.read_bsrn
|
|
142
|
+
pvlib.iotools.read_bsrn
|
|
140
143
|
|
|
141
144
|
References
|
|
142
145
|
----------
|
|
@@ -159,8 +162,7 @@ def get_bsrn(station, start, end, username, password,
|
|
|
159
162
|
end = pd.to_datetime(end)
|
|
160
163
|
|
|
161
164
|
# Generate list files to download based on start/end (SSSMMYY.dat.gz)
|
|
162
|
-
filenames = pd.date_range(
|
|
163
|
-
start, end.replace(day=1) + pd.DateOffset(months=1), freq='1M')\
|
|
165
|
+
filenames = pd.date_range(start.date().replace(day=1), end, freq='1MS')\
|
|
164
166
|
.strftime(f"{station}%m%y.dat.gz").tolist()
|
|
165
167
|
|
|
166
168
|
# Create FTP connection
|
|
@@ -191,7 +193,7 @@ def get_bsrn(station, start, end, username, password,
|
|
|
191
193
|
bio.seek(0) # reset buffer to start of file
|
|
192
194
|
gzip_file = io.TextIOWrapper(gzip.GzipFile(fileobj=bio),
|
|
193
195
|
encoding='latin1')
|
|
194
|
-
dfi, metadata =
|
|
196
|
+
dfi, metadata = _parse_bsrn(gzip_file, logical_records)
|
|
195
197
|
dfs.append(dfi)
|
|
196
198
|
# FTP client raises an error if the file does not exist on server
|
|
197
199
|
except ftplib.error_perm as e:
|
|
@@ -217,7 +219,7 @@ def get_bsrn(station, start, end, username, password,
|
|
|
217
219
|
return data, metadata
|
|
218
220
|
|
|
219
221
|
|
|
220
|
-
def
|
|
222
|
+
def _parse_bsrn(fbuf, logical_records=('0100',)):
|
|
221
223
|
"""
|
|
222
224
|
Parse a file-like buffer of a BSRN station-to-archive file.
|
|
223
225
|
|
|
@@ -382,7 +384,7 @@ def read_bsrn(filename, logical_records=('0100',)):
|
|
|
382
384
|
Parameters
|
|
383
385
|
----------
|
|
384
386
|
filename: str or path-like
|
|
385
|
-
Name or
|
|
387
|
+
Name, path, or in-memory buffer of a BSRN station-to-archive data file
|
|
386
388
|
logical_records: list or tuple, default: ('0100',)
|
|
387
389
|
List of the logical records (LR) to parse. Options include: '0100',
|
|
388
390
|
'0300', and '0500'.
|
|
@@ -439,7 +441,7 @@ def read_bsrn(filename, logical_records=('0100',)):
|
|
|
439
441
|
|
|
440
442
|
See Also
|
|
441
443
|
--------
|
|
442
|
-
pvlib.iotools.
|
|
444
|
+
pvlib.iotools.get_bsrn
|
|
443
445
|
|
|
444
446
|
References
|
|
445
447
|
----------
|
|
@@ -457,7 +459,11 @@ def read_bsrn(filename, logical_records=('0100',)):
|
|
|
457
459
|
if str(filename).endswith('.gz'): # check if file is a gzipped (.gz) file
|
|
458
460
|
open_func, mode = gzip.open, 'rt'
|
|
459
461
|
else:
|
|
460
|
-
open_func, mode =
|
|
462
|
+
open_func, mode = _file_context_manager, 'r'
|
|
461
463
|
with open_func(filename, mode) as f:
|
|
462
|
-
content =
|
|
464
|
+
content = _parse_bsrn(f, logical_records)
|
|
463
465
|
return content
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
parse_bsrn = deprecated(since="0.13.0", name="parse_bsrn",
|
|
469
|
+
alternative="read_bsrn")(read_bsrn)
|
pvlib/iotools/epw.py
CHANGED
|
@@ -6,6 +6,9 @@ import io
|
|
|
6
6
|
from urllib.request import urlopen, Request
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
+
from pvlib.tools import _file_context_manager
|
|
10
|
+
from pvlib._deprecation import deprecated
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
def read_epw(filename, coerce_year=None):
|
|
11
14
|
r'''
|
|
@@ -23,7 +26,8 @@ def read_epw(filename, coerce_year=None):
|
|
|
23
26
|
Parameters
|
|
24
27
|
----------
|
|
25
28
|
filename : String
|
|
26
|
-
Can be a relative file path, absolute file path, or
|
|
29
|
+
Can be a relative file path, absolute file path, url, or in-memory
|
|
30
|
+
file buffer.
|
|
27
31
|
|
|
28
32
|
coerce_year : int, optional
|
|
29
33
|
If supplied, the year of the data will be set to this value. This can
|
|
@@ -43,10 +47,6 @@ def read_epw(filename, coerce_year=None):
|
|
|
43
47
|
metadata : dict
|
|
44
48
|
The site metadata available in the file.
|
|
45
49
|
|
|
46
|
-
See Also
|
|
47
|
-
--------
|
|
48
|
-
pvlib.iotools.parse_epw
|
|
49
|
-
|
|
50
50
|
Notes
|
|
51
51
|
-----
|
|
52
52
|
|
|
@@ -226,18 +226,17 @@ def read_epw(filename, coerce_year=None):
|
|
|
226
226
|
'Safari/537.36')})
|
|
227
227
|
response = urlopen(request)
|
|
228
228
|
with io.StringIO(response.read().decode(errors='ignore')) as csvdata:
|
|
229
|
-
data, meta =
|
|
229
|
+
data, meta = _parse_epw(csvdata, coerce_year)
|
|
230
230
|
|
|
231
231
|
else:
|
|
232
|
-
# Assume it's accessible via the file system
|
|
233
|
-
with
|
|
234
|
-
data, meta =
|
|
235
|
-
|
|
232
|
+
# Assume it's a buffer or accessible via the file system
|
|
233
|
+
with _file_context_manager(filename, 'r') as csvdata:
|
|
234
|
+
data, meta = _parse_epw(csvdata, coerce_year)
|
|
236
235
|
|
|
237
236
|
return data, meta
|
|
238
237
|
|
|
239
238
|
|
|
240
|
-
def
|
|
239
|
+
def _parse_epw(csvdata, coerce_year=None):
|
|
241
240
|
"""
|
|
242
241
|
Given a file-like buffer with data in Energy Plus Weather (EPW) format,
|
|
243
242
|
parse the data into a dataframe.
|
|
@@ -310,3 +309,7 @@ def parse_epw(csvdata, coerce_year=None):
|
|
|
310
309
|
data.index = idx
|
|
311
310
|
|
|
312
311
|
return data, meta
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
parse_epw = deprecated(since="0.13.0", name="parse_epw",
|
|
315
|
+
alternative="read_epw")(read_epw)
|
pvlib/iotools/psm3.py
CHANGED
|
@@ -7,8 +7,8 @@ import io
|
|
|
7
7
|
import requests
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from json import JSONDecodeError
|
|
10
|
-
import
|
|
11
|
-
from pvlib
|
|
10
|
+
from pvlib._deprecation import deprecated
|
|
11
|
+
from pvlib import tools
|
|
12
12
|
|
|
13
13
|
NSRDB_API_BASE = "https://developer.nrel.gov"
|
|
14
14
|
PSM_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-2-2-download.csv"
|
|
@@ -127,7 +127,7 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
127
127
|
timeseries data from NREL PSM3
|
|
128
128
|
metadata : dict
|
|
129
129
|
metadata from NREL PSM3 about the record, see
|
|
130
|
-
:func:`pvlib.iotools.
|
|
130
|
+
:func:`pvlib.iotools.read_psm3` for fields
|
|
131
131
|
|
|
132
132
|
Raises
|
|
133
133
|
------
|
|
@@ -152,7 +152,7 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
152
152
|
|
|
153
153
|
See Also
|
|
154
154
|
--------
|
|
155
|
-
pvlib.iotools.read_psm3
|
|
155
|
+
pvlib.iotools.read_psm3
|
|
156
156
|
|
|
157
157
|
References
|
|
158
158
|
----------
|
|
@@ -216,12 +216,12 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
216
216
|
# the CSV is in the response content as a UTF-8 bytestring
|
|
217
217
|
# to use pandas we need to create a file buffer from the response
|
|
218
218
|
fbuf = io.StringIO(response.content.decode('utf-8'))
|
|
219
|
-
return
|
|
219
|
+
return read_psm3(fbuf, map_variables)
|
|
220
220
|
|
|
221
221
|
|
|
222
|
-
def
|
|
222
|
+
def read_psm3(filename, map_variables=True):
|
|
223
223
|
"""
|
|
224
|
-
|
|
224
|
+
Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
|
|
225
225
|
is described in [1]_ and the SAM CSV format is described in [2]_.
|
|
226
226
|
|
|
227
227
|
.. versionchanged:: 0.9.0
|
|
@@ -231,8 +231,8 @@ def parse_psm3(fbuf, map_variables=True):
|
|
|
231
231
|
|
|
232
232
|
Parameters
|
|
233
233
|
----------
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
filename: str, path-like, or buffer
|
|
235
|
+
Filename or in-memory buffer of a file containing data to read.
|
|
236
236
|
map_variables: bool, default True
|
|
237
237
|
When true, renames columns of the Dataframe to pvlib variable names
|
|
238
238
|
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
@@ -302,12 +302,15 @@ def parse_psm3(fbuf, map_variables=True):
|
|
|
302
302
|
Examples
|
|
303
303
|
--------
|
|
304
304
|
>>> # Read a local PSM3 file:
|
|
305
|
+
>>> df, metadata = iotools.read_psm3("data.csv") # doctest: +SKIP
|
|
306
|
+
|
|
307
|
+
>>> # Read a file object or an in-memory buffer:
|
|
305
308
|
>>> with open(filename, 'r') as f: # doctest: +SKIP
|
|
306
|
-
... df, metadata = iotools.
|
|
309
|
+
... df, metadata = iotools.read_psm3(f) # doctest: +SKIP
|
|
307
310
|
|
|
308
311
|
See Also
|
|
309
312
|
--------
|
|
310
|
-
pvlib.iotools.
|
|
313
|
+
pvlib.iotools.get_psm3
|
|
311
314
|
|
|
312
315
|
References
|
|
313
316
|
----------
|
|
@@ -316,11 +319,25 @@ def parse_psm3(fbuf, map_variables=True):
|
|
|
316
319
|
.. [2] `Standard Time Series Data File Format
|
|
317
320
|
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
|
|
318
321
|
"""
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
with tools._file_context_manager(filename) as fbuf:
|
|
323
|
+
# The first 2 lines of the response are headers with metadata
|
|
324
|
+
metadata_fields = fbuf.readline().split(',')
|
|
325
|
+
metadata_values = fbuf.readline().split(',')
|
|
326
|
+
# get the column names so we can set the dtypes
|
|
327
|
+
columns = fbuf.readline().split(',')
|
|
328
|
+
columns[-1] = columns[-1].strip() # strip trailing newline
|
|
329
|
+
# Since the header has so many columns, excel saves blank cols in the
|
|
330
|
+
# data below the header lines.
|
|
331
|
+
columns = [col for col in columns if col != '']
|
|
332
|
+
dtypes = dict.fromkeys(columns, float) # all floats except datevec
|
|
333
|
+
dtypes.update({'Year': int, 'Month': int, 'Day': int, 'Hour': int,
|
|
334
|
+
'Minute': int, 'Cloud Type': int, 'Fill Flag': int})
|
|
335
|
+
data = pd.read_csv(
|
|
336
|
+
fbuf, header=None, names=columns, usecols=columns, dtype=dtypes,
|
|
337
|
+
delimiter=',', lineterminator='\n') # skip carriage returns \r
|
|
338
|
+
|
|
339
|
+
metadata_fields[-1] = metadata_fields[-1].strip() # trailing newline
|
|
340
|
+
metadata_values[-1] = metadata_values[-1].strip() # trailing newline
|
|
324
341
|
metadata = dict(zip(metadata_fields, metadata_values))
|
|
325
342
|
# the response is all strings, so set some metadata types to numbers
|
|
326
343
|
metadata['Local Time Zone'] = int(metadata['Local Time Zone'])
|
|
@@ -328,22 +345,9 @@ def parse_psm3(fbuf, map_variables=True):
|
|
|
328
345
|
metadata['Latitude'] = float(metadata['Latitude'])
|
|
329
346
|
metadata['Longitude'] = float(metadata['Longitude'])
|
|
330
347
|
metadata['Elevation'] = int(metadata['Elevation'])
|
|
331
|
-
|
|
332
|
-
columns = fbuf.readline().split(',')
|
|
333
|
-
columns[-1] = columns[-1].strip() # strip trailing newline
|
|
334
|
-
# Since the header has so many columns, excel saves blank cols in the
|
|
335
|
-
# data below the header lines.
|
|
336
|
-
columns = [col for col in columns if col != '']
|
|
337
|
-
dtypes = dict.fromkeys(columns, float) # all floats except datevec
|
|
338
|
-
dtypes.update(Year=int, Month=int, Day=int, Hour=int, Minute=int)
|
|
339
|
-
dtypes['Cloud Type'] = int
|
|
340
|
-
dtypes['Fill Flag'] = int
|
|
341
|
-
data = pd.read_csv(
|
|
342
|
-
fbuf, header=None, names=columns, usecols=columns, dtype=dtypes,
|
|
343
|
-
delimiter=',', lineterminator='\n') # skip carriage returns \r
|
|
348
|
+
|
|
344
349
|
# the response 1st 5 columns are a date vector, convert to datetime
|
|
345
|
-
dtidx = pd.to_datetime(
|
|
346
|
-
data[['Year', 'Month', 'Day', 'Hour', 'Minute']])
|
|
350
|
+
dtidx = pd.to_datetime(data[['Year', 'Month', 'Day', 'Hour', 'Minute']])
|
|
347
351
|
# in USA all timezones are integers
|
|
348
352
|
tz = 'Etc/GMT%+d' % -metadata['Time Zone']
|
|
349
353
|
data.index = pd.DatetimeIndex(dtidx).tz_localize(tz)
|
|
@@ -357,43 +361,5 @@ def parse_psm3(fbuf, map_variables=True):
|
|
|
357
361
|
return data, metadata
|
|
358
362
|
|
|
359
363
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
|
|
363
|
-
is described in [1]_ and the SAM CSV format is described in [2]_.
|
|
364
|
-
|
|
365
|
-
.. versionchanged:: 0.9.0
|
|
366
|
-
The function now returns a tuple where the first element is a dataframe
|
|
367
|
-
and the second element is a dictionary containing metadata. Previous
|
|
368
|
-
versions of this function had the return values switched.
|
|
369
|
-
|
|
370
|
-
Parameters
|
|
371
|
-
----------
|
|
372
|
-
filename: str
|
|
373
|
-
Filename of a file containing data to read.
|
|
374
|
-
map_variables: bool, default True
|
|
375
|
-
When true, renames columns of the Dataframe to pvlib variable names
|
|
376
|
-
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
377
|
-
|
|
378
|
-
Returns
|
|
379
|
-
-------
|
|
380
|
-
data : pandas.DataFrame
|
|
381
|
-
timeseries data from NREL PSM3
|
|
382
|
-
metadata : dict
|
|
383
|
-
metadata from NREL PSM3 about the record, see
|
|
384
|
-
:func:`pvlib.iotools.parse_psm3` for fields
|
|
385
|
-
|
|
386
|
-
See Also
|
|
387
|
-
--------
|
|
388
|
-
pvlib.iotools.parse_psm3, pvlib.iotools.get_psm3
|
|
389
|
-
|
|
390
|
-
References
|
|
391
|
-
----------
|
|
392
|
-
.. [1] `NREL National Solar Radiation Database (NSRDB)
|
|
393
|
-
<https://nsrdb.nrel.gov/>`_
|
|
394
|
-
.. [2] `Standard Time Series Data File Format
|
|
395
|
-
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
|
|
396
|
-
"""
|
|
397
|
-
with open(str(filename), 'r') as fbuf:
|
|
398
|
-
content = parse_psm3(fbuf, map_variables)
|
|
399
|
-
return content
|
|
364
|
+
parse_psm3 = deprecated(since="0.13.0", name="parse_psm3",
|
|
365
|
+
alternative="read_psm3")(read_psm3)
|