Repository: pvlib/pvlib-python

Issue:
`pvsystem._DC_MODEL_PARAMS` lists unnecessary parameters for SAPM
`pvlib.pvsystem._DC_MODEL_PARAMS` lists parameter names for each of several DC models, including the SAPM:

https://github.com/pvlib/pvlib-python/blob/6440adac8ee8af28c7b5bf083f9398b01bfa97c1/pvlib/pvsystem.py#L29-L36

Many of these SAPM parameters are not used in the SAPM DC model.  `A0-A4` are for the airmass modifier.  `B0-B5` are for beam IAM. `FD` is for diffuse IAM.  None of these are required to run the DC portion of the SAPM, implemented in `pvlib.pvsystem.sapm`.

However, because these non-DC parameters are listed in `_DC_MODEL_PARAMS`, `ModelChain` raises an error if you do not supply them when setting `dc_model='sapm'`.  Here is an example of code that I would like to execute successfully:

```python
import pvlib
sapm_parameters = {
    # required parameters
    'C0': 1.02, 'C1': -0.018, 'C2': -0.15, 'C3': -12.26,
    'Isco': 14.03, 'Impo': 13.38, 'Voco': 51.54, 'Vmpo': 42.89,
    'Aisc': 0.00049, 'Aimp': 0.00050, 'Bvoco': -0.132, 'Bvmpo': -0.150,
    'Mbvoc': 0, 'Mbvmp': 0,
    'N': 1.128, 'Cells_in_Series': 72,
    # required parameters, but only for uninteresting outputs, so supply dummy values:
    'IXO': 0, 'IXXO': 0,
    'C4': 0, 'C5': 0, 'C6': 0, 'C7': 0
}

location = pvlib.location.Location(40, -80)
system = pvlib.pvsystem.PVSystem(module_parameters=sapm_parameters, inverter_parameters={'pdc0': 300})

mc = pvlib.modelchain.ModelChain(system, location, dc_model='sapm', spectral_model='no_loss', aoi_model='no_loss')
```

However, with the current pvlib, it fails, complaining about the missing non-DC parameters:

```
ValueError: sapm selected for the DC model but one or more Arrays are missing one or more required parameters  : {'B4', 'FD', 'B5', 'B1', 'A3', 'B0', 'B2', 'A0', 'A4', 'A2', 'B3', 'A1'}
```

I propose we remove the `A*`, `B*`, and `FD` parameters from this dictionary.

I could not locate any previous discussion of this, aside from a very brief exchange when the dictionary was first added: https://github.com/pvlib/pvlib-python/pull/548#discussion_r213118530


Discussion:
> I propose we remove the A*, B*, and FD parameters from this dictionary.

I agree



Patch:
diff --git a/docs/sphinx/source/whatsnew/v0.11.3.rst b/docs/sphinx/source/whatsnew/v0.11.3.rst
index 4f2637f948..22aca60e9d 100644
--- a/docs/sphinx/source/whatsnew/v0.11.3.rst
+++ b/docs/sphinx/source/whatsnew/v0.11.3.rst
@@ -4,6 +4,17 @@
 v0.11.3 (Anticipated March, 2025)
 ---------------------------------
 
+Bug fixes
+~~~~~~~~~
+* Fix a bug in :py:func:`pvlib.bifacial.get_irradiance_poa` which may have yielded non-zero
+  ground irradiance when the sun was below the horizon. (:issue:`2245`, :pull:`2359`)
+* Fix a bug where :py:func:`pvlib.transformer.simple_efficiency` could only be imported
+  using the `from pvlib.transformer` syntax (:pull:`2388`)
+* :py:class:`~pvlib.modelchain.ModelChain` now requires only a minimal set of
+  parameters to run the SAPM electrical model. (:issue:`2369`, :pull:`2393`)
+* Correct keys for First Solar modules in `~pvlib.spectrum.spectral_factor_pvspec` (:issue:`2398`, :pull:`2400`)
+
+
 Deprecations
 ~~~~~~~~~~~~
 
@@ -12,15 +23,10 @@ Enhancements
 ~~~~~~~~~~~~
 * :py:func:`~pvlib.irradiance.gti_dirint` now raises an informative message
   when input data don't include values with AOI<90 (:issue:`1342`, :pull:`2347`)
-* Fix a bug in :py:func:`pvlib.bifacial.get_irradiance_poa` which may have yielded non-zero
-  ground irradiance when the sun was below the horizon. (:issue:`2245`, :pull:`2359`)
-* Fix a bug where :py:func:`pvlib.transformer.simple_efficiency` could only be imported
-  using the `from pvlib.transformer` syntax (:pull:`2388`)
 * Reduced space requirements by excluding tests and test files from wheel.
   Zipped wheel is now 66% of the previous size, and installed size is 50% of
   the previous size.
   (:issue:`2271`, :pull:`2277`)
-* Correct keys for First Solar modules in `~pvlib.spectrum.spectral_factor_pvspec` (:issue:`2398`, :pull:`2400`)
 
 Documentation
 ~~~~~~~~~~~~~
@@ -57,4 +63,5 @@ Contributors
 * Manoj K S (:ghuser:`manojks1999`)
 * Kurt Rhee (:ghuser:`kurt-rhee`)
 * Ayush jariyal (:ghuser:`ayushjariyal`)
+* Kevin Anderson (:ghuser:`kandersolar`)
 * Echedey Luis (:ghuser:`echedey-ls`)
diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py
index f99f0275af..662ea6befa 100644
--- a/pvlib/pvsystem.py
+++ b/pvlib/pvsystem.py
@@ -29,11 +29,10 @@
 # a dict of required parameter names for each DC power model
 _DC_MODEL_PARAMS = {
     'sapm': {
-        'A0', 'A1', 'A2', 'A3', 'A4', 'B0', 'B1', 'B2', 'B3',
-        'B4', 'B5', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6',
-        'C7', 'Isco', 'Impo', 'Voco', 'Vmpo', 'Aisc', 'Aimp', 'Bvoco',
+        'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7',
+        'Isco', 'Impo', 'Voco', 'Vmpo', 'Aisc', 'Aimp', 'Bvoco',
         'Mbvoc', 'Bvmpo', 'Mbvmp', 'N', 'Cells_in_Series',
-        'IXO', 'IXXO', 'FD'},
+        'IXO', 'IXXO'},
     'desoto': {
         'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
         'R_sh_ref', 'R_s'},


Test patch:
diff --git a/tests/test_modelchain.py b/tests/test_modelchain.py
index 836fd3c3a0..815703a435 100644
--- a/tests/test_modelchain.py
+++ b/tests/test_modelchain.py
@@ -1217,6 +1217,22 @@ def test_infer_dc_model(sapm_dc_snl_ac_system, cec_dc_snl_ac_system,
     assert isinstance(mc.results.dc, (pd.Series, pd.DataFrame))
 
 
+def test_infer_dc_model_sapm_minimal(location):
+    # GH 2369 -- Omit A*, B*, FD parameters; specify only DC electrical keys
+    dc_keys = ['C0', 'C1', 'C2', 'C3', 'Isco', 'Impo', 'Voco', 'Vmpo',
+               'Aisc', 'Aimp', 'Bvoco', 'Bvmpo', 'Mbvoc', 'Mbvmp', 'N',
+               'Cells_in_Series', 'IXO', 'IXXO', 'C4', 'C5', 'C6', 'C7']
+    sapm_parameters = {key: 0 for key in dc_keys}
+
+    system = pvsystem.PVSystem(module_parameters=sapm_parameters,
+                               temperature_model_parameters={'u0': 0, 'u1': 0},
+                               inverter_parameters={'pdc0': 0})
+
+    mc = ModelChain(system, location, dc_model='sapm',
+                    spectral_model='no_loss', aoi_model='no_loss')
+    assert isinstance(mc, ModelChain)
+
+
 def test_infer_dc_model_incomplete(multi_array_sapm_dc_snl_ac_system,
                                    location):
     match = 'Could not infer DC model from the module_parameters attributes '
@@ -1730,7 +1746,7 @@ def test_invalid_dc_model_params(sapm_dc_snl_ac_system, cec_dc_snl_ac_system,
               'aoi_model': 'no_loss', 'spectral_model': 'no_loss',
               'temperature_model': 'sapm', 'losses_model': 'no_loss'}
     for array in sapm_dc_snl_ac_system.arrays:
-        array.module_parameters.pop('A0')  # remove a parameter
+        array.module_parameters.pop('C0')  # remove a parameter
     with pytest.raises(ValueError):
         ModelChain(sapm_dc_snl_ac_system, location, **kwargs)