pvlib 0.10.4__py3-none-any.whl → 0.11.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 (47) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/albedo.py +168 -0
  3. pvlib/bifacial/utils.py +2 -1
  4. pvlib/data/ASTMG173.csv +2004 -0
  5. pvlib/iam.py +28 -28
  6. pvlib/iotools/__init__.py +0 -1
  7. pvlib/iotools/midc.py +15 -10
  8. pvlib/iotools/psm3.py +10 -25
  9. pvlib/iotools/srml.py +1 -61
  10. pvlib/iotools/surfrad.py +1 -1
  11. pvlib/irradiance.py +133 -95
  12. pvlib/location.py +16 -6
  13. pvlib/modelchain.py +2 -165
  14. pvlib/pvarray.py +7 -5
  15. pvlib/pvsystem.py +75 -106
  16. pvlib/scaling.py +4 -2
  17. pvlib/shading.py +350 -0
  18. pvlib/singlediode.py +37 -9
  19. pvlib/snow.py +3 -1
  20. pvlib/spectrum/__init__.py +5 -0
  21. pvlib/spectrum/mismatch.py +573 -43
  22. pvlib/spectrum/spectrl2.py +8 -8
  23. pvlib/tests/bifacial/test_utils.py +6 -5
  24. pvlib/tests/iotools/test_psm3.py +0 -18
  25. pvlib/tests/iotools/test_srml.py +1 -43
  26. pvlib/tests/test_albedo.py +84 -0
  27. pvlib/tests/test_inverter.py +2 -2
  28. pvlib/tests/test_irradiance.py +35 -2
  29. pvlib/tests/test_location.py +26 -18
  30. pvlib/tests/test_modelchain.py +0 -57
  31. pvlib/tests/test_pvsystem.py +73 -128
  32. pvlib/tests/test_shading.py +167 -1
  33. pvlib/tests/test_singlediode.py +68 -29
  34. pvlib/tests/test_spectrum.py +283 -22
  35. pvlib/tests/test_temperature.py +7 -7
  36. pvlib/tests/test_tools.py +24 -0
  37. pvlib/tests/test_transformer.py +60 -0
  38. pvlib/tools.py +27 -0
  39. pvlib/transformer.py +117 -0
  40. pvlib/version.py +1 -5
  41. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/METADATA +3 -4
  42. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/RECORD +46 -42
  43. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/WHEEL +1 -1
  44. pvlib/data/astm_g173_am15g.csv +0 -2003
  45. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/AUTHORS.md +0 -0
  46. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/LICENSE +0 -0
  47. {pvlib-0.10.4.dist-info → pvlib-0.11.0.dist-info}/top_level.txt +0 -0
pvlib/pvsystem.py CHANGED
@@ -7,7 +7,7 @@ from collections import OrderedDict
7
7
  import functools
8
8
  import io
9
9
  import itertools
10
- import os
10
+ from pathlib import Path
11
11
  import inspect
12
12
  from urllib.request import urlopen
13
13
  import numpy as np
@@ -19,6 +19,7 @@ from typing import Optional, Union
19
19
 
20
20
  from pvlib._deprecation import deprecated, warn_deprecated
21
21
 
22
+ import pvlib # used to avoid albedo name collision in the Array class
22
23
  from pvlib import (atmosphere, iam, inverter, irradiance,
23
24
  singlediode as _singlediode, spectrum, temperature)
24
25
  from pvlib.tools import _build_kwargs, _build_args
@@ -131,13 +132,13 @@ class PVSystem:
131
132
 
132
133
  albedo : float, optional
133
134
  Ground surface albedo. If not supplied, then ``surface_type`` is used
134
- to look up a value in ``irradiance.SURFACE_ALBEDOS``.
135
+ to look up a value in :py:const:`pvlib.albedo.SURFACE_ALBEDOS`.
135
136
  If ``surface_type`` is also not supplied then a ground surface albedo
136
137
  of 0.25 is used.
137
138
 
138
139
  surface_type : string, optional
139
- The ground surface type. See ``irradiance.SURFACE_ALBEDOS`` for
140
- valid values.
140
+ The ground surface type. See :py:const:`pvlib.albedo.SURFACE_ALBEDOS`
141
+ for valid values.
141
142
 
142
143
  module : string, optional
143
144
  The model name of the modules.
@@ -721,15 +722,13 @@ class PVSystem:
721
722
  )
722
723
 
723
724
  def singlediode(self, photocurrent, saturation_current,
724
- resistance_series, resistance_shunt, nNsVth,
725
- ivcurve_pnts=None):
725
+ resistance_series, resistance_shunt, nNsVth):
726
726
  """Wrapper around the :py:func:`pvlib.pvsystem.singlediode` function.
727
727
 
728
728
  See :py:func:`pvsystem.singlediode` for details
729
729
  """
730
730
  return singlediode(photocurrent, saturation_current,
731
- resistance_series, resistance_shunt, nNsVth,
732
- ivcurve_pnts=ivcurve_pnts)
731
+ resistance_series, resistance_shunt, nNsVth)
733
732
 
734
733
  def i_from_v(self, voltage, photocurrent, saturation_current,
735
734
  resistance_series, resistance_shunt, nNsVth):
@@ -907,13 +906,13 @@ class Array:
907
906
 
908
907
  albedo : float, optional
909
908
  Ground surface albedo. If not supplied, then ``surface_type`` is used
910
- to look up a value in ``irradiance.SURFACE_ALBEDOS``.
909
+ to look up a value in :py:const:`pvlib.albedo.SURFACE_ALBEDOS`.
911
910
  If ``surface_type`` is also not supplied then a ground surface albedo
912
911
  of 0.25 is used.
913
912
 
914
913
  surface_type : string, optional
915
- The ground surface type. See ``irradiance.SURFACE_ALBEDOS`` for valid
916
- values.
914
+ The ground surface type. See :py:const:`pvlib.albedo.SURFACE_ALBEDOS`
915
+ for valid values.
917
916
 
918
917
  module : string, optional
919
918
  The model name of the modules.
@@ -956,7 +955,7 @@ class Array:
956
955
 
957
956
  self.surface_type = surface_type
958
957
  if albedo is None:
959
- self.albedo = irradiance.SURFACE_ALBEDOS.get(surface_type, 0.25)
958
+ self.albedo = pvlib.albedo.SURFACE_ALBEDOS.get(surface_type, 0.25)
960
959
  else:
961
960
  self.albedo = albedo
962
961
 
@@ -1487,8 +1486,10 @@ def calcparams_desoto(effective_irradiance, temp_cell,
1487
1486
  '''
1488
1487
  Calculates five parameter values for the single diode equation at
1489
1488
  effective irradiance and cell temperature using the De Soto et al.
1490
- model described in [1]_. The five values returned by calcparams_desoto
1491
- can be used by singlediode to calculate an IV curve.
1489
+ model. The five values returned by ``calcparams_desoto`` can be used by
1490
+ singlediode to calculate an IV curve.
1491
+
1492
+ The model is described in [1]_.
1492
1493
 
1493
1494
  Parameters
1494
1495
  ----------
@@ -1958,9 +1959,9 @@ def calcparams_pvsyst(effective_irradiance, temp_cell,
1958
1959
 
1959
1960
 
1960
1961
  def retrieve_sam(name=None, path=None):
1961
- '''
1962
- Retrieve latest module and inverter info from a local file or the
1963
- SAM website.
1962
+ """
1963
+ Retrieve latest module and inverter info from a file bundled with pvlib,
1964
+ a path or an URL (like SAM's website).
1964
1965
 
1965
1966
  This function will retrieve either:
1966
1967
 
@@ -1971,10 +1972,14 @@ def retrieve_sam(name=None, path=None):
1971
1972
 
1972
1973
  and return it as a pandas DataFrame.
1973
1974
 
1975
+ .. note::
1976
+ Only provide one of ``name`` or ``path``.
1977
+
1974
1978
  Parameters
1975
1979
  ----------
1976
1980
  name : string, optional
1977
- Name can be one of:
1981
+ Use one of the following strings to retrieve a database bundled with
1982
+ pvlib:
1978
1983
 
1979
1984
  * 'CECMod' - returns the CEC module database
1980
1985
  * 'CECInverter' - returns the CEC Inverter database
@@ -1985,7 +1990,7 @@ def retrieve_sam(name=None, path=None):
1985
1990
  * 'ADRInverter' - returns the ADR Inverter database
1986
1991
 
1987
1992
  path : string, optional
1988
- Path to the SAM file. May also be a URL.
1993
+ Path to a CSV file or a URL.
1989
1994
 
1990
1995
  Returns
1991
1996
  -------
@@ -1997,7 +2002,11 @@ def retrieve_sam(name=None, path=None):
1997
2002
  Raises
1998
2003
  ------
1999
2004
  ValueError
2000
- If no name or path is provided.
2005
+ If no ``name`` or ``path`` is provided.
2006
+ ValueError
2007
+ If both ``name`` and ``path`` are provided.
2008
+ KeyError
2009
+ If the provided ``name`` is not a valid database name.
2001
2010
 
2002
2011
  Notes
2003
2012
  -----
@@ -2030,38 +2039,38 @@ def retrieve_sam(name=None, path=None):
2030
2039
  CEC_Date NaN
2031
2040
  CEC_Type Utility Interactive
2032
2041
  Name: AE_Solar_Energy__AE6_0__277V_, dtype: object
2033
- '''
2034
-
2035
- if name is not None:
2036
- name = name.lower()
2037
- data_path = os.path.join(
2038
- os.path.dirname(os.path.abspath(__file__)), 'data')
2039
- if name == 'cecmod':
2040
- csvdata = os.path.join(
2041
- data_path, 'sam-library-cec-modules-2019-03-05.csv')
2042
- elif name == 'sandiamod':
2043
- csvdata = os.path.join(
2044
- data_path, 'sam-library-sandia-modules-2015-6-30.csv')
2045
- elif name == 'adrinverter':
2046
- csvdata = os.path.join(
2047
- data_path, 'adr-library-cec-inverters-2019-03-05.csv')
2048
- elif name in ['cecinverter', 'sandiainverter']:
2049
- # Allowing either, to provide for old code,
2050
- # while aligning with current expectations
2051
- csvdata = os.path.join(
2052
- data_path, 'sam-library-cec-inverters-2019-03-05.csv')
2053
- else:
2054
- raise ValueError(f'invalid name {name}')
2055
- elif path is not None:
2056
- if path.startswith('http'):
2057
- response = urlopen(path)
2058
- csvdata = io.StringIO(response.read().decode(errors='ignore'))
2059
- else:
2060
- csvdata = path
2042
+ """
2043
+ # error: path was previously silently ignored if name was given GH#2018
2044
+ if name is not None and path is not None:
2045
+ raise ValueError("Please provide either 'name' or 'path', not both.")
2061
2046
  elif name is None and path is None:
2062
- raise ValueError("A name or path must be provided!")
2063
-
2064
- return _parse_raw_sam_df(csvdata)
2047
+ raise ValueError("Please provide either 'name' or 'path'.")
2048
+ elif name is not None:
2049
+ internal_dbs = {
2050
+ "cecmod": "sam-library-cec-modules-2019-03-05.csv",
2051
+ "sandiamod": "sam-library-sandia-modules-2015-6-30.csv",
2052
+ "adrinverter": "adr-library-cec-inverters-2019-03-05.csv",
2053
+ # Both 'cecinverter' and 'sandiainverter', point to same database
2054
+ # to provide for old code, while aligning with current expectations
2055
+ "cecinverter": "sam-library-cec-inverters-2019-03-05.csv",
2056
+ "sandiainverter": "sam-library-cec-inverters-2019-03-05.csv",
2057
+ }
2058
+ try:
2059
+ csvdata_path = Path(__file__).parent.joinpath(
2060
+ "data", internal_dbs[name.lower()]
2061
+ )
2062
+ except KeyError:
2063
+ raise KeyError(
2064
+ f"Invalid name {name}. "
2065
+ + f"Provide one of {list(internal_dbs.keys())}."
2066
+ ) from None
2067
+ else: # path is not None
2068
+ if path.lower().startswith("http"): # URL check is not case-sensitive
2069
+ response = urlopen(path) # URL is case-sensitive
2070
+ csvdata_path = io.StringIO(response.read().decode(errors="ignore"))
2071
+ else:
2072
+ csvdata_path = path
2073
+ return _parse_raw_sam_df(csvdata_path)
2065
2074
 
2066
2075
 
2067
2076
  def _normalize_sam_product_names(names):
@@ -2254,10 +2263,9 @@ def sapm(effective_irradiance, temp_cell, module):
2254
2263
  module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
2255
2264
  (1 + module['Aisc']*(temp_cell - temp_ref)))
2256
2265
 
2257
- # the Ixx calculation in King 2004 has a typo (mixes up Aisc and Aimp)
2258
2266
  out['i_xx'] = (
2259
2267
  module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
2260
- (1 + module['Aisc']*(temp_cell - temp_ref)))
2268
+ (1 + module['Aimp']*(temp_cell - temp_ref)))
2261
2269
 
2262
2270
  if isinstance(out['i_sc'], pd.Series):
2263
2271
  out = pd.DataFrame(out)
@@ -2309,9 +2317,10 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,
2309
2317
  a module's cells.
2310
2318
 
2311
2319
  The model is
2320
+
2312
2321
  .. math::
2313
2322
 
2314
- `Ee = f_1(AM_a) (E_b f_2(AOI) + f_d E_d)`
2323
+ Ee = f_1(AM_a) (E_b f_2(AOI) + f_d E_d)
2315
2324
 
2316
2325
  where :math:`Ee` is effective irradiance (W/m2), :math:`f_1` is a fourth
2317
2326
  degree polynomial in air mass :math:`AM_a`, :math:`E_b` is beam (direct)
@@ -2341,8 +2350,7 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,
2341
2350
 
2342
2351
 
2343
2352
  def singlediode(photocurrent, saturation_current, resistance_series,
2344
- resistance_shunt, nNsVth, ivcurve_pnts=None,
2345
- method='lambertw'):
2353
+ resistance_shunt, nNsVth, method='lambertw'):
2346
2354
  r"""
2347
2355
  Solve the single diode equation to obtain a photovoltaic IV curve.
2348
2356
 
@@ -2394,14 +2402,6 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2394
2402
  junction in Kelvin, and :math:`q` is the charge of an electron
2395
2403
  (coulombs). ``0 < nNsVth``. [V]
2396
2404
 
2397
- ivcurve_pnts : int, optional
2398
- Number of points in the desired IV curve. If not specified or 0, no
2399
- points on the IV curves will be produced.
2400
-
2401
- .. deprecated:: 0.10.0
2402
- Use :py:func:`pvlib.pvsystem.v_from_i` and
2403
- :py:func:`pvlib.pvsystem.i_from_v` instead.
2404
-
2405
2405
  method : str, default 'lambertw'
2406
2406
  Determines the method used to calculate points on the IV curve. The
2407
2407
  options are ``'lambertw'``, ``'newton'``, or ``'brentq'``.
@@ -2411,20 +2411,15 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2411
2411
  dict or pandas.DataFrame
2412
2412
  The returned dict-like object always contains the keys/columns:
2413
2413
 
2414
- * i_sc - short circuit current in amperes.
2415
- * v_oc - open circuit voltage in volts.
2416
- * i_mp - current at maximum power point in amperes.
2417
- * v_mp - voltage at maximum power point in volts.
2418
- * p_mp - power at maximum power point in watts.
2419
- * i_x - current, in amperes, at ``v = 0.5*v_oc``.
2420
- * i_xx - current, in amperes, at ``v = 0.5*(v_oc+v_mp)``.
2414
+ * i_sc - short circuit current in amperes.
2415
+ * v_oc - open circuit voltage in volts.
2416
+ * i_mp - current at maximum power point in amperes.
2417
+ * v_mp - voltage at maximum power point in volts.
2418
+ * p_mp - power at maximum power point in watts.
2419
+ * i_x - current, in amperes, at ``v = 0.5*v_oc``.
2420
+ * i_xx - current, in amperes, at ``v = 0.5*(v_oc+v_mp)``.
2421
2421
 
2422
- A dict is returned when the input parameters are scalars or
2423
- ``ivcurve_pnts > 0``. If ``ivcurve_pnts > 0``, the output dictionary
2424
- will also include the keys:
2425
-
2426
- * i - IV curve current in amperes.
2427
- * v - IV curve voltage in volts.
2422
+ A dict is returned when the input parameters are scalars.
2428
2423
 
2429
2424
  See also
2430
2425
  --------
@@ -2448,13 +2443,6 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2448
2443
  that guarantees convergence by bounding the voltage between zero and
2449
2444
  open-circuit.
2450
2445
 
2451
- If the method is either ``'newton'`` or ``'brentq'`` and ``ivcurve_pnts``
2452
- are indicated, then :func:`pvlib.singlediode.bishop88` [4]_ is used to
2453
- calculate the points on the IV curve points at diode voltages from zero to
2454
- open-circuit voltage with a log spacing that gets closer as voltage
2455
- increases. If the method is ``'lambertw'`` then the calculated points on
2456
- the IV curve are linearly spaced.
2457
-
2458
2446
  References
2459
2447
  ----------
2460
2448
  .. [1] S.R. Wenham, M.A. Green, M.E. Watt, "Applied Photovoltaics" ISBN
@@ -2471,21 +2459,13 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2471
2459
  photovoltaic cell interconnection circuits" JW Bishop, Solar Cell (1988)
2472
2460
  https://doi.org/10.1016/0379-6787(88)90059-2
2473
2461
  """
2474
- if ivcurve_pnts:
2475
- warn_deprecated('0.10.0', name='pvlib.pvsystem.singlediode',
2476
- alternative=('pvlib.pvsystem.v_from_i and '
2477
- 'pvlib.pvsystem.i_from_v'),
2478
- obj_type='parameter ivcurve_pnts',
2479
- removal='0.11.0')
2480
2462
  args = (photocurrent, saturation_current, resistance_series,
2481
2463
  resistance_shunt, nNsVth) # collect args
2482
2464
  # Calculate points on the IV curve using the LambertW solution to the
2483
2465
  # single diode equation
2484
2466
  if method.lower() == 'lambertw':
2485
- out = _singlediode._lambertw(*args, ivcurve_pnts)
2467
+ out = _singlediode._lambertw(*args)
2486
2468
  points = out[:7]
2487
- if ivcurve_pnts:
2488
- ivcurve_i, ivcurve_v = out[7:]
2489
2469
  else:
2490
2470
  # Calculate points on the IV curve using either 'newton' or 'brentq'
2491
2471
  # methods. Voltages are determined by first solving the single diode
@@ -2507,21 +2487,10 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2507
2487
  )
2508
2488
  points = i_sc, v_oc, i_mp, v_mp, p_mp, i_x, i_xx
2509
2489
 
2510
- # calculate the IV curve if requested using bishop88
2511
- if ivcurve_pnts:
2512
- vd = v_oc * (
2513
- (11.0 - np.logspace(np.log10(11.0), 0.0, ivcurve_pnts)) / 10.0
2514
- )
2515
- ivcurve_i, ivcurve_v, _ = _singlediode.bishop88(vd, *args)
2516
-
2517
2490
  columns = ('i_sc', 'v_oc', 'i_mp', 'v_mp', 'p_mp', 'i_x', 'i_xx')
2518
2491
 
2519
- if all(map(np.isscalar, args)) or ivcurve_pnts:
2492
+ if all(map(np.isscalar, args)):
2520
2493
  out = {c: p for c, p in zip(columns, points)}
2521
-
2522
- if ivcurve_pnts:
2523
- out.update(i=ivcurve_i, v=ivcurve_v)
2524
-
2525
2494
  return out
2526
2495
 
2527
2496
  points = np.atleast_1d(*points) # convert scalars to 1d-arrays
@@ -2536,7 +2505,7 @@ def singlediode(photocurrent, saturation_current, resistance_series,
2536
2505
 
2537
2506
 
2538
2507
  def max_power_point(photocurrent, saturation_current, resistance_series,
2539
- resistance_shunt, nNsVth, d2mutau=0, NsVbi=np.Inf,
2508
+ resistance_shunt, nNsVth, d2mutau=0, NsVbi=np.inf,
2540
2509
  method='brentq'):
2541
2510
  """
2542
2511
  Given the single diode equation coefficients, calculates the maximum power
pvlib/scaling.py CHANGED
@@ -13,8 +13,10 @@ from scipy.spatial.distance import pdist
13
13
  def wvm(clearsky_index, positions, cloud_speed, dt=None):
14
14
  """
15
15
  Compute spatial aggregation time series smoothing on clear sky index based
16
- on the Wavelet Variability model of Lave et al. [1]_, [2]_. Implementation
17
- is basically a port of the Matlab version of the code [3]_.
16
+ on the Wavelet Variability model.
17
+
18
+ This model is described in Lave et al. [1]_, [2]_.
19
+ Implementation is basically a port of the Matlab version of the code [3]_.
18
20
 
19
21
  Parameters
20
22
  ----------