Skip to content

Commit f4202bd

Browse files
authored
Merge branch 'main' into no_more_parse
2 parents 72313ea + cb8be87 commit f4202bd

File tree

8 files changed

+111
-62
lines changed

8 files changed

+111
-62
lines changed

docs/sphinx/source/whatsnew/v0.12.1.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,30 @@ Enhancements
1717
* :py:mod:`pvlib.ivtools.sdm` is now a subpackage. (:issue:`2252`, :pull:`2256`)
1818
* Add a function for estimating PVsyst SDM parameters from IEC 61853-1 matrix
1919
data (:py:func:`~pvlib.ivtools.sdm.fit_pvsyst_iec61853_sandia_2025`). (:issue:`2185`, :pull:`2429`)
20+
* The parameters for the Ix and Ixx points are now optional when using
21+
:py:func:`pvlib.pvsystem.sapm` directly and through
22+
:py:class:`~pvlib.pvsystem.PVSystem` and :py:class:`~pvlib.modelchain.ModelChain`.
23+
(:issue:`2402`, :pull:`2433`)
2024
* Add optional arguments ``temperature_ref`` and ``irradiance_ref`` to
2125
:py:func:`~pvlib.pvsystem.sapm`(:issue:`2432`, :pull:`2434`)
2226
* Add NREL NSRDB PSM v4 API client to :py:mod:`pvlib.iotools`. See
2327
:py:func:`~pvlib.iotools.get_nsrdb_psm4_aggregated`,
2428
:py:func:`~pvlib.iotools.get_nsrdb_psm4_tmy`,
2529
:py:func:`~pvlib.iotools.get_nsrdb_psm4_conus`,
2630
:py:func:`~pvlib.iotools.get_nsrdb_psm4_full_disc`, and
27-
:py:func:`~pvlib.iotools.read_nsrdb_psm4`. (:issue:`2326`, :pull:`2378`,
28-
:pull:`2445`)
31+
:py:func:`~pvlib.iotools.read_nsrdb_psm4`. (:issue:`2326`, :pull:`2378`, :pull:`2445`)
32+
* :py:mod:`pvlib.bifacial.infinite_sheds` no longer emits "invalid value" warnings
33+
when supplying irradiance arrays with nighttime zero values. (:issue:`2450`, :pull:`2451`)
2934

3035
Documentation
3136
~~~~~~~~~~~~~
3237
* Add a supporting reference to :py:func:`pvlib.atmosphere.get_relative_airmass` (:issue:`2390`, :pull:`2424`)
33-
* Documented how `np.nan` values are handled by :py:func:`~pvlib.spectrum.average_photon_energy`
38+
* Document how ``np.nan`` values are handled by :py:func:`~pvlib.spectrum.average_photon_energy`
3439
(:issue:`2423`, :pull:`2426`)
40+
* Clarify which SAPM coefficients are required by the ``module`` parameter in
41+
:py:func:`~pvlib.pvsystem.sapm` (:issue:`2392`, :pull:`2435`)
42+
* Update references in :py:func`~pvlib.irradiance.get_extra_radiation`
43+
(:issue:`2333`, :pull:`2347`)
3544

3645
Requirements
3746
~~~~~~~~~~~~

pvlib/bifacial/infinite_sheds.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,23 @@
99
from pvlib.irradiance import beam_component, aoi, haydavies
1010

1111

12-
def _poa_ground_shadows(poa_ground, f_gnd_beam, df, vf_gnd_sky):
12+
def _poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam, vf_gnd_sky):
1313
"""
1414
Reduce ground-reflected irradiance to the tilted plane (poa_ground) to
1515
account for shadows on the ground.
1616
1717
Parameters
1818
----------
19-
poa_ground : numeric
20-
Ground reflected irradiance on the tilted surface, assuming full GHI
21-
illumination on all of the ground. [W/m^2]
19+
ghi : numeric
20+
Global horizontal irradiance, with no adjustments. [W/m^2]
21+
dhi : numeric
22+
Diffuse horizontal irradiance, with no adjustments. [W/m^2]
23+
albedo : numeric
24+
Ground albedo, the ratio of reflected to incident irradiance of the
25+
ground surface. [W/m^2]
2226
f_gnd_beam : numeric
2327
Fraction of the distance between rows that is illuminated (unshaded).
2428
[unitless]
25-
df : numeric
26-
Diffuse fraction, the ratio of DHI to GHI. [unitless]
2729
vf_gnd_sky : numeric
2830
View factor from the ground to the sky, integrated along the distance
2931
between rows. [unitless]
@@ -35,7 +37,7 @@ def _poa_ground_shadows(poa_ground, f_gnd_beam, df, vf_gnd_sky):
3537
ground. [W/m^2]
3638
3739
"""
38-
return poa_ground * (f_gnd_beam*(1 - df) + df*vf_gnd_sky)
40+
return albedo * (f_gnd_beam * (ghi - dhi) + vf_gnd_sky * dhi)
3941

4042

4143
def _poa_sky_diffuse_pv(dhi, gcr, surface_tilt):
@@ -339,18 +341,11 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
339341
# and restricted views
340342
# this is a deviation from [1], because the row to ground view factor
341343
# is accounted for in a different manner
342-
ground_diffuse = ghi * albedo
343-
344-
# diffuse fraction
345-
diffuse_fraction = np.clip(dhi / ghi, 0., 1.)
346-
# make diffuse fraction 0 when ghi is small
347-
diffuse_fraction = np.where(ghi < 0.0001, 0., diffuse_fraction)
348-
349344
# Reduce ground-reflected irradiance because other rows in the array
350345
# block irradiance from reaching the ground.
351346
# [2], Eq. 9
352-
ground_diffuse = _poa_ground_shadows(
353-
ground_diffuse, f_gnd_beam, diffuse_fraction, vf_gnd_sky)
347+
ground_diffuse = _poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam,
348+
vf_gnd_sky)
354349

355350
# Ground-reflected irradiance on the row surface accounting for
356351
# the view to the ground. This deviates from [1], Eq. 10, 11 and

pvlib/irradiance.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,30 @@ def get_extra_radiation(datetime_or_doy, solar_constant=1366.1,
3535
"""
3636
Determine extraterrestrial radiation from day of year.
3737
38+
Specific references for each method are cited in the parameter descriptions
39+
below, while a more general discussion of the different models may also be
40+
found in [1]_ and [2]_.
41+
3842
Parameters
3943
----------
4044
datetime_or_doy : numeric, array, date, datetime, Timestamp, DatetimeIndex
4145
Day of year, array of days of year, or datetime-like object
4246
4347
solar_constant : float, default 1366.1
44-
The solar constant.
48+
The solar constant. [Wm⁻²]
4549
46-
method : string, default 'spencer'
47-
The method by which the ET radiation should be calculated.
48-
Options include ``'pyephem', 'spencer', 'asce', 'nrel'``.
50+
method : string, default `spencer`
51+
The method by which the extraterrestrial radiation should be
52+
calculated. Options include: `pyephem`, `spencer` [3]_, `asce` [4]_,
53+
'nrel' [6]_.
4954
5055
epoch_year : int, default 2014
5156
The year in which a day of year input will be calculated. Only
52-
applies to day of year input used with the pyephem or nrel
57+
applies to day of year input used with the `pyephem` or `nrel`
5358
methods.
5459
5560
kwargs :
56-
Passed to solarposition.nrel_earthsun_distance
61+
Passed to :py:func:`~pvlib.solarposition.nrel_earthsun_distance`.
5762
5863
Returns
5964
-------
@@ -68,19 +73,23 @@ def get_extra_radiation(datetime_or_doy, solar_constant=1366.1,
6873
.. [1] M. Reno, C. Hansen, and J. Stein, "Global Horizontal Irradiance
6974
Clear Sky Models: Implementation and Analysis", Sandia National
7075
Laboratories, SAND2012-2389, 2012.
76+
:doi:`10.2172/1039404`
7177
72-
.. [2] http://solardata.uoregon.edu/SolarRadiationBasics.html, Eqs.
73-
SR1 and SR2
78+
.. [2] J. A. Duffie, W. A. Beckman, N. Blair, "Solar Radiation", in Solar
79+
Engineering of Thermal Processes, Photovoltaics and Wind, 5th ed,
80+
New York, USA: J. Wiley and Sons, 2020, pp. 3-44.
81+
:doi:`10.1002/9781119540328`
7482
75-
.. [3] Partridge, G. W. and Platt, C. M. R. 1976. Radiative Processes
76-
in Meteorology and Climatology.
83+
.. [3] J. W. Spencer, "Fourier series representation of the sun," Search,
84+
vol. 2, p. 172, 1971.
7785
78-
.. [4] Duffie, J. A. and Beckman, W. A. 1991. Solar Engineering of
79-
Thermal Processes, 2nd edn. J. Wiley and Sons, New York.
86+
.. [4] R. G. Allen et al., Eds. The ASCE standardized reference
87+
evapotranspiration equation. Reston, Va.: American Society of Civil
88+
Engineers, 2005. :doi:`10.1061/9780784408056`
8089
81-
.. [5] ASCE, 2005. The ASCE Standardized Reference Evapotranspiration
82-
Equation, Environmental and Water Resources Institute of the American
83-
Civil Engineers, Ed. R. G. Allen et al.
90+
.. [6] I. Reda, A. Andreas, "Solar position algorithm for solar
91+
radiation applications" NREL Golden, USA. NREL/TP-560-34302,
92+
Revised 2008. :doi:`10.2172/15003974`
8493
"""
8594

8695
to_doy, to_datetimeindex, to_output = \

pvlib/modelchain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ def infer_dc_model(self):
611611
"""Infer DC power model from Array module parameters."""
612612
params = _common_keys(
613613
tuple(array.module_parameters for array in self.system.arrays))
614-
if {'A0', 'A1', 'C7'} <= params:
614+
if {'A0', 'A1', 'C3'} <= params:
615615
return self.sapm, 'sapm'
616616
elif {'a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref', 'R_s',
617617
'Adjust'} <= params:

pvlib/pvsystem.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
# a dict of required parameter names for each DC power model
2828
_DC_MODEL_PARAMS = {
2929
'sapm': {
30-
'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7',
30+
# i_x and i_xx params (IXO, IXXO, C4-C7) not required
31+
'C0', 'C1', 'C2', 'C3',
3132
'Isco', 'Impo', 'Voco', 'Vmpo', 'Aisc', 'Aimp', 'Bvoco',
32-
'Mbvoc', 'Bvmpo', 'Mbvmp', 'N', 'Cells_in_Series',
33-
'IXO', 'IXXO'},
33+
'Mbvoc', 'Bvmpo', 'Mbvmp', 'N', 'Cells_in_Series'},
3434
'desoto': {
3535
'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
3636
'R_sh_ref', 'R_s'},
@@ -2229,18 +2229,33 @@ def sapm(effective_irradiance, temp_cell, module, *, temperature_ref=25,
22292229
* v_mp : Voltage at maximum-power point (V)
22302230
* p_mp : Power at maximum-power point (W)
22312231
* i_x : Current at module V = 0.5Voc, defines 4th point on I-V
2232-
curve for modeling curve shape
2232+
curve for modeling curve shape. Omitted if ``IXO``, ``C4``, and
2233+
``C5`` parameters are not supplied.
22332234
* i_xx : Current at module V = 0.5(Voc+Vmp), defines 5th point on
2234-
I-V curve for modeling curve shape
2235+
I-V curve for modeling curve shape. Omitted if ``IXXO``, ``C6``,
2236+
and ``C7`` parameters are not supplied.
22352237
22362238
Notes
22372239
-----
2238-
The SAPM parameters which are required in ``module`` are
2239-
listed in the following table.
2240-
22412240
The Sandia module database contains parameter values for a limited set
22422241
of modules. The CEC module database does not contain these parameters.
2243-
Both databases can be accessed using :py:func:`retrieve_sam`.
2242+
Both databases can be accessed using :py:func:`retrieve_sam`. The full list
2243+
of SAPM parameters is presented in the table below. Those that are required
2244+
in the ``module`` parameter to run this model are as follows:
2245+
2246+
* ``C0``, ``C1``, ``C2``, ``C3``
2247+
* ``Isco``
2248+
* ``Impo``
2249+
* ``Voco``
2250+
* ``Vmpo``
2251+
* ``Aisc``
2252+
* ``Aimp``
2253+
* ``Bvoco``
2254+
* ``Mbvoc``
2255+
* ``Bvmpo``
2256+
* ``Mbvmp``
2257+
* ``N``
2258+
* ``Cells_in_series``
22442259
22452260
================ ========================================================
22462261
Key Description
@@ -2335,13 +2350,15 @@ def sapm(effective_irradiance, temp_cell, module, *, temperature_ref=25,
23352350

23362351
out['p_mp'] = out['i_mp'] * out['v_mp']
23372352

2338-
out['i_x'] = (
2339-
module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
2340-
(1 + module['Aisc']*(temp_cell - temperature_ref)))
2353+
if 'IXO' in module and 'C4' in module and 'C5' in module:
2354+
out['i_x'] = (
2355+
module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
2356+
(1 + module['Aisc']*(temp_cell - temperature_ref)))
23412357

2342-
out['i_xx'] = (
2343-
module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
2344-
(1 + module['Aimp']*(temp_cell - temperature_ref)))
2358+
if 'IXXO' in module and 'C6' in module and 'C7' in module:
2359+
out['i_xx'] = (
2360+
module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
2361+
(1 + module['Aimp']*(temp_cell - temperature_ref)))
23452362

23462363
if isinstance(out['i_sc'], pd.Series):
23472364
out = pd.DataFrame(out)

tests/bifacial/test_infinite_sheds.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,20 @@ def test_system():
4242

4343

4444
def test__poa_ground_shadows():
45-
poa_ground, f_gnd_beam, df, vf_gnd_sky = (300., 0.5, 0.5, 0.2)
46-
result = infinite_sheds._poa_ground_shadows(
47-
poa_ground, f_gnd_beam, df, vf_gnd_sky)
48-
expected = 300. * (0.5 * 0.5 + 0.5 * 0.2)
45+
ghi, dhi, albedo, f_gnd_beam, vf_gnd_sky = (300., 100, 0.3, 0.5, 0.2)
46+
result = infinite_sheds._poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam,
47+
vf_gnd_sky)
48+
49+
expected = 0.3 * (200 * 0.5 + 100 * 0.2)
4950
assert np.isclose(result, expected)
5051
# vector inputs
51-
poa_ground = np.array([300., 300.])
52-
f_gnd_beam = np.array([0.5, 0.5])
53-
df = np.array([0.5, 0.])
54-
vf_gnd_sky = np.array([0.2, 0.2])
55-
result = infinite_sheds._poa_ground_shadows(
56-
poa_ground, f_gnd_beam, df, vf_gnd_sky)
57-
expected_vec = np.array([expected, 300. * 0.5])
52+
ghi = np.array([ghi, ghi])
53+
dhi = np.array([dhi, 0])
54+
f_gnd_beam = np.array([f_gnd_beam, f_gnd_beam])
55+
vf_gnd_sky = np.array([vf_gnd_sky, vf_gnd_sky])
56+
result = infinite_sheds._poa_ground_shadows(ghi, dhi, albedo, f_gnd_beam,
57+
vf_gnd_sky)
58+
expected_vec = np.array([expected, 300. * 0.5 * 0.3])
5859
assert np.allclose(result, expected_vec)
5960

6061

tests/test_modelchain.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,16 @@ def test_invalid_dc_model_params(sapm_dc_snl_ac_system, cec_dc_snl_ac_system,
17621762
ModelChain(pvwatts_dc_pvwatts_ac_system, location, **kwargs)
17631763

17641764

1765+
def test_sapm_optional_params(sapm_dc_snl_ac_system, location):
1766+
# inference works when the optional (i_x, i_xx) SAPM parameters are missing
1767+
for array in sapm_dc_snl_ac_system.arrays:
1768+
for key in ['IXO', 'IXXO', 'C4', 'C5', 'C6', 'C7']:
1769+
array.module_parameters.pop(key)
1770+
1771+
# no error:
1772+
ModelChain(sapm_dc_snl_ac_system, location)
1773+
1774+
17651775
@pytest.mark.parametrize('model', [
17661776
'dc_model', 'ac_model', 'aoi_model', 'spectral_model',
17671777
'temperature_model', 'losses_model'

tests/test_pvsystem.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from pvlib.location import Location
1818
from pvlib.pvsystem import FixedMount
1919
from pvlib import temperature
20-
from pvlib._deprecation import pvlibDeprecationWarning
2120
from pvlib.tools import cosd
2221
from pvlib.singlediode import VOLTAGE_BUILTIN
2322

@@ -197,6 +196,15 @@ def test_sapm(sapm_module_params):
197196
pvsystem.sapm(effective_irradiance, temp_cell,
198197
pd.Series(sapm_module_params))
199198

199+
# ensure C4-C7 are optional
200+
optional_keys = ['IXO', 'IXXO', 'C4', 'C5', 'C6', 'C7']
201+
params_no_c4c7 = {
202+
k: v for k, v in sapm_module_params.items() if k not in optional_keys
203+
}
204+
out = pvsystem.sapm(effective_irradiance, temp_cell, params_no_c4c7)
205+
assert 'i_x' not in out.keys()
206+
assert 'i_xx' not in out.keys()
207+
200208

201209
def test_PVSystem_sapm(sapm_module_params, mocker):
202210
mocker.spy(pvsystem, 'sapm')

0 commit comments

Comments
 (0)