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/__init__.py CHANGED
@@ -27,4 +27,5 @@ from pvlib import ( # noqa: F401
27
27
  temperature,
28
28
  tools,
29
29
  tracking,
30
+ transformer,
30
31
  )
pvlib/_deprecation.py CHANGED
@@ -316,3 +316,76 @@ def deprecated(since, message='', name='', alternative='', pending=False,
316
316
  return finalize(wrapper, new_doc)
317
317
 
318
318
  return deprecate
319
+
320
+
321
+ def renamed_kwarg_warning(since, old_param_name, new_param_name, removal=""):
322
+ """
323
+ Decorator to mark a possible keyword argument as deprecated and replaced
324
+ with other name.
325
+
326
+ Raises a warning when the deprecated argument is used, and replaces the
327
+ call with the new argument name. Does not modify the function signature.
328
+
329
+ .. warning::
330
+ Ensure ``removal`` date with a ``fail_on_pvlib_version`` decorator in
331
+ the test suite.
332
+
333
+ .. note::
334
+ Not compatible with positional-only arguments.
335
+
336
+ .. note::
337
+ Documentation for the function may updated to reflect the new parameter
338
+ name; it is suggested to add a |.. versionchanged::| directive.
339
+
340
+ Parameters
341
+ ----------
342
+ since : str
343
+ The release at which this API became deprecated.
344
+ old_param_name : str
345
+ The name of the deprecated parameter.
346
+ new_param_name : str
347
+ The name of the new parameter.
348
+ removal : str, optional
349
+ The expected removal version, in order to compose the Warning message.
350
+
351
+ Examples
352
+ --------
353
+ >>> @renamed_kwarg_warning("1.4.0", "old_name", "new_name", "1.6.0")
354
+ >>> def some_function(new_name=None):
355
+ >>> pass
356
+ >>> some_function(old_name=1)
357
+ Parameter 'old_name' has been renamed since 1.4.0. and
358
+ will be removed in 1.6.0. Please use 'new_name' instead.
359
+
360
+ >>> @renamed_kwarg_warning("1.4.0", "old_name", "new_name")
361
+ >>> def some_function(new_name=None):
362
+ >>> pass
363
+ >>> some_function(old_name=1)
364
+ Parameter 'old_name' has been renamed since 1.4.0. and
365
+ will be removed soon. Please use 'new_name' instead.
366
+ """
367
+
368
+ def deprecate(func, old=old_param_name, new=new_param_name, since=since):
369
+ def wrapper(*args, **kwargs):
370
+ if old in kwargs:
371
+ if new in kwargs:
372
+ raise ValueError(
373
+ f"{func.__name__} received both '{old}' and '{new}', "
374
+ "which are mutually exclusive since they refer to the "
375
+ f"same parameter. Please remove deprecated '{old}'."
376
+ )
377
+ warnings.warn(
378
+ f"Parameter '{old}' has been renamed since {since}. "
379
+ f"and will be removed "
380
+ + (f"in {removal}" if removal else "soon")
381
+ + f". Please use '{new}' instead.",
382
+ _projectWarning,
383
+ stacklevel=2,
384
+ )
385
+ kwargs[new] = kwargs.pop(old)
386
+ return func(*args, **kwargs)
387
+
388
+ wrapper = functools.wraps(func)(wrapper)
389
+ return wrapper
390
+
391
+ return deprecate
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')
@@ -337,10 +334,83 @@ def gueymard94_pw(temp_air, relative_humidity):
337
334
  return pw
338
335
 
339
336
 
340
- first_solar_spectral_correction = deprecated(
341
- since='0.10.0',
342
- alternative='pvlib.spectrum.spectral_factor_firstsolar'
343
- )(pvlib.spectrum.spectral_factor_firstsolar)
337
+ def rh_from_tdew(temp_air, temp_dew, coeff=(6.112, 17.62, 243.12)):
338
+ """
339
+ Calculate relative humidity from dewpoint temperature using the Magnus
340
+ equation.
341
+
342
+ Parameters
343
+ ----------
344
+ temp_air : numeric
345
+ Air temperature (dry-bulb temperature). [°C]
346
+ temp_dew : numeric
347
+ Dew-point temperature. [°C]
348
+ coeff : tuple, default (6.112, 17.62, 243.12)
349
+ Magnus equation coefficients (A, B, C). The default values are those
350
+ recommended by the WMO [1]_.
351
+
352
+ Returns
353
+ -------
354
+ numeric
355
+ Relative humidity (0.0-100.0). [%]
356
+
357
+ References
358
+ ----------
359
+ .. [1] "Guide to Instruments and Methods of Observation",
360
+ World Meteorological Organization, WMO-No. 8, 2023.
361
+ https://library.wmo.int/idurl/4/68695
362
+ """
363
+
364
+ # Calculate vapor pressure (e) and saturation vapor pressure (es)
365
+ e = coeff[0] * np.exp((coeff[1] * temp_air) / (coeff[2] + temp_air))
366
+ es = coeff[0] * np.exp((coeff[1] * temp_dew) / (coeff[2] + temp_dew))
367
+
368
+ # Calculate relative humidity as percentage
369
+ relative_humidity = 100 * (es / e)
370
+
371
+ return relative_humidity
372
+
373
+
374
+ def tdew_from_rh(temp_air, relative_humidity, coeff=(6.112, 17.62, 243.12)):
375
+ """
376
+ Calculate dewpoint temperature using the Magnus equation.
377
+ This is a reversal of the calculation in :py:func:`rh_from_tdew`.
378
+
379
+ Parameters
380
+ ----------
381
+ temp_air : numeric
382
+ Air temperature (dry-bulb temperature). [°C]
383
+ relative_humidity : numeric
384
+ Relative humidity (0-100). [%]
385
+ coeff: tuple, default (6.112, 17.62, 243.12)
386
+ Magnus equation coefficients (A, B, C). The default values are those
387
+ recommended by the WMO [1]_.
388
+
389
+ Returns
390
+ -------
391
+ numeric
392
+ Dewpoint temperature. [°C]
393
+
394
+ References
395
+ ----------
396
+ .. [1] "Guide to Instruments and Methods of Observation",
397
+ World Meteorological Organization, WMO-No. 8, 2023.
398
+ https://library.wmo.int/idurl/4/68695
399
+ """
400
+ # Calculate the term inside the log
401
+ # From RH = 100 * (es/e), we get es = (RH/100) * e
402
+ # Substituting the Magnus equation and solving for dewpoint
403
+
404
+ # First calculate ln(es/A)
405
+ ln_term = (
406
+ (coeff[1] * temp_air) / (coeff[2] + temp_air)
407
+ + np.log(relative_humidity/100)
408
+ )
409
+
410
+ # Then solve for dewpoint
411
+ dewpoint = coeff[2] * ln_term / (coeff[1] - ln_term)
412
+
413
+ return dewpoint
344
414
 
345
415
 
346
416
  def bird_hulstrom80_aod_bb(aod380, aod500):
@@ -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 input ghi is a Series. See Notes for
264
- descriptions of content.
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(poa_global, pd.Series):
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
- np.where(solar_zenith > max_zenith, 0., f_gnd_beam) # [1], Eq. 4
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/clearsky.py CHANGED
@@ -327,13 +327,13 @@ def haurwitz(apparent_zenith):
327
327
  '''
328
328
 
329
329
  cos_zenith = tools.cosd(apparent_zenith.values)
330
- clearsky_ghi = np.zeros_like(apparent_zenith.values)
330
+ ghi_clear = np.zeros_like(apparent_zenith.values)
331
331
  cos_zen_gte_0 = cos_zenith > 0
332
- clearsky_ghi[cos_zen_gte_0] = (1098.0 * cos_zenith[cos_zen_gte_0] *
333
- np.exp(-0.059/cos_zenith[cos_zen_gte_0]))
332
+ ghi_clear[cos_zen_gte_0] = (1098.0 * cos_zenith[cos_zen_gte_0] *
333
+ np.exp(-0.059/cos_zenith[cos_zen_gte_0]))
334
334
 
335
335
  df_out = pd.DataFrame(index=apparent_zenith.index,
336
- data=clearsky_ghi,
336
+ data=ghi_clear,
337
337
  columns=['ghi'])
338
338
 
339
339
  return df_out
@@ -683,22 +683,26 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
683
683
  var_diff=0.005, slope_dev=8, max_iterations=20,
684
684
  return_components=False):
685
685
  """
686
- Detects clear sky times according to the algorithm developed by Reno
687
- and Hansen for GHI measurements. The algorithm [1]_ was designed and
688
- validated for analyzing GHI time series only. Users may attempt to
689
- apply it to other types of time series data using different filter
690
- settings, but should be skeptical of the results.
686
+ Detects clear sky times using the algorithm developed by Reno
687
+ and Hansen.
691
688
 
692
- The algorithm detects clear sky times by comparing statistics for a
689
+ The algorithm [1]_ was designed and
690
+ validated for analyzing GHI time series. Jordan and Hansen [2]_ extended
691
+ the algorithm to plane-of-array (POA) irradiance measurements.
692
+
693
+ The algorithm [1]_ detects clear sky times by comparing statistics for a
693
694
  measured time series and an expected clearsky time series.
694
695
  Statistics are calculated using a sliding time window (e.g., 10
695
696
  minutes). An iterative algorithm identifies clear periods, uses the
696
697
  identified periods to estimate bias in the clearsky data, scales the
697
698
  clearsky data and repeats.
698
699
 
699
- Clear times are identified by meeting 5 criteria. Default values for
700
+ Clear times are identified by meeting five criteria. Default values for
700
701
  these thresholds are appropriate for 10 minute windows of 1 minute
701
- GHI data.
702
+ GHI data. For data at longer intervals, it is recommended
703
+ to set ``infer_limits=True`` to use the thresholds from [2]_.
704
+
705
+ For POA data, ``clearsky`` must be on the same plane as ``measured``.
702
706
 
703
707
  Parameters
704
708
  ----------
@@ -713,8 +717,8 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
713
717
  If True, does not use passed in kwargs (or defaults), but instead
714
718
  interpolates these values from Table 1 in [2]_.
715
719
  window_length : int, default 10
716
- Length of sliding time window in minutes. Must be greater than 2
717
- periods.
720
+ Length of sliding time window in minutes. Each window must contain at
721
+ least three data points.
718
722
  mean_diff : float, default 75
719
723
  Threshold value for agreement between mean values of measured
720
724
  and clearsky in each interval, see Eq. 6 in [1]. [W/m2]
@@ -723,8 +727,6 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
723
727
  clearsky values in each interval, see Eq. 7 in [1]. [W/m2]
724
728
  lower_line_length : float, default -5
725
729
  Lower limit of line length criterion from Eq. 8 in [1].
726
- Criterion satisfied when lower_line_length < line length difference
727
- < upper_line_length.
728
730
  upper_line_length : float, default 10
729
731
  Upper limit of line length criterion from Eq. 8 in [1].
730
732
  var_diff : float, default 0.005
@@ -736,7 +738,7 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
736
738
  change in successive values, see Eqs. 12 through 14 in [1].
737
739
  max_iterations : int, default 20
738
740
  Maximum number of times to apply a different scaling factor to
739
- the clearsky and redetermine clear_samples. Must be 1 or larger.
741
+ the clearsky and redetermine ``clear_samples``. Must be 1 or larger.
740
742
  return_components : bool, default False
741
743
  Controls if additional output should be returned. See below.
742
744
 
@@ -748,19 +750,23 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
748
750
 
749
751
  components : OrderedDict, optional
750
752
  Dict of arrays of whether or not the given time window is clear
751
- for each condition. Only provided if return_components is True.
753
+ for each condition. Only provided if ``return_components`` is True.
752
754
 
753
755
  alpha : scalar, optional
754
- Scaling factor applied to the clearsky_ghi to obtain the
755
- detected clear_samples. Only provided if return_components is
756
+ Scaling factor applied to ``clearsky`` to obtain the
757
+ detected ``clear_samples``. Only provided if ``return_components`` is
756
758
  True.
757
759
 
758
760
  Raises
759
761
  ------
760
762
  ValueError
761
- If measured is not a Series and times is not provided
763
+ If ``measured`` is not a Series and times is not provided.
764
+ ValueError
765
+ If a window contains less than three data points.
766
+ ValueError
767
+ If the measured data is not sufficient to fill a window.
762
768
  NotImplementedError
763
- If timestamps are not equally spaced
769
+ If timestamps are not equally spaced.
764
770
 
765
771
  References
766
772
  ----------
@@ -812,6 +818,13 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
812
818
  sample_interval, samples_per_window = \
813
819
  tools._get_sample_intervals(times, window_length)
814
820
 
821
+ if samples_per_window < 3:
822
+ raise ValueError(f"Samples per window of {samples_per_window}"
823
+ " found. Each window must contain at least 3 data"
824
+ " points."
825
+ f" Window length of {window_length} found; increase"
826
+ f" window length to {3*sample_interval} or longer.")
827
+
815
828
  # if infer_limits, find threshold values using the sample interval
816
829
  if infer_limits:
817
830
  window_length, mean_diff, max_diff, lower_line_length, \
pvlib/iam.py CHANGED
@@ -269,8 +269,8 @@ def martin_ruiz(aoi, a_r=0.16):
269
269
 
270
270
  which is presented as :math:`AL(\alpha) = 1 - IAM` in equation 4 of [1]_,
271
271
  with :math:`\alpha` representing the angle of incidence AOI. Thus IAM = 1
272
- at AOI = 0, and IAM = 0 at AOI = 90. This equation is only valid for
273
- -90 <= aoi <= 90, therefore `iam` is constrained to 0.0 outside this
272
+ at AOI = 0°, and IAM = 0 at AOI = 90°. This equation is only valid for
273
+ <= aoi <= 90°, therefore `iam` is constrained to 0.0 outside this
274
274
  interval.
275
275
 
276
276
  References
@@ -891,8 +891,8 @@ def schlick_diffuse(surface_tilt):
891
891
  implements only the integrated Schlick approximation.
892
892
 
893
893
  Note also that the output of this function (which is an exact integration)
894
- can be compared with the output of :py:func:`marion_diffuse` which numerically
895
- integrates the Schlick approximation:
894
+ can be compared with the output of :py:func:`marion_diffuse` which
895
+ numerically integrates the Schlick approximation:
896
896
 
897
897
  .. code::
898
898
 
pvlib/iotools/midc.py CHANGED
@@ -193,7 +193,7 @@ def read_midc(filename, variable_map={}, raw_data=False, **kwargs):
193
193
 
194
194
  See the MIDC_VARIABLE_MAP for collection of mappings by site.
195
195
  For a full list of pvlib variable names see the
196
- :ref:`variables_style_rules`.
196
+ :ref:`nomenclature`.
197
197
 
198
198
  Be sure to check the units for the variables you will use on the
199
199
  `MIDC site <https://midcdmz.nrel.gov/>`_.
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
- 'zenith': 'solar_zenith_angle',
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
@@ -467,16 +467,6 @@ def get_pvgis_tmy(latitude, longitude, outputformat='json', usehorizon=True,
467
467
  metadata : list or dict
468
468
  file metadata, ``None`` for basic
469
469
 
470
- Note
471
- ----
472
- The PVGIS website uses 10 years of data to generate the TMY, whereas the
473
- API accessed by this function defaults to using all available years. This
474
- means that the TMY returned by this function may not be identical to the
475
- one generated by the website. To replicate the website requests, specify
476
- the corresponding 10 year period using ``startyear`` and ``endyear``.
477
- Specifying ``endyear`` also avoids the TMY changing when new data becomes
478
- available.
479
-
480
470
  Raises
481
471
  ------
482
472
  requests.HTTPError
@@ -569,9 +559,17 @@ def _parse_pvgis_tmy_csv(src):
569
559
  inputs['longitude'] = float(src.readline().split(b':')[1])
570
560
  # Elevation (m): 1389.0\r\n
571
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
572
571
  # then there's a 13 row comma separated table with two columns: month, year
573
- # which contains the year used for that month in the
574
- src.readline() # get "month,year\r\n"
572
+ # which contains the year used for that month in the TMY
575
573
  months_selected = []
576
574
  for month in range(12):
577
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=None, recolumn=None,
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, optional
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
- # shouldnt' specify both recolumn and map_variables
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.