pvlib 0.11.1__py3-none-any.whl → 0.11.2__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 (43) hide show
  1. pvlib/_deprecation.py +73 -0
  2. pvlib/atmosphere.py +79 -0
  3. pvlib/clearsky.py +35 -22
  4. pvlib/data/pvgis_tmy_test.csv +8761 -0
  5. pvlib/data/tmy_45.000_8.000_2005_2023.csv +8789 -0
  6. pvlib/data/tmy_45.000_8.000_2005_2023.epw +8768 -0
  7. pvlib/data/tmy_45.000_8.000_2005_2023.json +1 -0
  8. pvlib/data/tmy_45.000_8.000_2005_2023.txt +8761 -0
  9. pvlib/data/tmy_45.000_8.000_userhorizon.json +1 -1
  10. pvlib/iam.py +4 -4
  11. pvlib/iotools/midc.py +1 -1
  12. pvlib/iotools/pvgis.py +0 -10
  13. pvlib/irradiance.py +98 -55
  14. pvlib/ivtools/sdm.py +75 -52
  15. pvlib/pvsystem.py +132 -84
  16. pvlib/solarposition.py +46 -30
  17. pvlib/spa.py +4 -2
  18. pvlib/spectrum/irradiance.py +2 -1
  19. pvlib/spectrum/spectrl2.py +2 -1
  20. pvlib/temperature.py +49 -3
  21. pvlib/tests/iotools/test_pvgis.py +9 -9
  22. pvlib/tests/ivtools/test_sdm.py +23 -1
  23. pvlib/tests/test__deprecation.py +97 -0
  24. pvlib/tests/test_atmosphere.py +147 -0
  25. pvlib/tests/test_clearsky.py +7 -1
  26. pvlib/tests/test_conftest.py +0 -44
  27. pvlib/tests/test_irradiance.py +56 -10
  28. pvlib/tests/test_pvsystem.py +17 -1
  29. pvlib/tests/test_solarposition.py +33 -0
  30. pvlib/tests/test_spa.py +29 -0
  31. {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/METADATA +11 -10
  32. {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/RECORD +36 -37
  33. {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/WHEEL +1 -1
  34. pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
  35. pvlib/data/pvgis_tmy_test.dat +0 -8761
  36. pvlib/data/tmy_45.000_8.000_2005_2020.csv +0 -8789
  37. pvlib/data/tmy_45.000_8.000_2005_2020.epw +0 -8768
  38. pvlib/data/tmy_45.000_8.000_2005_2020.json +0 -1
  39. pvlib/data/tmy_45.000_8.000_2005_2020.txt +0 -8761
  40. pvlib/data/variables_style_rules.csv +0 -56
  41. {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/AUTHORS.md +0 -0
  42. {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/LICENSE +0 -0
  43. {pvlib-0.11.1.dist-info → pvlib-0.11.2.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,
@@ -104,22 +104,22 @@ class PVSystem:
104
104
  ----------
105
105
  arrays : Array or iterable of Array, optional
106
106
  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.
107
+ specified, a single array is created from the other parameters (e.g.
108
108
  `surface_tilt`, `surface_azimuth`). If specified as a list, the list
109
109
  must contain at least one Array;
110
110
  if length of arrays is 0 a ValueError is raised. If `arrays` is
111
111
  specified the following PVSystem parameters are ignored:
112
112
 
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`
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``
123
123
 
124
124
  surface_tilt: float or array-like, default 0
125
125
  Surface tilt angles in decimal degrees.
@@ -127,7 +127,7 @@ class PVSystem:
127
127
  (e.g. surface facing up = 0, surface facing horizon = 90)
128
128
 
129
129
  surface_azimuth: float or array-like, default 180
130
- Azimuth angle of the module surface.
130
+ Azimuth angle of the module surface in decimal degrees.
131
131
  North=0, East=90, South=180, West=270.
132
132
 
133
133
  albedo : float, optional
@@ -142,8 +142,6 @@ class PVSystem:
142
142
 
143
143
  module : string, optional
144
144
  The model name of the modules.
145
- May be used to look up the module_parameters dictionary
146
- via some other method.
147
145
 
148
146
  module_type : string, default 'glass_polymer'
149
147
  Describes the module's construction. Valid strings are 'glass_polymer'
@@ -154,7 +152,8 @@ class PVSystem:
154
152
 
155
153
  temperature_model_parameters : dict or Series, optional
156
154
  Temperature model parameters as required by one of the models in
157
- pvlib.temperature (excluding poa_global, temp_air and wind_speed).
155
+ :py:mod:`pvlib.temperature` (excluding ``poa_global``, ``temp_air`` and
156
+ ``wind_speed``).
158
157
 
159
158
  modules_per_string: int or float, default 1
160
159
  See system topology discussion above.
@@ -164,15 +163,17 @@ class PVSystem:
164
163
 
165
164
  inverter : string, optional
166
165
  The model name of the inverters.
167
- May be used to look up the inverter_parameters dictionary
168
- via some other method.
169
166
 
170
167
  inverter_parameters : dict or Series, optional
171
168
  Inverter parameters as defined by the SAPM, CEC, or other.
172
169
 
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.
170
+ racking_model : string, optional
171
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
172
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
173
+ Used to identify a parameter set for the SAPM or PVsyst cell
174
+ temperature model.
175
+ See :py:func:`~pvlib.temperature.sapm_module` and
176
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
176
177
 
177
178
  losses_parameters : dict or Series, optional
178
179
  Losses parameters as defined by PVWatts or other.
@@ -186,7 +187,7 @@ class PVSystem:
186
187
  Raises
187
188
  ------
188
189
  ValueError
189
- If `arrays` is not None and has length 0.
190
+ If ``arrays`` is not None and has length 0.
190
191
 
191
192
  See also
192
193
  --------
@@ -312,7 +313,7 @@ class PVSystem:
312
313
  dni_extra=None, airmass=None, albedo=None,
313
314
  model='haydavies', **kwargs):
314
315
  """
315
- Uses the :py:func:`irradiance.get_total_irradiance` function to
316
+ Uses :py:func:`pvlib.irradiance.get_total_irradiance` to
316
317
  calculate the plane of array irradiance components on the tilted
317
318
  surfaces defined by each array's ``surface_tilt`` and
318
319
  ``surface_azimuth``.
@@ -323,11 +324,11 @@ class PVSystem:
323
324
  Solar zenith angle.
324
325
  solar_azimuth : float or Series
325
326
  Solar azimuth angle.
326
- dni : float or Series or tuple of float or Series
327
+ dni : float, Series, or tuple of float or Series
327
328
  Direct Normal Irradiance. [W/m2]
328
- ghi : float or Series or tuple of float or Series
329
+ ghi : float, Series, or tuple of float or Series
329
330
  Global horizontal irradiance. [W/m2]
330
- dhi : float or Series or tuple of float or Series
331
+ dhi : float, Series, or tuple of float or Series
331
332
  Diffuse horizontal irradiance. [W/m2]
332
333
  dni_extra : float, Series or tuple of float or Series, optional
333
334
  Extraterrestrial direct normal irradiance. [W/m2]
@@ -339,15 +340,22 @@ class PVSystem:
339
340
  Irradiance model.
340
341
 
341
342
  kwargs
342
- Extra parameters passed to :func:`irradiance.get_total_irradiance`.
343
+ Extra parameters passed to
344
+ :py:func:`pvlib.irradiance.get_total_irradiance`.
343
345
 
344
346
  Notes
345
347
  -----
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.
348
+ Each of ``dni``, ``ghi``, and ``dni`` may be passed as a float, Series,
349
+ or tuple of float or Series. If passed as a float or Series, these
350
+ values are used for all Arrays. If passed as a tuple, the tuple length
351
+ must be the same as the number of Arrays. The first tuple element is
352
+ used for the first Array, the second tuple element for the second
353
+ Array, and so forth.
354
+
355
+ Some sky irradiance models require ``dni_extra``. For these models,
356
+ if ``dni_extra`` is not provided and ``solar_zenith`` has a
357
+ ``DatetimeIndex``, then ``dni_extra`` is calculated.
358
+ Otherwise, ``dni_extra=1367`` is assumed.
351
359
 
352
360
  Returns
353
361
  -------
@@ -1077,7 +1085,7 @@ class Array:
1077
1085
  """
1078
1086
  Get plane of array irradiance components.
1079
1087
 
1080
- Uses the :py:func:`pvlib.irradiance.get_total_irradiance` function to
1088
+ Uses :py:func:`pvlib.irradiance.get_total_irradiance` to
1081
1089
  calculate the plane of array irradiance components for a surface
1082
1090
  defined by ``self.surface_tilt`` and ``self.surface_azimuth``.
1083
1091
 
@@ -1112,6 +1120,13 @@ class Array:
1112
1120
  Column names are: ``'poa_global', 'poa_direct', 'poa_diffuse',
1113
1121
  'poa_sky_diffuse', 'poa_ground_diffuse'``.
1114
1122
 
1123
+ Notes
1124
+ -----
1125
+ Some sky irradiance models require ``dni_extra``. For these models,
1126
+ if ``dni_extra`` is not provided and ``solar_zenith`` has a
1127
+ ``DatetimeIndex``, then ``dni_extra`` is calculated.
1128
+ Otherwise, ``dni_extra=1367`` is assumed.
1129
+
1115
1130
  See also
1116
1131
  --------
1117
1132
  :py:func:`pvlib.irradiance.get_total_irradiance`
@@ -1119,9 +1134,16 @@ class Array:
1119
1134
  if albedo is None:
1120
1135
  albedo = self.albedo
1121
1136
 
1122
- # not needed for all models, but this is easier
1137
+ # dni_extra is not needed for all models, but this is easier
1123
1138
  if dni_extra is None:
1124
- dni_extra = irradiance.get_extra_radiation(solar_zenith.index)
1139
+ if (hasattr(solar_zenith, 'index') and
1140
+ isinstance(solar_zenith.index, pd.DatetimeIndex)):
1141
+ # calculate extraterrestrial irradiance
1142
+ dni_extra = irradiance.get_extra_radiation(
1143
+ solar_zenith.index)
1144
+ else:
1145
+ # use the solar constant
1146
+ dni_extra = 1367.0
1125
1147
 
1126
1148
  if airmass is None:
1127
1149
  airmass = atmosphere.get_relative_airmass(solar_zenith)
@@ -1374,8 +1396,12 @@ class FixedMount(AbstractMount):
1374
1396
  West=270. [degrees]
1375
1397
 
1376
1398
  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.
1399
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
1400
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
1401
+ Used to identify a parameter set for the SAPM or PVsyst cell
1402
+ temperature model.
1403
+ See :py:func:`~pvlib.temperature.sapm_module` and
1404
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
1379
1405
 
1380
1406
  module_height : float, optional
1381
1407
  The height above ground of the center of the module [m]. Used for
@@ -1451,8 +1477,13 @@ class SingleAxisTrackerMount(AbstractMount):
1451
1477
  `cross_axis_tilt`. [degrees]
1452
1478
 
1453
1479
  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.
1480
+ Valid strings are ``'open_rack'``, ``'close_mount'``,
1481
+ ``'insulated_back'``, ``'freestanding'`` and ``'insulated'``.
1482
+ Used to identify a parameter set for the SAPM or PVsyst cell
1483
+ temperature model. ``'open_rack'`` or ``'freestanding'`` should
1484
+ be used for systems with single-axis trackers.
1485
+ See :py:func:`~pvlib.temperature.sapm_module` and
1486
+ :py:func:`~pvlib.temperature.pvsyst_cell` for definitions.
1456
1487
 
1457
1488
  module_height : float, optional
1458
1489
  The height above ground of the center of the module [m]. Used for
@@ -1965,10 +1996,10 @@ def retrieve_sam(name=None, path=None):
1965
1996
 
1966
1997
  This function will retrieve either:
1967
1998
 
1968
- * CEC module database
1969
- * Sandia Module database
1970
- * CEC Inverter database
1971
- * Anton Driesse Inverter database
1999
+ * CEC module database
2000
+ * Sandia Module database
2001
+ * CEC Inverter database
2002
+ * Anton Driesse Inverter database
1972
2003
 
1973
2004
  and return it as a pandas DataFrame.
1974
2005
 
@@ -1981,20 +2012,20 @@ def retrieve_sam(name=None, path=None):
1981
2012
  Use one of the following strings to retrieve a database bundled with
1982
2013
  pvlib:
1983
2014
 
1984
- * 'CECMod' - returns the CEC module database
1985
- * 'CECInverter' - returns the CEC Inverter database
1986
- * 'SandiaInverter' - returns the CEC Inverter database
2015
+ * ``'CECMod'`` - returns the CEC module database
2016
+ * ``'CECInverter'`` - returns the CEC Inverter database
2017
+ * ``'SandiaInverter'`` - returns the CEC Inverter database
1987
2018
  (CEC is only current inverter db available; tag kept for
1988
2019
  backwards compatibility)
1989
- * 'SandiaMod' - returns the Sandia Module database
1990
- * 'ADRInverter' - returns the ADR Inverter database
2020
+ * ``'SandiaMod'`` - returns the Sandia Module database
2021
+ * ``'ADRInverter'`` - returns the ADR Inverter database
1991
2022
 
1992
2023
  path : string, optional
1993
2024
  Path to a CSV file or a URL.
1994
2025
 
1995
2026
  Returns
1996
2027
  -------
1997
- samfile : DataFrame
2028
+ DataFrame
1998
2029
  A DataFrame containing all the elements of the desired database.
1999
2030
  Each column represents a module or inverter, and a specific
2000
2031
  dataset can be retrieved by the command
@@ -2012,14 +2043,13 @@ def retrieve_sam(name=None, path=None):
2012
2043
  -----
2013
2044
  Files available at
2014
2045
  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
2046
 
2018
2047
  Examples
2019
2048
  --------
2049
+ Using a database bundled with pvlib:
2020
2050
 
2021
2051
  >>> from pvlib import pvsystem
2022
- >>> invdb = pvsystem.retrieve_sam('CECInverter')
2052
+ >>> invdb = pvsystem.retrieve_sam(name='CECInverter')
2023
2053
  >>> inverter = invdb.AE_Solar_Energy__AE6_0__277V_
2024
2054
  >>> inverter
2025
2055
  Vac 277
@@ -2039,7 +2069,15 @@ def retrieve_sam(name=None, path=None):
2039
2069
  CEC_Date NaN
2040
2070
  CEC_Type Utility Interactive
2041
2071
  Name: AE_Solar_Energy__AE6_0__277V_, dtype: object
2042
- """
2072
+
2073
+ Using a remote database, via URL:
2074
+
2075
+ >>> url = "https://raw.githubusercontent.com/NREL/SAM/refs/heads/develop/deploy/libraries/CEC%20Inverters.csv"
2076
+ >>> inv_db = pvsystem.retrieve_sam(path=url)
2077
+ >>> inv_db.keys()
2078
+ Index(['ABB__PVI_3_0_OUTD_S_US_A__208V_', 'ABB__PVI_3_0_OUTD_S_US_A__240V_', ...],
2079
+ dtype='object', length=...)
2080
+ """ # noqa: E501
2043
2081
  # error: path was previously silently ignored if name was given GH#2018
2044
2082
  if name is not None and path is not None:
2045
2083
  raise ValueError("Please provide either 'name' or 'path', not both.")
@@ -2871,46 +2909,49 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2,
2871
2909
  def dc_ohms_from_percent(vmp_ref, imp_ref, dc_ohmic_percent,
2872
2910
  modules_per_string=1,
2873
2911
  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
2912
+ r"""
2913
+ Calculate the equivalent resistance of the conductors from the percent
2914
+ ohmic loss of an array at reference conditions.
2887
2915
 
2888
2916
  Parameters
2889
2917
  ----------
2890
2918
  vmp_ref: numeric
2891
- Voltage at maximum power in reference conditions [V]
2919
+ Maximum power voltage of one module at reference conditions. [V]
2892
2920
  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
2921
+ Maximum power current of one module at reference conditions. [A]
2922
+ dc_ohmic_percent: numeric
2923
+ Array DC power loss as a percent of DC power loss at reference
2924
+ conditions. In percent, e.g. 1.5% loss is input as 1.5.
2896
2925
  modules_per_string: int, default 1
2897
- Number of modules per string in the array.
2926
+ Number of series-connected modules per string in the array.
2898
2927
  strings: int, default 1
2899
2928
  Number of parallel strings in the array.
2900
2929
 
2901
2930
  Returns
2902
2931
  ----------
2903
2932
  Rw: numeric
2904
- Equivalent resistance [ohm]
2933
+ Equivalent resistance. [ohm]
2905
2934
 
2906
2935
  See Also
2907
2936
  --------
2908
2937
  pvlib.pvsystem.dc_ohmic_losses
2909
2938
 
2910
- References
2911
- ----------
2912
- .. [1] PVsyst 7 Help. "Array ohmic wiring loss".
2913
- https://www.pvsyst.com/help/ohmic_loss.htm
2939
+ Notes
2940
+ -----
2941
+ Equivalent resistance is calculated as:
2942
+
2943
+ .. math::
2944
+
2945
+ R_w = \left(\frac{L_{stc}}{100}\right) \times \left(\frac{
2946
+ V_{array}}{I_{array}}\right)
2947
+
2948
+ :math:`R_w` is the equivalent resistance in ohms.
2949
+ :math:`V_{array}` is the array voltage, equal to ``vmp_ref`` times
2950
+ ``modules_per_string``.
2951
+ :math:`I_{array}` is the array current, equal to ``imp_ref`` times
2952
+ ``strings``.
2953
+ :math:`L_{stc}` is the input DC loss percent at reference conditions.
2954
+
2914
2955
  """
2915
2956
  vmp = modules_per_string * vmp_ref
2916
2957
 
@@ -2922,30 +2963,37 @@ def dc_ohms_from_percent(vmp_ref, imp_ref, dc_ohmic_percent,
2922
2963
 
2923
2964
 
2924
2965
  def dc_ohmic_losses(resistance, current):
2925
- """
2966
+ r"""
2926
2967
  Returns ohmic losses in units of power from the equivalent
2927
2968
  resistance of the wires and the operating current.
2928
2969
 
2929
2970
  Parameters
2930
2971
  ----------
2931
2972
  resistance: numeric
2932
- Equivalent resistance of wires [ohm]
2973
+ Equivalent resistance of wires. [ohm]
2933
2974
  current: numeric, float or array-like
2934
- Operating current [A]
2975
+ Operating current. [A]
2935
2976
 
2936
2977
  Returns
2937
2978
  ----------
2938
2979
  loss: numeric
2939
- Power Loss [W]
2980
+ Power loss. [W]
2940
2981
 
2941
2982
  See Also
2942
2983
  --------
2943
2984
  pvlib.pvsystem.dc_ohms_from_percent
2944
2985
 
2945
- References
2946
- ----------
2947
- .. [1] PVsyst 7 Help. "Array ohmic wiring loss".
2948
- https://www.pvsyst.com/help/ohmic_loss.htm
2986
+ Notes
2987
+ -----
2988
+ Ohmic (also termed joule or heat) loss is the power lost due to current
2989
+ flowing through a conductor. Ohmic loss, :math:`L`, is computed as
2990
+
2991
+ .. math::
2992
+
2993
+ L = I^2 \times R
2994
+
2995
+ where :math:`I` is the current (A) and :math:`R` is the resistance of the
2996
+ conductor (ohms).
2949
2997
  """
2950
2998
  return resistance * current * current
2951
2999
 
pvlib/solarposition.py CHANGED
@@ -30,7 +30,7 @@ from pvlib.tools import datetime_to_djd, djd_to_datetime
30
30
  def get_solarposition(time, latitude, longitude,
31
31
  altitude=None, pressure=None,
32
32
  method='nrel_numpy',
33
- temperature=12, **kwargs):
33
+ temperature=12.0, **kwargs):
34
34
  """
35
35
  A convenience wrapper for the solar position calculators.
36
36
 
@@ -125,8 +125,8 @@ def get_solarposition(time, latitude, longitude,
125
125
  return ephem_df
126
126
 
127
127
 
128
- def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
129
- temperature=12, delta_t=67.0,
128
+ def spa_c(time, latitude, longitude, pressure=101325., altitude=0.,
129
+ temperature=12., delta_t=67.0,
130
130
  raw_spa_output=False):
131
131
  r"""
132
132
  Calculate the solar position using the C implementation of the NREL
@@ -149,11 +149,11 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
149
149
  longitude : float
150
150
  Longitude in decimal degrees. Positive east of prime meridian,
151
151
  negative to west.
152
- pressure : float, default 101325
152
+ pressure : float, default 101325.0
153
153
  Pressure in Pascals
154
- altitude : float, default 0
154
+ altitude : float, default 0.0
155
155
  Height above sea level. [m]
156
- temperature : float, default 12
156
+ temperature : float, default 12.0
157
157
  Temperature in C
158
158
  delta_t : float, default 67.0
159
159
  Difference between terrestrial time and UT1.
@@ -279,7 +279,7 @@ def _datetime_to_unixtime(dtindex):
279
279
 
280
280
 
281
281
  def spa_python(time, latitude, longitude,
282
- altitude=0, pressure=101325, temperature=12, delta_t=67.0,
282
+ altitude=0., pressure=101325., temperature=12., delta_t=67.0,
283
283
  atmos_refract=None, how='numpy', numthreads=4):
284
284
  """
285
285
  Calculate the solar position using a python implementation of the
@@ -302,11 +302,11 @@ def spa_python(time, latitude, longitude,
302
302
  longitude : float
303
303
  Longitude in decimal degrees. Positive east of prime meridian,
304
304
  negative to west.
305
- altitude : float, default 0
305
+ altitude : float, default 0.0
306
306
  Distance above sea level.
307
- pressure : int or float, optional, default 101325
307
+ pressure : int or float, optional, default 101325.0
308
308
  avg. yearly air pressure in Pascals.
309
- temperature : int or float, optional, default 12
309
+ temperature : int or float, optional, default 12.0
310
310
  avg. yearly air temperature in degrees C.
311
311
  delta_t : float or array, optional, default 67.0
312
312
  Difference between terrestrial time and UT1.
@@ -507,9 +507,9 @@ def _ephem_setup(latitude, longitude, altitude, pressure, temperature,
507
507
 
508
508
  def sun_rise_set_transit_ephem(times, latitude, longitude,
509
509
  next_or_previous='next',
510
- altitude=0,
511
- pressure=101325,
512
- temperature=12, horizon='0:00'):
510
+ altitude=0.,
511
+ pressure=101325.,
512
+ temperature=12., horizon='0:00'):
513
513
  """
514
514
  Calculate the next sunrise and sunset times using the PyEphem package.
515
515
 
@@ -523,11 +523,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
523
523
  Longitude in degrees, positive east of prime meridian, negative to west
524
524
  next_or_previous : str
525
525
  'next' or 'previous' sunrise and sunset relative to time
526
- altitude : float, default 0
526
+ altitude : float, default 0.0
527
527
  distance above sea level in meters.
528
- pressure : int or float, optional, default 101325
528
+ pressure : int or float, optional, default 101325.0
529
529
  air pressure in Pascals.
530
- temperature : int or float, optional, default 12
530
+ temperature : int or float, optional, default 12.0
531
531
  air temperature in degrees C.
532
532
  horizon : string, format +/-X:YY
533
533
  arc degrees:arc minutes from geometrical horizon for sunrise and
@@ -590,8 +590,8 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
590
590
  'transit': trans})
591
591
 
592
592
 
593
- def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
594
- temperature=12, horizon='+0:00'):
593
+ def pyephem(time, latitude, longitude, altitude=0., pressure=101325.,
594
+ temperature=12., horizon='+0:00'):
595
595
  """
596
596
  Calculate the solar position using the PyEphem package.
597
597
 
@@ -605,11 +605,11 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
605
605
  longitude : float
606
606
  Longitude in decimal degrees. Positive east of prime meridian,
607
607
  negative to west.
608
- altitude : float, default 0
608
+ altitude : float, default 0.0
609
609
  Height above sea level in meters. [m]
610
- pressure : int or float, optional, default 101325
610
+ pressure : int or float, optional, default 101325.0
611
611
  air pressure in Pascals.
612
- temperature : int or float, optional, default 12
612
+ temperature : int or float, optional, default 12.0
613
613
  air temperature in degrees C.
614
614
  horizon : string, optional, default '+0:00'
615
615
  arc degrees:arc minutes from geometrical horizon for sunrise and
@@ -679,7 +679,7 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
679
679
  return sun_coords
680
680
 
681
681
 
682
- def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
682
+ def ephemeris(time, latitude, longitude, pressure=101325.0, temperature=12.0):
683
683
  """
684
684
  Python-native solar position calculator.
685
685
  The accuracy of this code is not guaranteed.
@@ -695,9 +695,9 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
695
695
  longitude : float
696
696
  Longitude in decimal degrees. Positive east of prime meridian,
697
697
  negative to west.
698
- pressure : float or Series, default 101325
698
+ pressure : float or Series, default 101325.0
699
699
  Ambient pressure (Pascals)
700
- temperature : float or Series, default 12
700
+ temperature : float or Series, default 12.0
701
701
  Ambient temperature (C)
702
702
 
703
703
  Returns
@@ -856,8 +856,8 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
856
856
 
857
857
 
858
858
  def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value,
859
- altitude=0, pressure=101325, temperature=12, horizon='+0:00',
860
- xtol=1.0e-12):
859
+ altitude=0.0, pressure=101325.0, temperature=12.0,
860
+ horizon='+0:00', xtol=1.0e-12):
861
861
  """
862
862
  Calculate the time between lower_bound and upper_bound
863
863
  where the attribute is equal to value. Uses PyEphem for
@@ -879,12 +879,12 @@ def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value,
879
879
  and 'az' (which must be given in radians).
880
880
  value : int or float
881
881
  The value of the attribute to solve for
882
- altitude : float, default 0
882
+ altitude : float, default 0.0
883
883
  Distance above sea level.
884
- pressure : int or float, optional, default 101325
884
+ pressure : int or float, optional, default 101325.0
885
885
  Air pressure in Pascals. Set to 0 for no
886
886
  atmospheric correction.
887
- temperature : int or float, optional, default 12
887
+ temperature : int or float, optional, default 12.0
888
888
  Air temperature in degrees C.
889
889
  horizon : string, optional, default '+0:00'
890
890
  arc degrees:arc minutes from geometrical horizon for sunrise and
@@ -1349,6 +1349,12 @@ def hour_angle(times, longitude, equation_of_time):
1349
1349
  times : :class:`pandas.DatetimeIndex`
1350
1350
  Corresponding timestamps, must be localized to the timezone for the
1351
1351
  ``longitude``.
1352
+
1353
+ A `pytz.exceptions.AmbiguousTimeError` will be raised if any of the
1354
+ given times are on a day when the local daylight savings transition
1355
+ happens at midnight. If you're working with such a timezone,
1356
+ consider converting to a non-DST timezone (e.g. GMT-4) before
1357
+ calling this function.
1352
1358
  longitude : numeric
1353
1359
  Longitude in degrees
1354
1360
  equation_of_time : numeric
@@ -1421,7 +1427,17 @@ def _times_to_hours_after_local_midnight(times):
1421
1427
  if not times.tz:
1422
1428
  raise ValueError('times must be localized')
1423
1429
 
1424
- hrs = (times - times.normalize()) / pd.Timedelta('1h')
1430
+ # Some timezones have a DST shift at midnight:
1431
+ # 11:59pm -> 1:00am - results in a nonexistent midnight
1432
+ # 12:59am -> 12:00am - results in an ambiguous midnight
1433
+ # We remove the timezone before normalizing for this reason.
1434
+ naive_normalized_times = times.tz_localize(None).normalize()
1435
+
1436
+ # Use Pandas functionality for shifting nonexistent times forward
1437
+ normalized_times = naive_normalized_times.tz_localize(
1438
+ times.tz, nonexistent='shift_forward', ambiguous='raise')
1439
+
1440
+ hrs = (times - normalized_times) / pd.Timedelta('1h')
1425
1441
 
1426
1442
  # ensure array return instead of a version-dependent pandas <T>Index
1427
1443
  return np.array(hrs)
pvlib/spa.py CHANGED
@@ -413,8 +413,10 @@ def julian_day_dt(year, month, day, hour, minute, second, microsecond):
413
413
  frac_of_day = (microsecond / 1e6 + (second + minute * 60 + hour * 3600)
414
414
  ) * 1.0 / (3600*24)
415
415
  d = day + frac_of_day
416
- jd = (int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + d +
417
- b - 1524.5)
416
+ jd = int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + d - 1524.5
417
+ if jd > 2299160.0:
418
+ jd += b
419
+
418
420
  return jd
419
421
 
420
422
 
@@ -189,7 +189,8 @@ def average_photon_energy(spectra):
189
189
  ----------
190
190
  spectra : pandas.Series or pandas.DataFrame
191
191
 
192
- Spectral irradiance, must be positive. [Wm⁻²nm⁻¹]
192
+ Spectral irradiance, must be positive [Wm⁻²nm⁻¹].
193
+ See :term:`spectra`.
193
194
 
194
195
  A single spectrum must be a :py:class:`pandas.Series` with wavelength
195
196
  [nm] as the index, while multiple spectra must be rows in a
@@ -228,10 +228,11 @@ def spectrl2(apparent_zenith, aoi, surface_tilt, ground_albedo,
228
228
  Returns
229
229
  -------
230
230
  spectra_components : dict
231
- A dict of arrays. With the exception of `wavelength`, which has length
231
+ A dict of arrays. With the exception of `wavelength`, which has length
232
232
  122, each array has shape (122, N) where N is the length of the
233
233
  input ``apparent_zenith``. All values are spectral irradiance
234
234
  with units Wm⁻²nm⁻¹, except for `wavelength`, which is in nanometers.
235
+ See :term:`spectra_components`.
235
236
 
236
237
  * wavelength
237
238
  * dni_extra