Skip to content

Commit 47b8df2

Browse files
authored
Make i_x and i_xx SAPM parameters optional (#2433)
* make C4-C7 optional in pvlib.pvsystem.sapm * make optional in PVSystem and ModelChain as well * incidental cleanup * whatsnew * lint * make IXO and IXXO optional too
1 parent 8a7927a commit 47b8df2

File tree

5 files changed

+39
-13
lines changed

5 files changed

+39
-13
lines changed

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

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ 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

pvlib/modelchain.py

+1-1
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

+15-11
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,9 +2229,11 @@ 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
-----
@@ -2335,13 +2337,15 @@ def sapm(effective_irradiance, temp_cell, module, *, temperature_ref=25,
23352337

23362338
out['p_mp'] = out['i_mp'] * out['v_mp']
23372339

2338-
out['i_x'] = (
2339-
module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
2340-
(1 + module['Aisc']*(temp_cell - temperature_ref)))
2340+
if 'IXO' in module and 'C4' in module and 'C5' in module:
2341+
out['i_x'] = (
2342+
module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
2343+
(1 + module['Aisc']*(temp_cell - temperature_ref)))
23412344

2342-
out['i_xx'] = (
2343-
module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
2344-
(1 + module['Aimp']*(temp_cell - temperature_ref)))
2345+
if 'IXXO' in module and 'C6' in module and 'C7' in module:
2346+
out['i_xx'] = (
2347+
module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
2348+
(1 + module['Aimp']*(temp_cell - temperature_ref)))
23452349

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

tests/test_modelchain.py

+10
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

+9-1
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)