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/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
- timezone, and altitude data associated with a particular
22
- geographic location. You can also assign a name to a location object.
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 timezone attributes:
25
+ Location objects have two time-zone attributes:
25
26
 
26
- * ``tz`` is a IANA timezone string.
27
- * ``pytz`` is a pytz timezone object.
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 pytz.timezone, default 'UTC'.
42
- See
43
- http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
44
- for a list of valid time zones.
45
- pytz.timezone objects will be converted to strings.
46
- ints and floats must be in hours from UTC.
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__(self, latitude, longitude, tz='UTC', altitude=None,
63
- name=None):
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='pyephem', **kwargs):
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 'pyephem'
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 provdied,
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, or function, optional
334
- If not specified, the model will be inferred from the parameters that
335
- are common to all of system.arrays[i].module_parameters.
336
- Valid strings are 'sapm', 'first_solar', 'no_loss'.
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 is None:
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
- else:
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
- ``'module_temperaure'``.
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)