From 51f4346b8f81a45b70b53c04e28a6eb3131c92fd Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 10:47:32 -0700 Subject: [PATCH 01/10] create PVSystem.get_ac --- pvlib/pvsystem.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index afc1c195cf..d089bbd82a 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -852,6 +852,40 @@ def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage, return i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, saturation_current, photocurrent) + def get_ac(self, model, p_dc, v_dc=None): + r"""Calculates AC power from p_dc using the inverter model indicated + by model and self.inverter_parameters. + + Parameter model must be one of 'sandia', 'adr', or 'pvwatts'. + + Parameter v_dc is required for model='sandia' or model='adr'. + + """ + model = model.lower() + if model == 'sandia': + if self.num_arrays > 1: + p_dc = self._validate_per_array(p_dc) + v_dc = self._validate_per_array(v_dc) + inv_fun = inverter.sandia_multi + else: + inv_fun = inverter.sandia + return inv_fun(v_dc, p_dc, self.inverter_parameters) + elif model == 'pvwatts': + kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], + self.inverter_parameters) + if self.num_arrays > 1: + p_dc = self._validate_per_array(p_dc) + inv_fun = inverter.pvwatts_multi + else: + inv_fun = inverter.pvwatts + return inv_fun(p_dc, self.inverter_parameters['pdc0'], **kwargs) + elif model == 'adr': + return inverter.adrinverter(v_dc, p_dc, self.inverter_parameters) + else: + raise ValueError( + model + ' is not a valid AC power model.', + ' model must be one of "sandia", "adr" or "pvwatts"') + # inverter now specified by self.inverter_parameters def snlinverter(self, v_dc, p_dc): """Uses :py:func:`pvlib.inverter.sandia` to calculate AC power based on From c0769e7d9f74d77bfed2f650e8eef220ba05f717 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 10:55:10 -0700 Subject: [PATCH 02/10] add docstring --- pvlib/pvsystem.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index d089bbd82a..24ce45336d 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -856,10 +856,37 @@ def get_ac(self, model, p_dc, v_dc=None): r"""Calculates AC power from p_dc using the inverter model indicated by model and self.inverter_parameters. - Parameter model must be one of 'sandia', 'adr', or 'pvwatts'. + Parameters + ---------- + model : str + Must be one of 'sandia', 'adr', or 'pvwatts'. + p_dc : numeric, or tuple, list or array of numeric + DC power on each MPPT input of the inverter. Use tuple, list or + array for inverters with multiple MPPT inputs. If type is array, + p_dc must be 2d with axis 0 being the MPPT inputs. [W] + v_dc : numeric, or tuple, list or array of numeric + DC voltage on each MPPT input of the inverter. Required when + model='sandia' or model='adr'. Use tuple, list or + array for inverters with multiple MPPT inputs. If type is array, + v_dc must be 2d with axis 0 being the MPPT inputs. [V] - Parameter v_dc is required for model='sandia' or model='adr'. + Returns + ------- + power_ac : numeric, or tuple of numeric + AC power output for the inverter. [W] + Raises + ------ + ValueError + If model is not one of 'sandia', 'adr' or 'pvwatts'. + + See also + -------- + pvlib.inverter.sandia + pvlib.inverter.sandia_multi + pvlib.inverter.adr + pvlib.inverter.pvwatts + pvlib.inverter.pvwatts_multi """ model = model.lower() if model == 'sandia': From 18434f69e28266d2c2431e1384830a154a801cb5 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 11:21:16 -0700 Subject: [PATCH 03/10] add tests for get_ac --- pvlib/tests/test_pvsystem.py | 111 +++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 311820828b..269bf0d7f4 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1374,6 +1374,21 @@ def test_PVSystem_multi_scale_voltage_current_power(mocker): system.scale_voltage_current_power(None) +def test_PVSystem_get_ac_sandia(cec_inverter_parameters, mocker): + inv_fun = mocker.spy(inverter, 'sandia') + system = pvsystem.PVSystem( + inverter=cec_inverter_parameters['Name'], + inverter_parameters=cec_inverter_parameters, + ) + vdcs = pd.Series(np.linspace(0, 50, 3)) + idcs = pd.Series(np.linspace(0, 11, 3)) + pdcs = idcs * vdcs + pacs = system.get_ac('sandia', vdcs, pdcs) + assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) + inv_fun.assert_called_once() + + +# remove after deprecation period for PVSystem.snlinverter def test_PVSystem_snlinverter(cec_inverter_parameters): system = pvsystem.PVSystem( inverter=cec_inverter_parameters['Name'], @@ -1387,6 +1402,31 @@ def test_PVSystem_snlinverter(cec_inverter_parameters): assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) +def test_PVSystem_get_ac_sandia_multi(cec_inverter_parameters, mocker): + inv_fun = mocker.spy(inverter, 'sandia_multi') + system = pvsystem.PVSystem( + arrays=[pvsystem.Array(), pvsystem.Array()], + inverter=cec_inverter_parameters['Name'], + inverter_parameters=cec_inverter_parameters, + ) + vdcs = pd.Series(np.linspace(0, 50, 3)) + idcs = pd.Series(np.linspace(0, 11, 3)) / 2 + pdcs = idcs * vdcs + pacs = system.get_ac('sandia', (vdcs, vdcs), (pdcs, pdcs)) + assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) + inv_fun.assert_called_once() + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('sandia', vdcs, (pdcs, pdcs)) + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('sandia', vdcs, (pdcs,)) + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('sandia', (vdcs, vdcs), (pdcs, pdcs, pdcs)) + + +# remove after deprecation period for PVSystem.sandia_multi def test_PVSystem_sandia_multi(cec_inverter_parameters): system = pvsystem.PVSystem( arrays=[pvsystem.Array(), pvsystem.Array()], @@ -1409,7 +1449,7 @@ def test_PVSystem_sandia_multi(cec_inverter_parameters): system.sandia_multi((vdcs, vdcs), (pdcs, pdcs, pdcs)) -def test_PVSystem_sandia_multi_single_array(cec_inverter_parameters): +def test_PVSystem_get_ac_sandia_multi_single_array(cec_inverter_parameters): system = pvsystem.PVSystem( arrays=[pvsystem.Array()], inverter=cec_inverter_parameters['Name'], @@ -1419,16 +1459,74 @@ def test_PVSystem_sandia_multi_single_array(cec_inverter_parameters): idcs = pd.Series(np.linspace(0, 11, 3)) pdcs = idcs * vdcs - pacs = system.sandia_multi(vdcs, pdcs) + pacs = system.get_ac('sandia', vdcs, pdcs) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) - pacs = system.sandia_multi((vdcs,), (pdcs,)) + pacs = system.get_ac('sandia', (vdcs,), (pdcs,)) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.sandia_multi((vdcs, vdcs), pdcs) + system.get_ac('sandia', (vdcs, vdcs), pdcs) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.sandia_multi((vdcs,), (pdcs, pdcs)) + system.get_ac('sandia', (vdcs,), (pdcs, pdcs)) + + +def test_PVSystem_get_ac_pvwatts(pvwatts_system_defaults, mocker): + mocker.spy(inverter, 'pvwatts') + pdc = 50 + out = pvwatts_system_defaults.get_ac('pvwatts', pdc) + inverter.pvwatts.assert_called_once_with( + pdc, **pvwatts_system_defaults.inverter_parameters) + assert out < pdc + + +def test_PVSystem_get_ac_pvwatts_kwargs(pvwatts_system_kwargs, mocker): + mocker.spy(inverter, 'pvwatts') + pdc = 50 + out = pvwatts_system_kwargs.get_ac('pvwatts', pdc) + inverter.pvwatts.assert_called_once_with( + pdc, **pvwatts_system_kwargs.inverter_parameters) + assert out < pdc + + +def test_PVSystem_get_ac_pvwatts_multi( + pvwatts_system_defaults, pvwatts_system_kwargs, mocker): + mocker.spy(inverter, 'pvwatts_multi') + expected = [pd.Series([0.0, 48.123524, 86.400000]), + pd.Series([0.0, 45.893550, 85.500000])] + systems = [pvwatts_system_defaults, pvwatts_system_kwargs] + for base_sys, exp in zip(systems, expected): + system = pvsystem.PVSystem( + arrays=[pvsystem.Array(), pvsystem.Array()], + inverter_parameters=base_sys.inverter_parameters, + ) + pdcs = pd.Series([0., 25., 50.]) + pacs = system.get_ac('pvwatts', (pdcs, pdcs)) + assert_series_equal(pacs, exp) + assert inverter.pvwatts_multi.call_count == 2 + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('pvwatts', (pdcs,)) + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('pvwatts', pdcs) + with pytest.raises(ValueError, + match="Length mismatch for per-array parameter"): + system.get_ac('pvwatts', (pdcs, pdcs, pdcs)) + + +def test_PVSystem_get_ac_adr(adr_inverter_parameters, mocker): + mocker.spy(inverter, 'adr') + system = pvsystem.PVSystem( + inverter_parameters=adr_inverter_parameters, + ) + vdcs = pd.Series([135, 154, 390, 420, 551]) + pdcs = pd.Series([135, 1232, 1170, 420, 551]) + pacs = system.get_ac('adr', vdcs, pdcs) + assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459, + 382.6679, np.nan])) + inverter.adr.assert_called_once_with(vdcs, pdcs, + **system.inverter_parameters) def test_PVSystem_creation(): @@ -1891,6 +1989,7 @@ def test_PVSystem_pvwatts_losses(pvwatts_system_defaults, mocker): assert out < expected +# remove after deprecation period for PVSystem.pvwatts_ac def test_PVSystem_pvwatts_ac(pvwatts_system_defaults, mocker): mocker.spy(inverter, 'pvwatts') pdc = 50 @@ -1900,6 +1999,7 @@ def test_PVSystem_pvwatts_ac(pvwatts_system_defaults, mocker): assert out < pdc +# remove after deprecation period for PVSystem.pvwatts_ac def test_PVSystem_pvwatts_ac_kwargs(pvwatts_system_kwargs, mocker): mocker.spy(inverter, 'pvwatts') pdc = 50 @@ -1909,6 +2009,7 @@ def test_PVSystem_pvwatts_ac_kwargs(pvwatts_system_kwargs, mocker): assert out < pdc +# remove after deprecation period for PVSystem.pvwatts_ac def test_PVSystem_pvwatts_multi(pvwatts_system_defaults, pvwatts_system_kwargs): expected = [pd.Series([0.0, 48.123524, 86.400000]), From 607cf4c256e07ec6643677baee50b8d486af6f2e Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 13:07:27 -0700 Subject: [PATCH 04/10] fix adrinverter name, revert change to test_PVSystem_sandia_multi_single_array --- pvlib/pvsystem.py | 2 +- pvlib/tests/test_pvsystem.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 24ce45336d..659d48dafb 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -907,7 +907,7 @@ def get_ac(self, model, p_dc, v_dc=None): inv_fun = inverter.pvwatts return inv_fun(p_dc, self.inverter_parameters['pdc0'], **kwargs) elif model == 'adr': - return inverter.adrinverter(v_dc, p_dc, self.inverter_parameters) + return inverter.adr(v_dc, p_dc, self.inverter_parameters) else: raise ValueError( model + ' is not a valid AC power model.', diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 269bf0d7f4..3fe411ecb6 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1449,7 +1449,7 @@ def test_PVSystem_sandia_multi(cec_inverter_parameters): system.sandia_multi((vdcs, vdcs), (pdcs, pdcs, pdcs)) -def test_PVSystem_get_ac_sandia_multi_single_array(cec_inverter_parameters): +def test_PVSystem_sandia_multi_single_array(cec_inverter_parameters): system = pvsystem.PVSystem( arrays=[pvsystem.Array()], inverter=cec_inverter_parameters['Name'], @@ -1459,16 +1459,16 @@ def test_PVSystem_get_ac_sandia_multi_single_array(cec_inverter_parameters): idcs = pd.Series(np.linspace(0, 11, 3)) pdcs = idcs * vdcs - pacs = system.get_ac('sandia', vdcs, pdcs) + pacs = system.system.sandia_multi(vdcs, pdcs) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) - pacs = system.get_ac('sandia', (vdcs,), (pdcs,)) + pacs = system.system.sandia_multi((vdcs,), (pdcs,)) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.get_ac('sandia', (vdcs, vdcs), pdcs) + system.system.sandia_multi((vdcs, vdcs), pdcs) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.get_ac('sandia', (vdcs,), (pdcs, pdcs)) + system.system.sandia_multi((vdcs,), (pdcs, pdcs)) def test_PVSystem_get_ac_pvwatts(pvwatts_system_defaults, mocker): From cb06bbc0e713b41bf265c24991176b024a742b3f Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 13:27:21 -0700 Subject: [PATCH 05/10] more fixes --- pvlib/tests/test_pvsystem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 3fe411ecb6..a97ebe8eb1 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1459,16 +1459,16 @@ def test_PVSystem_sandia_multi_single_array(cec_inverter_parameters): idcs = pd.Series(np.linspace(0, 11, 3)) pdcs = idcs * vdcs - pacs = system.system.sandia_multi(vdcs, pdcs) + pacs = system.sandia_multi(vdcs, pdcs) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) - pacs = system.system.sandia_multi((vdcs,), (pdcs,)) + pacs = system.sandia_multi((vdcs,), (pdcs,)) assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.system.sandia_multi((vdcs, vdcs), pdcs) + system.sandia_multi((vdcs, vdcs), pdcs) with pytest.raises(ValueError, match="Length mismatch for per-array parameter"): - system.system.sandia_multi((vdcs,), (pdcs, pdcs)) + system.sandia_multi((vdcs,), (pdcs, pdcs)) def test_PVSystem_get_ac_pvwatts(pvwatts_system_defaults, mocker): @@ -1522,7 +1522,7 @@ def test_PVSystem_get_ac_adr(adr_inverter_parameters, mocker): ) vdcs = pd.Series([135, 154, 390, 420, 551]) pdcs = pd.Series([135, 1232, 1170, 420, 551]) - pacs = system.get_ac('adr', vdcs, pdcs) + pacs = system.get_ac('adr', pdcs, vdcs) assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459, 382.6679, np.nan])) inverter.adr.assert_called_once_with(vdcs, pdcs, From 1766912c70d03eddffcd5763321b4f931ce7581e Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 25 Jan 2021 16:32:20 -0700 Subject: [PATCH 06/10] improve test coverage, restructure if/else --- pvlib/pvsystem.py | 15 ++++++++++++--- pvlib/tests/test_pvsystem.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 659d48dafb..ceaaba0529 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -852,6 +852,7 @@ def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage, return i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, saturation_current, photocurrent) + @_unwrap_single_value def get_ac(self, model, p_dc, v_dc=None): r"""Calculates AC power from p_dc using the inverter model indicated by model and self.inverter_parameters. @@ -879,6 +880,8 @@ def get_ac(self, model, p_dc, v_dc=None): ------ ValueError If model is not one of 'sandia', 'adr' or 'pvwatts'. + ValueError + If model='adr' and the PVSystem has more than one array. See also -------- @@ -889,8 +892,9 @@ def get_ac(self, model, p_dc, v_dc=None): pvlib.inverter.pvwatts_multi """ model = model.lower() + mulitple_arrays = self.num_arrays > 1 if model == 'sandia': - if self.num_arrays > 1: + if mulitple_arrays: p_dc = self._validate_per_array(p_dc) v_dc = self._validate_per_array(v_dc) inv_fun = inverter.sandia_multi @@ -900,14 +904,19 @@ def get_ac(self, model, p_dc, v_dc=None): elif model == 'pvwatts': kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], self.inverter_parameters) - if self.num_arrays > 1: + if mulitple_arrays: p_dc = self._validate_per_array(p_dc) inv_fun = inverter.pvwatts_multi else: inv_fun = inverter.pvwatts return inv_fun(p_dc, self.inverter_parameters['pdc0'], **kwargs) elif model == 'adr': - return inverter.adr(v_dc, p_dc, self.inverter_parameters) + if mulitple_arrays: + raise ValueError( + 'The adr inverter function cannot be used for an inverter', + 'with multiple MPPT inputs') + else: + return inverter.adr(v_dc, p_dc, self.inverter_parameters) else: raise ValueError( model + ' is not a valid AC power model.', diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index a97ebe8eb1..43558084a2 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1449,6 +1449,7 @@ def test_PVSystem_sandia_multi(cec_inverter_parameters): system.sandia_multi((vdcs, vdcs), (pdcs, pdcs, pdcs)) +# remove after deprecation period for PVSystem.sandia_multi def test_PVSystem_sandia_multi_single_array(cec_inverter_parameters): system = pvsystem.PVSystem( arrays=[pvsystem.Array()], @@ -1529,6 +1530,26 @@ def test_PVSystem_get_ac_adr(adr_inverter_parameters, mocker): **system.inverter_parameters) +def test_PVSystem_get_ac_adr_multi(adr_inverter_parameters): + system = pvsystem.PVSystem( + arrays=[pvsystem.Array(), pvsystem.Array()], + inverter_parameters=adr_inverter_parameters, + ) + pdcs = pd.Series([135, 1232, 1170, 420, 551]) + with pytest.raises(ValueError, + match="The adr inverter function cannot be used"): + system.get_ac(model='adr', p_dc=pdcs) + + +def test_PVSystem_get_ac_invalid(cec_inverter_parameters): + system = pvsystem.PVSystem( + inverter_parameters=cec_inverter_parameters, + ) + pdcs = pd.Series(np.linspace(0, 50, 3)) + with pytest.raises(ValueError, match="is not a valid AC power model"): + system.get_ac(model='not_a_model', p_dc=pdcs) + + def test_PVSystem_creation(): pv_system = pvsystem.PVSystem(module='blah', inverter='blarg') # ensure that parameter attributes are dict-like. GH 294 From 36dac157ac45a241b16ec70cec865829dcda95b9 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 26 Jan 2021 10:48:20 -0700 Subject: [PATCH 07/10] remove unwrap decorator, fix adr called_once_with --- pvlib/pvsystem.py | 1 - pvlib/tests/test_pvsystem.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index ceaaba0529..c5d4e3a8c3 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -852,7 +852,6 @@ def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage, return i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, saturation_current, photocurrent) - @_unwrap_single_value def get_ac(self, model, p_dc, v_dc=None): r"""Calculates AC power from p_dc using the inverter model indicated by model and self.inverter_parameters. diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 43558084a2..dd6a51abc2 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1527,7 +1527,7 @@ def test_PVSystem_get_ac_adr(adr_inverter_parameters, mocker): assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459, 382.6679, np.nan])) inverter.adr.assert_called_once_with(vdcs, pdcs, - **system.inverter_parameters) + system.inverter_parameters) def test_PVSystem_get_ac_adr_multi(adr_inverter_parameters): From 7a3f3f7cf2d3d73ceae6c2f2c24a6ef5743789d4 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 26 Jan 2021 12:01:43 -0700 Subject: [PATCH 08/10] docstrings, api, whatsnew, deprecations --- docs/sphinx/source/api.rst | 1 + docs/sphinx/source/whatsnew/v0.9.0.rst | 12 ++++ pvlib/pvsystem.py | 79 ++++++++++---------------- 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index f043894ee6..5586c4e44e 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -292,6 +292,7 @@ Inverter models (DC to AC conversion) .. autosummary:: :toctree: generated/ + pvsystem.PVSystem.get_ac inverter.sandia inverter.sandia_multi inverter.adr diff --git a/docs/sphinx/source/whatsnew/v0.9.0.rst b/docs/sphinx/source/whatsnew/v0.9.0.rst index 91254807c8..c265d00768 100644 --- a/docs/sphinx/source/whatsnew/v0.9.0.rst +++ b/docs/sphinx/source/whatsnew/v0.9.0.rst @@ -56,6 +56,15 @@ Deprecations * ``ModelChain.total_irrad`` * ``ModelChain.tracking`` +* The following ``PVSystem`` methods are deprecated. Use ``PVsystem.get_ac`` + instead. + * ``PVSystem.snlinverter`` + * ``PVSystem.sandia_multi`` + * ``PVSystem.adrinverter`` + * ``PVSystem.pvwatts`` + * ``PVSystem.pvwatts_multi`` + + Enhancements ~~~~~~~~~~~~ * In :py:class:`~pvlib.modelchain.ModelChain`, attributes which contain @@ -87,6 +96,9 @@ Enhancements by ``pvsystem.PVSystem.modules_per_strings`` and ``pvsystem.PVSystem.strings_per_inverter``. Note that both attributes still default to 1. (:pull:`1138`) +* :py:meth:`~pvlib.pvsystem.PVSystem.get_ac` is added to calculate AC power + from DC power. Use parameter 'model' to specify which inverter model to use. + (:pull:`1147`, :issue:`998`) Bug fixes ~~~~~~~~~ diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index c5d4e3a8c3..dfeaf6eeb0 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -872,7 +872,7 @@ def get_ac(self, model, p_dc, v_dc=None): Returns ------- - power_ac : numeric, or tuple of numeric + power_ac : numeric AC power output for the inverter. [W] Raises @@ -891,9 +891,9 @@ def get_ac(self, model, p_dc, v_dc=None): pvlib.inverter.pvwatts_multi """ model = model.lower() - mulitple_arrays = self.num_arrays > 1 + multiple_arrays = self.num_arrays > 1 if model == 'sandia': - if mulitple_arrays: + if multiple_arrays: p_dc = self._validate_per_array(p_dc) v_dc = self._validate_per_array(v_dc) inv_fun = inverter.sandia_multi @@ -903,17 +903,17 @@ def get_ac(self, model, p_dc, v_dc=None): elif model == 'pvwatts': kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], self.inverter_parameters) - if mulitple_arrays: + if multiple_arrays: p_dc = self._validate_per_array(p_dc) inv_fun = inverter.pvwatts_multi else: inv_fun = inverter.pvwatts return inv_fun(p_dc, self.inverter_parameters['pdc0'], **kwargs) elif model == 'adr': - if mulitple_arrays: + if multiple_arrays: raise ValueError( 'The adr inverter function cannot be used for an inverter', - 'with multiple MPPT inputs') + ' with multiple MPPT inputs') else: return inverter.adr(v_dc, p_dc, self.inverter_parameters) else: @@ -921,35 +921,29 @@ def get_ac(self, model, p_dc, v_dc=None): model + ' is not a valid AC power model.', ' model must be one of "sandia", "adr" or "pvwatts"') - # inverter now specified by self.inverter_parameters def snlinverter(self, v_dc, p_dc): - """Uses :py:func:`pvlib.inverter.sandia` to calculate AC power based on - ``self.inverter_parameters`` and the input voltage and power. - - See :py:func:`pvlib.inverter.sandia` for details """ - return inverter.sandia(v_dc, p_dc, self.inverter_parameters) + Deprecated. Use ``PVSystem.get_ac`` instead. + """ + warnings.warn('PVsystem.sandia_multi is deprecated and will be', + ' removed in v0.10. Use PVSystem.get_ac instead') + return self.get_ac('sandia', p_dc, v_dc) def sandia_multi(self, v_dc, p_dc): - """Uses :py:func:`pvlib.inverter.sandia_multi` to calculate AC power - based on ``self.inverter_parameters`` and the input voltage and power. - - The parameters `v_dc` and `p_dc` must be tuples with length equal to - ``self.num_arrays`` if the system has more than one array. - - See :py:func:`pvlib.inverter.sandia_multi` for details. """ - v_dc = self._validate_per_array(v_dc) - p_dc = self._validate_per_array(p_dc) - return inverter.sandia_multi(v_dc, p_dc, self.inverter_parameters) + Deprecated. Use ``PVSystem.get_ac`` instead. + """ + warnings.warn('PVsystem.sandia_multi is deprecated and will be', + ' removed in v0.10. Use PVSystem.get_ac instead') + return self.get_ac('sandia', p_dc, v_dc) def adrinverter(self, v_dc, p_dc): - """Uses :py:func:`pvlib.inverter.adr` to calculate AC power based on - ``self.inverter_parameters`` and the input voltage and power. - - See :py:func:`pvlib.inverter.adr` for details """ - return inverter.adr(v_dc, p_dc, self.inverter_parameters) + Deprecated. Use ``PVSystem.get_ac`` instead. + """ + warnings.warn('PVsystem.sandia_multi is deprecated and will be', + ' removed in v0.10. Use PVSystem.get_ac instead') + return self.get_ac('adr', p_dc, v_dc) @_unwrap_single_value def scale_voltage_current_power(self, data): @@ -1012,32 +1006,19 @@ def pvwatts_losses(self): def pvwatts_ac(self, pdc): """ - Calculates AC power according to the PVWatts model using - :py:func:`pvlib.inverter.pvwatts`, `self.module_parameters["pdc0"]`, - and `eta_inv_nom=self.inverter_parameters["eta_inv_nom"]`. - - See :py:func:`pvlib.inverter.pvwatts` for details. + Deprecated. Use ``PVSystem.get_ac`` instead. """ - kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], - self.inverter_parameters) - - return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], - **kwargs) + warnings.warn('PVsystem.sandia_multi is deprecated and will be', + ' removed in v0.10. Use PVSystem.get_ac instead') + return self.get_ac('pvwatts', pdc) def pvwatts_multi(self, p_dc): - """Uses :py:func:`pvlib.inverter.pvwatts_multi` to calculate AC power - based on ``self.inverter_parameters`` and the input voltage and power. - - The parameter `p_dc` must be a tuple with length equal to - ``self.num_arrays`` if the system has more than one array. - - See :py:func:`pvlib.inverter.pvwatts_multi` for details. """ - p_dc = self._validate_per_array(p_dc) - kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], - self.inverter_parameters) - return inverter.pvwatts_multi(p_dc, self.inverter_parameters['pdc0'], - **kwargs) + Deprecated. Use ``PVSystem.get_ac`` instead. + """ + warnings.warn('PVsystem.sandia_multi is deprecated and will be', + ' removed in v0.10. Use PVSystem.get_ac instead') + return self.get_ac('pvwatts', p_dc) @property @_unwrap_single_value From b53e48fafb9bf442b41346701e051e3e16b974d5 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 26 Jan 2021 12:13:54 -0700 Subject: [PATCH 09/10] test deprecations --- pvlib/tests/test_pvsystem.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index dd6a51abc2..1fa9de0cfb 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -2077,3 +2077,33 @@ def test_combine_loss_factors(): def test_no_extra_kwargs(): with pytest.raises(TypeError, match="arbitrary_kwarg"): pvsystem.PVSystem(arbitrary_kwarg='value') + + +def test_deprecated_inverter_methods(cec_inverter_parameters, + adr_inverter_parameters, + pvwatts_system_defaults): + system = pvsystem.PVSystem( + inverter=cec_inverter_parameters['Name'], + inverter_parameters=cec_inverter_parameters, + ) + vdcs = pd.Series(np.linspace(0, 50, 3)) + idcs = pd.Series(np.linspace(0, 11, 3)) + pdcs = idcs * vdcs + matchtxt = "Use PVSystem.get_ac instead" + with pytest.warns(match=matchtxt): + system.snlinverter(vdcs, pdcs) + with pytest.warns(match=matchtxt): + system.sandia_multi((vdcs,), (pdcs,)) + system = pvsystem.PVSystem( + inverter_parameters=adr_inverter_parameters, + ) + with pytest.warns(match=matchtxt): + system.adrinverter(vdcs, pdcs) + with pytest.warns(match=matchtxt): + pvwatts_system_defaults.pvwatts_ac(pdcs) + system = pvsystem.PVSystem( + arrays=[pvsystem.Array(), pvsystem.Array()], + inverter_parameters=pvwatts_system_defaults.inverter_parameters, + ) + with pytest.warns(match=matchtxt): + system.pvwatts_ac((pdcs, pdcs)) From fc3eafc4b8797b23420f07a0cb0b52de90f346d2 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 26 Jan 2021 13:08:43 -0700 Subject: [PATCH 10/10] undeprecate existing methods --- docs/sphinx/source/whatsnew/v0.9.0.rst | 9 ---- pvlib/pvsystem.py | 67 ++++++++++++++++---------- pvlib/tests/test_pvsystem.py | 30 ------------ 3 files changed, 42 insertions(+), 64 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.9.0.rst b/docs/sphinx/source/whatsnew/v0.9.0.rst index c265d00768..446f4ac25d 100644 --- a/docs/sphinx/source/whatsnew/v0.9.0.rst +++ b/docs/sphinx/source/whatsnew/v0.9.0.rst @@ -56,15 +56,6 @@ Deprecations * ``ModelChain.total_irrad`` * ``ModelChain.tracking`` -* The following ``PVSystem`` methods are deprecated. Use ``PVsystem.get_ac`` - instead. - * ``PVSystem.snlinverter`` - * ``PVSystem.sandia_multi`` - * ``PVSystem.adrinverter`` - * ``PVSystem.pvwatts`` - * ``PVSystem.pvwatts_multi`` - - Enhancements ~~~~~~~~~~~~ * In :py:class:`~pvlib.modelchain.ModelChain`, attributes which contain diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index dfeaf6eeb0..cb003f2b3f 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -922,28 +922,33 @@ def get_ac(self, model, p_dc, v_dc=None): ' model must be one of "sandia", "adr" or "pvwatts"') def snlinverter(self, v_dc, p_dc): + """Uses :py:func:`pvlib.inverter.sandia` to calculate AC power based on + ``self.inverter_parameters`` and the input voltage and power. + + See :py:func:`pvlib.inverter.sandia` for details """ - Deprecated. Use ``PVSystem.get_ac`` instead. - """ - warnings.warn('PVsystem.sandia_multi is deprecated and will be', - ' removed in v0.10. Use PVSystem.get_ac instead') - return self.get_ac('sandia', p_dc, v_dc) + return inverter.sandia(v_dc, p_dc, self.inverter_parameters) def sandia_multi(self, v_dc, p_dc): + """Uses :py:func:`pvlib.inverter.sandia_multi` to calculate AC power + based on ``self.inverter_parameters`` and the input voltage and power. + + The parameters `v_dc` and `p_dc` must be tuples with length equal to + ``self.num_arrays`` if the system has more than one array. + + See :py:func:`pvlib.inverter.sandia_multi` for details. """ - Deprecated. Use ``PVSystem.get_ac`` instead. - """ - warnings.warn('PVsystem.sandia_multi is deprecated and will be', - ' removed in v0.10. Use PVSystem.get_ac instead') - return self.get_ac('sandia', p_dc, v_dc) + v_dc = self._validate_per_array(v_dc) + p_dc = self._validate_per_array(p_dc) + return inverter.sandia_multi(v_dc, p_dc, self.inverter_parameters) def adrinverter(self, v_dc, p_dc): + """Uses :py:func:`pvlib.inverter.adr` to calculate AC power based on + ``self.inverter_parameters`` and the input voltage and power. + + See :py:func:`pvlib.inverter.adr` for details """ - Deprecated. Use ``PVSystem.get_ac`` instead. - """ - warnings.warn('PVsystem.sandia_multi is deprecated and will be', - ' removed in v0.10. Use PVSystem.get_ac instead') - return self.get_ac('adr', p_dc, v_dc) + return inverter.adr(v_dc, p_dc, self.inverter_parameters) @_unwrap_single_value def scale_voltage_current_power(self, data): @@ -1006,20 +1011,32 @@ def pvwatts_losses(self): def pvwatts_ac(self, pdc): """ - Deprecated. Use ``PVSystem.get_ac`` instead. + Calculates AC power according to the PVWatts model using + :py:func:`pvlib.inverter.pvwatts`, `self.module_parameters["pdc0"]`, + and `eta_inv_nom=self.inverter_parameters["eta_inv_nom"]`. + + See :py:func:`pvlib.inverter.pvwatts` for details. """ - warnings.warn('PVsystem.sandia_multi is deprecated and will be', - ' removed in v0.10. Use PVSystem.get_ac instead') - return self.get_ac('pvwatts', pdc) + kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], + self.inverter_parameters) + + return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], + **kwargs) def pvwatts_multi(self, p_dc): - """ - Deprecated. Use ``PVSystem.get_ac`` instead. - """ - warnings.warn('PVsystem.sandia_multi is deprecated and will be', - ' removed in v0.10. Use PVSystem.get_ac instead') - return self.get_ac('pvwatts', p_dc) + """Uses :py:func:`pvlib.inverter.pvwatts_multi` to calculate AC power + based on ``self.inverter_parameters`` and the input voltage and power. + + The parameter `p_dc` must be a tuple with length equal to + ``self.num_arrays`` if the system has more than one array. + See :py:func:`pvlib.inverter.pvwatts_multi` for details. + """ + p_dc = self._validate_per_array(p_dc) + kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], + self.inverter_parameters) + return inverter.pvwatts_multi(p_dc, self.inverter_parameters['pdc0'], + **kwargs) @property @_unwrap_single_value def module_parameters(self): diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 1fa9de0cfb..dd6a51abc2 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -2077,33 +2077,3 @@ def test_combine_loss_factors(): def test_no_extra_kwargs(): with pytest.raises(TypeError, match="arbitrary_kwarg"): pvsystem.PVSystem(arbitrary_kwarg='value') - - -def test_deprecated_inverter_methods(cec_inverter_parameters, - adr_inverter_parameters, - pvwatts_system_defaults): - system = pvsystem.PVSystem( - inverter=cec_inverter_parameters['Name'], - inverter_parameters=cec_inverter_parameters, - ) - vdcs = pd.Series(np.linspace(0, 50, 3)) - idcs = pd.Series(np.linspace(0, 11, 3)) - pdcs = idcs * vdcs - matchtxt = "Use PVSystem.get_ac instead" - with pytest.warns(match=matchtxt): - system.snlinverter(vdcs, pdcs) - with pytest.warns(match=matchtxt): - system.sandia_multi((vdcs,), (pdcs,)) - system = pvsystem.PVSystem( - inverter_parameters=adr_inverter_parameters, - ) - with pytest.warns(match=matchtxt): - system.adrinverter(vdcs, pdcs) - with pytest.warns(match=matchtxt): - pvwatts_system_defaults.pvwatts_ac(pdcs) - system = pvsystem.PVSystem( - arrays=[pvsystem.Array(), pvsystem.Array()], - inverter_parameters=pvwatts_system_defaults.inverter_parameters, - ) - with pytest.warns(match=matchtxt): - system.pvwatts_ac((pdcs, pdcs))