pvlib 0.11.1__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.
Files changed (149) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/_deprecation.py +73 -0
  3. pvlib/atmosphere.py +77 -7
  4. pvlib/bifacial/infinite_sheds.py +4 -3
  5. pvlib/bifacial/utils.py +2 -1
  6. pvlib/clearsky.py +35 -22
  7. pvlib/iam.py +4 -4
  8. pvlib/iotools/midc.py +1 -1
  9. pvlib/iotools/psm3.py +1 -1
  10. pvlib/iotools/pvgis.py +10 -12
  11. pvlib/iotools/tmy.py +3 -69
  12. pvlib/irradiance.py +112 -55
  13. pvlib/ivtools/sdm.py +75 -52
  14. pvlib/location.py +73 -33
  15. pvlib/modelchain.py +18 -35
  16. pvlib/pvsystem.py +139 -94
  17. pvlib/snow.py +64 -28
  18. pvlib/solarposition.py +46 -30
  19. pvlib/spa.py +4 -2
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/spectrum/spectrl2.py +2 -1
  24. pvlib/temperature.py +49 -3
  25. pvlib/tools.py +6 -5
  26. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/METADATA +14 -11
  27. pvlib-0.12.0.dist-info/RECORD +75 -0
  28. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/WHEEL +1 -1
  29. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  30. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  31. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  32. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  33. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  34. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  35. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  36. pvlib/data/CRN_with_problems.txt +0 -3
  37. pvlib/data/ET-M772BH550GL.PAN +0 -75
  38. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  39. pvlib/data/PVsyst_demo.csv +0 -10757
  40. pvlib/data/PVsyst_demo_model.csv +0 -3588
  41. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  42. pvlib/data/abq19056.dat +0 -6
  43. pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
  44. pvlib/data/bishop88_numerical_precision.csv +0 -101
  45. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  46. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  47. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  48. pvlib/data/cams_mcclear_monthly.csv +0 -42
  49. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  50. pvlib/data/cams_radiation_monthly.csv +0 -47
  51. pvlib/data/detect_clearsky_data.csv +0 -35
  52. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  53. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  54. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  55. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  56. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  57. pvlib/data/ivtools_numdiff.csv +0 -52
  58. pvlib/data/midc_20181014.txt +0 -1441
  59. pvlib/data/midc_raw_20181018.txt +0 -1441
  60. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  61. pvlib/data/msn19056.dat +0 -6
  62. pvlib/data/precise_iv_curves1.json +0 -10251
  63. pvlib/data/precise_iv_curves2.json +0 -10251
  64. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  65. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  66. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  67. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  68. pvlib/data/pvgis_tmy_meta.json +0 -32
  69. pvlib/data/pvgis_tmy_test.dat +0 -8761
  70. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  71. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  72. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  73. pvlib/data/spectrl2_example_spectra.csv +0 -123
  74. pvlib/data/surfrad-slv16001.dat +0 -1442
  75. pvlib/data/test_psm3_2017.csv +0 -17521
  76. pvlib/data/test_psm3_2019_5min.csv +0 -289
  77. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  78. pvlib/data/test_read_psm3.csv +0 -17523
  79. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  80. pvlib/data/tmy_45.000_8.000_2005_2020.csv +0 -8789
  81. pvlib/data/tmy_45.000_8.000_2005_2020.epw +0 -8768
  82. pvlib/data/tmy_45.000_8.000_2005_2020.json +0 -1
  83. pvlib/data/tmy_45.000_8.000_2005_2020.txt +0 -8761
  84. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  85. pvlib/data/variables_style_rules.csv +0 -56
  86. pvlib/spa_c_files/README.md +0 -81
  87. pvlib/spa_c_files/cspa_py.pxd +0 -43
  88. pvlib/spa_c_files/spa_py.pyx +0 -30
  89. pvlib/tests/__init__.py +0 -0
  90. pvlib/tests/bifacial/__init__.py +0 -0
  91. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  92. pvlib/tests/bifacial/test_losses_models.py +0 -54
  93. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  94. pvlib/tests/bifacial/test_utils.py +0 -192
  95. pvlib/tests/conftest.py +0 -476
  96. pvlib/tests/iotools/__init__.py +0 -0
  97. pvlib/tests/iotools/test_acis.py +0 -213
  98. pvlib/tests/iotools/test_bsrn.py +0 -131
  99. pvlib/tests/iotools/test_crn.py +0 -95
  100. pvlib/tests/iotools/test_epw.py +0 -23
  101. pvlib/tests/iotools/test_midc.py +0 -89
  102. pvlib/tests/iotools/test_panond.py +0 -32
  103. pvlib/tests/iotools/test_psm3.py +0 -198
  104. pvlib/tests/iotools/test_pvgis.py +0 -644
  105. pvlib/tests/iotools/test_sodapro.py +0 -298
  106. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  107. pvlib/tests/iotools/test_solargis.py +0 -68
  108. pvlib/tests/iotools/test_solcast.py +0 -324
  109. pvlib/tests/iotools/test_solrad.py +0 -152
  110. pvlib/tests/iotools/test_srml.py +0 -124
  111. pvlib/tests/iotools/test_surfrad.py +0 -75
  112. pvlib/tests/iotools/test_tmy.py +0 -133
  113. pvlib/tests/ivtools/__init__.py +0 -0
  114. pvlib/tests/ivtools/test_sde.py +0 -230
  115. pvlib/tests/ivtools/test_sdm.py +0 -407
  116. pvlib/tests/ivtools/test_utils.py +0 -173
  117. pvlib/tests/spectrum/__init__.py +0 -0
  118. pvlib/tests/spectrum/conftest.py +0 -40
  119. pvlib/tests/spectrum/test_irradiance.py +0 -138
  120. pvlib/tests/spectrum/test_mismatch.py +0 -304
  121. pvlib/tests/spectrum/test_response.py +0 -124
  122. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  123. pvlib/tests/test_albedo.py +0 -84
  124. pvlib/tests/test_atmosphere.py +0 -204
  125. pvlib/tests/test_clearsky.py +0 -878
  126. pvlib/tests/test_conftest.py +0 -81
  127. pvlib/tests/test_iam.py +0 -555
  128. pvlib/tests/test_inverter.py +0 -213
  129. pvlib/tests/test_irradiance.py +0 -1441
  130. pvlib/tests/test_location.py +0 -356
  131. pvlib/tests/test_modelchain.py +0 -2020
  132. pvlib/tests/test_numerical_precision.py +0 -124
  133. pvlib/tests/test_pvarray.py +0 -71
  134. pvlib/tests/test_pvsystem.py +0 -2495
  135. pvlib/tests/test_scaling.py +0 -207
  136. pvlib/tests/test_shading.py +0 -391
  137. pvlib/tests/test_singlediode.py +0 -608
  138. pvlib/tests/test_snow.py +0 -212
  139. pvlib/tests/test_soiling.py +0 -230
  140. pvlib/tests/test_solarposition.py +0 -933
  141. pvlib/tests/test_spa.py +0 -425
  142. pvlib/tests/test_temperature.py +0 -470
  143. pvlib/tests/test_tools.py +0 -146
  144. pvlib/tests/test_tracking.py +0 -474
  145. pvlib/tests/test_transformer.py +0 -60
  146. pvlib-0.11.1.dist-info/RECORD +0 -192
  147. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
  148. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
  149. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
pvlib/pvsystem.py CHANGED
@@ -17,7 +17,7 @@ from dataclasses import dataclass
17
17
  from abc import ABC, abstractmethod
18
18
  from typing import Optional, Union
19
19
 
20
- from pvlib._deprecation import deprecated, warn_deprecated
20
+ from pvlib._deprecation import deprecated
21
21
 
22
22
  import pvlib # used to avoid albedo name collision in the Array class
23
23
  from pvlib import (atmosphere, iam, inverter, irradiance,
@@ -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
- 'A0', 'A1', 'A2', 'A3', 'A4', 'B0', 'B1', 'B2', 'B3',
33
- 'B4', 'B5', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6',
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', 'FD'},
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'},
@@ -104,22 +103,22 @@ class PVSystem:
104
103
  ----------
105
104
  arrays : Array or iterable of Array, optional
106
105
  An Array or list of arrays that are part of the system. If not
107
- specified a single array is created from the other parameters (e.g.
106
+ specified, a single array is created from the other parameters (e.g.
108
107
  `surface_tilt`, `surface_azimuth`). If specified as a list, the list
109
108
  must contain at least one Array;
110
109
  if length of arrays is 0 a ValueError is raised. If `arrays` is
111
110
  specified the following PVSystem parameters are ignored:
112
111
 
113
- - `surface_tilt`
114
- - `surface_azimuth`
115
- - `albedo`
116
- - `surface_type`
117
- - `module`
118
- - `module_type`
119
- - `module_parameters`
120
- - `temperature_model_parameters`
121
- - `modules_per_string`
122
- - `strings_per_inverter`
112
+ - ``surface_tilt``
113
+ - ``surface_azimuth``
114
+ - ``albedo``
115
+ - ``surface_type``
116
+ - ``module``
117
+ - ``module_type``
118
+ - ``module_parameters``
119
+ - ``temperature_model_parameters``
120
+ - ``modules_per_string``
121
+ - ``strings_per_inverter``
123
122
 
124
123
  surface_tilt: float or array-like, default 0
125
124
  Surface tilt angles in decimal degrees.
@@ -127,7 +126,7 @@ class PVSystem:
127
126
  (e.g. surface facing up = 0, surface facing horizon = 90)
128
127
 
129
128
  surface_azimuth: float or array-like, default 180
130
- Azimuth angle of the module surface.
129
+ Azimuth angle of the module surface in decimal degrees.
131
130
  North=0, East=90, South=180, West=270.
132
131
 
133
132
  albedo : float, optional
@@ -142,8 +141,6 @@ class PVSystem:
142
141
 
143
142
  module : string, optional
144
143
  The model name of the modules.
145
- May be used to look up the module_parameters dictionary
146
- via some other method.
147
144
 
148
145
  module_type : string, default 'glass_polymer'
149
146
  Describes the module's construction. Valid strings are 'glass_polymer'
@@ -154,7 +151,8 @@ class PVSystem:
154
151
 
155
152
  temperature_model_parameters : dict or Series, optional
156
153
  Temperature model parameters as required by one of the models in
157
- pvlib.temperature (excluding poa_global, temp_air and wind_speed).
154
+ :py:mod:`pvlib.temperature` (excluding ``poa_global``, ``temp_air`` and
155
+ ``wind_speed``).
158
156
 
159
157
  modules_per_string: int or float, default 1
160
158
  See system topology discussion above.
@@ -164,15 +162,17 @@ class PVSystem:
164
162
 
165
163
  inverter : string, optional
166
164
  The model name of the inverters.
167
- May be used to look up the inverter_parameters dictionary
168
- via some other method.
169
165
 
170
166
  inverter_parameters : dict or Series, optional
171
167
  Inverter parameters as defined by the SAPM, CEC, or other.
172
168
 
173
- racking_model : string, default 'open_rack'
174
- Valid strings are 'open_rack', 'close_mount', and 'insulated_back'.
175
- Used to identify a parameter set for the SAPM cell temperature model.
169
+ racking_model : string, optional
170
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
171
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
172
+ Used to identify a parameter set for the SAPM or PVsyst cell
173
+ temperature model.
174
+ See :py:func:`~pvlib.temperature.sapm_module` and
175
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
176
176
 
177
177
  losses_parameters : dict or Series, optional
178
178
  Losses parameters as defined by PVWatts or other.
@@ -186,7 +186,7 @@ class PVSystem:
186
186
  Raises
187
187
  ------
188
188
  ValueError
189
- If `arrays` is not None and has length 0.
189
+ If ``arrays`` is not None and has length 0.
190
190
 
191
191
  See also
192
192
  --------
@@ -312,7 +312,7 @@ class PVSystem:
312
312
  dni_extra=None, airmass=None, albedo=None,
313
313
  model='haydavies', **kwargs):
314
314
  """
315
- Uses the :py:func:`irradiance.get_total_irradiance` function to
315
+ Uses :py:func:`pvlib.irradiance.get_total_irradiance` to
316
316
  calculate the plane of array irradiance components on the tilted
317
317
  surfaces defined by each array's ``surface_tilt`` and
318
318
  ``surface_azimuth``.
@@ -323,11 +323,11 @@ class PVSystem:
323
323
  Solar zenith angle.
324
324
  solar_azimuth : float or Series
325
325
  Solar azimuth angle.
326
- dni : float or Series or tuple of float or Series
326
+ dni : float, Series, or tuple of float or Series
327
327
  Direct Normal Irradiance. [W/m2]
328
- ghi : float or Series or tuple of float or Series
328
+ ghi : float, Series, or tuple of float or Series
329
329
  Global horizontal irradiance. [W/m2]
330
- dhi : float or Series or tuple of float or Series
330
+ dhi : float, Series, or tuple of float or Series
331
331
  Diffuse horizontal irradiance. [W/m2]
332
332
  dni_extra : float, Series or tuple of float or Series, optional
333
333
  Extraterrestrial direct normal irradiance. [W/m2]
@@ -339,15 +339,22 @@ class PVSystem:
339
339
  Irradiance model.
340
340
 
341
341
  kwargs
342
- Extra parameters passed to :func:`irradiance.get_total_irradiance`.
342
+ Extra parameters passed to
343
+ :py:func:`pvlib.irradiance.get_total_irradiance`.
343
344
 
344
345
  Notes
345
346
  -----
346
- Each of `dni`, `ghi`, and `dni` parameters may be passed as a tuple
347
- to provide different irradiance for each array in the system. If not
348
- passed as a tuple then the same value is used for input to each Array.
349
- If passed as a tuple the length must be the same as the number of
350
- Arrays.
347
+ Each of ``dni``, ``ghi``, and ``dni`` may be passed as a float, Series,
348
+ or tuple of float or Series. If passed as a float or Series, these
349
+ values are used for all Arrays. If passed as a tuple, the tuple length
350
+ must be the same as the number of Arrays. The first tuple element is
351
+ used for the first Array, the second tuple element for the second
352
+ Array, and so forth.
353
+
354
+ Some sky irradiance models require ``dni_extra``. For these models,
355
+ if ``dni_extra`` is not provided and ``solar_zenith`` has a
356
+ ``DatetimeIndex``, then ``dni_extra`` is calculated.
357
+ Otherwise, ``dni_extra=1367`` is assumed.
351
358
 
352
359
  Returns
353
360
  -------
@@ -1077,7 +1084,7 @@ class Array:
1077
1084
  """
1078
1085
  Get plane of array irradiance components.
1079
1086
 
1080
- Uses the :py:func:`pvlib.irradiance.get_total_irradiance` function to
1087
+ Uses :py:func:`pvlib.irradiance.get_total_irradiance` to
1081
1088
  calculate the plane of array irradiance components for a surface
1082
1089
  defined by ``self.surface_tilt`` and ``self.surface_azimuth``.
1083
1090
 
@@ -1112,6 +1119,13 @@ class Array:
1112
1119
  Column names are: ``'poa_global', 'poa_direct', 'poa_diffuse',
1113
1120
  'poa_sky_diffuse', 'poa_ground_diffuse'``.
1114
1121
 
1122
+ Notes
1123
+ -----
1124
+ Some sky irradiance models require ``dni_extra``. For these models,
1125
+ if ``dni_extra`` is not provided and ``solar_zenith`` has a
1126
+ ``DatetimeIndex``, then ``dni_extra`` is calculated.
1127
+ Otherwise, ``dni_extra=1367`` is assumed.
1128
+
1115
1129
  See also
1116
1130
  --------
1117
1131
  :py:func:`pvlib.irradiance.get_total_irradiance`
@@ -1119,9 +1133,16 @@ class Array:
1119
1133
  if albedo is None:
1120
1134
  albedo = self.albedo
1121
1135
 
1122
- # not needed for all models, but this is easier
1136
+ # dni_extra is not needed for all models, but this is easier
1123
1137
  if dni_extra is None:
1124
- dni_extra = irradiance.get_extra_radiation(solar_zenith.index)
1138
+ if (hasattr(solar_zenith, 'index') and
1139
+ isinstance(solar_zenith.index, pd.DatetimeIndex)):
1140
+ # calculate extraterrestrial irradiance
1141
+ dni_extra = irradiance.get_extra_radiation(
1142
+ solar_zenith.index)
1143
+ else:
1144
+ # use the solar constant
1145
+ dni_extra = 1367.0
1125
1146
 
1126
1147
  if airmass is None:
1127
1148
  airmass = atmosphere.get_relative_airmass(solar_zenith)
@@ -1374,8 +1395,12 @@ class FixedMount(AbstractMount):
1374
1395
  West=270. [degrees]
1375
1396
 
1376
1397
  racking_model : str, optional
1377
- Valid strings are 'open_rack', 'close_mount', and 'insulated_back'.
1378
- Used to identify a parameter set for the SAPM cell temperature model.
1398
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
1399
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
1400
+ Used to identify a parameter set for the SAPM or PVsyst cell
1401
+ temperature model.
1402
+ See :py:func:`~pvlib.temperature.sapm_module` and
1403
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
1379
1404
 
1380
1405
  module_height : float, optional
1381
1406
  The height above ground of the center of the module [m]. Used for
@@ -1451,8 +1476,13 @@ class SingleAxisTrackerMount(AbstractMount):
1451
1476
  `cross_axis_tilt`. [degrees]
1452
1477
 
1453
1478
  racking_model : str, optional
1454
- Valid strings are 'open_rack', 'close_mount', and 'insulated_back'.
1455
- Used to identify a parameter set for the SAPM cell temperature model.
1479
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
1480
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
1481
+ Used to identify a parameter set for the SAPM or PVsyst cell
1482
+ temperature model. ``'open_rack'`` or ``'freestanding'`` should
1483
+ be used for systems with single-axis trackers.
1484
+ See :py:func:`~pvlib.temperature.sapm_module` and
1485
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
1456
1486
 
1457
1487
  module_height : float, optional
1458
1488
  The height above ground of the center of the module [m]. Used for
@@ -1679,6 +1709,8 @@ def calcparams_desoto(effective_irradiance, temp_cell,
1679
1709
  Rs = R_s
1680
1710
 
1681
1711
  numeric_args = (effective_irradiance, temp_cell)
1712
+ # IL: photocurrent, I0: saturation_current, Rs: resistance_series,
1713
+ # Rsh: resistance_shunt
1682
1714
  out = (IL, I0, Rs, Rsh, nNsVth)
1683
1715
 
1684
1716
  if all(map(np.isscalar, numeric_args)):
@@ -1945,6 +1977,8 @@ def calcparams_pvsyst(effective_irradiance, temp_cell,
1945
1977
  Rs = R_s
1946
1978
 
1947
1979
  numeric_args = (effective_irradiance, temp_cell)
1980
+ # IL: photocurrent, I0: saturation_current, Rs: resistance_series,
1981
+ # Rsh: resistance_shunt
1948
1982
  out = (IL, I0, Rs, Rsh, nNsVth)
1949
1983
 
1950
1984
  if all(map(np.isscalar, numeric_args)):
@@ -1965,10 +1999,10 @@ def retrieve_sam(name=None, path=None):
1965
1999
 
1966
2000
  This function will retrieve either:
1967
2001
 
1968
- * CEC module database
1969
- * Sandia Module database
1970
- * CEC Inverter database
1971
- * Anton Driesse Inverter database
2002
+ * CEC module database
2003
+ * Sandia Module database
2004
+ * CEC Inverter database
2005
+ * Anton Driesse Inverter database
1972
2006
 
1973
2007
  and return it as a pandas DataFrame.
1974
2008
 
@@ -1981,20 +2015,20 @@ def retrieve_sam(name=None, path=None):
1981
2015
  Use one of the following strings to retrieve a database bundled with
1982
2016
  pvlib:
1983
2017
 
1984
- * 'CECMod' - returns the CEC module database
1985
- * 'CECInverter' - returns the CEC Inverter database
1986
- * 'SandiaInverter' - returns the CEC Inverter database
2018
+ * ``'CECMod'`` - returns the CEC module database
2019
+ * ``'CECInverter'`` - returns the CEC Inverter database
2020
+ * ``'SandiaInverter'`` - returns the CEC Inverter database
1987
2021
  (CEC is only current inverter db available; tag kept for
1988
2022
  backwards compatibility)
1989
- * 'SandiaMod' - returns the Sandia Module database
1990
- * 'ADRInverter' - returns the ADR Inverter database
2023
+ * ``'SandiaMod'`` - returns the Sandia Module database
2024
+ * ``'ADRInverter'`` - returns the ADR Inverter database
1991
2025
 
1992
2026
  path : string, optional
1993
2027
  Path to a CSV file or a URL.
1994
2028
 
1995
2029
  Returns
1996
2030
  -------
1997
- samfile : DataFrame
2031
+ DataFrame
1998
2032
  A DataFrame containing all the elements of the desired database.
1999
2033
  Each column represents a module or inverter, and a specific
2000
2034
  dataset can be retrieved by the command
@@ -2012,14 +2046,13 @@ def retrieve_sam(name=None, path=None):
2012
2046
  -----
2013
2047
  Files available at
2014
2048
  https://github.com/NREL/SAM/tree/develop/deploy/libraries
2015
- Documentation for module and inverter data sets:
2016
- https://sam.nrel.gov/photovoltaic/pv-sub-page-2.html
2017
2049
 
2018
2050
  Examples
2019
2051
  --------
2052
+ Using a database bundled with pvlib:
2020
2053
 
2021
2054
  >>> from pvlib import pvsystem
2022
- >>> invdb = pvsystem.retrieve_sam('CECInverter')
2055
+ >>> invdb = pvsystem.retrieve_sam(name='CECInverter')
2023
2056
  >>> inverter = invdb.AE_Solar_Energy__AE6_0__277V_
2024
2057
  >>> inverter
2025
2058
  Vac 277
@@ -2039,7 +2072,15 @@ def retrieve_sam(name=None, path=None):
2039
2072
  CEC_Date NaN
2040
2073
  CEC_Type Utility Interactive
2041
2074
  Name: AE_Solar_Energy__AE6_0__277V_, dtype: object
2042
- """
2075
+
2076
+ Using a remote database, via URL:
2077
+
2078
+ >>> url = "https://raw.githubusercontent.com/NREL/SAM/refs/heads/develop/deploy/libraries/CEC%20Inverters.csv"
2079
+ >>> inv_db = pvsystem.retrieve_sam(path=url)
2080
+ >>> inv_db.keys()
2081
+ Index(['ABB__PVI_3_0_OUTD_S_US_A__208V_', 'ABB__PVI_3_0_OUTD_S_US_A__240V_', ...],
2082
+ dtype='object', length=...)
2083
+ """ # noqa: E501
2043
2084
  # error: path was previously silently ignored if name was given GH#2018
2044
2085
  if name is not None and path is not None:
2045
2086
  raise ValueError("Please provide either 'name' or 'path', not both.")
@@ -2273,12 +2314,6 @@ def sapm(effective_irradiance, temp_cell, module):
2273
2314
  return out
2274
2315
 
2275
2316
 
2276
- sapm_spectral_loss = deprecated(
2277
- since='0.10.0',
2278
- alternative='pvlib.spectrum.spectral_factor_sapm'
2279
- )(spectrum.spectral_factor_sapm)
2280
-
2281
-
2282
2317
  def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,
2283
2318
  module):
2284
2319
  r"""
@@ -2871,46 +2906,49 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2,
2871
2906
  def dc_ohms_from_percent(vmp_ref, imp_ref, dc_ohmic_percent,
2872
2907
  modules_per_string=1,
2873
2908
  strings=1):
2874
- """
2875
- Calculates the equivalent resistance of the wires from a percent
2876
- ohmic loss at STC.
2877
-
2878
- Equivalent resistance is calculated with the function:
2879
-
2880
- .. math::
2881
- Rw = (L_{stc} / 100) * (Varray / Iarray)
2882
-
2883
- :math:`Rw` is the equivalent resistance in ohms
2884
- :math:`Varray` is the Vmp of the modules times modules per string
2885
- :math:`Iarray` is the Imp of the modules times strings per array
2886
- :math:`L_{stc}` is the input dc loss percent
2909
+ r"""
2910
+ Calculate the equivalent resistance of the conductors from the percent
2911
+ ohmic loss of an array at reference conditions.
2887
2912
 
2888
2913
  Parameters
2889
2914
  ----------
2890
2915
  vmp_ref: numeric
2891
- Voltage at maximum power in reference conditions [V]
2916
+ Maximum power voltage of one module at reference conditions. [V]
2892
2917
  imp_ref: numeric
2893
- Current at maximum power in reference conditions [V]
2894
- dc_ohmic_percent: numeric, default 0
2895
- input dc loss as a percent, e.g. 1.5% loss is input as 1.5
2918
+ Maximum power current of one module at reference conditions. [A]
2919
+ dc_ohmic_percent: numeric
2920
+ Array DC power loss as a percent of DC power loss at reference
2921
+ conditions. In percent, e.g. 1.5% loss is input as 1.5.
2896
2922
  modules_per_string: int, default 1
2897
- Number of modules per string in the array.
2923
+ Number of series-connected modules per string in the array.
2898
2924
  strings: int, default 1
2899
2925
  Number of parallel strings in the array.
2900
2926
 
2901
2927
  Returns
2902
2928
  ----------
2903
2929
  Rw: numeric
2904
- Equivalent resistance [ohm]
2930
+ Equivalent resistance. [ohm]
2905
2931
 
2906
2932
  See Also
2907
2933
  --------
2908
2934
  pvlib.pvsystem.dc_ohmic_losses
2909
2935
 
2910
- References
2911
- ----------
2912
- .. [1] PVsyst 7 Help. "Array ohmic wiring loss".
2913
- https://www.pvsyst.com/help/ohmic_loss.htm
2936
+ Notes
2937
+ -----
2938
+ Equivalent resistance is calculated as:
2939
+
2940
+ .. math::
2941
+
2942
+ R_w = \left(\frac{L_{stc}}{100}\right) \times \left(\frac{
2943
+ V_{array}}{I_{array}}\right)
2944
+
2945
+ :math:`R_w` is the equivalent resistance in ohms.
2946
+ :math:`V_{array}` is the array voltage, equal to ``vmp_ref`` times
2947
+ ``modules_per_string``.
2948
+ :math:`I_{array}` is the array current, equal to ``imp_ref`` times
2949
+ ``strings``.
2950
+ :math:`L_{stc}` is the input DC loss percent at reference conditions.
2951
+
2914
2952
  """
2915
2953
  vmp = modules_per_string * vmp_ref
2916
2954
 
@@ -2922,30 +2960,37 @@ def dc_ohms_from_percent(vmp_ref, imp_ref, dc_ohmic_percent,
2922
2960
 
2923
2961
 
2924
2962
  def dc_ohmic_losses(resistance, current):
2925
- """
2963
+ r"""
2926
2964
  Returns ohmic losses in units of power from the equivalent
2927
2965
  resistance of the wires and the operating current.
2928
2966
 
2929
2967
  Parameters
2930
2968
  ----------
2931
2969
  resistance: numeric
2932
- Equivalent resistance of wires [ohm]
2970
+ Equivalent resistance of wires. [ohm]
2933
2971
  current: numeric, float or array-like
2934
- Operating current [A]
2972
+ Operating current. [A]
2935
2973
 
2936
2974
  Returns
2937
2975
  ----------
2938
2976
  loss: numeric
2939
- Power Loss [W]
2977
+ Power loss. [W]
2940
2978
 
2941
2979
  See Also
2942
2980
  --------
2943
2981
  pvlib.pvsystem.dc_ohms_from_percent
2944
2982
 
2945
- References
2946
- ----------
2947
- .. [1] PVsyst 7 Help. "Array ohmic wiring loss".
2948
- https://www.pvsyst.com/help/ohmic_loss.htm
2983
+ Notes
2984
+ -----
2985
+ Ohmic (also termed joule or heat) loss is the power lost due to current
2986
+ flowing through a conductor. Ohmic loss, :math:`L`, is computed as
2987
+
2988
+ .. math::
2989
+
2990
+ L = I^2 \times R
2991
+
2992
+ where :math:`I` is the current (A) and :math:`R` is the resistance of the
2993
+ conductor (ohms).
2949
2994
  """
2950
2995
  return resistance * current * current
2951
2996
 
pvlib/snow.py CHANGED
@@ -13,30 +13,38 @@ def _time_delta_in_hours(times):
13
13
  return delta.dt.total_seconds().div(3600)
14
14
 
15
15
 
16
- def fully_covered_nrel(snowfall, threshold_snowfall=1.):
16
+ def fully_covered_nrel(snowfall, snow_depth=None, threshold_snowfall=1.,
17
+ threshold_depth=1.):
17
18
  '''
18
- Calculates the timesteps when the row's slant height is fully covered
19
- by snow.
19
+ Calculates the timesteps when modules are fully covered by snow.
20
20
 
21
21
  Parameters
22
22
  ----------
23
- snowfall : Series
24
- Accumulated snowfall in each time period [cm]
25
-
26
- threshold_snowfall : float, default 1.0
27
- Hourly snowfall above which snow coverage is set to the row's slant
28
- height. [cm/hr]
23
+ snowfall: Series
24
+ Snowfall in each time period. [cm]
25
+ snow_depth: Series, optional
26
+ Snow depth on the ground at the beginning of each time period.
27
+ Must have the same index as ``snowfall``. [cm]
28
+ threshold_snowfall: float, default 1.0
29
+ Hourly snowfall above which the row is fully covered for that hour.
30
+ [cm/hr]
31
+ threshold_depth: float, default 1.0
32
+ Snow depth on the ground, above which snow can affect the modules. [cm]
29
33
 
30
34
  Returns
31
35
  ----------
32
- boolean: Series
33
- True where the snowfall exceeds the defined threshold to fully cover
34
- the panel.
36
+ covered: Series
37
+ A Series of boolean, True where the snowfall exceeds the defined
38
+ threshold to fully cover the panel.
35
39
 
36
40
  Notes
37
41
  -----
38
42
  Implements the model described in [1]_ with minor improvements in [2]_.
39
43
 
44
+ ``snow_depth`` is used to return `False` (not fully covered) when snow
45
+ is less than ``threshold_depth``. This check is described in [2]_ as needed
46
+ for systems with low tilt angle.
47
+
40
48
  References
41
49
  ----------
42
50
  .. [1] Marion, B.; Schaefer, R.; Caine, H.; Sanchez, G. (2013).
@@ -56,15 +64,20 @@ def fully_covered_nrel(snowfall, threshold_snowfall=1.):
56
64
  hourly_snow_rate.iloc[0] = snowfall.iloc[0] / timedelta
57
65
  else: # can't infer frequency from index
58
66
  hourly_snow_rate.iloc[0] = 0 # replaces NaN
59
- return hourly_snow_rate > threshold_snowfall
67
+ covered = (hourly_snow_rate > threshold_snowfall)
68
+ # no coverage when no snow on the ground
69
+ if snow_depth is not None:
70
+ covered = covered & (snow_depth >= threshold_depth)
71
+ return covered
60
72
 
61
73
 
62
74
  def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
63
- initial_coverage=0, threshold_snowfall=1.,
64
- can_slide_coefficient=-80., slide_amount_coefficient=0.197):
75
+ snow_depth=None, initial_coverage=0, threshold_snowfall=1.,
76
+ threshold_depth=1., can_slide_coefficient=-80.,
77
+ slide_amount_coefficient=0.197):
65
78
  '''
66
- Calculates the fraction of the slant height of a row of modules covered by
67
- snow at every time step.
79
+ Calculates the fraction of the slant height of a row of modules that is
80
+ covered by snow at every time step.
68
81
 
69
82
  Implements the model described in [1]_ with minor improvements in [2]_,
70
83
  with the change that the output is in fraction of the row's slant height
@@ -74,7 +87,7 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
74
87
  Parameters
75
88
  ----------
76
89
  snowfall : Series
77
- Accumulated snowfall within each time period. [cm]
90
+ Snowfall within each time period. [cm]
78
91
  poa_irradiance : Series
79
92
  Total in-plane irradiance [W/m^2]
80
93
  temp_air : Series
@@ -82,12 +95,17 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
82
95
  surface_tilt : numeric
83
96
  Tilt of module's from horizontal, e.g. surface facing up = 0,
84
97
  surface facing horizon = 90. [degrees]
98
+ snow_depth : Series, optional
99
+ Snow depth on the ground at the beginning of each time period.
100
+ Must have the same index as ``snowfall``. [cm]
85
101
  initial_coverage : float, default 0
86
102
  Fraction of row's slant height that is covered with snow at the
87
103
  beginning of the simulation. [unitless]
88
- threshold_snowfall : float, default 1.0
89
- Hourly snowfall above which snow coverage is set to the row's slant
90
- height. [cm/hr]
104
+ threshold_snowfall: float, default 1.0
105
+ Hourly snowfall above which the row is fully covered for that hour.
106
+ [cm/hr]
107
+ threshold_depth: float, default 1.0
108
+ Snow depth on the ground, above which snow can affect the modules. [cm]
91
109
  can_slide_coefficient : float, default -80.
92
110
  Coefficient to determine if snow can slide given irradiance and air
93
111
  temperature. [W/(m^2 C)]
@@ -103,8 +121,12 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
103
121
 
104
122
  Notes
105
123
  -----
106
- In [1]_, `can_slide_coefficient` is termed `m`, and the value of
107
- `slide_amount_coefficient` is given in tenths of a module's slant height.
124
+ In [1]_, ``can_slide_coefficient`` is termed `m`, and the value of
125
+ ``slide_amount_coefficient`` is given in tenths of a module's slant height.
126
+
127
+ ``snow_depth`` is used to set ``snow_coverage`` to 0 (not fully covered)
128
+ when snow is less than ``threshold_depth``. This check is described in
129
+ [2]_ as needed for systems with low tilt angle.
108
130
 
109
131
  References
110
132
  ----------
@@ -117,7 +139,8 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
117
139
  '''
118
140
 
119
141
  # find times with new snowfall
120
- new_snowfall = fully_covered_nrel(snowfall, threshold_snowfall)
142
+ new_snowfall = fully_covered_nrel(snowfall, snow_depth, threshold_snowfall,
143
+ threshold_depth)
121
144
 
122
145
  # set up output Series
123
146
  snow_coverage = pd.Series(np.nan, index=poa_irradiance.index)
@@ -132,6 +155,13 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
132
155
  # don't slide in the interval preceding the snowfall data
133
156
  slide_amt.iloc[0] = 0
134
157
 
158
+ if snow_depth is not None:
159
+ # All slides off if snow on the ground is less than threshold_depth.
160
+ # Described in [2] to avoid non-sliding snow for low-tilt systems.
161
+ # Default threshold_depth of 1cm is from [2[ and SAM's implementation.
162
+ # https://github.com/NREL/ssc/issues/1265
163
+ slide_amt[snow_depth < threshold_depth] = 1.
164
+
135
165
  # build time series of cumulative slide amounts
136
166
  sliding_period_ID = new_snowfall.cumsum()
137
167
  cumulative_sliding = slide_amt.groupby(sliding_period_ID).cumsum()
@@ -143,7 +173,6 @@ def coverage_nrel(snowfall, poa_irradiance, temp_air, surface_tilt,
143
173
  snow_coverage.ffill(inplace=True)
144
174
  snow_coverage -= cumulative_sliding
145
175
 
146
- # clean up periods where row is completely uncovered
147
176
  return snow_coverage.clip(lower=0)
148
177
 
149
178
 
@@ -278,9 +307,8 @@ def loss_townsend(snow_total, snow_events, surface_tilt, relative_humidity,
278
307
  axis to the module edge.
279
308
 
280
309
  The parameter `string_factor` is an enhancement added to the model after
281
- publication of [1]_ per private communication with the model's author. The
282
- definition for snow events documented above is also based on private
283
- communication with the model's author.
310
+ publication of [1]_, as described in [2]_.
311
+ The definition for snow events documented above is based on [3]_.
284
312
 
285
313
  References
286
314
  ----------
@@ -288,6 +316,14 @@ def loss_townsend(snow_total, snow_events, surface_tilt, relative_humidity,
288
316
  update from two winters of measurements in the SIERRA. 37th IEEE
289
317
  Photovoltaic Specialists Conference, Seattle, WA, USA.
290
318
  :doi:`10.1109/PVSC.2011.6186627`
319
+ .. [2] Townsend, T. and Previtali, J. (2023). A Fresh Dusting: Current
320
+ Uses of the Townsend Snow Model. In "Photovoltaic Reliability
321
+ Workshop (PVRW) 2023 Proceedings: Posters.", ed. Silverman,
322
+ T. J. Dec. 2023. NREL/CP-5900-87918.
323
+ Available at: https://www.nrel.gov/docs/fy25osti/90585.pdf
324
+ .. [3] Townsend, T. (2013). Predicting PV Energy Loss Caused by Snow.
325
+ Solar Power International, Chicago IL.
326
+ :doi:`10.13140/RG.2.2.14299.68647`
291
327
  '''
292
328
 
293
329
  # unit conversions from cm and m to in, from C to K, and from % to fraction