pvlib 0.9.5__py3-none-any.whl → 0.10.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/__init__.py +3 -2
- pvlib/atmosphere.py +6 -171
- pvlib/bifacial/infinite_sheds.py +30 -267
- pvlib/bifacial/utils.py +225 -5
- pvlib/data/test_psm3_2017.csv +17521 -17521
- pvlib/data/test_read_psm3.csv +17522 -17522
- pvlib/data/test_read_pvgis_horizon.csv +49 -0
- pvlib/data/variables_style_rules.csv +3 -0
- pvlib/iam.py +17 -4
- pvlib/inverter.py +6 -1
- pvlib/iotools/__init__.py +7 -2
- pvlib/iotools/acis.py +516 -0
- pvlib/iotools/midc.py +4 -4
- pvlib/iotools/psm3.py +32 -31
- pvlib/iotools/pvgis.py +84 -28
- pvlib/iotools/sodapro.py +8 -6
- pvlib/iotools/srml.py +121 -18
- pvlib/iotools/surfrad.py +2 -2
- pvlib/iotools/tmy.py +146 -102
- pvlib/irradiance.py +151 -0
- pvlib/ivtools/sde.py +11 -7
- pvlib/ivtools/sdm.py +16 -10
- pvlib/ivtools/utils.py +6 -6
- pvlib/location.py +3 -2
- pvlib/modelchain.py +67 -70
- pvlib/pvsystem.py +160 -532
- pvlib/shading.py +41 -0
- pvlib/singlediode.py +215 -65
- pvlib/soiling.py +3 -3
- pvlib/spa.py +327 -368
- pvlib/spectrum/__init__.py +8 -2
- pvlib/spectrum/mismatch.py +335 -0
- pvlib/temperature.py +1 -8
- pvlib/tests/bifacial/test_infinite_sheds.py +0 -111
- pvlib/tests/bifacial/test_utils.py +101 -4
- pvlib/tests/conftest.py +0 -31
- pvlib/tests/iotools/test_acis.py +213 -0
- pvlib/tests/iotools/test_midc.py +6 -6
- pvlib/tests/iotools/test_psm3.py +3 -3
- pvlib/tests/iotools/test_pvgis.py +21 -14
- pvlib/tests/iotools/test_sodapro.py +1 -1
- pvlib/tests/iotools/test_srml.py +71 -6
- pvlib/tests/iotools/test_tmy.py +43 -8
- pvlib/tests/ivtools/test_sde.py +19 -17
- pvlib/tests/ivtools/test_sdm.py +9 -4
- pvlib/tests/test_atmosphere.py +6 -62
- pvlib/tests/test_iam.py +12 -0
- pvlib/tests/test_irradiance.py +40 -2
- pvlib/tests/test_location.py +1 -1
- pvlib/tests/test_modelchain.py +33 -76
- pvlib/tests/test_pvsystem.py +366 -201
- pvlib/tests/test_shading.py +28 -0
- pvlib/tests/test_singlediode.py +166 -30
- pvlib/tests/test_soiling.py +8 -7
- pvlib/tests/test_spa.py +6 -7
- pvlib/tests/test_spectrum.py +145 -1
- pvlib/tests/test_temperature.py +0 -7
- pvlib/tests/test_tools.py +25 -0
- pvlib/tests/test_tracking.py +0 -149
- pvlib/tools.py +26 -1
- pvlib/tracking.py +1 -269
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/METADATA +1 -9
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/RECORD +67 -68
- pvlib/forecast.py +0 -1211
- pvlib/iotools/ecmwf_macc.py +0 -312
- pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
- pvlib/tests/test_forecast.py +0 -228
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/LICENSE +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/WHEEL +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
pvlib/iotools/midc.py
CHANGED
|
@@ -102,7 +102,7 @@ TZ_MAP = {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def
|
|
105
|
+
def _format_index(data):
|
|
106
106
|
"""Create DatetimeIndex for the Dataframe localized to the timezone provided
|
|
107
107
|
as the label of the second (time) column.
|
|
108
108
|
|
|
@@ -126,7 +126,7 @@ def format_index(data):
|
|
|
126
126
|
return data
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
def
|
|
129
|
+
def _format_index_raw(data):
|
|
130
130
|
"""Create DatetimeIndex for the Dataframe localized to the timezone provided
|
|
131
131
|
as the label of the third column.
|
|
132
132
|
|
|
@@ -200,9 +200,9 @@ def read_midc(filename, variable_map={}, raw_data=False, **kwargs):
|
|
|
200
200
|
"""
|
|
201
201
|
data = pd.read_csv(filename, **kwargs)
|
|
202
202
|
if raw_data:
|
|
203
|
-
data =
|
|
203
|
+
data = _format_index_raw(data)
|
|
204
204
|
else:
|
|
205
|
-
data =
|
|
205
|
+
data = _format_index(data)
|
|
206
206
|
data = data.rename(columns=variable_map)
|
|
207
207
|
return data
|
|
208
208
|
|
pvlib/iotools/psm3.py
CHANGED
|
@@ -11,7 +11,7 @@ import warnings
|
|
|
11
11
|
from pvlib._deprecation import pvlibDeprecationWarning
|
|
12
12
|
|
|
13
13
|
NSRDB_API_BASE = "https://developer.nrel.gov"
|
|
14
|
-
PSM_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-download.csv"
|
|
14
|
+
PSM_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-2-2-download.csv"
|
|
15
15
|
TMY_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-tmy-download.csv"
|
|
16
16
|
PSM5MIN_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-5min-download.csv"
|
|
17
17
|
|
|
@@ -63,7 +63,8 @@ REQUEST_VARIABLE_MAP = {
|
|
|
63
63
|
|
|
64
64
|
def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
65
65
|
attributes=ATTRIBUTES, leap_day=None, full_name=PVLIB_PYTHON,
|
|
66
|
-
affiliation=PVLIB_PYTHON, map_variables=None,
|
|
66
|
+
affiliation=PVLIB_PYTHON, map_variables=None, url=None,
|
|
67
|
+
timeout=30):
|
|
67
68
|
"""
|
|
68
69
|
Retrieve NSRDB PSM3 timeseries weather data from the PSM3 API. The NSRDB
|
|
69
70
|
is described in [1]_ and the PSM3 API is described in [2]_, [3]_, and [4]_.
|
|
@@ -73,6 +74,12 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
73
74
|
and the second element is a dictionary containing metadata. Previous
|
|
74
75
|
versions of this function had the return values switched.
|
|
75
76
|
|
|
77
|
+
.. versionchanged:: 0.10.0
|
|
78
|
+
The default endpoint for hourly single-year datasets is now v3.2.2.
|
|
79
|
+
The previous datasets can still be accessed (for now) by setting
|
|
80
|
+
the ``url`` parameter to the original API endpoint
|
|
81
|
+
(``"https://developer.nrel.gov/api/nsrdb/v2/solar/psm3-download.csv"``).
|
|
82
|
+
|
|
76
83
|
Parameters
|
|
77
84
|
----------
|
|
78
85
|
latitude : float or int
|
|
@@ -85,16 +92,19 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
85
92
|
NREL API uses this to automatically communicate messages back
|
|
86
93
|
to the user only if necessary
|
|
87
94
|
names : str, default 'tmy'
|
|
88
|
-
PSM3 API parameter specifing year or TMY variant
|
|
89
|
-
|
|
95
|
+
PSM3 API parameter specifing year (e.g. ``2020``) or TMY variant
|
|
96
|
+
to download (e.g. ``'tmy'`` or ``'tgy-2019'``). The allowed values
|
|
97
|
+
update periodically, so consult the NSRDB references below for the
|
|
98
|
+
current set of options.
|
|
90
99
|
interval : int, {60, 5, 15, 30}
|
|
91
|
-
interval size in minutes, must be 5, 15, 30 or 60.
|
|
92
|
-
|
|
100
|
+
interval size in minutes, must be 5, 15, 30 or 60. Must be 60 for
|
|
101
|
+
typical year requests (i.e., tmy/tgy/tdy).
|
|
93
102
|
attributes : list of str, optional
|
|
94
103
|
meteorological fields to fetch. If not specified, defaults to
|
|
95
104
|
``pvlib.iotools.psm3.ATTRIBUTES``. See references [2]_, [3]_, and [4]_
|
|
96
105
|
for lists of available fields. Alternatively, pvlib names may also be
|
|
97
106
|
used (e.g. 'ghi' rather than 'GHI'); see :const:`REQUEST_VARIABLE_MAP`.
|
|
107
|
+
To retrieve all available fields, set ``attributes=[]``.
|
|
98
108
|
leap_day : boolean, default False
|
|
99
109
|
include leap day in the results. Only used for single-year requests
|
|
100
110
|
(i.e., it is ignored for tmy/tgy/tdy requests).
|
|
@@ -102,9 +112,12 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
102
112
|
optional
|
|
103
113
|
affiliation : str, default 'pvlib python'
|
|
104
114
|
optional
|
|
105
|
-
map_variables: boolean, optional
|
|
115
|
+
map_variables : boolean, optional
|
|
106
116
|
When true, renames columns of the Dataframe to pvlib variable names
|
|
107
117
|
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
118
|
+
url : str, optional
|
|
119
|
+
API endpoint URL. If not specified, the endpoint is determined from
|
|
120
|
+
the ``names`` and ``interval`` parameters.
|
|
108
121
|
timeout : int, default 30
|
|
109
122
|
time in seconds to wait for server response before timeout
|
|
110
123
|
|
|
@@ -132,21 +145,6 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
132
145
|
.. warning:: The "DEMO_KEY" `api_key` is severely rate limited and may
|
|
133
146
|
result in rejected requests.
|
|
134
147
|
|
|
135
|
-
The PSM3 API `names` parameter must be a single value from one of these
|
|
136
|
-
lists:
|
|
137
|
-
|
|
138
|
-
+-----------+-------------------------------------------------------------+
|
|
139
|
-
| Category | Allowed values |
|
|
140
|
-
+===========+=============================================================+
|
|
141
|
-
| Year | 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
|
|
142
|
-
| | 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, |
|
|
143
|
-
| | 2018, 2019, 2020 |
|
|
144
|
-
+-----------+-------------------------------------------------------------+
|
|
145
|
-
| TMY | tmy, tmy-2016, tmy-2017, tdy-2017, tgy-2017, |
|
|
146
|
-
| | tmy-2018, tdy-2018, tgy-2018, tmy-2019, tdy-2019, tgy-2019 |
|
|
147
|
-
| | tmy-2020, tdy-2020, tgy-2020 |
|
|
148
|
-
+-----------+-------------------------------------------------------------+
|
|
149
|
-
|
|
150
148
|
.. warning:: PSM3 is limited to data found in the NSRDB, please consult the
|
|
151
149
|
references below for locations with available data. Additionally,
|
|
152
150
|
querying data with < 30-minute resolution uses a different API endpoint
|
|
@@ -161,8 +159,8 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
161
159
|
|
|
162
160
|
.. [1] `NREL National Solar Radiation Database (NSRDB)
|
|
163
161
|
<https://nsrdb.nrel.gov/>`_
|
|
164
|
-
.. [2] `Physical Solar Model (PSM) v3
|
|
165
|
-
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-download/>`_
|
|
162
|
+
.. [2] `Physical Solar Model (PSM) v3.2.2
|
|
163
|
+
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-2-2-download/>`_
|
|
166
164
|
.. [3] `Physical Solar Model (PSM) v3 TMY
|
|
167
165
|
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-tmy-download/>`_
|
|
168
166
|
.. [4] `Physical Solar Model (PSM) v3 - Five Minute Temporal Resolution
|
|
@@ -205,13 +203,16 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
|
|
|
205
203
|
'interval': interval
|
|
206
204
|
}
|
|
207
205
|
# request CSV download from NREL PSM3
|
|
208
|
-
if
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
if url is None:
|
|
207
|
+
# determine the endpoint that suits the user inputs
|
|
208
|
+
if any(prefix in names for prefix in ('tmy', 'tgy', 'tdy')):
|
|
209
|
+
url = TMY_URL
|
|
210
|
+
elif interval in (5, 15):
|
|
211
|
+
url = PSM5MIN_URL
|
|
212
|
+
else:
|
|
213
|
+
url = PSM_URL
|
|
214
|
+
|
|
215
|
+
response = requests.get(url, params=params, timeout=timeout)
|
|
215
216
|
if not response.ok:
|
|
216
217
|
# if the API key is rejected, then the response status will be 403
|
|
217
218
|
# Forbidden, and then the error is in the content and there is no JSON
|
pvlib/iotools/pvgis.py
CHANGED
|
@@ -45,7 +45,7 @@ VARIABLE_MAP = {
|
|
|
45
45
|
|
|
46
46
|
def get_pvgis_hourly(latitude, longitude, start=None, end=None,
|
|
47
47
|
raddatabase=None, components=True,
|
|
48
|
-
surface_tilt=0, surface_azimuth=
|
|
48
|
+
surface_tilt=0, surface_azimuth=180,
|
|
49
49
|
outputformat='json',
|
|
50
50
|
usehorizon=True, userhorizon=None,
|
|
51
51
|
pvcalculation=False,
|
|
@@ -76,9 +76,15 @@ def get_pvgis_hourly(latitude, longitude, start=None, end=None,
|
|
|
76
76
|
Otherwise only global irradiance is returned.
|
|
77
77
|
surface_tilt: float, default: 0
|
|
78
78
|
Tilt angle from horizontal plane. Ignored for two-axis tracking.
|
|
79
|
-
surface_azimuth: float, default:
|
|
80
|
-
Orientation (azimuth angle) of the (fixed) plane.
|
|
81
|
-
|
|
79
|
+
surface_azimuth: float, default: 180
|
|
80
|
+
Orientation (azimuth angle) of the (fixed) plane. Counter-clockwise
|
|
81
|
+
from north (north=0, south=180). This is offset 180 degrees from
|
|
82
|
+
the convention used by PVGIS. Ignored for tracking systems.
|
|
83
|
+
|
|
84
|
+
.. versionchanged:: 0.10.0
|
|
85
|
+
The `surface_azimuth` parameter now follows the pvlib convention, which
|
|
86
|
+
is counterclockwise from north. However, the convention used by the
|
|
87
|
+
PVGIS website and pvlib<=0.9.5 is offset by 180 degrees.
|
|
82
88
|
usehorizon: bool, default: True
|
|
83
89
|
Include effects of horizon
|
|
84
90
|
userhorizon: list of float, default: None
|
|
@@ -144,6 +150,13 @@ def get_pvgis_hourly(latitude, longitude, start=None, end=None,
|
|
|
144
150
|
time stamp convention, e.g., SARAH and SARAH2 provide instantaneous values,
|
|
145
151
|
whereas values from ERA5 are averages for the hour.
|
|
146
152
|
|
|
153
|
+
Warning
|
|
154
|
+
-------
|
|
155
|
+
The azimuth orientation specified in the output metadata does not
|
|
156
|
+
correspond to the pvlib convention, but is offset 180 degrees. This is
|
|
157
|
+
despite the fact that the input parameter `surface_tilt` has to be
|
|
158
|
+
specified according to the pvlib convention.
|
|
159
|
+
|
|
147
160
|
Notes
|
|
148
161
|
-----
|
|
149
162
|
data includes the following fields:
|
|
@@ -191,7 +204,7 @@ def get_pvgis_hourly(latitude, longitude, start=None, end=None,
|
|
|
191
204
|
""" # noqa: E501
|
|
192
205
|
# use requests to format the query string by passing params dictionary
|
|
193
206
|
params = {'lat': latitude, 'lon': longitude, 'outputformat': outputformat,
|
|
194
|
-
'angle': surface_tilt, 'aspect': surface_azimuth,
|
|
207
|
+
'angle': surface_tilt, 'aspect': surface_azimuth-180,
|
|
195
208
|
'pvcalculation': int(pvcalculation),
|
|
196
209
|
'pvtechchoice': pvtechchoice, 'mountingplace': mountingplace,
|
|
197
210
|
'trackingtype': trackingtype, 'components': int(components),
|
|
@@ -315,6 +328,11 @@ def read_pvgis_hourly(filename, pvgis_format=None, map_variables=True):
|
|
|
315
328
|
metadata : dict
|
|
316
329
|
metadata
|
|
317
330
|
|
|
331
|
+
Warning
|
|
332
|
+
-------
|
|
333
|
+
The azimuth orientation specified in the output metadata does not
|
|
334
|
+
correspond to the pvlib convention, but is offset 180 degrees.
|
|
335
|
+
|
|
318
336
|
Raises
|
|
319
337
|
------
|
|
320
338
|
ValueError
|
|
@@ -373,8 +391,8 @@ def read_pvgis_hourly(filename, pvgis_format=None, map_variables=True):
|
|
|
373
391
|
|
|
374
392
|
|
|
375
393
|
def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
|
|
376
|
-
userhorizon=None, startyear=None, endyear=None,
|
|
377
|
-
map_variables=
|
|
394
|
+
userhorizon=None, startyear=None, endyear=None,
|
|
395
|
+
map_variables=True, url=URL, timeout=30):
|
|
378
396
|
"""
|
|
379
397
|
Get TMY data from PVGIS.
|
|
380
398
|
|
|
@@ -400,11 +418,11 @@ def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
|
|
|
400
418
|
first year to calculate TMY
|
|
401
419
|
endyear : int, default None
|
|
402
420
|
last year to calculate TMY, must be at least 10 years from first year
|
|
421
|
+
map_variables: bool, default True
|
|
422
|
+
When true, renames columns of the Dataframe to pvlib variable names
|
|
423
|
+
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
403
424
|
url : str, default: :const:`pvlib.iotools.pvgis.URL`
|
|
404
425
|
base url of PVGIS API, append ``tmy`` to get TMY endpoint
|
|
405
|
-
map_variables: bool
|
|
406
|
-
When true, renames columns of the Dataframe to pvlib variable names
|
|
407
|
-
where applicable. See variable const:`VARIABLE_MAP`.
|
|
408
426
|
timeout : int, default 30
|
|
409
427
|
time in seconds to wait for server response before timeout
|
|
410
428
|
|
|
@@ -490,14 +508,6 @@ def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
|
|
|
490
508
|
# the response is HTTP/1.1 400 BAD REQUEST which is handled earlier
|
|
491
509
|
pass
|
|
492
510
|
|
|
493
|
-
if map_variables is None:
|
|
494
|
-
warnings.warn(
|
|
495
|
-
'PVGIS variable names will be renamed to pvlib conventions by '
|
|
496
|
-
'default starting in pvlib 0.10.0. Specify map_variables=True '
|
|
497
|
-
'to enable that behavior now, or specify map_variables=False '
|
|
498
|
-
'to hide this warning.', pvlibDeprecationWarning
|
|
499
|
-
)
|
|
500
|
-
map_variables = False
|
|
501
511
|
if map_variables:
|
|
502
512
|
data = data.rename(columns=VARIABLE_MAP)
|
|
503
513
|
|
|
@@ -555,7 +565,7 @@ def _parse_pvgis_tmy_basic(src):
|
|
|
555
565
|
return data, None, None, None
|
|
556
566
|
|
|
557
567
|
|
|
558
|
-
def read_pvgis_tmy(filename, pvgis_format=None, map_variables=
|
|
568
|
+
def read_pvgis_tmy(filename, pvgis_format=None, map_variables=True):
|
|
559
569
|
"""
|
|
560
570
|
Read a file downloaded from PVGIS.
|
|
561
571
|
|
|
@@ -571,7 +581,7 @@ def read_pvgis_tmy(filename, pvgis_format=None, map_variables=None):
|
|
|
571
581
|
``outputformat='basic'``, please set ``pvgis_format`` to ``'basic'``.
|
|
572
582
|
If ``filename`` is a buffer, then ``pvgis_format`` is required and must
|
|
573
583
|
be in ``['csv', 'epw', 'json', 'basic']``.
|
|
574
|
-
map_variables: bool
|
|
584
|
+
map_variables: bool, default True
|
|
575
585
|
When true, renames columns of the Dataframe to pvlib variable names
|
|
576
586
|
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
577
587
|
|
|
@@ -653,15 +663,61 @@ def read_pvgis_tmy(filename, pvgis_format=None, map_variables=None):
|
|
|
653
663
|
"'csv', or 'basic'").format(outputformat)
|
|
654
664
|
raise ValueError(err_msg)
|
|
655
665
|
|
|
656
|
-
if map_variables is None:
|
|
657
|
-
warnings.warn(
|
|
658
|
-
'PVGIS variable names will be renamed to pvlib conventions by '
|
|
659
|
-
'default starting in pvlib 0.10.0. Specify map_variables=True '
|
|
660
|
-
'to enable that behavior now, or specify map_variables=False '
|
|
661
|
-
'to hide this warning.', pvlibDeprecationWarning
|
|
662
|
-
)
|
|
663
|
-
map_variables = False
|
|
664
666
|
if map_variables:
|
|
665
667
|
data = data.rename(columns=VARIABLE_MAP)
|
|
666
668
|
|
|
667
669
|
return data, months_selected, inputs, meta
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def get_pvgis_horizon(latitude, longitude, url=URL, **kwargs):
|
|
673
|
+
"""Get horizon data from PVGIS.
|
|
674
|
+
|
|
675
|
+
Parameters
|
|
676
|
+
----------
|
|
677
|
+
latitude : float
|
|
678
|
+
Latitude in degrees north
|
|
679
|
+
longitude : float
|
|
680
|
+
Longitude in degrees east
|
|
681
|
+
url: str, default: :const:`pvlib.iotools.pvgis.URL`
|
|
682
|
+
Base URL for PVGIS
|
|
683
|
+
kwargs:
|
|
684
|
+
Passed to requests.get
|
|
685
|
+
|
|
686
|
+
Returns
|
|
687
|
+
-------
|
|
688
|
+
data : pd.Series
|
|
689
|
+
Pandas Series of the retrived horizon elevation angles. Index is the
|
|
690
|
+
corresponding horizon azimuth angles.
|
|
691
|
+
metadata : dict
|
|
692
|
+
Metadata returned by PVGIS.
|
|
693
|
+
|
|
694
|
+
Notes
|
|
695
|
+
-----
|
|
696
|
+
The horizon azimuths are specified clockwise from north, e.g., south=180.
|
|
697
|
+
This is the standard pvlib convention, although the PVGIS website specifies
|
|
698
|
+
south=0.
|
|
699
|
+
|
|
700
|
+
References
|
|
701
|
+
----------
|
|
702
|
+
.. [1] `PVGIS horizon profile tool
|
|
703
|
+
<https://ec.europa.eu/jrc/en/PVGIS/tools/horizon>`_
|
|
704
|
+
"""
|
|
705
|
+
params = {'lat': latitude, 'lon': longitude, 'outputformat': 'json'}
|
|
706
|
+
res = requests.get(url + 'printhorizon', params=params, **kwargs)
|
|
707
|
+
if not res.ok:
|
|
708
|
+
try:
|
|
709
|
+
err_msg = res.json()
|
|
710
|
+
except Exception:
|
|
711
|
+
res.raise_for_status()
|
|
712
|
+
else:
|
|
713
|
+
raise requests.HTTPError(err_msg['message'])
|
|
714
|
+
json_output = res.json()
|
|
715
|
+
metadata = json_output['meta']
|
|
716
|
+
data = pd.DataFrame(json_output['outputs']['horizon_profile'])
|
|
717
|
+
data.columns = ['horizon_azimuth', 'horizon_elevation']
|
|
718
|
+
# Convert azimuth to pvlib convention (north=0, south=180)
|
|
719
|
+
data['horizon_azimuth'] += 180
|
|
720
|
+
data.set_index('horizon_azimuth', inplace=True)
|
|
721
|
+
data = data['horizon_elevation'] # convert to pd.Series
|
|
722
|
+
data = data[data.index < 360] # remove duplicate north point (0 and 360)
|
|
723
|
+
return data, metadata
|
pvlib/iotools/sodapro.py
CHANGED
|
@@ -9,6 +9,8 @@ import io
|
|
|
9
9
|
import warnings
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
URL = 'api.soda-solardata.com'
|
|
13
|
+
|
|
12
14
|
CAMS_INTEGRATED_COLUMNS = [
|
|
13
15
|
'TOA', 'Clear sky GHI', 'Clear sky BHI', 'Clear sky DHI', 'Clear sky BNI',
|
|
14
16
|
'GHI', 'BHI', 'DHI', 'BNI',
|
|
@@ -44,7 +46,7 @@ SUMMATION_PERIOD_TO_TIME_STEP = {'0 year 0 month 0 day 0 h 1 min 0 s': '1min',
|
|
|
44
46
|
def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
|
|
45
47
|
altitude=None, time_step='1h', time_ref='UT', verbose=False,
|
|
46
48
|
integrated=False, label=None, map_variables=True,
|
|
47
|
-
server=
|
|
49
|
+
server=URL, timeout=30):
|
|
48
50
|
"""
|
|
49
51
|
Retrieve time-series of radiation and/or clear-sky global, beam, and
|
|
50
52
|
diffuse radiation from CAMS (see [1]_). Data is retrieved from SoDa [2]_.
|
|
@@ -91,8 +93,8 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
|
|
|
91
93
|
map_variables: bool, default: True
|
|
92
94
|
When true, renames columns of the DataFrame to pvlib variable names
|
|
93
95
|
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
94
|
-
server: str, default:
|
|
95
|
-
|
|
96
|
+
server: str, default: :const:`pvlib.iotools.sodapro.URL`
|
|
97
|
+
Base url of the SoDa Pro CAMS Radiation API.
|
|
96
98
|
timeout : int, default: 30
|
|
97
99
|
Time in seconds to wait for server response before timeout
|
|
98
100
|
|
|
@@ -344,13 +346,13 @@ def read_cams(filename, integrated=False, label=None, map_variables=True):
|
|
|
344
346
|
all time steps except for '1M' which has a default of 'right'.
|
|
345
347
|
map_variables: bool, default: True
|
|
346
348
|
When true, renames columns of the Dataframe to pvlib variable names
|
|
347
|
-
where applicable. See variable VARIABLE_MAP
|
|
349
|
+
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
348
350
|
|
|
349
351
|
Returns
|
|
350
352
|
-------
|
|
351
353
|
data: pandas.DataFrame
|
|
352
|
-
Timeseries data from CAMS Radiation or McClear
|
|
353
|
-
:func:`pvlib.iotools.get_cams` for fields
|
|
354
|
+
Timeseries data from CAMS Radiation or McClear.
|
|
355
|
+
See :func:`pvlib.iotools.get_cams` for fields.
|
|
354
356
|
metadata: dict
|
|
355
357
|
Metadata available in the file.
|
|
356
358
|
|
pvlib/iotools/srml.py
CHANGED
|
@@ -3,7 +3,10 @@ Radiation Monitoring Laboratory (SRML) data.
|
|
|
3
3
|
"""
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas as pd
|
|
6
|
+
import urllib
|
|
7
|
+
import warnings
|
|
6
8
|
|
|
9
|
+
from pvlib._deprecation import deprecated
|
|
7
10
|
|
|
8
11
|
# VARIABLE_MAP is a dictionary mapping SRML data element numbers to their
|
|
9
12
|
# pvlib names. For most variables, only the first three digits are used,
|
|
@@ -15,7 +18,7 @@ VARIABLE_MAP = {
|
|
|
15
18
|
'100': 'ghi',
|
|
16
19
|
'201': 'dni',
|
|
17
20
|
'300': 'dhi',
|
|
18
|
-
'920': '
|
|
21
|
+
'920': 'wind_direction',
|
|
19
22
|
'921': 'wind_speed',
|
|
20
23
|
'930': 'temp_air',
|
|
21
24
|
'931': 'temp_dew',
|
|
@@ -24,22 +27,24 @@ VARIABLE_MAP = {
|
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
|
|
27
|
-
def read_srml(filename):
|
|
30
|
+
def read_srml(filename, map_variables=True):
|
|
28
31
|
"""
|
|
29
|
-
Read University of Oregon SRML 1min .tsv file into pandas dataframe.
|
|
30
|
-
|
|
32
|
+
Read University of Oregon SRML 1min .tsv file into pandas dataframe.
|
|
33
|
+
|
|
34
|
+
The SRML is described in [1]_.
|
|
31
35
|
|
|
32
36
|
Parameters
|
|
33
37
|
----------
|
|
34
38
|
filename: str
|
|
35
39
|
filepath or url to read for the tsv file.
|
|
40
|
+
map_variables: bool, default: True
|
|
41
|
+
When true, renames columns of the DataFrame to pvlib variable names
|
|
42
|
+
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
36
43
|
|
|
37
44
|
Returns
|
|
38
45
|
-------
|
|
39
46
|
data: Dataframe
|
|
40
|
-
A dataframe with datetime index
|
|
41
|
-
in the `VARIABLE_MAP` dict inside of the map_columns function,
|
|
42
|
-
along with their associated quality control flags.
|
|
47
|
+
A dataframe with datetime index
|
|
43
48
|
|
|
44
49
|
Notes
|
|
45
50
|
-----
|
|
@@ -50,21 +55,22 @@ def read_srml(filename):
|
|
|
50
55
|
the time of the row until the time of the next row. This is consistent
|
|
51
56
|
with pandas' default labeling behavior.
|
|
52
57
|
|
|
53
|
-
See
|
|
54
|
-
|
|
55
|
-
.. _Archival Files: http://solardat.uoregon.edu/ArchivalFiles.html
|
|
58
|
+
See [2]_ for more information concerning the file format.
|
|
56
59
|
|
|
57
60
|
References
|
|
58
61
|
----------
|
|
59
62
|
.. [1] University of Oregon Solar Radiation Monitoring Laboratory
|
|
60
63
|
`http://solardat.uoregon.edu/ <http://solardat.uoregon.edu/>`_
|
|
64
|
+
.. [2] `Archival (short interval) data files
|
|
65
|
+
<http://solardat.uoregon.edu/ArchivalFiles.html>`_
|
|
61
66
|
"""
|
|
62
67
|
tsv_data = pd.read_csv(filename, delimiter='\t')
|
|
63
|
-
data =
|
|
68
|
+
data = _format_index(tsv_data)
|
|
64
69
|
# Drop day of year and time columns
|
|
65
70
|
data = data[data.columns[2:]]
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
if map_variables:
|
|
73
|
+
data = data.rename(columns=_map_columns)
|
|
68
74
|
|
|
69
75
|
# Quality flag columns are all labeled 0 in the original data. They
|
|
70
76
|
# appear immediately after their associated variable and are suffixed
|
|
@@ -90,7 +96,7 @@ def read_srml(filename):
|
|
|
90
96
|
return data
|
|
91
97
|
|
|
92
98
|
|
|
93
|
-
def
|
|
99
|
+
def _map_columns(col):
|
|
94
100
|
"""Map data element numbers to pvlib names.
|
|
95
101
|
|
|
96
102
|
Parameters
|
|
@@ -118,7 +124,7 @@ def map_columns(col):
|
|
|
118
124
|
return col
|
|
119
125
|
|
|
120
126
|
|
|
121
|
-
def
|
|
127
|
+
def _format_index(df):
|
|
122
128
|
"""Create a datetime index from day of year, and time columns.
|
|
123
129
|
|
|
124
130
|
Parameters
|
|
@@ -166,9 +172,12 @@ def format_index(df):
|
|
|
166
172
|
return df
|
|
167
173
|
|
|
168
174
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
@deprecated('0.10.0', alternative='pvlib.iotools.get_srml', removal='0.11.0')
|
|
176
|
+
def read_srml_month_from_solardat(station, year, month, filetype='PO',
|
|
177
|
+
map_variables=True):
|
|
178
|
+
"""Request a month of SRML data and read it into a Dataframe.
|
|
179
|
+
|
|
180
|
+
The SRML is described in [1]_.
|
|
172
181
|
|
|
173
182
|
Parameters
|
|
174
183
|
----------
|
|
@@ -180,6 +189,9 @@ def read_srml_month_from_solardat(station, year, month, filetype='PO'):
|
|
|
180
189
|
Month to request data for.
|
|
181
190
|
filetype: string
|
|
182
191
|
SRML file type to gather. See notes for explanation.
|
|
192
|
+
map_variables: bool, default: True
|
|
193
|
+
When true, renames columns of the DataFrame to pvlib variable names
|
|
194
|
+
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
183
195
|
|
|
184
196
|
Returns
|
|
185
197
|
-------
|
|
@@ -214,5 +226,96 @@ def read_srml_month_from_solardat(station, year, month, filetype='PO'):
|
|
|
214
226
|
year=year % 100,
|
|
215
227
|
month=month)
|
|
216
228
|
url = "http://solardat.uoregon.edu/download/Archive/"
|
|
217
|
-
data = read_srml(url + file_name)
|
|
229
|
+
data = read_srml(url + file_name, map_variables=map_variables)
|
|
218
230
|
return data
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def get_srml(station, start, end, filetype='PO', map_variables=True,
|
|
234
|
+
url="http://solardat.uoregon.edu/download/Archive/"):
|
|
235
|
+
"""Request data from UoO SRML and read it into a Dataframe.
|
|
236
|
+
|
|
237
|
+
The University of Oregon Solar Radiation Monitoring Laboratory (SRML) is
|
|
238
|
+
described in [1]_. A list of stations can be found in [2]_.
|
|
239
|
+
|
|
240
|
+
Data is returned for the entire months between and including start and end.
|
|
241
|
+
|
|
242
|
+
Parameters
|
|
243
|
+
----------
|
|
244
|
+
station : str
|
|
245
|
+
Two letter station abbreviation.
|
|
246
|
+
start : datetime like
|
|
247
|
+
First day of the requested period
|
|
248
|
+
end : datetime like
|
|
249
|
+
Last day of the requested period
|
|
250
|
+
filetype : string, default: 'PO'
|
|
251
|
+
SRML file type to gather. See notes for explanation.
|
|
252
|
+
map_variables : bool, default: True
|
|
253
|
+
When true, renames columns of the DataFrame to pvlib variable names
|
|
254
|
+
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
255
|
+
url : str, default: 'http://solardat.uoregon.edu/download/Archive/'
|
|
256
|
+
API endpoint URL
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
data : pd.DataFrame
|
|
261
|
+
Dataframe with data from SRML.
|
|
262
|
+
meta : dict
|
|
263
|
+
Metadata.
|
|
264
|
+
|
|
265
|
+
Notes
|
|
266
|
+
-----
|
|
267
|
+
File types designate the time interval of a file and if it contains
|
|
268
|
+
raw or processed data. For instance, `RO` designates raw, one minute
|
|
269
|
+
data and `PO` designates processed one minute data. The availability
|
|
270
|
+
of file types varies between sites. Below is a table of file types
|
|
271
|
+
and their time intervals. See [1] for site information.
|
|
272
|
+
|
|
273
|
+
============= ============ ==================
|
|
274
|
+
time interval raw filetype processed filetype
|
|
275
|
+
============= ============ ==================
|
|
276
|
+
1 minute RO PO
|
|
277
|
+
5 minute RF PF
|
|
278
|
+
15 minute RQ PQ
|
|
279
|
+
hourly RH PH
|
|
280
|
+
============= ============ ==================
|
|
281
|
+
|
|
282
|
+
Warning
|
|
283
|
+
-------
|
|
284
|
+
SRML data has nighttime data prefilled with 0s through the end of the
|
|
285
|
+
current month (i.e., values are provided for data in the future).
|
|
286
|
+
|
|
287
|
+
References
|
|
288
|
+
----------
|
|
289
|
+
.. [1] University of Oregon Solar Radiation Measurement Laboratory
|
|
290
|
+
`http://solardat.uoregon.edu/ <http://solardat.uoregon.edu/>`_
|
|
291
|
+
.. [2] Station ID codes - Solar Radiation Measurement Laboratory
|
|
292
|
+
`http://solardat.uoregon.edu/StationIDCodes.html
|
|
293
|
+
<http://solardat.uoregon.edu/StationIDCodes.html>`_
|
|
294
|
+
"""
|
|
295
|
+
# Use pd.to_datetime so that strings (e.g. '2021-01-01') are accepted
|
|
296
|
+
start = pd.to_datetime(start)
|
|
297
|
+
end = pd.to_datetime(end)
|
|
298
|
+
|
|
299
|
+
# Generate list of months
|
|
300
|
+
months = pd.date_range(
|
|
301
|
+
start, end.replace(day=1) + pd.DateOffset(months=1), freq='1M')
|
|
302
|
+
months_str = months.strftime('%y%m')
|
|
303
|
+
|
|
304
|
+
# Generate list of filenames
|
|
305
|
+
filenames = [f"{station}{filetype}{m}.txt" for m in months_str]
|
|
306
|
+
|
|
307
|
+
dfs = [] # Initialize list of monthly dataframes
|
|
308
|
+
for f in filenames:
|
|
309
|
+
try:
|
|
310
|
+
dfi = read_srml(url + f, map_variables=map_variables)
|
|
311
|
+
dfs.append(dfi)
|
|
312
|
+
except urllib.error.HTTPError:
|
|
313
|
+
warnings.warn(f"The following file was not found: {f}")
|
|
314
|
+
|
|
315
|
+
data = pd.concat(dfs, axis='rows')
|
|
316
|
+
|
|
317
|
+
meta = {'filetype': filetype,
|
|
318
|
+
'station': station,
|
|
319
|
+
'filenames': filenames}
|
|
320
|
+
|
|
321
|
+
return data, meta
|
pvlib/iotools/surfrad.py
CHANGED
|
@@ -150,7 +150,7 @@ def read_surfrad(filename, map_variables=True):
|
|
|
150
150
|
header=None, names=SURFRAD_COLUMNS)
|
|
151
151
|
file_buffer.close()
|
|
152
152
|
|
|
153
|
-
data =
|
|
153
|
+
data = _format_index(data)
|
|
154
154
|
missing = data == -9999.9
|
|
155
155
|
data = data.where(~missing, np.NaN)
|
|
156
156
|
|
|
@@ -159,7 +159,7 @@ def read_surfrad(filename, map_variables=True):
|
|
|
159
159
|
return data, metadata
|
|
160
160
|
|
|
161
161
|
|
|
162
|
-
def
|
|
162
|
+
def _format_index(data):
|
|
163
163
|
"""Create UTC localized DatetimeIndex for the dataframe.
|
|
164
164
|
|
|
165
165
|
Parameters
|