pvlib 0.11.2__py3-none-any.whl → 0.12.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 +1 -0
- pvlib/atmosphere.py +0 -9
- pvlib/bifacial/infinite_sheds.py +4 -3
- pvlib/bifacial/utils.py +2 -1
- pvlib/iotools/psm3.py +1 -1
- pvlib/iotools/pvgis.py +10 -2
- pvlib/iotools/tmy.py +3 -69
- pvlib/irradiance.py +14 -0
- pvlib/location.py +73 -33
- pvlib/modelchain.py +18 -35
- pvlib/pvsystem.py +7 -10
- pvlib/snow.py +64 -28
- pvlib/spectrum/__init__.py +0 -1
- pvlib/spectrum/irradiance.py +0 -63
- pvlib/spectrum/mismatch.py +3 -3
- pvlib/tools.py +6 -5
- {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/METADATA +5 -3
- pvlib-0.12.0.dist-info/RECORD +75 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/WHEEL +1 -1
- pvlib/data/BIRD_08_16_2012.csv +0 -8761
- pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
- pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
- pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
- pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
- pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
- pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
- pvlib/data/CRN_with_problems.txt +0 -3
- pvlib/data/ET-M772BH550GL.PAN +0 -75
- pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
- pvlib/data/PVsyst_demo.csv +0 -10757
- pvlib/data/PVsyst_demo_model.csv +0 -3588
- pvlib/data/SRML-day-EUPO1801.txt +0 -1441
- pvlib/data/abq19056.dat +0 -6
- pvlib/data/bishop88_numerical_precision.csv +0 -101
- pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
- pvlib/data/bsrn-pay0616.dat.gz +0 -0
- pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
- pvlib/data/cams_mcclear_monthly.csv +0 -42
- pvlib/data/cams_radiation_1min_verbose.csv +0 -72
- pvlib/data/cams_radiation_monthly.csv +0 -47
- pvlib/data/detect_clearsky_data.csv +0 -35
- pvlib/data/detect_clearsky_threshold_data.csv +0 -126
- pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
- pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
- pvlib/data/inverter_fit_snl_meas.csv +0 -127
- pvlib/data/inverter_fit_snl_sim.csv +0 -19
- pvlib/data/ivtools_numdiff.csv +0 -52
- pvlib/data/midc_20181014.txt +0 -1441
- pvlib/data/midc_raw_20181018.txt +0 -1441
- pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
- pvlib/data/msn19056.dat +0 -6
- pvlib/data/precise_iv_curves1.json +0 -10251
- pvlib/data/precise_iv_curves2.json +0 -10251
- pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
- pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
- pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
- pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
- pvlib/data/pvgis_tmy_meta.json +0 -32
- pvlib/data/pvgis_tmy_test.csv +0 -8761
- pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
- pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
- pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
- pvlib/data/spectrl2_example_spectra.csv +0 -123
- pvlib/data/surfrad-slv16001.dat +0 -1442
- pvlib/data/test_psm3_2017.csv +0 -17521
- pvlib/data/test_psm3_2019_5min.csv +0 -289
- pvlib/data/test_psm3_tmy-2017.csv +0 -8761
- pvlib/data/test_read_psm3.csv +0 -17523
- pvlib/data/test_read_pvgis_horizon.csv +0 -49
- pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
- pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
- pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
- pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
- pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
- pvlib/spa_c_files/README.md +0 -81
- pvlib/spa_c_files/cspa_py.pxd +0 -43
- pvlib/spa_c_files/spa_py.pyx +0 -30
- pvlib/tests/__init__.py +0 -0
- pvlib/tests/bifacial/__init__.py +0 -0
- pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
- pvlib/tests/bifacial/test_losses_models.py +0 -54
- pvlib/tests/bifacial/test_pvfactors.py +0 -82
- pvlib/tests/bifacial/test_utils.py +0 -192
- pvlib/tests/conftest.py +0 -476
- pvlib/tests/iotools/__init__.py +0 -0
- pvlib/tests/iotools/test_acis.py +0 -213
- pvlib/tests/iotools/test_bsrn.py +0 -131
- pvlib/tests/iotools/test_crn.py +0 -95
- pvlib/tests/iotools/test_epw.py +0 -23
- pvlib/tests/iotools/test_midc.py +0 -89
- pvlib/tests/iotools/test_panond.py +0 -32
- pvlib/tests/iotools/test_psm3.py +0 -198
- pvlib/tests/iotools/test_pvgis.py +0 -644
- pvlib/tests/iotools/test_sodapro.py +0 -298
- pvlib/tests/iotools/test_solaranywhere.py +0 -287
- pvlib/tests/iotools/test_solargis.py +0 -68
- pvlib/tests/iotools/test_solcast.py +0 -324
- pvlib/tests/iotools/test_solrad.py +0 -152
- pvlib/tests/iotools/test_srml.py +0 -124
- pvlib/tests/iotools/test_surfrad.py +0 -75
- pvlib/tests/iotools/test_tmy.py +0 -133
- pvlib/tests/ivtools/__init__.py +0 -0
- pvlib/tests/ivtools/test_sde.py +0 -230
- pvlib/tests/ivtools/test_sdm.py +0 -429
- pvlib/tests/ivtools/test_utils.py +0 -173
- pvlib/tests/spectrum/__init__.py +0 -0
- pvlib/tests/spectrum/conftest.py +0 -40
- pvlib/tests/spectrum/test_irradiance.py +0 -138
- pvlib/tests/spectrum/test_mismatch.py +0 -304
- pvlib/tests/spectrum/test_response.py +0 -124
- pvlib/tests/spectrum/test_spectrl2.py +0 -72
- pvlib/tests/test__deprecation.py +0 -97
- pvlib/tests/test_albedo.py +0 -84
- pvlib/tests/test_atmosphere.py +0 -351
- pvlib/tests/test_clearsky.py +0 -884
- pvlib/tests/test_conftest.py +0 -37
- pvlib/tests/test_iam.py +0 -555
- pvlib/tests/test_inverter.py +0 -213
- pvlib/tests/test_irradiance.py +0 -1487
- pvlib/tests/test_location.py +0 -356
- pvlib/tests/test_modelchain.py +0 -2020
- pvlib/tests/test_numerical_precision.py +0 -124
- pvlib/tests/test_pvarray.py +0 -71
- pvlib/tests/test_pvsystem.py +0 -2511
- pvlib/tests/test_scaling.py +0 -207
- pvlib/tests/test_shading.py +0 -391
- pvlib/tests/test_singlediode.py +0 -608
- pvlib/tests/test_snow.py +0 -212
- pvlib/tests/test_soiling.py +0 -230
- pvlib/tests/test_solarposition.py +0 -966
- pvlib/tests/test_spa.py +0 -454
- pvlib/tests/test_temperature.py +0 -470
- pvlib/tests/test_tools.py +0 -146
- pvlib/tests/test_tracking.py +0 -474
- pvlib/tests/test_transformer.py +0 -60
- pvlib-0.11.2.dist-info/RECORD +0 -191
- {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
pvlib/__init__.py
CHANGED
pvlib/atmosphere.py
CHANGED
|
@@ -6,9 +6,6 @@ speed at different heights.
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
9
|
-
import pvlib
|
|
10
|
-
|
|
11
|
-
from pvlib._deprecation import deprecated
|
|
12
9
|
|
|
13
10
|
APPARENT_ZENITH_MODELS = ('simple', 'kasten1966', 'kastenyoung1989',
|
|
14
11
|
'gueymard1993', 'pickering2002')
|
|
@@ -416,12 +413,6 @@ def tdew_from_rh(temp_air, relative_humidity, coeff=(6.112, 17.62, 243.12)):
|
|
|
416
413
|
return dewpoint
|
|
417
414
|
|
|
418
415
|
|
|
419
|
-
first_solar_spectral_correction = deprecated(
|
|
420
|
-
since='0.10.0',
|
|
421
|
-
alternative='pvlib.spectrum.spectral_factor_firstsolar'
|
|
422
|
-
)(pvlib.spectrum.spectral_factor_firstsolar)
|
|
423
|
-
|
|
424
|
-
|
|
425
416
|
def bird_hulstrom80_aod_bb(aod380, aod500):
|
|
426
417
|
"""
|
|
427
418
|
Approximate broadband aerosol optical depth.
|
pvlib/bifacial/infinite_sheds.py
CHANGED
|
@@ -260,8 +260,9 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
|
|
|
260
260
|
Returns
|
|
261
261
|
-------
|
|
262
262
|
output : dict or DataFrame
|
|
263
|
-
Output is a DataFrame when
|
|
264
|
-
|
|
263
|
+
Output is a ``pandas.DataFrame`` when ``ghi`` is a Series.
|
|
264
|
+
Otherwise it is a dict of ``numpy.ndarray``
|
|
265
|
+
See Notes for descriptions of content.
|
|
265
266
|
|
|
266
267
|
Notes
|
|
267
268
|
-----
|
|
@@ -372,7 +373,7 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
|
|
|
372
373
|
'poa_global': poa_global, 'poa_direct': poa_direct,
|
|
373
374
|
'poa_diffuse': poa_diffuse, 'poa_ground_diffuse': poa_gnd_pv,
|
|
374
375
|
'poa_sky_diffuse': poa_sky_pv, 'shaded_fraction': f_x}
|
|
375
|
-
if isinstance(
|
|
376
|
+
if isinstance(ghi, pd.Series):
|
|
376
377
|
output = pd.DataFrame(output)
|
|
377
378
|
return output
|
|
378
379
|
|
pvlib/bifacial/utils.py
CHANGED
|
@@ -87,7 +87,8 @@ def _unshaded_ground_fraction(surface_tilt, surface_azimuth, solar_zenith,
|
|
|
87
87
|
surface_azimuth)
|
|
88
88
|
f_gnd_beam = 1.0 - np.minimum(
|
|
89
89
|
1.0, gcr * np.abs(cosd(surface_tilt) + sind(surface_tilt) * tan_phi))
|
|
90
|
-
|
|
90
|
+
# [1], Eq. 4
|
|
91
|
+
f_gnd_beam = np.where(solar_zenith > max_zenith, 0., f_gnd_beam)
|
|
91
92
|
return f_gnd_beam # 1 - min(1, abs()) < 1 always
|
|
92
93
|
|
|
93
94
|
|
pvlib/iotools/psm3.py
CHANGED
|
@@ -49,7 +49,7 @@ REQUEST_VARIABLE_MAP = {
|
|
|
49
49
|
'ghi_clear': 'clearsky_ghi',
|
|
50
50
|
'dhi_clear': 'clearsky_dhi',
|
|
51
51
|
'dni_clear': 'clearsky_dni',
|
|
52
|
-
'
|
|
52
|
+
'solar_zenith': 'solar_zenith_angle',
|
|
53
53
|
'temp_air': 'air_temperature',
|
|
54
54
|
'temp_dew': 'dew_point',
|
|
55
55
|
'relative_humidity': 'relative_humidity',
|
pvlib/iotools/pvgis.py
CHANGED
|
@@ -559,9 +559,17 @@ def _parse_pvgis_tmy_csv(src):
|
|
|
559
559
|
inputs['longitude'] = float(src.readline().split(b':')[1])
|
|
560
560
|
# Elevation (m): 1389.0\r\n
|
|
561
561
|
inputs['elevation'] = float(src.readline().split(b':')[1])
|
|
562
|
+
|
|
563
|
+
# TMY has an extra line here: Irradiance Time Offset (h): 0.1761\r\n
|
|
564
|
+
line = src.readline()
|
|
565
|
+
if line.startswith(b'Irradiance Time Offset'):
|
|
566
|
+
inputs['irradiance time offset'] = float(line.split(b':')[1])
|
|
567
|
+
src.readline() # skip over the "month,year\r\n"
|
|
568
|
+
else:
|
|
569
|
+
# `line` is already the "month,year\r\n" line, so nothing to do
|
|
570
|
+
pass
|
|
562
571
|
# then there's a 13 row comma separated table with two columns: month, year
|
|
563
|
-
# which contains the year used for that month in the
|
|
564
|
-
src.readline() # get "month,year\r\n"
|
|
572
|
+
# which contains the year used for that month in the TMY
|
|
565
573
|
months_selected = []
|
|
566
574
|
for month in range(12):
|
|
567
575
|
months_selected.append(
|
pvlib/iotools/tmy.py
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import datetime
|
|
4
4
|
import re
|
|
5
5
|
import pandas as pd
|
|
6
|
-
import warnings
|
|
7
|
-
from pvlib._deprecation import pvlibDeprecationWarning
|
|
8
6
|
|
|
9
7
|
# Dictionary mapping TMY3 names to pvlib names
|
|
10
8
|
VARIABLE_MAP = {
|
|
@@ -24,8 +22,7 @@ VARIABLE_MAP = {
|
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
|
|
27
|
-
def read_tmy3(filename, coerce_year=None, map_variables=
|
|
28
|
-
encoding=None):
|
|
25
|
+
def read_tmy3(filename, coerce_year=None, map_variables=True, encoding=None):
|
|
29
26
|
"""Read a TMY3 file into a pandas dataframe.
|
|
30
27
|
|
|
31
28
|
Note that values contained in the metadata dictionary are unchanged
|
|
@@ -44,13 +41,9 @@ def read_tmy3(filename, coerce_year=None, map_variables=None, recolumn=None,
|
|
|
44
41
|
If supplied, the year of the index will be set to ``coerce_year``, except
|
|
45
42
|
for the last index value which will be set to the *next* year so that
|
|
46
43
|
the index increases monotonically.
|
|
47
|
-
map_variables : bool,
|
|
44
|
+
map_variables : bool, default True
|
|
48
45
|
When True, renames columns of the DataFrame to pvlib variable names
|
|
49
46
|
where applicable. See variable :const:`VARIABLE_MAP`.
|
|
50
|
-
recolumn : bool (deprecated, use map_variables instead)
|
|
51
|
-
If ``True``, apply standard names to TMY3 columns. Typically this
|
|
52
|
-
results in stripping the units from the column name.
|
|
53
|
-
Cannot be used in combination with ``map_variables``.
|
|
54
47
|
encoding : str, optional
|
|
55
48
|
Encoding of the file. For files that contain non-UTF8 characters it may
|
|
56
49
|
be necessary to specify an alternative encoding, e.g., for
|
|
@@ -233,74 +226,15 @@ def read_tmy3(filename, coerce_year=None, map_variables=None, recolumn=None,
|
|
|
233
226
|
# unit must be in (D,h,m,s,ms,us,ns), but pandas>=0.24 allows unit='hour'
|
|
234
227
|
data.index = data_ymd + pd.to_timedelta(shifted_hour, unit='h') \
|
|
235
228
|
+ pd.to_timedelta(minutes, unit='min')
|
|
236
|
-
|
|
237
|
-
if recolumn is not None and map_variables is not None:
|
|
238
|
-
msg = "`map_variables` and `recolumn` cannot both be specified"
|
|
239
|
-
raise ValueError(msg)
|
|
240
|
-
elif map_variables is None and recolumn is not None:
|
|
241
|
-
warnings.warn(
|
|
242
|
-
'The recolumn parameter is deprecated and will be removed in '
|
|
243
|
-
'pvlib 0.11.0. Use `map_variables` instead, although note that '
|
|
244
|
-
'its behavior is different from `recolumn`.',
|
|
245
|
-
pvlibDeprecationWarning)
|
|
246
|
-
elif map_variables is None and recolumn is None:
|
|
247
|
-
warnings.warn(
|
|
248
|
-
'TMY3 variable names will be renamed to pvlib conventions by '
|
|
249
|
-
'default starting in pvlib 0.11.0. Specify map_variables=True '
|
|
250
|
-
'to enable that behavior now, or specify map_variables=False '
|
|
251
|
-
'to hide this warning.', pvlibDeprecationWarning)
|
|
229
|
+
|
|
252
230
|
if map_variables:
|
|
253
231
|
data = data.rename(columns=VARIABLE_MAP)
|
|
254
|
-
elif recolumn or (recolumn is None and map_variables is None):
|
|
255
|
-
data = _recolumn(data)
|
|
256
232
|
|
|
257
233
|
data = data.tz_localize(int(meta['TZ'] * 3600))
|
|
258
234
|
|
|
259
235
|
return data, meta
|
|
260
236
|
|
|
261
237
|
|
|
262
|
-
def _recolumn(tmy3_dataframe):
|
|
263
|
-
"""
|
|
264
|
-
Rename the columns of the TMY3 DataFrame.
|
|
265
|
-
|
|
266
|
-
Parameters
|
|
267
|
-
----------
|
|
268
|
-
tmy3_dataframe : DataFrame
|
|
269
|
-
inplace : bool
|
|
270
|
-
passed to DataFrame.rename()
|
|
271
|
-
|
|
272
|
-
Returns
|
|
273
|
-
-------
|
|
274
|
-
Recolumned DataFrame.
|
|
275
|
-
"""
|
|
276
|
-
# paste in the header as one long line
|
|
277
|
-
raw_columns = 'ETR (W/m^2),ETRN (W/m^2),GHI (W/m^2),GHI source,GHI uncert (%),DNI (W/m^2),DNI source,DNI uncert (%),DHI (W/m^2),DHI source,DHI uncert (%),GH illum (lx),GH illum source,Global illum uncert (%),DN illum (lx),DN illum source,DN illum uncert (%),DH illum (lx),DH illum source,DH illum uncert (%),Zenith lum (cd/m^2),Zenith lum source,Zenith lum uncert (%),TotCld (tenths),TotCld source,TotCld uncert (code),OpqCld (tenths),OpqCld source,OpqCld uncert (code),Dry-bulb (C),Dry-bulb source,Dry-bulb uncert (code),Dew-point (C),Dew-point source,Dew-point uncert (code),RHum (%),RHum source,RHum uncert (code),Pressure (mbar),Pressure source,Pressure uncert (code),Wdir (degrees),Wdir source,Wdir uncert (code),Wspd (m/s),Wspd source,Wspd uncert (code),Hvis (m),Hvis source,Hvis uncert (code),CeilHgt (m),CeilHgt source,CeilHgt uncert (code),Pwat (cm),Pwat source,Pwat uncert (code),AOD (unitless),AOD source,AOD uncert (code),Alb (unitless),Alb source,Alb uncert (code),Lprecip depth (mm),Lprecip quantity (hr),Lprecip source,Lprecip uncert (code),PresWth (METAR code),PresWth source,PresWth uncert (code)' # noqa: E501
|
|
278
|
-
|
|
279
|
-
new_columns = [
|
|
280
|
-
'ETR', 'ETRN', 'GHI', 'GHISource', 'GHIUncertainty',
|
|
281
|
-
'DNI', 'DNISource', 'DNIUncertainty', 'DHI', 'DHISource',
|
|
282
|
-
'DHIUncertainty', 'GHillum', 'GHillumSource', 'GHillumUncertainty',
|
|
283
|
-
'DNillum', 'DNillumSource', 'DNillumUncertainty', 'DHillum',
|
|
284
|
-
'DHillumSource', 'DHillumUncertainty', 'Zenithlum',
|
|
285
|
-
'ZenithlumSource', 'ZenithlumUncertainty', 'TotCld', 'TotCldSource',
|
|
286
|
-
'TotCldUncertainty', 'OpqCld', 'OpqCldSource', 'OpqCldUncertainty',
|
|
287
|
-
'DryBulb', 'DryBulbSource', 'DryBulbUncertainty', 'DewPoint',
|
|
288
|
-
'DewPointSource', 'DewPointUncertainty', 'RHum', 'RHumSource',
|
|
289
|
-
'RHumUncertainty', 'Pressure', 'PressureSource',
|
|
290
|
-
'PressureUncertainty', 'Wdir', 'WdirSource', 'WdirUncertainty',
|
|
291
|
-
'Wspd', 'WspdSource', 'WspdUncertainty', 'Hvis', 'HvisSource',
|
|
292
|
-
'HvisUncertainty', 'CeilHgt', 'CeilHgtSource', 'CeilHgtUncertainty',
|
|
293
|
-
'Pwat', 'PwatSource', 'PwatUncertainty', 'AOD', 'AODSource',
|
|
294
|
-
'AODUncertainty', 'Alb', 'AlbSource', 'AlbUncertainty',
|
|
295
|
-
'Lprecipdepth', 'Lprecipquantity', 'LprecipSource',
|
|
296
|
-
'LprecipUncertainty', 'PresWth', 'PresWthSource',
|
|
297
|
-
'PresWthUncertainty']
|
|
298
|
-
|
|
299
|
-
mapping = dict(zip(raw_columns.split(','), new_columns))
|
|
300
|
-
|
|
301
|
-
return tmy3_dataframe.rename(columns=mapping)
|
|
302
|
-
|
|
303
|
-
|
|
304
238
|
def read_tmy2(filename):
|
|
305
239
|
"""
|
|
306
240
|
Read a TMY2 file into a DataFrame.
|
pvlib/irradiance.py
CHANGED
|
@@ -2368,6 +2368,9 @@ def gti_dirint(poa_global, aoi, solar_zenith, solar_azimuth, times,
|
|
|
2368
2368
|
irradiance, Solar Energy 122, 1037-1046.
|
|
2369
2369
|
:doi:`10.1016/j.solener.2015.10.024`
|
|
2370
2370
|
"""
|
|
2371
|
+
# check input data and raise Exceptions where data will cause the
|
|
2372
|
+
# algorithm to fail
|
|
2373
|
+
_gti_dirint_check_input(aoi)
|
|
2371
2374
|
|
|
2372
2375
|
aoi_lt_90 = aoi < 90
|
|
2373
2376
|
|
|
@@ -2399,6 +2402,17 @@ def gti_dirint(poa_global, aoi, solar_zenith, solar_azimuth, times,
|
|
|
2399
2402
|
return output
|
|
2400
2403
|
|
|
2401
2404
|
|
|
2405
|
+
def _gti_dirint_check_input(aoi):
|
|
2406
|
+
r"""
|
|
2407
|
+
Helper for gti_dirint
|
|
2408
|
+
|
|
2409
|
+
Raises Exceptions from input data that cause the algorithm to fail.
|
|
2410
|
+
"""
|
|
2411
|
+
if not (aoi < 90).any():
|
|
2412
|
+
raise ValueError("There are no times with AOI < 90. "
|
|
2413
|
+
"gti_dirint requires some data with AOI < 90.")
|
|
2414
|
+
|
|
2415
|
+
|
|
2402
2416
|
def _gti_dirint_lt_90(poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth,
|
|
2403
2417
|
times, surface_tilt, surface_azimuth, pressure=101325.,
|
|
2404
2418
|
use_delta_kt_prime=True, temp_dew=None, albedo=.25,
|
pvlib/location.py
CHANGED
|
@@ -6,6 +6,7 @@ This module contains the Location class.
|
|
|
6
6
|
|
|
7
7
|
import pathlib
|
|
8
8
|
import datetime
|
|
9
|
+
import zoneinfo
|
|
9
10
|
|
|
10
11
|
import pandas as pd
|
|
11
12
|
import pytz
|
|
@@ -18,13 +19,16 @@ from pvlib.tools import _degrees_to_index
|
|
|
18
19
|
class Location:
|
|
19
20
|
"""
|
|
20
21
|
Location objects are convenient containers for latitude, longitude,
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
time zone, and altitude data associated with a particular geographic
|
|
23
|
+
location. You can also assign a name to a location object.
|
|
23
24
|
|
|
24
|
-
Location objects have two
|
|
25
|
+
Location objects have two time-zone attributes:
|
|
25
26
|
|
|
26
|
-
* ``tz`` is
|
|
27
|
-
* ``pytz`` is a pytz
|
|
27
|
+
* ``tz`` is an IANA time-zone string.
|
|
28
|
+
* ``pytz`` is a pytz-based time-zone object (read only).
|
|
29
|
+
|
|
30
|
+
The read-only ``pytz`` attribute will stay in sync with any changes made
|
|
31
|
+
using ``tz``.
|
|
28
32
|
|
|
29
33
|
Location objects support the print method.
|
|
30
34
|
|
|
@@ -38,12 +42,16 @@ class Location:
|
|
|
38
42
|
Positive is east of the prime meridian.
|
|
39
43
|
Use decimal degrees notation.
|
|
40
44
|
|
|
41
|
-
tz : str, int, float, or
|
|
42
|
-
See
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
tz : time zone as str, int, float, or datetime.tzinfo, default 'UTC'.
|
|
46
|
+
See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a
|
|
47
|
+
list of valid name strings. An `int` or `float` must be a whole-number
|
|
48
|
+
hour offsets from UTC that can be converted to the IANA-supported
|
|
49
|
+
'Etc/GMT-N' format. (Note the limited range of the offset N and its
|
|
50
|
+
sign-change convention.) Time zones from the pytz and zoneinfo packages
|
|
51
|
+
may also be passed here, as they are subclasses of datetime.tzinfo.
|
|
52
|
+
|
|
53
|
+
The `tz` attribute is represented as a valid IANA time zone name
|
|
54
|
+
string.
|
|
47
55
|
|
|
48
56
|
altitude : float, optional
|
|
49
57
|
Altitude from sea level in meters.
|
|
@@ -54,43 +62,75 @@ class Location:
|
|
|
54
62
|
name : string, optional
|
|
55
63
|
Sets the name attribute of the Location object.
|
|
56
64
|
|
|
65
|
+
Raises
|
|
66
|
+
------
|
|
67
|
+
ValueError
|
|
68
|
+
when the time zone ``tz`` cannot be converted.
|
|
69
|
+
|
|
70
|
+
zoneinfo.ZoneInfoNotFoundError
|
|
71
|
+
when the time zone ``tz`` is not recognizable as an IANA time zone by
|
|
72
|
+
the ``zoneinfo.ZoneInfo`` initializer used for internal time-zone
|
|
73
|
+
representation.
|
|
74
|
+
|
|
57
75
|
See also
|
|
58
76
|
--------
|
|
59
77
|
pvlib.pvsystem.PVSystem
|
|
60
78
|
"""
|
|
61
79
|
|
|
62
|
-
def __init__(
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
def __init__(
|
|
81
|
+
self, latitude, longitude, tz='UTC', altitude=None, name=None
|
|
82
|
+
):
|
|
65
83
|
self.latitude = latitude
|
|
66
84
|
self.longitude = longitude
|
|
67
|
-
|
|
68
|
-
if isinstance(tz, str):
|
|
69
|
-
self.tz = tz
|
|
70
|
-
self.pytz = pytz.timezone(tz)
|
|
71
|
-
elif isinstance(tz, datetime.timezone):
|
|
72
|
-
self.tz = 'UTC'
|
|
73
|
-
self.pytz = pytz.UTC
|
|
74
|
-
elif isinstance(tz, datetime.tzinfo):
|
|
75
|
-
self.tz = tz.zone
|
|
76
|
-
self.pytz = tz
|
|
77
|
-
elif isinstance(tz, (int, float)):
|
|
78
|
-
self.tz = tz
|
|
79
|
-
self.pytz = pytz.FixedOffset(tz*60)
|
|
80
|
-
else:
|
|
81
|
-
raise TypeError('Invalid tz specification')
|
|
85
|
+
self.tz = tz
|
|
82
86
|
|
|
83
87
|
if altitude is None:
|
|
84
88
|
altitude = lookup_altitude(latitude, longitude)
|
|
85
89
|
|
|
86
90
|
self.altitude = altitude
|
|
87
|
-
|
|
88
91
|
self.name = name
|
|
89
92
|
|
|
90
93
|
def __repr__(self):
|
|
91
94
|
attrs = ['name', 'latitude', 'longitude', 'altitude', 'tz']
|
|
95
|
+
# Use None as getattr default in case __repr__ is called during
|
|
96
|
+
# initialization before all attributes have been assigned.
|
|
92
97
|
return ('Location: \n ' + '\n '.join(
|
|
93
|
-
f'{attr}: {getattr(self, attr)}' for attr in attrs))
|
|
98
|
+
f'{attr}: {getattr(self, attr, None)}' for attr in attrs))
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def tz(self):
|
|
102
|
+
"""The location's IANA time-zone string."""
|
|
103
|
+
return str(self._zoneinfo)
|
|
104
|
+
|
|
105
|
+
@tz.setter
|
|
106
|
+
def tz(self, tz_):
|
|
107
|
+
# self._zoneinfo holds single source of time-zone truth as IANA name.
|
|
108
|
+
if isinstance(tz_, str):
|
|
109
|
+
self._zoneinfo = zoneinfo.ZoneInfo(tz_)
|
|
110
|
+
elif isinstance(tz_, int):
|
|
111
|
+
self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-tz_:+d}")
|
|
112
|
+
elif isinstance(tz_, float):
|
|
113
|
+
if tz_ % 1 != 0:
|
|
114
|
+
raise TypeError(
|
|
115
|
+
"Floating-point tz has non-zero fractional part: "
|
|
116
|
+
f"{tz_}. Only whole-number offsets are supported."
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-int(tz_):+d}")
|
|
120
|
+
elif isinstance(tz_, datetime.tzinfo):
|
|
121
|
+
# Includes time zones generated by pytz and zoneinfo packages.
|
|
122
|
+
self._zoneinfo = zoneinfo.ZoneInfo(str(tz_))
|
|
123
|
+
else:
|
|
124
|
+
raise TypeError(
|
|
125
|
+
f"invalid tz specification: {tz_}, must be an IANA time zone "
|
|
126
|
+
"string, a whole-number int/float UTC offset, or a "
|
|
127
|
+
"datetime.tzinfo object (including subclasses)"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def pytz(self):
|
|
132
|
+
"""The location's pytz time zone (read only)."""
|
|
133
|
+
return pytz.timezone(str(self._zoneinfo))
|
|
94
134
|
|
|
95
135
|
@classmethod
|
|
96
136
|
def from_tmy(cls, tmy_metadata, tmy_data=None, **kwargs):
|
|
@@ -328,7 +368,7 @@ class Location:
|
|
|
328
368
|
|
|
329
369
|
return airmass
|
|
330
370
|
|
|
331
|
-
def get_sun_rise_set_transit(self, times, method='
|
|
371
|
+
def get_sun_rise_set_transit(self, times, method='spa', **kwargs):
|
|
332
372
|
"""
|
|
333
373
|
Calculate sunrise, sunset and transit times.
|
|
334
374
|
|
|
@@ -336,7 +376,7 @@ class Location:
|
|
|
336
376
|
----------
|
|
337
377
|
times : DatetimeIndex
|
|
338
378
|
Must be localized to the Location
|
|
339
|
-
method : str, default '
|
|
379
|
+
method : str, default 'spa'
|
|
340
380
|
'pyephem', 'spa', or 'geometric'
|
|
341
381
|
|
|
342
382
|
kwargs :
|
pvlib/modelchain.py
CHANGED
|
@@ -29,7 +29,7 @@ POA_KEYS = ('poa_global', 'poa_direct', 'poa_diffuse')
|
|
|
29
29
|
|
|
30
30
|
# Optional keys to communicate temperature data. If provided,
|
|
31
31
|
# 'cell_temperature' overrides ModelChain.temperature_model and sets
|
|
32
|
-
# ModelChain.cell_temperature to the data. If 'module_temperature' is
|
|
32
|
+
# ModelChain.cell_temperature to the data. If 'module_temperature' is provided,
|
|
33
33
|
# overrides ModelChain.temperature_model with
|
|
34
34
|
# pvlib.temperature.sapm_celL_from_module
|
|
35
35
|
TEMPERATURE_KEYS = ('module_temperature', 'cell_temperature')
|
|
@@ -253,7 +253,7 @@ class ModelChainResult:
|
|
|
253
253
|
def _head(obj):
|
|
254
254
|
try:
|
|
255
255
|
return obj[:3]
|
|
256
|
-
except:
|
|
256
|
+
except Exception:
|
|
257
257
|
return obj
|
|
258
258
|
|
|
259
259
|
if type(self.dc) is tuple:
|
|
@@ -269,7 +269,7 @@ class ModelChainResult:
|
|
|
269
269
|
'\n')
|
|
270
270
|
lines = []
|
|
271
271
|
for attr in mc_attrs:
|
|
272
|
-
if not (attr.startswith('_') or attr=='times'):
|
|
272
|
+
if not (attr.startswith('_') or attr == 'times'):
|
|
273
273
|
lines.append(f' {attr}: ' + _mcr_repr(getattr(self, attr)))
|
|
274
274
|
desc4 = '\n'.join(lines)
|
|
275
275
|
return (desc1 + desc2 + desc3 + desc4)
|
|
@@ -330,12 +330,15 @@ class ModelChain:
|
|
|
330
330
|
'interp' and 'no_loss'. The ModelChain instance will be passed as the
|
|
331
331
|
first argument to a user-defined function.
|
|
332
332
|
|
|
333
|
-
spectral_model : str
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
333
|
+
spectral_model : str or function, optional
|
|
334
|
+
Valid strings are:
|
|
335
|
+
|
|
336
|
+
- ``'sapm'``
|
|
337
|
+
- ``'first_solar'``
|
|
338
|
+
- ``'no_loss'``
|
|
339
|
+
|
|
337
340
|
The ModelChain instance will be passed as the first argument to
|
|
338
|
-
a user-defined function.
|
|
341
|
+
a user-defined function. If not specified, ``'no_loss'`` is assumed.
|
|
339
342
|
|
|
340
343
|
temperature_model : str or function, optional
|
|
341
344
|
Valid strings are: 'sapm', 'pvsyst', 'faiman', 'fuentes', 'noct_sam'.
|
|
@@ -386,7 +389,6 @@ class ModelChain:
|
|
|
386
389
|
|
|
387
390
|
self.results = ModelChainResult()
|
|
388
391
|
|
|
389
|
-
|
|
390
392
|
@classmethod
|
|
391
393
|
def with_pvwatts(cls, system, location,
|
|
392
394
|
clearsky_model='ineichen',
|
|
@@ -855,9 +857,7 @@ class ModelChain:
|
|
|
855
857
|
|
|
856
858
|
@spectral_model.setter
|
|
857
859
|
def spectral_model(self, model):
|
|
858
|
-
if model
|
|
859
|
-
self._spectral_model = self.infer_spectral_model()
|
|
860
|
-
elif isinstance(model, str):
|
|
860
|
+
if isinstance(model, str):
|
|
861
861
|
model = model.lower()
|
|
862
862
|
if model == 'first_solar':
|
|
863
863
|
self._spectral_model = self.first_solar_spectral_loss
|
|
@@ -867,30 +867,12 @@ class ModelChain:
|
|
|
867
867
|
self._spectral_model = self.no_spectral_loss
|
|
868
868
|
else:
|
|
869
869
|
raise ValueError(model + ' is not a valid spectral loss model')
|
|
870
|
-
|
|
870
|
+
elif model is None:
|
|
871
|
+
# not setting a model is equivalent to setting no_loss
|
|
872
|
+
self._spectral_model = self.no_spectral_loss
|
|
873
|
+
else: # assume model is callable with 1st argument = the MC instance
|
|
871
874
|
self._spectral_model = partial(model, self)
|
|
872
875
|
|
|
873
|
-
def infer_spectral_model(self):
|
|
874
|
-
"""Infer spectral model from system attributes."""
|
|
875
|
-
module_parameters = tuple(
|
|
876
|
-
array.module_parameters for array in self.system.arrays)
|
|
877
|
-
params = _common_keys(module_parameters)
|
|
878
|
-
if {'A4', 'A3', 'A2', 'A1', 'A0'} <= params:
|
|
879
|
-
return self.sapm_spectral_loss
|
|
880
|
-
elif ((('Technology' in params or
|
|
881
|
-
'Material' in params) and
|
|
882
|
-
(self.system._infer_cell_type() is not None)) or
|
|
883
|
-
'first_solar_spectral_coefficients' in params):
|
|
884
|
-
return self.first_solar_spectral_loss
|
|
885
|
-
else:
|
|
886
|
-
raise ValueError('could not infer spectral model from '
|
|
887
|
-
'system.arrays[i].module_parameters. Check that '
|
|
888
|
-
'the module_parameters for all Arrays in '
|
|
889
|
-
'system.arrays contain valid '
|
|
890
|
-
'first_solar_spectral_coefficients, a valid '
|
|
891
|
-
'Material or Technology value, or set '
|
|
892
|
-
'spectral_model="no_loss".')
|
|
893
|
-
|
|
894
876
|
def first_solar_spectral_loss(self):
|
|
895
877
|
self.results.spectral_modifier = self.system.first_solar_spectral_loss(
|
|
896
878
|
_tuple_from_dfs(self.results.weather, 'precipitable_water'),
|
|
@@ -1570,7 +1552,7 @@ class ModelChain:
|
|
|
1570
1552
|
----------
|
|
1571
1553
|
data : DataFrame
|
|
1572
1554
|
May contain columns ``'cell_temperature'`` or
|
|
1573
|
-
``'
|
|
1555
|
+
``'module_temperature'``.
|
|
1574
1556
|
|
|
1575
1557
|
Returns
|
|
1576
1558
|
-------
|
|
@@ -1679,6 +1661,7 @@ class ModelChain:
|
|
|
1679
1661
|
self.prepare_inputs(weather)
|
|
1680
1662
|
self.aoi_model()
|
|
1681
1663
|
self.spectral_model()
|
|
1664
|
+
|
|
1682
1665
|
self.effective_irradiance_model()
|
|
1683
1666
|
|
|
1684
1667
|
self._run_from_effective_irrad(weather)
|
pvlib/pvsystem.py
CHANGED
|
@@ -29,11 +29,10 @@ import pvlib.tools as tools
|
|
|
29
29
|
# a dict of required parameter names for each DC power model
|
|
30
30
|
_DC_MODEL_PARAMS = {
|
|
31
31
|
'sapm': {
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'C7', 'Isco', 'Impo', 'Voco', 'Vmpo', 'Aisc', 'Aimp', 'Bvoco',
|
|
32
|
+
'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7',
|
|
33
|
+
'Isco', 'Impo', 'Voco', 'Vmpo', 'Aisc', 'Aimp', 'Bvoco',
|
|
35
34
|
'Mbvoc', 'Bvmpo', 'Mbvmp', 'N', 'Cells_in_Series',
|
|
36
|
-
'IXO', 'IXXO'
|
|
35
|
+
'IXO', 'IXXO'},
|
|
37
36
|
'desoto': {
|
|
38
37
|
'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
|
|
39
38
|
'R_sh_ref', 'R_s'},
|
|
@@ -1710,6 +1709,8 @@ def calcparams_desoto(effective_irradiance, temp_cell,
|
|
|
1710
1709
|
Rs = R_s
|
|
1711
1710
|
|
|
1712
1711
|
numeric_args = (effective_irradiance, temp_cell)
|
|
1712
|
+
# IL: photocurrent, I0: saturation_current, Rs: resistance_series,
|
|
1713
|
+
# Rsh: resistance_shunt
|
|
1713
1714
|
out = (IL, I0, Rs, Rsh, nNsVth)
|
|
1714
1715
|
|
|
1715
1716
|
if all(map(np.isscalar, numeric_args)):
|
|
@@ -1976,6 +1977,8 @@ def calcparams_pvsyst(effective_irradiance, temp_cell,
|
|
|
1976
1977
|
Rs = R_s
|
|
1977
1978
|
|
|
1978
1979
|
numeric_args = (effective_irradiance, temp_cell)
|
|
1980
|
+
# IL: photocurrent, I0: saturation_current, Rs: resistance_series,
|
|
1981
|
+
# Rsh: resistance_shunt
|
|
1979
1982
|
out = (IL, I0, Rs, Rsh, nNsVth)
|
|
1980
1983
|
|
|
1981
1984
|
if all(map(np.isscalar, numeric_args)):
|
|
@@ -2311,12 +2314,6 @@ def sapm(effective_irradiance, temp_cell, module):
|
|
|
2311
2314
|
return out
|
|
2312
2315
|
|
|
2313
2316
|
|
|
2314
|
-
sapm_spectral_loss = deprecated(
|
|
2315
|
-
since='0.10.0',
|
|
2316
|
-
alternative='pvlib.spectrum.spectral_factor_sapm'
|
|
2317
|
-
)(spectrum.spectral_factor_sapm)
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
2317
|
def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,
|
|
2321
2318
|
module):
|
|
2322
2319
|
r"""
|