From e9fe39c93a38434813a61248822c244275219e28 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 11 Feb 2020 14:46:42 -0700 Subject: [PATCH 01/31] create inverter.py, move code, add adrinverter fixture --- pvlib/inverter.py | 325 +++++++++++++++++++++++++++++++++++ pvlib/pvsystem.py | 322 ++-------------------------------- pvlib/tests/conftest.py | 27 +++ pvlib/tests/test_inverter.py | 134 +++++++++++++++ pvlib/tests/test_pvsystem.py | 144 ++-------------- 5 files changed, 513 insertions(+), 439 deletions(-) create mode 100644 pvlib/inverter.py create mode 100644 pvlib/tests/test_inverter.py diff --git a/pvlib/inverter.py b/pvlib/inverter.py new file mode 100644 index 0000000000..c0344bd2fb --- /dev/null +++ b/pvlib/inverter.py @@ -0,0 +1,325 @@ +# -*- coding: utf-8 -*- +""" +This module contains functions for inverter modeling, primarily conversion of +DC to AC power. +""" + +import numpy as np +import pandas as pd + + +def sandia(v_dc, p_dc, inverter): + r''' + Converts DC power and voltage to AC power using Sandia's + Grid-Connected PV Inverter model. + + Parameters + ---------- + v_dc : numeric + DC voltages, in volts, which are provided as input to the + inverter. Vdc should be >= 0. + + p_dc : numeric + A scalar or DataFrame of DC powers, in watts, which are provided + as input to the inverter. Pdc should be >= 0. + + inverter : dict-like + A dict-like object defining the inverter to be used, giving the + inverter performance parameters according to the Sandia + Grid-Connected Photovoltaic Inverter Model (SAND 2007-5036) [1]_. + A set of inverter performance parameters are provided with + pvlib, or may be generated from a System Advisor Model (SAM) [2]_ + library using retrievesam. See Notes for required keys. + + Returns + ------- + ac_power : numeric + Modeled AC power output given the input DC voltage, Vdc, and + input DC power, Pdc. When ac_power would be greater than Pac0, + it is set to Pac0 to represent inverter "clipping". When + ac_power would be less than Ps0 (startup power required), then + ac_power is set to -1*abs(Pnt) to represent nightly power + losses. ac_power is not adjusted for maximum power point + tracking (MPPT) voltage windows or maximum current limits of the + inverter. + + Notes + ----- + + Determines the AC power output of an inverter given the DC voltage and DC + power. Output AC power is clipped at the inverter's maximum power output + and output power can be negative during low-input power conditions. The + Sandia inverter model does NOT account for maximum power point + tracking voltage windows nor maximum current or voltage limits on + the inverter. + + Required inverter keys are: + + ====== ============================================================ + Column Description + ====== ============================================================ + Pac0 AC-power output from inverter based on input power + and voltage (W) + Pdc0 DC-power input to inverter, typically assumed to be equal + to the PV array maximum power (W) + Vdc0 DC-voltage level at which the AC-power rating is achieved + at the reference operating condition (V) + Ps0 DC-power required to start the inversion process, or + self-consumption by inverter, strongly influences inverter + efficiency at low power levels (W) + C0 Parameter defining the curvature (parabolic) of the + relationship between ac-power and dc-power at the reference + operating condition, default value of zero gives a + linear relationship (1/W) + C1 Empirical coefficient allowing Pdco to vary linearly + with dc-voltage input, default value is zero (1/V) + C2 Empirical coefficient allowing Pso to vary linearly with + dc-voltage input, default value is zero (1/V) + C3 Empirical coefficient allowing Co to vary linearly with + dc-voltage input, default value is zero (1/V) + Pnt AC-power consumed by inverter at night (night tare) to + maintain circuitry required to sense PV array voltage (W) + ====== ============================================================ + + References + ---------- + .. [1] SAND2007-5036, "Performance Model for Grid-Connected + Photovoltaic Inverters by D. King, S. Gonzalez, G. Galbraith, W. + Boyson + + .. [2] System Advisor Model web page. https://sam.nrel.gov. + + See also + -------- + pvlib.pvsystem.sapm + ''' + + Paco = inverter['Paco'] + Pdco = inverter['Pdco'] + Vdco = inverter['Vdco'] + Pso = inverter['Pso'] + C0 = inverter['C0'] + C1 = inverter['C1'] + C2 = inverter['C2'] + C3 = inverter['C3'] + Pnt = inverter['Pnt'] + + A = Pdco * (1 + C1*(v_dc - Vdco)) + B = Pso * (1 + C2*(v_dc - Vdco)) + C = C0 * (1 + C3*(v_dc - Vdco)) + + ac_power = (Paco/(A-B) - C*(A-B)) * (p_dc-B) + C*((p_dc-B)**2) + ac_power = np.minimum(Paco, ac_power) + ac_power = np.where(p_dc < Pso, -1.0 * abs(Pnt), ac_power) + + if isinstance(p_dc, pd.Series): + ac_power = pd.Series(ac_power, index=p_dc.index) + + return ac_power + + +def adrinverter(v_dc, p_dc, inverter, vtol=0.10): + r''' + Converts DC power and voltage to AC power using Anton Driesse's + Grid-Connected PV Inverter efficiency model + + Parameters + ---------- + v_dc : numeric + A scalar or pandas series of DC voltages, in volts, which are provided + as input to the inverter. If Vdc and Pdc are vectors, they must be + of the same size. v_dc must be >= 0. [V] + + p_dc : numeric + A scalar or pandas series of DC powers, in watts, which are provided + as input to the inverter. If Vdc and Pdc are vectors, they must be + of the same size. p_dc must be >= 0. [W] + + inverter : dict-like + A dict-like object defining the inverter to be used, giving the + inverter performance parameters according to the model + developed by Anton Driesse [1]_. + A set of inverter performance parameters may be loaded from the + supplied data table using retrievesam. + See Notes for required keys. + + vtol : numeric, default 0.1 + A unit-less fraction that determines how far the efficiency model is + allowed to extrapolate beyond the inverter's normal input voltage + operating range. 0.0 <= vtol <= 1.0 + + Returns + ------- + ac_power : numeric + A numpy array or pandas series of modeled AC power output given the + input DC voltage, v_dc, and input DC power, p_dc. When ac_power would + be greater than pac_max, it is set to p_max to represent inverter + "clipping". When ac_power would be less than -p_nt (energy consumed + rather than produced) then ac_power is set to -p_nt to represent + nightly power losses. ac_power is not adjusted for maximum power point + tracking (MPPT) voltage windows or maximum current limits of the + inverter. [W] + + Notes + ----- + + Required inverter keys are: + + ======= ============================================================ + Column Description + ======= ============================================================ + Pnom The nominal power value used to normalize all power values, + typically the DC power needed to produce maximum AC power + output. [W] + + Vnom The nominal DC voltage value used to normalize DC voltage + values, typically the level at which the highest efficiency + is achieved. [V] + + Vmax . [V] + + Vmin . [V] + + Vdcmax . [V] + + MPPTHi . [unit] + + MPPTLow . [unit] + + Pacmax The maximum AC output power value, used to clip the output + if needed, (W). + + ADRCoefficients A list of 9 coefficients that capture the influence + of input voltage and power on inverter losses, and thereby + efficiency. + + Pnt AC power consumed by inverter at night (night tare) to + maintain circuitry required to sense PV array voltage. [W] + + ======= ============================================================ + + References + ---------- + .. [1] Beyond the Curves: Modeling the Electrical Efficiency + of Photovoltaic Inverters, PVSC 2008, Anton Driesse et. al. + + See also + -------- + pvlib.inverter.sandia + ''' + + p_nom = inverter['Pnom'] + v_nom = inverter['Vnom'] + pac_max = inverter['Pacmax'] + p_nt = inverter['Pnt'] + ce_list = inverter['ADRCoefficients'] + v_max = inverter['Vmax'] + v_min = inverter['Vmin'] + vdc_max = inverter['Vdcmax'] + mppt_hi = inverter['MPPTHi'] + mppt_low = inverter['MPPTLow'] + + v_lim_upper = float(np.nanmax([v_max, vdc_max, mppt_hi]) * (1 + vtol)) + v_lim_lower = float(np.nanmax([v_min, mppt_low]) * (1 - vtol)) + + pdc = p_dc / p_nom + vdc = v_dc / v_nom + # zero voltage will lead to division by zero, but since power is + # set to night time value later, these errors can be safely ignored + with np.errstate(invalid='ignore', divide='ignore'): + poly = np.array([pdc**0, # replace with np.ones_like? + pdc, + pdc**2, + vdc - 1, + pdc * (vdc - 1), + pdc**2 * (vdc - 1), + 1. / vdc - 1, # divide by 0 + pdc * (1. / vdc - 1), # invalid 0./0. --> nan + pdc**2 * (1. / vdc - 1)]) # divide by 0 + p_loss = np.dot(np.array(ce_list), poly) + ac_power = p_nom * (pdc-p_loss) + p_nt = -1 * np.absolute(p_nt) + + # set output to nan where input is outside of limits + # errstate silences case where input is nan + with np.errstate(invalid='ignore'): + invalid = (v_lim_upper < v_dc) | (v_dc < v_lim_lower) + ac_power = np.where(invalid, np.nan, ac_power) + + # set night values + ac_power = np.where(vdc == 0, p_nt, ac_power) + ac_power = np.maximum(ac_power, p_nt) + + # set max ac output + ac_power = np.minimum(ac_power, pac_max) + + if isinstance(p_dc, pd.Series): + ac_power = pd.Series(ac_power, index=pdc.index) + + return ac_power + + + +def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): + r""" + Implements NREL's PVWatts inverter model [1]_. + + .. math:: + + \eta = \frac{\eta_{nom}}{\eta_{ref}} (-0.0162\zeta - \frac{0.0059} + {\zeta} + 0.9858) + + .. math:: + + P_{ac} = \min(\eta P_{dc}, P_{ac0}) + + where :math:`\zeta=P_{dc}/P_{dc0}` and :math:`P_{dc0}=P_{ac0}/\eta_{nom}`. + + Note that pdc0 is also used as a symbol in + :py:func:`pvlib.pvsystem.pvwatts_dc`. pdc0 in this function refers to the + DC power input limit of the inverter. pdc0 in + :py:func:`pvlib.pvsystem.pvwatts_dc` refers to the DC power of the module's + at reference conditions. + + Parameters + ---------- + pdc: numeric + DC power. + pdc0: numeric + DC input limit of the inverter. + eta_inv_nom: numeric, default 0.96 + Nominal inverter efficiency. + eta_inv_ref: numeric, default 0.9637 + Reference inverter efficiency. PVWatts defines it to be 0.9637 + and is included here for flexibility. + + Returns + ------- + pac: numeric + AC power. + + References + ---------- + .. [1] A. P. Dobos, "PVWatts Version 5 Manual," + http://pvwatts.nrel.gov/downloads/pvwattsv5.pdf + (2014). + """ + + pac0 = eta_inv_nom * pdc0 + zeta = pdc / pdc0 + + # arrays to help avoid divide by 0 for scalar and array + eta = np.zeros_like(pdc, dtype=float) + pdc_neq_0 = ~np.equal(pdc, 0) + + # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 + eta = eta_inv_nom / eta_inv_ref * ( + - 0.0162*zeta + - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + + 0.9858) + + pac = eta * pdc + pac = np.minimum(pac0, pac) + pac = np.maximum(0, pac) # GH 541 + + return pac \ No newline at end of file diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index d9a24b9b52..6b217b0e28 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -13,8 +13,8 @@ from pvlib._deprecation import deprecated -from pvlib import (atmosphere, iam, irradiance, singlediode as _singlediode, - temperature) +from pvlib import (atmosphere, iam, inverter, irradiance, + singlediode as _singlediode, temperature) from pvlib.tools import _build_kwargs from pvlib.location import Location from pvlib._deprecation import pvlibDeprecationWarning @@ -2363,249 +2363,6 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, return I -def snlinverter(v_dc, p_dc, inverter): - r''' - Converts DC power and voltage to AC power using Sandia's - Grid-Connected PV Inverter model. - - Determines the AC power output of an inverter given the DC voltage, - DC power, and appropriate Sandia Grid-Connected Photovoltaic - Inverter Model parameters. The output, ac_power, is clipped at the - maximum power output, and gives a negative power during low-input - power conditions, but does NOT account for maximum power point - tracking voltage windows nor maximum current or voltage limits on - the inverter. - - Parameters - ---------- - v_dc : numeric - DC voltages, in volts, which are provided as input to the - inverter. Vdc must be >= 0. - - p_dc : numeric - A scalar or DataFrame of DC powers, in watts, which are provided - as input to the inverter. Pdc must be >= 0. - - inverter : dict-like - A dict-like object defining the inverter to be used, giving the - inverter performance parameters according to the Sandia - Grid-Connected Photovoltaic Inverter Model (SAND 2007-5036) [1]_. - A set of inverter performance parameters are provided with - pvlib, or may be generated from a System Advisor Model (SAM) [2]_ - library using retrievesam. See Notes for required keys. - - Returns - ------- - ac_power : numeric - Modeled AC power output given the input DC voltage, Vdc, and - input DC power, Pdc. When ac_power would be greater than Pac0, - it is set to Pac0 to represent inverter "clipping". When - ac_power would be less than Ps0 (startup power required), then - ac_power is set to -1*abs(Pnt) to represent nightly power - losses. ac_power is not adjusted for maximum power point - tracking (MPPT) voltage windows or maximum current limits of the - inverter. - - Notes - ----- - - Required inverter keys are: - - ====== ============================================================ - Column Description - ====== ============================================================ - Pac0 AC-power output from inverter based on input power - and voltage (W) - Pdc0 DC-power input to inverter, typically assumed to be equal - to the PV array maximum power (W) - Vdc0 DC-voltage level at which the AC-power rating is achieved - at the reference operating condition (V) - Ps0 DC-power required to start the inversion process, or - self-consumption by inverter, strongly influences inverter - efficiency at low power levels (W) - C0 Parameter defining the curvature (parabolic) of the - relationship between ac-power and dc-power at the reference - operating condition, default value of zero gives a - linear relationship (1/W) - C1 Empirical coefficient allowing Pdco to vary linearly - with dc-voltage input, default value is zero (1/V) - C2 Empirical coefficient allowing Pso to vary linearly with - dc-voltage input, default value is zero (1/V) - C3 Empirical coefficient allowing Co to vary linearly with - dc-voltage input, default value is zero (1/V) - Pnt AC-power consumed by inverter at night (night tare) to - maintain circuitry required to sense PV array voltage (W) - ====== ============================================================ - - References - ---------- - .. [1] SAND2007-5036, "Performance Model for Grid-Connected - Photovoltaic Inverters by D. King, S. Gonzalez, G. Galbraith, W. - Boyson - - .. [2] System Advisor Model web page. https://sam.nrel.gov. - - See also - -------- - sapm - singlediode - ''' - - Paco = inverter['Paco'] - Pdco = inverter['Pdco'] - Vdco = inverter['Vdco'] - Pso = inverter['Pso'] - C0 = inverter['C0'] - C1 = inverter['C1'] - C2 = inverter['C2'] - C3 = inverter['C3'] - Pnt = inverter['Pnt'] - - A = Pdco * (1 + C1*(v_dc - Vdco)) - B = Pso * (1 + C2*(v_dc - Vdco)) - C = C0 * (1 + C3*(v_dc - Vdco)) - - ac_power = (Paco/(A-B) - C*(A-B)) * (p_dc-B) + C*((p_dc-B)**2) - ac_power = np.minimum(Paco, ac_power) - ac_power = np.where(p_dc < Pso, -1.0 * abs(Pnt), ac_power) - - if isinstance(p_dc, pd.Series): - ac_power = pd.Series(ac_power, index=p_dc.index) - - return ac_power - - -def adrinverter(v_dc, p_dc, inverter, vtol=0.10): - r''' - Converts DC power and voltage to AC power using Anton Driesse's - Grid-Connected PV Inverter efficiency model - - Parameters - ---------- - v_dc : numeric - A scalar or pandas series of DC voltages, in volts, which are provided - as input to the inverter. If Vdc and Pdc are vectors, they must be - of the same size. v_dc must be >= 0. (V) - - p_dc : numeric - A scalar or pandas series of DC powers, in watts, which are provided - as input to the inverter. If Vdc and Pdc are vectors, they must be - of the same size. p_dc must be >= 0. (W) - - inverter : dict-like - A dict-like object defining the inverter to be used, giving the - inverter performance parameters according to the model - developed by Anton Driesse [1]. - A set of inverter performance parameters may be loaded from the - supplied data table using retrievesam. - See Notes for required keys. - - vtol : numeric, default 0.1 - A unit-less fraction that determines how far the efficiency model is - allowed to extrapolate beyond the inverter's normal input voltage - operating range. 0.0 <= vtol <= 1.0 - - Returns - ------- - ac_power : numeric - A numpy array or pandas series of modeled AC power output given the - input DC voltage, v_dc, and input DC power, p_dc. When ac_power would - be greater than pac_max, it is set to p_max to represent inverter - "clipping". When ac_power would be less than -p_nt (energy consumed - rather than produced) then ac_power is set to -p_nt to represent - nightly power losses. ac_power is not adjusted for maximum power point - tracking (MPPT) voltage windows or maximum current limits of the - inverter. - - Notes - ----- - - Required inverter keys are: - - ======= ============================================================ - Column Description - ======= ============================================================ - p_nom The nominal power value used to normalize all power values, - typically the DC power needed to produce maximum AC power - output, (W). - - v_nom The nominal DC voltage value used to normalize DC voltage - values, typically the level at which the highest efficiency - is achieved, (V). - - pac_max The maximum AC output power value, used to clip the output - if needed, (W). - - ce_list This is a list of 9 coefficients that capture the influence - of input voltage and power on inverter losses, and thereby - efficiency. - - p_nt ac-power consumed by inverter at night (night tare) to - maintain circuitry required to sense PV array voltage, (W). - ======= ============================================================ - - References - ---------- - .. [1] Beyond the Curves: Modeling the Electrical Efficiency - of Photovoltaic Inverters, PVSC 2008, Anton Driesse et. al. - - See also - -------- - sapm - singlediode - ''' - - p_nom = inverter['Pnom'] - v_nom = inverter['Vnom'] - pac_max = inverter['Pacmax'] - p_nt = inverter['Pnt'] - ce_list = inverter['ADRCoefficients'] - v_max = inverter['Vmax'] - v_min = inverter['Vmin'] - vdc_max = inverter['Vdcmax'] - mppt_hi = inverter['MPPTHi'] - mppt_low = inverter['MPPTLow'] - - v_lim_upper = float(np.nanmax([v_max, vdc_max, mppt_hi]) * (1 + vtol)) - v_lim_lower = float(np.nanmax([v_min, mppt_low]) * (1 - vtol)) - - pdc = p_dc / p_nom - vdc = v_dc / v_nom - # zero voltage will lead to division by zero, but since power is - # set to night time value later, these errors can be safely ignored - with np.errstate(invalid='ignore', divide='ignore'): - poly = np.array([pdc**0, # replace with np.ones_like? - pdc, - pdc**2, - vdc - 1, - pdc * (vdc - 1), - pdc**2 * (vdc - 1), - 1. / vdc - 1, # divide by 0 - pdc * (1. / vdc - 1), # invalid 0./0. --> nan - pdc**2 * (1. / vdc - 1)]) # divide by 0 - p_loss = np.dot(np.array(ce_list), poly) - ac_power = p_nom * (pdc-p_loss) - p_nt = -1 * np.absolute(p_nt) - - # set output to nan where input is outside of limits - # errstate silences case where input is nan - with np.errstate(invalid='ignore'): - invalid = (v_lim_upper < v_dc) | (v_dc < v_lim_lower) - ac_power = np.where(invalid, np.nan, ac_power) - - # set night values - ac_power = np.where(vdc == 0, p_nt, ac_power) - ac_power = np.maximum(ac_power, p_nt) - - # set max ac output - ac_power = np.minimum(ac_power, pac_max) - - if isinstance(p_dc, pd.Series): - ac_power = pd.Series(ac_power, index=pdc.index) - - return ac_power - - def scale_voltage_current_power(data, voltage=1, current=1): """ Scales the voltage, current, and power of the DataFrames @@ -2742,69 +2499,6 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, return losses -def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): - r""" - Implements NREL's PVWatts inverter model [1]_. - - .. math:: - - \eta = \frac{\eta_{nom}}{\eta_{ref}} (-0.0162\zeta - \frac{0.0059}{\zeta} + 0.9858) - - .. math:: - - P_{ac} = \min(\eta P_{dc}, P_{ac0}) - - where :math:`\zeta=P_{dc}/P_{dc0}` and :math:`P_{dc0}=P_{ac0}/\eta_{nom}`. - - Note that the pdc0 is also used as a symbol in :py:func:`pvwatts_dc`. pdc0 - in this function refers to the DC power input limit of the inverter. - pdc0 in :py:func:`pvwatts_dc` refers to the DC power of the modules - at reference conditions. - - Parameters - ---------- - pdc: numeric - DC power. - pdc0: numeric - DC input limit of the inverter. - eta_inv_nom: numeric, default 0.96 - Nominal inverter efficiency. - eta_inv_ref: numeric, default 0.9637 - Reference inverter efficiency. PVWatts defines it to be 0.9637 - and is included here for flexibility. - - Returns - ------- - pac: numeric - AC power. - - References - ---------- - .. [1] A. P. Dobos, "PVWatts Version 5 Manual," - http://pvwatts.nrel.gov/downloads/pvwattsv5.pdf - (2014). - """ - - pac0 = eta_inv_nom * pdc0 - zeta = pdc / pdc0 - - # arrays to help avoid divide by 0 for scalar and array - eta = np.zeros_like(pdc, dtype=float) - pdc_neq_0 = ~np.equal(pdc, 0) - - # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 - eta = eta_inv_nom / eta_inv_ref * ( - - 0.0162*zeta - - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) - + 0.9858) - - pac = eta * pdc - pac = np.minimum(pac0, pac) - pac = np.maximum(0, pac) # GH 541 - - return pac - - ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', removal='0.8')(iam.ashrae) @@ -2815,3 +2509,15 @@ def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): sapm_aoi_loss = deprecated('0.7', alternative='iam.sapm', name='sapm_aoi_loss', removal='0.8')(iam.sapm) + + +snlinverter = deprecated('0.8', alternative='inverter.sandia', + name='snlinverter', removal='0.9')(inverter.sandia) + + +adrinverter = deprecated('0.8', alternative='inverter.adr', name='adrinverter', + removal='0.9')(inverter.adr) + + +pvwatts_ac = deprecated('0.8', alternative='inverter.pvwatts', + name='pvwatts_ac', removal='0.9')(inverter.pvwatts) diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index b803d04c81..bf520a26a9 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -190,6 +190,33 @@ def pvsyst_module_params(): return parameters +@pytest.fixture(scope='function') +def adr_inverter_parameters(): + """ + Define some ADR inverter parameters for testing. + + The scope of the fixture is set to ``'function'`` to allow tests to modify + parameters if required without affecting other tests. + """ + parameters = { + 'Name': 'Ablerex Electronics Co., Ltd.: ES 2200-US-240 (240Vac)' \ + '[CEC 2011]', + 'Vac': 240., + 'Pacmax': 2110., + 'Pnom': 2200., + 'Vnom': 396., + 'Vmin': 155., + 'Vmax': 413., + 'Vdcmax': 500., + 'MPPTHi':450., + 'MPPTLow': 150., + 'Pnt': 0.25, + 'ADRCoefficients': [0.01385, 0.0152, 0.00794, 0.00286, -0.01872, + -0.01305, 0.0, 0.0, 0.0] + } + return parameters + + @pytest.fixture(scope='function') def cec_inverter_parameters(): """ diff --git a/pvlib/tests/test_inverter.py b/pvlib/tests/test_inverter.py new file mode 100644 index 0000000000..69adc18e71 --- /dev/null +++ b/pvlib/tests/test_inverter.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- + +import numpy as np +import pandas as pd + +from pandas.util.testing import assert_series_equal +from numpy.testing import assert_allclose + +from pvlib import inverter +from conftest import needs_numpy_1_10 + + +def test_adr(adr_inverter_parameters): + vdcs = pd.Series([135, 154, 390, 420, 551]) + pdcs = pd.Series([135, 1232, 1170, 420, 551]) + + pacs = inverter.adr(vdcs, pdcs, adr_inverter_parameters) + assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459, + 382.6679, np.nan])) + + +def test_adr_vtol(adr_inverter_parameters): + vdcs = pd.Series([135, 154, 390, 420, 551]) + pdcs = pd.Series([135, 1232, 1170, 420, 551]) + + pacs = inverter.adr(vdcs, pdcs, adr_inverter_parameters, vtol=0.20) + assert_series_equal(pacs, pd.Series([104.8223, 1161.5745, 1116.4459, + 382.6679, 513.3385])) + + +def test_adr_float(adr_inverter_parameters): + vdcs = 154. + pdcs = 1232. + + pacs = inverter.adr(vdcs, pdcs, adr_inverter_parameters) + assert_allclose(pacs, 1161.5745) + + +def test_adr_invalid_and_night(sam_data): + # also tests if inverter.adr can read the output from pvsystem.retrieve_sam + inverters = sam_data['adrinverter'] + testinv = 'Zigor__Sunzet_3_TL_US_240V__CEC_2011_' + vdcs = np.array([39.873036, 0., np.nan, 420]) + pdcs = np.array([188.09182, 0., 420, np.nan]) + + pacs = inverter.adr(vdcs, pdcs, inverters[testinv]) + assert_allclose(pacs, np.array([np.nan, -0.25, np.nan, np.nan])) + + +def test_sandia(cec_inverter_parameters): + vdcs = pd.Series(np.linspace(0,50,3)) + idcs = pd.Series(np.linspace(0,11,3)) + pdcs = idcs * vdcs + + pacs = inverter.sandia(vdcs, pdcs, cec_inverter_parameters) + assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) + + +def test_sandia_float(cec_inverter_parameters): + vdcs = 25. + idcs = 5.5 + pdcs = idcs * vdcs + + pacs = inverter.sandia(vdcs, pdcs, cec_inverter_parameters) + assert_allclose(pacs, 132.004278, 5) + + +def test_sandia_Pnt_micro(): + """ + Test for issue #140, where some microinverters were giving a positive AC + power output when the DC power was 0. + """ + inverter_parameters = { + 'Name': 'Enphase Energy: M250-60-2LL-S2x (-ZC) (-NA) 208V [CEC 2013]', + 'Vac': 208.0, + 'Paco': 240.0, + 'Pdco': 250.5311318, + 'Vdco': 32.06160667, + 'Pso': 1.12048857, + 'C0': -5.76E-05, + 'C1': -6.24E-04, + 'C2': 8.09E-02, + 'C3': -0.111781106, + 'Pnt': 0.043, + 'Vdcmax': 48.0, + 'Idcmax': 9.8, + 'Mppt_low': 27.0, + 'Mppt_high': 39.0, + } + vdcs = pd.Series(np.linspace(0,50,3)) + idcs = pd.Series(np.linspace(0,11,3)) + pdcs = idcs * vdcs + + pacs = inverter.sandia(vdcs, pdcs, inverter_parameters) + assert_series_equal(pacs, pd.Series([-0.043, 132.545914746, 240.0])) + + +def test_pvwatts_ac_scalars(): + expected = 85.58556604752516 + out = inverter.pvwatts_ac(90, 100, 0.95) + assert_allclose(out, expected) + # GH 675 + expected = 0. + out = inverter.pvwatts_ac(0., 100) + assert_allclose(out, expected) + + +def test_pvwatts_ac_possible_negative(): + # pvwatts_ac could return a negative value for (pdc / pdc0) < 0.006 + # unless it is clipped. see GH 541 for more + expected = 0 + out = inverter.pvwatts_ac(0.001, 1) + assert_allclose(out, expected) + + +@needs_numpy_1_10 +def test_pvwatts_ac_arrays(): + pdc = np.array([[np.nan], [0], [50], [100]]) + pdc0 = 100 + expected = np.array([[np.nan], + [0.], + [47.60843624], + [95.]]) + out = inverter.pvwatts_ac(pdc, pdc0, 0.95) + assert_allclose(out, expected, equal_nan=True) + + +def test_pvwatts_ac_series(): + pdc = pd.Series([np.nan, 0, 50, 100]) + pdc0 = 100 + expected = pd.Series(np.array([np.nan, 0., 47.608436, 95.])) + out = inverter.pvwatts_ac(pdc, pdc0, 0.95) + assert_series_equal(expected, out) + diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 97a60e4c19..40906e31ce 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1107,60 +1107,6 @@ def test_PVSystem_scale_voltage_current_power(mocker): m.assert_called_once_with(data, voltage=2, current=3) -def test_adrinverter(sam_data): - inverters = sam_data['adrinverter'] - testinv = 'Ablerex_Electronics_Co___Ltd___' \ - 'ES_2200_US_240__240_Vac__240V__CEC_2011_' - vdcs = pd.Series([135, 154, 390, 420, 551]) - pdcs = pd.Series([135, 1232, 1170, 420, 551]) - - pacs = pvsystem.adrinverter(vdcs, pdcs, inverters[testinv]) - assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459, - 382.6679, np.nan])) - - -def test_adrinverter_vtol(sam_data): - inverters = sam_data['adrinverter'] - testinv = 'Ablerex_Electronics_Co___Ltd___' \ - 'ES_2200_US_240__240_Vac__240V__CEC_2011_' - vdcs = pd.Series([135, 154, 390, 420, 551]) - pdcs = pd.Series([135, 1232, 1170, 420, 551]) - - pacs = pvsystem.adrinverter(vdcs, pdcs, inverters[testinv], vtol=0.20) - assert_series_equal(pacs, pd.Series([104.8223, 1161.5745, 1116.4459, - 382.6679, 513.3385])) - - -def test_adrinverter_float(sam_data): - inverters = sam_data['adrinverter'] - testinv = 'Ablerex_Electronics_Co___Ltd___' \ - 'ES_2200_US_240__240_Vac__240V__CEC_2011_' - vdcs = 154. - pdcs = 1232. - - pacs = pvsystem.adrinverter(vdcs, pdcs, inverters[testinv]) - assert_allclose(pacs, 1161.5745) - - -def test_adrinverter_invalid_and_night(sam_data): - inverters = sam_data['adrinverter'] - testinv = 'Zigor__Sunzet_3_TL_US_240V__CEC_2011_' - vdcs = np.array([39.873036, 0., np.nan, 420]) - pdcs = np.array([188.09182, 0., 420, np.nan]) - - pacs = pvsystem.adrinverter(vdcs, pdcs, inverters[testinv]) - assert_allclose(pacs, np.array([np.nan, -0.25, np.nan, np.nan])) - - -def test_snlinverter(cec_inverter_parameters): - vdcs = pd.Series(np.linspace(0,50,3)) - idcs = pd.Series(np.linspace(0,11,3)) - pdcs = idcs * vdcs - - pacs = pvsystem.snlinverter(vdcs, pdcs, cec_inverter_parameters) - assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) - - def test_PVSystem_snlinverter(cec_inverter_parameters): system = pvsystem.PVSystem( inverter=cec_inverter_parameters['Name'], @@ -1174,45 +1120,6 @@ def test_PVSystem_snlinverter(cec_inverter_parameters): assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000])) -def test_snlinverter_float(cec_inverter_parameters): - vdcs = 25. - idcs = 5.5 - pdcs = idcs * vdcs - - pacs = pvsystem.snlinverter(vdcs, pdcs, cec_inverter_parameters) - assert_allclose(pacs, 132.004278, 5) - - -def test_snlinverter_Pnt_micro(): - """ - Test for issue #140, where some microinverters were giving a positive AC - power output when the DC power was 0. - """ - inverter_parameters = { - 'Name': 'Enphase Energy: M250-60-2LL-S2x (-ZC) (-NA) 208V [CEC 2013]', - 'Vac': 208.0, - 'Paco': 240.0, - 'Pdco': 250.5311318, - 'Vdco': 32.06160667, - 'Pso': 1.12048857, - 'C0': -5.76E-05, - 'C1': -6.24E-04, - 'C2': 8.09E-02, - 'C3': -0.111781106, - 'Pnt': 0.043, - 'Vdcmax': 48.0, - 'Idcmax': 9.8, - 'Mppt_low': 27.0, - 'Mppt_high': 39.0, - } - vdcs = pd.Series(np.linspace(0,50,3)) - idcs = pd.Series(np.linspace(0,11,3)) - pdcs = idcs * vdcs - - pacs = pvsystem.snlinverter(vdcs, pdcs, inverter_parameters) - assert_series_equal(pacs, pd.Series([-0.043, 132.545914746, 240.0])) - - def test_PVSystem_creation(): pv_system = pvsystem.PVSystem(module='blah', inverter='blarg') # ensure that parameter attributes are dict-like. GH 294 @@ -1354,44 +1261,6 @@ def test_pvwatts_dc_series(): assert_series_equal(expected, out) -def test_pvwatts_ac_scalars(): - expected = 85.58556604752516 - out = pvsystem.pvwatts_ac(90, 100, 0.95) - assert_allclose(out, expected) - # GH 675 - expected = 0. - out = pvsystem.pvwatts_ac(0., 100) - assert_allclose(out, expected) - - -def test_pvwatts_ac_possible_negative(): - # pvwatts_ac could return a negative value for (pdc / pdc0) < 0.006 - # unless it is clipped. see GH 541 for more - expected = 0 - out = pvsystem.pvwatts_ac(0.001, 1) - assert_allclose(out, expected) - - -@needs_numpy_1_10 -def test_pvwatts_ac_arrays(): - pdc = np.array([[np.nan], [0], [50], [100]]) - pdc0 = 100 - expected = np.array([[nan], - [0.], - [47.60843624], - [95.]]) - out = pvsystem.pvwatts_ac(pdc, pdc0, 0.95) - assert_allclose(out, expected, equal_nan=True) - - -def test_pvwatts_ac_series(): - pdc = pd.Series([np.nan, 0, 50, 100]) - pdc0 = 100 - expected = pd.Series(np.array([nan, 0., 47.608436, 95.])) - out = pvsystem.pvwatts_ac(pdc, pdc0, 0.95) - assert_series_equal(expected, out) - - def test_pvwatts_losses_default(): expected = 14.075660688264469 out = pvsystem.pvwatts_losses() @@ -1570,3 +1439,16 @@ def test__sapm_celltemp_translator(): [params['a'], params['b'], params['deltaT']]) assert_allclose(result, 43.509, 3) + + +@fail_on_pvlib_version('0.9') +def test_deprecated_09(cec_inverter_parameters, adr_inverter_parameters): + # deprecated function pvsystem.snlinverter + with pytest.warns(pvlibDeprecationWarning): + pvsystem.snlinverter(250, 40, cec_inverter_parameters) + # deprecated function pvsystem.adrinverter + with pytest.warns(pvlibDeprecationWarning): + pvsystem.adrinverter(1232, 154, adr_inverter_parameters) + # deprecated function pvsystem.spvwatts_ac + with pytest.warns(pvlibDeprecationWarning): + pvsystem.pvwatts_ac(90, 100, 0.95) From 4be25ba17d86a99c2554441fd4ae841665296a53 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 11 Feb 2020 15:24:39 -0700 Subject: [PATCH 02/31] stickler, adjust PVSystem methods --- pvlib/inverter.py | 10 ++++------ pvlib/modelchain.py | 13 +++++++------ pvlib/pvsystem.py | 24 ++++++++++++++++++------ pvlib/tests/conftest.py | 2 +- pvlib/tests/test_inverter.py | 29 ++++++++++++++--------------- 5 files changed, 44 insertions(+), 34 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index c0344bd2fb..527540f74b 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -118,7 +118,7 @@ def sandia(v_dc, p_dc, inverter): return ac_power -def adrinverter(v_dc, p_dc, inverter, vtol=0.10): +def adr(v_dc, p_dc, inverter, vtol=0.10): r''' Converts DC power and voltage to AC power using Anton Driesse's Grid-Connected PV Inverter efficiency model @@ -259,8 +259,7 @@ def adrinverter(v_dc, p_dc, inverter, vtol=0.10): return ac_power - -def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): +def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): r""" Implements NREL's PVWatts inverter model [1]_. @@ -315,11 +314,10 @@ def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( - 0.0162*zeta - - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) - + 0.9858) + - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + 0.9858) pac = eta * pdc pac = np.minimum(pac0, pac) pac = np.maximum(0, pac) # GH 541 - return pac \ No newline at end of file + return pac diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 45a9f5ca98..a790b83596 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -56,7 +56,7 @@ def basic_chain(times, latitude, longitude, See temperature.sapm_cell for details. inverter_parameters : None, dict or Series - Inverter parameters as defined by the CEC. See pvsystem.snlinverter for + Inverter parameters as defined by the CEC. See inverter.sandia for details. irradiance : None or DataFrame, default None @@ -183,7 +183,7 @@ def basic_chain(times, latitude, longitude, dc = pvsystem.sapm(effective_irradiance, cell_temperature, module_parameters) - ac = pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter_parameters) + ac = inverter.sandia(dc['v_mp'], dc['p_mp'], inverter_parameters) return dc, ac @@ -265,7 +265,7 @@ class ModelChain(object): ac_model: None, str, or function, default None If None, the model will be inferred from the contents of system.inverter_parameters and system.module_parameters. Valid - strings are 'snlinverter', 'adrinverter', 'pvwatts'. The + strings are 'sandia', 'adr', 'pvwatts'. The ModelChain instance will be passed as the first argument to a user-defined function. @@ -492,11 +492,12 @@ def ac_model(self, model): self._ac_model = self.infer_ac_model() elif isinstance(model, str): model = model.lower() - if model == 'snlinverter': + # TODO in v0.9: remove 'snlinverter', 'adrinverter', 'pvwatts' + if model in ['sandia', 'snlinverter']: self._ac_model = self.snlinverter - elif model == 'adrinverter': + elif model in ['adr', 'adrinverter']: self._ac_model = self.adrinverter - elif model == 'pvwatts': + elif model in ['pvwatts']: self._ac_model = self.pvwatts_inverter else: raise ValueError(model + ' is not a valid AC power model') diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 6b217b0e28..31a480ce61 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -739,21 +739,32 @@ def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage, # inverter now specified by self.inverter_parameters def snlinverter(self, v_dc, p_dc): - """Uses :func:`snlinverter` to calculate AC power based on + """Uses :pyfunc:`pvlib.inverter.sandia` to calculate AC power based on ``self.inverter_parameters`` and the input parameters. Parameters ---------- - See pvsystem.snlinverter for details + See pvlib.inverter.sandia for details Returns ------- - See pvsystem.snlinverter for details + See pvlib.inverter.sandia for details """ - return snlinverter(v_dc, p_dc, self.inverter_parameters) + return inverter.sandia(v_dc, p_dc, self.inverter_parameters) def adrinverter(self, v_dc, p_dc): - return adrinverter(v_dc, p_dc, self.inverter_parameters) + """Uses :pyfunc:`pvlib.inverter.adr` to calculate AC power based on + ``self.inverter_parameters`` and the input parameters. + + Parameters + ---------- + See pvlib.inverter.adr for details + + Returns + ------- + See pvlib.inverter.adr for details + """ + return inverter.adr(v_dc, p_dc, self.inverter_parameters) def scale_voltage_current_power(self, data): """ @@ -816,7 +827,8 @@ def pvwatts_ac(self, pdc): kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], self.inverter_parameters) - return pvwatts_ac(pdc, self.inverter_parameters['pdc0'], **kwargs) + return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], + **kwargs) def localize(self, location=None, latitude=None, longitude=None, **kwargs): diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index bf520a26a9..8a2c9972f7 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -199,7 +199,7 @@ def adr_inverter_parameters(): parameters if required without affecting other tests. """ parameters = { - 'Name': 'Ablerex Electronics Co., Ltd.: ES 2200-US-240 (240Vac)' \ + 'Name': 'Ablerex Electronics Co., Ltd.: ES 2200-US-240 (240Vac)' '[CEC 2011]', 'Vac': 240., 'Pacmax': 2110., diff --git a/pvlib/tests/test_inverter.py b/pvlib/tests/test_inverter.py index 69adc18e71..4f99f0a616 100644 --- a/pvlib/tests/test_inverter.py +++ b/pvlib/tests/test_inverter.py @@ -48,8 +48,8 @@ def test_adr_invalid_and_night(sam_data): def test_sandia(cec_inverter_parameters): - vdcs = pd.Series(np.linspace(0,50,3)) - idcs = pd.Series(np.linspace(0,11,3)) + vdcs = pd.Series(np.linspace(0, 50, 3)) + idcs = pd.Series(np.linspace(0, 11, 3)) pdcs = idcs * vdcs pacs = inverter.sandia(vdcs, pdcs, cec_inverter_parameters) @@ -87,48 +87,47 @@ def test_sandia_Pnt_micro(): 'Mppt_low': 27.0, 'Mppt_high': 39.0, } - vdcs = pd.Series(np.linspace(0,50,3)) - idcs = pd.Series(np.linspace(0,11,3)) + vdcs = pd.Series(np.linspace(0, 50, 3)) + idcs = pd.Series(np.linspace(0, 11, 3)) pdcs = idcs * vdcs pacs = inverter.sandia(vdcs, pdcs, inverter_parameters) assert_series_equal(pacs, pd.Series([-0.043, 132.545914746, 240.0])) -def test_pvwatts_ac_scalars(): +def test_pvwatts_scalars(): expected = 85.58556604752516 - out = inverter.pvwatts_ac(90, 100, 0.95) + out = inverter.pvwatts(90, 100, 0.95) assert_allclose(out, expected) # GH 675 expected = 0. - out = inverter.pvwatts_ac(0., 100) + out = inverter.pvwatts(0., 100) assert_allclose(out, expected) -def test_pvwatts_ac_possible_negative(): - # pvwatts_ac could return a negative value for (pdc / pdc0) < 0.006 +def test_pvwatts_possible_negative(): + # pvwatts could return a negative value for (pdc / pdc0) < 0.006 # unless it is clipped. see GH 541 for more expected = 0 - out = inverter.pvwatts_ac(0.001, 1) + out = inverter.pvwatts(0.001, 1) assert_allclose(out, expected) @needs_numpy_1_10 -def test_pvwatts_ac_arrays(): +def test_pvwatts_arrays(): pdc = np.array([[np.nan], [0], [50], [100]]) pdc0 = 100 expected = np.array([[np.nan], [0.], [47.60843624], [95.]]) - out = inverter.pvwatts_ac(pdc, pdc0, 0.95) + out = inverter.pvwatts(pdc, pdc0, 0.95) assert_allclose(out, expected, equal_nan=True) -def test_pvwatts_ac_series(): +def test_pvwatts_series(): pdc = pd.Series([np.nan, 0, 50, 100]) pdc0 = 100 expected = pd.Series(np.array([np.nan, 0., 47.608436, 95.])) - out = inverter.pvwatts_ac(pdc, pdc0, 0.95) + out = inverter.pvwatts(pdc, pdc0, 0.95) assert_series_equal(expected, out) - From 904595bea496abd509c365e60b40b1e8b84a07be Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 11 Feb 2020 15:47:34 -0700 Subject: [PATCH 03/31] update modelchain, test fixes --- pvlib/modelchain.py | 4 ++-- pvlib/tests/test_pvsystem.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index a790b83596..d755c5c697 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -10,8 +10,8 @@ import warnings import pandas as pd -from pvlib import (atmosphere, clearsky, pvsystem, solarposition, temperature, - tools) +from pvlib import (atmosphere, clearsky, inverter, pvsystem, solarposition, + temperature, tools) from pvlib.tracking import SingleAxisTracker import pvlib.irradiance # avoid name conflict with full import from pvlib.pvsystem import _DC_MODEL_PARAMS diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 40906e31ce..76aecd6bed 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -8,7 +8,7 @@ from pandas.util.testing import assert_series_equal, assert_frame_equal from numpy.testing import assert_allclose -from pvlib import pvsystem +from pvlib import inverter, pvsystem from pvlib import atmosphere from pvlib import iam as _iam from pvlib.location import Location @@ -1334,22 +1334,22 @@ def test_PVSystem_pvwatts_losses(mocker): def test_PVSystem_pvwatts_ac(mocker): - mocker.spy(pvsystem, 'pvwatts_ac') + mocker.spy(inverter, 'pvwatts') system = make_pvwatts_system_defaults() pdc = 50 out = system.pvwatts_ac(pdc) - pvsystem.pvwatts_ac.assert_called_once_with(pdc, - **system.inverter_parameters) + inverter.pvwatts.assert_called_once_with(pdc, + **system.inverter_parameters) assert out < pdc def test_PVSystem_pvwatts_ac_kwargs(mocker): - mocker.spy(pvsystem, 'pvwatts_ac') + mocker.spy(inverter, 'pvwatts') system = make_pvwatts_system_kwargs() pdc = 50 out = system.pvwatts_ac(pdc) - pvsystem.pvwatts_ac.assert_called_once_with(pdc, - **system.inverter_parameters) + inverter.pvwatts.assert_called_once_with(pdc, + **system.inverter_parameters) assert out < pdc From 17692957bc04b4834449bd71e5566899801d7a45 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 11 Feb 2020 15:49:19 -0700 Subject: [PATCH 04/31] sticker --- pvlib/inverter.py | 4 ++-- pvlib/tests/conftest.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 527540f74b..0ba1aba575 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -313,8 +313,8 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( - - 0.0162*zeta - - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + 0.9858) + -0.0162*zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + + 0.9858) pac = eta * pdc pac = np.minimum(pac0, pac) diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index 8a2c9972f7..90266db137 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -208,7 +208,7 @@ def adr_inverter_parameters(): 'Vmin': 155., 'Vmax': 413., 'Vdcmax': 500., - 'MPPTHi':450., + 'MPPTHi': 450., 'MPPTLow': 150., 'Pnt': 0.25, 'ADRCoefficients': [0.01385, 0.0152, 0.00794, 0.00286, -0.01872, From 06cb965d450a963a8af865de629decf2337de8e3 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Thu, 21 May 2020 10:51:42 -0600 Subject: [PATCH 05/31] docstring improvements --- pvlib/inverter.py | 97 ++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 0ba1aba575..ce379776f8 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -10,75 +10,62 @@ def sandia(v_dc, p_dc, inverter): r''' - Converts DC power and voltage to AC power using Sandia's + Convert DC power and voltage to AC power using Sandia's Grid-Connected PV Inverter model. Parameters ---------- v_dc : numeric - DC voltages, in volts, which are provided as input to the - inverter. Vdc should be >= 0. + DC voltage input to the inverter. [V] p_dc : numeric - A scalar or DataFrame of DC powers, in watts, which are provided - as input to the inverter. Pdc should be >= 0. + DC power input to the inverter. [W] inverter : dict-like - A dict-like object defining the inverter to be used, giving the - inverter performance parameters according to the Sandia - Grid-Connected Photovoltaic Inverter Model (SAND 2007-5036) [1]_. - A set of inverter performance parameters are provided with - pvlib, or may be generated from a System Advisor Model (SAM) [2]_ - library using retrievesam. See Notes for required keys. + Defines parameters for the inverter model in [1]_. See Notes for + required parameters. A copy of the parameter database from the System + Advisor Model (SAM) [2]_ is provided with pvlib and may be read using + :py:func:`pvlib.pvsystem.retrieve_sam. Returns ------- ac_power : numeric - Modeled AC power output given the input DC voltage, Vdc, and - input DC power, Pdc. When ac_power would be greater than Pac0, - it is set to Pac0 to represent inverter "clipping". When - ac_power would be less than Ps0 (startup power required), then - ac_power is set to -1*abs(Pnt) to represent nightly power - losses. ac_power is not adjusted for maximum power point - tracking (MPPT) voltage windows or maximum current limits of the - inverter. + AC power output. [W] Notes ----- Determines the AC power output of an inverter given the DC voltage and DC - power. Output AC power is clipped at the inverter's maximum power output - and output power can be negative during low-input power conditions. The - Sandia inverter model does NOT account for maximum power point - tracking voltage windows nor maximum current or voltage limits on - the inverter. + power. Output AC power is bounded above by the parameter ``Paco``, to + represent inverter "clipping". When `ac_power` would be less than + parameter ``Pso`` (startup power required), then `ac_power` is set to + ``-Pnt``, representing self-consumption. `ac_power` is not adjusted for + maximum power point tracking (MPPT) voltage windows or maximum current + limits of the inverter. - Required inverter keys are: + Required inverter parameters are: ====== ============================================================ Column Description ====== ============================================================ - Pac0 AC-power output from inverter based on input power - and voltage (W) - Pdc0 DC-power input to inverter, typically assumed to be equal - to the PV array maximum power (W) - Vdc0 DC-voltage level at which the AC-power rating is achieved - at the reference operating condition (V) - Ps0 DC-power required to start the inversion process, or + Paco AC power rating of the inverter. [W] + Pdco DC power input to inverter, typically assumed to be equal + to the PV array maximum power. [W] + Vdco DC voltage at which the AC power rating is achieved + at the reference operating condition. [V] + Pso DC power required to start the inversion process, or self-consumption by inverter, strongly influences inverter - efficiency at low power levels (W) + efficiency at low power levels. [W] C0 Parameter defining the curvature (parabolic) of the - relationship between ac-power and dc-power at the reference - operating condition, default value of zero gives a - linear relationship (1/W) - C1 Empirical coefficient allowing Pdco to vary linearly - with dc-voltage input, default value is zero (1/V) - C2 Empirical coefficient allowing Pso to vary linearly with - dc-voltage input, default value is zero (1/V) + relationship between AC power and DC power at the reference + operating condition. [1/W] + C1 Empirical coefficient allowing ``Pdco`` to vary linearly + with DC voltage input. [1/V] + C2 Empirical coefficient allowing ``Pso`` to vary linearly with + DC voltage input. [1/V] C3 Empirical coefficient allowing Co to vary linearly with - dc-voltage input, default value is zero (1/V) - Pnt AC-power consumed by inverter at night (night tare) to - maintain circuitry required to sense PV array voltage (W) + DC voltage input. [1/V] + Pnt AC power consumed by the inverter at night (night tare). [W] ====== ============================================================ References @@ -91,7 +78,7 @@ def sandia(v_dc, p_dc, inverter): See also -------- - pvlib.pvsystem.sapm + pvlib.pvsystem.retrieve_sam ''' Paco = inverter['Paco'] @@ -274,28 +261,28 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): where :math:`\zeta=P_{dc}/P_{dc0}` and :math:`P_{dc0}=P_{ac0}/\eta_{nom}`. - Note that pdc0 is also used as a symbol in - :py:func:`pvlib.pvsystem.pvwatts_dc`. pdc0 in this function refers to the - DC power input limit of the inverter. pdc0 in - :py:func:`pvlib.pvsystem.pvwatts_dc` refers to the DC power of the module's + Note that ``pdc0`` is also used as a symbol in + :py:func:`pvlib.pvsystem.pvwatts_dc`. ``pdc0`` in this function refers to + the DC power input limit of the inverter. ``pdc0`` in + :py:func:`pvlib.pvsystem.pvwatts_dc` refers to the DC power of the modules at reference conditions. Parameters ---------- pdc: numeric - DC power. + DC power. Same unit as ``pdc0``. pdc0: numeric - DC input limit of the inverter. + DC input limit of the inverter. Same unit as ``pdc``. eta_inv_nom: numeric, default 0.96 - Nominal inverter efficiency. + Nominal inverter efficiency. [unitless] eta_inv_ref: numeric, default 0.9637 Reference inverter efficiency. PVWatts defines it to be 0.9637 - and is included here for flexibility. + and is included here for flexibility. [unitless] Returns ------- pac: numeric - AC power. + AC power. Same unit as ``pdc0``. References ---------- @@ -313,8 +300,8 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( - -0.0162*zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + - 0.9858) + -0.0162*zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + + 0.9858) pac = eta * pdc pac = np.minimum(pac0, pac) From d13d162a3c94dc1460fd230bcf12cac222a3c038 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Thu, 21 May 2020 12:03:26 -0600 Subject: [PATCH 06/31] more docstring work --- pvlib/inverter.py | 87 ++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index ce379776f8..84488191ed 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -23,9 +23,9 @@ def sandia(v_dc, p_dc, inverter): inverter : dict-like Defines parameters for the inverter model in [1]_. See Notes for - required parameters. A copy of the parameter database from the System - Advisor Model (SAM) [2]_ is provided with pvlib and may be read using - :py:func:`pvlib.pvsystem.retrieve_sam. + required model parameters. A copy of the parameter database from the + System Advisor Model (SAM) [2]_ is provided with pvlib and may be read + using :py:func:`pvlib.pvsystem.retrieve_sam. Returns ------- @@ -43,7 +43,7 @@ def sandia(v_dc, p_dc, inverter): maximum power point tracking (MPPT) voltage windows or maximum current limits of the inverter. - Required inverter parameters are: + Required model parameters are: ====== ============================================================ Column Description @@ -70,9 +70,9 @@ def sandia(v_dc, p_dc, inverter): References ---------- - .. [1] SAND2007-5036, "Performance Model for Grid-Connected - Photovoltaic Inverters by D. King, S. Gonzalez, G. Galbraith, W. - Boyson + .. [1] D. King, S. Gonzalez, G. Galbraith, W. Boyson, "Performance Model + for Grid-Connected Photovoltaic Inverters", SAND2007-5036, Sandia + National Laboratories. .. [2] System Advisor Model web page. https://sam.nrel.gov. @@ -113,72 +113,65 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Parameters ---------- v_dc : numeric - A scalar or pandas series of DC voltages, in volts, which are provided - as input to the inverter. If Vdc and Pdc are vectors, they must be - of the same size. v_dc must be >= 0. [V] + DC voltage input to the inverter, should be >= 0. [V] p_dc : numeric - A scalar or pandas series of DC powers, in watts, which are provided - as input to the inverter. If Vdc and Pdc are vectors, they must be - of the same size. p_dc must be >= 0. [W] + DC power input to the inverter, should be >= 0. [W] inverter : dict-like - A dict-like object defining the inverter to be used, giving the - inverter performance parameters according to the model - developed by Anton Driesse [1]_. - A set of inverter performance parameters may be loaded from the - supplied data table using retrievesam. - See Notes for required keys. + Defines parameters for the inverter model in [1]_. See Notes for + required model parameters. A parameter database is provided with pvlib and + may be read using :py:func:`pvlib.pvsystem.retrieve_sam. vtol : numeric, default 0.1 - A unit-less fraction that determines how far the efficiency model is - allowed to extrapolate beyond the inverter's normal input voltage - operating range. 0.0 <= vtol <= 1.0 + Fraction of DC voltage that determines how far the efficiency model is + extrapolated beyond the inverter's normal input voltage operating + range. 0.0 <= vtol <= 1.0. [unitless] Returns ------- ac_power : numeric - A numpy array or pandas series of modeled AC power output given the - input DC voltage, v_dc, and input DC power, p_dc. When ac_power would - be greater than pac_max, it is set to p_max to represent inverter - "clipping". When ac_power would be less than -p_nt (energy consumed - rather than produced) then ac_power is set to -p_nt to represent - nightly power losses. ac_power is not adjusted for maximum power point - tracking (MPPT) voltage windows or maximum current limits of the - inverter. [W] + AC power output. [W] Notes ----- - Required inverter keys are: + Determines the AC power output of an inverter given the DC voltage and DC + power. Output AC power is bounded above by the parameter ``Pacmax``, to + represent inverter "clipping". AC power is bounded below by ``-Pnt`` + (negative when power is consumed rather than produced) which represents + self-consumption. `ac_power` is not adjusted for maximum power point + tracking (MPPT) voltage windows or maximum current limits of the inverter. + + Required model parameters are: ======= ============================================================ Column Description ======= ============================================================ - Pnom The nominal power value used to normalize all power values, - typically the DC power needed to produce maximum AC power - output. [W] + Pnom Nominal DC power, typically the DC power needed to produce + maximum AC power output. [W] - Vnom The nominal DC voltage value used to normalize DC voltage - values, typically the level at which the highest efficiency - is achieved. [V] + Vnom Nominal DC input voltage. Typically the level at which the + highest efficiency is achieved. [V] - Vmax . [V] + Vmax Maximum DC input voltage. [V] - Vmin . [V] + Vmin Minimum DC input voltage. [V] Vdcmax . [V] - MPPTHi . [unit] + MPPTHi Maximum DC voltage for MPPT range. [V] - MPPTLow . [unit] + MPPTLow Minimum DC voltage for MPPT range. [V] - Pacmax The maximum AC output power value, used to clip the output - if needed, (W). + Pacmax Maximum AC output power, used to clip the output power + if needed. [W] ADRCoefficients A list of 9 coefficients that capture the influence of input voltage and power on inverter losses, and thereby - efficiency. + efficiency. Corresponds to terms from [1]_ (in order): :math: + `b_{0,0}, b_{1,0}, b_{2,0}, b_{0,1}, b_{1,1}, b_{2,1}, b_{0,2}, + b_{1,2}, b_{1,2}`. Pnt AC power consumed by inverter at night (night tare) to maintain circuitry required to sense PV array voltage. [W] @@ -187,12 +180,14 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): References ---------- - .. [1] Beyond the Curves: Modeling the Electrical Efficiency - of Photovoltaic Inverters, PVSC 2008, Anton Driesse et. al. + .. [1] Driesse, A. "Beyond the Curves: Modeling the Electrical Efficiency + of Photovoltaic Inverters", 33rd IEEE Photovoltaic Specialist + Conference (PVSC), June 2008 See also -------- pvlib.inverter.sandia + pvlib.pvsystem.retrieve_sam ''' p_nom = inverter['Pnom'] From 592d33be67716ff5475c06bd8ab565e9868f9e02 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Thu, 21 May 2020 12:21:05 -0600 Subject: [PATCH 07/31] lint, kludge inverter.test_deprecated_09 --- pvlib/inverter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 84488191ed..f1f7b82e14 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -120,8 +120,8 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): inverter : dict-like Defines parameters for the inverter model in [1]_. See Notes for - required model parameters. A parameter database is provided with pvlib and - may be read using :py:func:`pvlib.pvsystem.retrieve_sam. + required model parameters. A parameter database is provided with pvlib + and may be read using :py:func:`pvlib.pvsystem.retrieve_sam. vtol : numeric, default 0.1 Fraction of DC voltage that determines how far the efficiency model is @@ -295,8 +295,8 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( - -0.0162*zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) - + 0.9858) + -0.0162 * zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + + 0.9858) #noQA W503 pac = eta * pdc pac = np.minimum(pac0, pac) From 1bb1567b95f58f0ef1b437d792902a8458711ee3 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Thu, 21 May 2020 12:26:52 -0600 Subject: [PATCH 08/31] lint, kludge test_deprecated_09 x2 --- pvlib/inverter.py | 2 +- pvlib/tests/test_pvsystem.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index f1f7b82e14..dd2aea0067 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -296,7 +296,7 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( -0.0162 * zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) - + 0.9858) #noQA W503 + + 0.9858) # noQA: W503 pac = eta * pdc pac = np.minimum(pac0, pac) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 81aca6cf9e..81e01ab6fa 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1436,13 +1436,17 @@ def test__sapm_celltemp_translator(): @fail_on_pvlib_version('0.9') -def test_deprecated_09(cec_inverter_parameters, adr_inverter_parameters): +def test_deprecated_09(): + # get parameters from fixtures + from conftest import (cec_inverter_parameters, adr_inverter_parameters) + cec_params = cec_inverter_parameters() + adr_params = adr_inverter_parameters() # deprecated function pvsystem.snlinverter with pytest.warns(pvlibDeprecationWarning): - pvsystem.snlinverter(250, 40, cec_inverter_parameters) + pvsystem.snlinverter(250, 40, cec_params) # deprecated function pvsystem.adrinverter with pytest.warns(pvlibDeprecationWarning): - pvsystem.adrinverter(1232, 154, adr_inverter_parameters) + pvsystem.adrinverter(1232, 154, adr_params) # deprecated function pvsystem.spvwatts_ac with pytest.warns(pvlibDeprecationWarning): pvsystem.pvwatts_ac(90, 100, 0.95) From d37171301ba6dff342d88904056814cfaa5f533c Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 12:46:53 -0600 Subject: [PATCH 09/31] use new conftest capability --- pvlib/tests/test_pvsystem.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 81e01ab6fa..976094067c 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1436,9 +1436,7 @@ def test__sapm_celltemp_translator(): @fail_on_pvlib_version('0.9') -def test_deprecated_09(): - # get parameters from fixtures - from conftest import (cec_inverter_parameters, adr_inverter_parameters) +def test_deprecated_09(cec_inverter_parameters, adr_inverter_parameters): cec_params = cec_inverter_parameters() adr_params = adr_inverter_parameters() # deprecated function pvsystem.snlinverter From f9f8ae7d8fa3baf666ac868b45ad28745b496e44 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 12:55:38 -0600 Subject: [PATCH 10/31] correct use of fixture --- pvlib/tests/test_pvsystem.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 976094067c..81aca6cf9e 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1437,14 +1437,12 @@ def test__sapm_celltemp_translator(): @fail_on_pvlib_version('0.9') def test_deprecated_09(cec_inverter_parameters, adr_inverter_parameters): - cec_params = cec_inverter_parameters() - adr_params = adr_inverter_parameters() # deprecated function pvsystem.snlinverter with pytest.warns(pvlibDeprecationWarning): - pvsystem.snlinverter(250, 40, cec_params) + pvsystem.snlinverter(250, 40, cec_inverter_parameters) # deprecated function pvsystem.adrinverter with pytest.warns(pvlibDeprecationWarning): - pvsystem.adrinverter(1232, 154, adr_params) + pvsystem.adrinverter(1232, 154, adr_inverter_parameters) # deprecated function pvsystem.spvwatts_ac with pytest.warns(pvlibDeprecationWarning): pvsystem.pvwatts_ac(90, 100, 0.95) From f6d6f7791f356ea19b2a594f149175a4c543a92e Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 13:36:02 -0600 Subject: [PATCH 11/31] add test for invalid ac model string --- pvlib/tests/test_modelchain.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index f846f036aa..08cd62683d 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -481,6 +481,14 @@ def test_ac_model_user_func(pvwatts_dc_pvwatts_ac_system, location, weather, assert not mc.ac.empty +def test_ac_model_not_a_model(pvwatts_dc_pvwatts_ac_system, location, weather): + exc_text = 'not a valid AC power model' + with pytest.raises(ValueError, match=exc_text): + ModelChain(pvwatts_dc_pvwatts_ac_system, location, + ac_model='not_a_model', aoi_model='no_loss', + spectral_model='no_loss') + + def constant_aoi_loss(mc): mc.aoi_modifier = 0.9 From d0e811f73573470e93690ff2d63eca15d3e1bcae Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 13:56:01 -0600 Subject: [PATCH 12/31] update whatsnew --- docs/sphinx/source/whatsnew/v0.8.0.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 2e9f12c484..2682d8f862 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -3,8 +3,14 @@ v0.8.0 (Month day, year) ------------------------- -API Changes -~~~~~~~~~~~ +API Changes with Deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Moved functions related to inverters from `pvsystem.py` to `inverter.py`. + Functions are renamed to follow a more consistent pattern, as follows: + - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverters.sandia` + - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverters.pvwatts` + - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverters.adr` + (:pull:`886`) Enhancements ~~~~~~~~~~~~ @@ -16,6 +22,8 @@ Testing ~~~~~~~ * Decorator :py:func:`pvlib.conftest.fail_on_pvlib_version` can now be applied to functions that require args or kwargs. (:pull:`973`) +* Test added for :py:method:`ModelChain.ac_model` to confirm ValueError when + ac_model is an invalid string. (:pull:`886`) Documentation ~~~~~~~~~~~~~ From f630f058a1cb9fd64bfde92eadd6d996701391fe Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 15:12:20 -0600 Subject: [PATCH 13/31] update api.rst --- docs/sphinx/source/api.rst | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index eb5691f567..7ec7486609 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -263,10 +263,20 @@ Low-level functions for solving the single diode equation. singlediode.bishop88_v_from_i singlediode.bishop88_mpp -SAPM model ----------- +Inverter models (DC to AC conversion) +------------------------------------- + +.. autosummary:: + :toctree: generated/ + + inverter.sandia + inverter.adr + inverter.pvwatts -Functions relevant for the SAPM model. +PV System Models +---------------- + +Functions relevant for the Sandia array performance model (SAPM). .. autosummary:: :toctree: generated/ @@ -275,28 +285,26 @@ Functions relevant for the SAPM model. pvsystem.sapm_effective_irradiance pvsystem.sapm_spectral_loss pvsystem.sapm_aoi_loss - pvsystem.snlinverter - pvsystem.adrinverter + inverter.sandia temperature.sapm_cell -Pvsyst model -------------- - Functions relevant for the Pvsyst model. .. autosummary:: :toctree: generated/ temperature.pvsyst_cell + pvsystem.calcparams_pvsyst + pvsystem.singlediode -PVWatts model +Functions relevant for the PVWatts model ------------- .. autosummary:: :toctree: generated/ pvsystem.pvwatts_dc - pvsystem.pvwatts_ac + inverter.pvwatts pvsystem.pvwatts_losses Functions for fitting diode models From 78a7611d085f6ac659eed7d60c478bb7db9b0bef Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 15:36:01 -0600 Subject: [PATCH 14/31] extend test_ac_models to new key values --- pvlib/tests/test_modelchain.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 08cd62683d..75b7c06431 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -447,13 +447,17 @@ def acdc(mc): mc.ac = mc.dc +# TODO in v0.9: remove 'snlinverter', 'adrinverter', 'pvwatts' @pytest.mark.parametrize('ac_model', [ - 'snlinverter', pytest.param('adrinverter', marks=requires_scipy), + 'sandia', 'snlinverter', pytest.param('adrinverter', marks=requires_scipy), + pytest.param('adr', marks=requires_scipy), 'pvwatts']) def test_ac_models(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, pvwatts_dc_pvwatts_ac_system, location, ac_model, weather, mocker): ac_systems = {'snlinverter': sapm_dc_snl_ac_system, + 'sandia': sapm_dc_snl_ac_system, + 'adr': cec_dc_adr_ac_system, 'adrinverter': cec_dc_adr_ac_system, 'pvwatts': pvwatts_dc_pvwatts_ac_system} system = ac_systems[ac_model] From 4a19d6720f0d6966899727e6bd12979881b13363 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 15:46:04 -0600 Subject: [PATCH 15/31] more for whatsnew --- docs/sphinx/source/whatsnew/v0.8.0.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 2682d8f862..fa578f49bd 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -11,6 +11,8 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverters.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverters.adr` (:pull:`886`) +* ModelChain.ac_model now accepts `'sandia'`, `'pvwatts'` and `'adr'` for the + inverter models. Enhancements ~~~~~~~~~~~~ @@ -33,6 +35,8 @@ Documentation * Clarify units for heat loss factors in :py:func:`pvlib.temperature.pvsyst_cell` and :py:func:`pvlib.temperature.faiman`. (:pull:`960`) +* Corrected key names for :py:func:`pvlib.inverter.sandia`. (:issue:`976', + :pull:`886`) Requirements ~~~~~~~~~~~~ From ea90bec748165293ac6fc18e70cee88a04ec3274 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 16:02:01 -0600 Subject: [PATCH 16/31] correct modelchain.ac_model test --- pvlib/tests/test_modelchain.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 75b7c06431..a3d7973781 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -457,16 +457,19 @@ def test_ac_models(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, weather, mocker): ac_systems = {'snlinverter': sapm_dc_snl_ac_system, 'sandia': sapm_dc_snl_ac_system, - 'adr': cec_dc_adr_ac_system, 'adrinverter': cec_dc_adr_ac_system, + 'adr': cec_dc_adr_ac_system, 'pvwatts': pvwatts_dc_pvwatts_ac_system} + ac_method_name = {'snlinverter': 'snlinverter', + 'sandia': 'snlinverter', + 'adrinverter': 'adrinverter', + 'adr': 'adrinverter', + 'pvwatts': 'pvwatts_ac'} system = ac_systems[ac_model] mc = ModelChain(system, location, ac_model=ac_model, aoi_model='no_loss', spectral_model='no_loss') - if ac_model == 'pvwatts': - ac_model += '_ac' - m = mocker.spy(system, ac_model) + m = mocker.spy(system, ac_method_name) mc.run_model(weather) assert m.call_count == 1 assert isinstance(mc.ac, pd.Series) From 1eb75cd4b5b36e6362b1743030b129b925dc95a2 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 10 Jun 2020 16:10:33 -0600 Subject: [PATCH 17/31] test correction --- pvlib/tests/test_modelchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index a3d7973781..856639f238 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -469,7 +469,7 @@ def test_ac_models(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, mc = ModelChain(system, location, ac_model=ac_model, aoi_model='no_loss', spectral_model='no_loss') - m = mocker.spy(system, ac_method_name) + m = mocker.spy(system, ac_method_name[ac_model]) mc.run_model(weather) assert m.call_count == 1 assert isinstance(mc.ac, pd.Series) From e471ec2f1ddf5cb9560899ae7662b0b609616daa Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Sun, 14 Jun 2020 09:30:46 -0600 Subject: [PATCH 18/31] edits from review --- docs/sphinx/source/whatsnew/v0.8.0.rst | 15 ++++---- pvlib/inverter.py | 2 +- pvlib/modelchain.py | 2 +- pvlib/pvsystem.py | 48 +++++++++++++------------- pvlib/tests/test_modelchain.py | 3 +- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index fa578f49bd..4c588e4757 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -6,13 +6,12 @@ v0.8.0 (Month day, year) API Changes with Deprecations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Moved functions related to inverters from `pvsystem.py` to `inverter.py`. - Functions are renamed to follow a more consistent pattern, as follows: - - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverters.sandia` - - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverters.pvwatts` - - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverters.adr` - (:pull:`886`) + Functions are renamed to follow a more consistent pattern, as follows (:pull:`886`): + - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` + - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` + - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` * ModelChain.ac_model now accepts `'sandia'`, `'pvwatts'` and `'adr'` for the - inverter models. + inverter models. (:pull:`886`) Enhancements ~~~~~~~~~~~~ @@ -24,7 +23,7 @@ Testing ~~~~~~~ * Decorator :py:func:`pvlib.conftest.fail_on_pvlib_version` can now be applied to functions that require args or kwargs. (:pull:`973`) -* Test added for :py:method:`ModelChain.ac_model` to confirm ValueError when +* Test added for :py:meth:`ModelChain.ac_model` to confirm ValueError when ac_model is an invalid string. (:pull:`886`) Documentation @@ -35,7 +34,7 @@ Documentation * Clarify units for heat loss factors in :py:func:`pvlib.temperature.pvsyst_cell` and :py:func:`pvlib.temperature.faiman`. (:pull:`960`) -* Corrected key names for :py:func:`pvlib.inverter.sandia`. (:issue:`976', +* Corrected key names for :py:func:`pvlib.inverter.sandia`. (:issue:`976`, :pull:`886`) Requirements diff --git a/pvlib/inverter.py b/pvlib/inverter.py index dd2aea0067..e5e7698a60 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -25,7 +25,7 @@ def sandia(v_dc, p_dc, inverter): Defines parameters for the inverter model in [1]_. See Notes for required model parameters. A copy of the parameter database from the System Advisor Model (SAM) [2]_ is provided with pvlib and may be read - using :py:func:`pvlib.pvsystem.retrieve_sam. + using :py:func:`pvlib.pvsystem.retrieve_sam`. Returns ------- diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 6a9707c4f0..8ea00764ee 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -493,7 +493,7 @@ def ac_model(self, model): self._ac_model = self.infer_ac_model() elif isinstance(model, str): model = model.lower() - # TODO in v0.9: remove 'snlinverter', 'adrinverter', 'pvwatts' + # TODO in v0.9: remove 'snlinverter', 'adrinverter' if model in ['sandia', 'snlinverter']: self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 49e41510fb..044abbea48 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -727,15 +727,15 @@ def _infer_cell_type(self): def singlediode(self, photocurrent, saturation_current, resistance_series, resistance_shunt, nNsVth, ivcurve_pnts=None): - """Wrapper around the :py:func:`singlediode` function. + """Wrapper around the :py:func:`pvlib.pvsystem.singlediode` function. Parameters ---------- - See pvsystem.singlediode for details + See :py:func:`pvsystem.singlediode` for details Returns ------- - See pvsystem.singlediode for details + See :py:func:`pvsystem.singlediode` for details """ return singlediode(photocurrent, saturation_current, resistance_series, resistance_shunt, nNsVth, @@ -743,52 +743,51 @@ def singlediode(self, photocurrent, saturation_current, def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage, saturation_current, photocurrent): - """Wrapper around the :py:func:`i_from_v` function. + """Wrapper around the :py:func:`pvlib.pvsystem.i_from_v` function. Parameters ---------- - See pvsystem.i_from_v for details + See :py:func:`pvsystem.i_from_v` for details Returns ------- - See pvsystem.i_from_v for details + See :py:func:`pvsystem.i_from_v` for details """ return i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, saturation_current, photocurrent) # inverter now specified by self.inverter_parameters def snlinverter(self, v_dc, p_dc): - """Uses :pyfunc:`pvlib.inverter.sandia` to calculate AC power based on - ``self.inverter_parameters`` and the input parameters. + """Uses :py:func:`pvlib.inverter.sandia` to calculate AC power based on + ``self.inverter_parameters`` and the input voltage and power. Parameters ---------- - See pvlib.inverter.sandia for details + See :py:func:`pvlib.inverter.sandia` for details Returns ------- - See pvlib.inverter.sandia for details + See :py:func:`pvlib.inverter.sandia` for details """ return inverter.sandia(v_dc, p_dc, self.inverter_parameters) def adrinverter(self, v_dc, p_dc): - """Uses :pyfunc:`pvlib.inverter.adr` to calculate AC power based on - ``self.inverter_parameters`` and the input parameters. + """Uses :py:func:`pvlib.inverter.adr` to calculate AC power based on + ``self.inverter_parameters`` and the input voltage and power. Parameters ---------- - See pvlib.inverter.adr for details + See :py:func:`pvlib.inverter.adr` for details Returns ------- - See pvlib.inverter.adr for details + See :py:func:`pvlib.inverter.adr` for details """ return inverter.adr(v_dc, p_dc, self.inverter_parameters) def scale_voltage_current_power(self, data): """ - Scales the voltage, current, and power of the DataFrames - returned by :py:func:`singlediode` and :py:func:`sapm` + Scales the voltage, current, and power of the `data` DataFrame by `self.modules_per_string` and `self.strings_per_inverter`. Parameters @@ -810,10 +809,10 @@ def scale_voltage_current_power(self, data): def pvwatts_dc(self, g_poa_effective, temp_cell): """ Calcuates DC power according to the PVWatts model using - :py:func:`pvwatts_dc`, `self.module_parameters['pdc0']`, and - `self.module_parameters['gamma_pdc']`. + :py:func:`pvlib.pvsystem.pvwatts_dc`, `self.module_parameters['pdc0']`, + and `self.module_parameters['gamma_pdc']`. - See :py:func:`pvwatts_dc` for details. + See :py:func:`pvlib.pvsystem.pvwatts_dc` for details. """ kwargs = _build_kwargs(['temp_ref'], self.module_parameters) @@ -825,9 +824,10 @@ def pvwatts_dc(self, g_poa_effective, temp_cell): def pvwatts_losses(self): """ Calculates DC power losses according the PVwatts model using - :py:func:`pvwatts_losses` and ``self.losses_parameters``.` + :py:func:`pvlib.pvsystem.pvwatts_losses` and + ``self.losses_parameters``. - See :py:func:`pvwatts_losses` for details. + See :py:func:`pvlib.pvsystem.pvwatts_losses` for details. """ kwargs = _build_kwargs(['soiling', 'shading', 'snow', 'mismatch', 'wiring', 'connections', 'lid', @@ -838,10 +838,10 @@ def pvwatts_losses(self): def pvwatts_ac(self, pdc): """ Calculates AC power according to the PVWatts model using - :py:func:`pvwatts_ac`, `self.module_parameters['pdc0']`, and - `eta_inv_nom=self.inverter_parameters['eta_inv_nom']`. + :py:func:`pvlib.inverter.pvwatts`, `self.module_parameters['pdc0']`, + and `eta_inv_nom=self.inverter_parameters['eta_inv_nom']`. - See :py:func:`pvwatts_ac` for details. + See :py:func:`pvlib.inverter.pvwatts` for details. """ kwargs = _build_kwargs(['eta_inv_nom', 'eta_inv_ref'], self.inverter_parameters) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 856639f238..d170e1cb02 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -447,7 +447,8 @@ def acdc(mc): mc.ac = mc.dc -# TODO in v0.9: remove 'snlinverter', 'adrinverter', 'pvwatts' +# TODO in v0.9: remove 'snlinverter', 'adrinverter' since these values for +# ModelChain.ac_model are superseded by 'sandia' and 'adr' @pytest.mark.parametrize('ac_model', [ 'sandia', 'snlinverter', pytest.param('adrinverter', marks=requires_scipy), pytest.param('adr', marks=requires_scipy), From 4759394b54838cd21c07a19428887d3e7852748f Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 15 Jun 2020 17:38:28 -0600 Subject: [PATCH 19/31] more edits from review --- pvlib/inverter.py | 61 +++++++++++++++++++++++---------------------- pvlib/modelchain.py | 11 +++++++- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index e5e7698a60..efb264c99a 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -29,7 +29,7 @@ def sandia(v_dc, p_dc, inverter): Returns ------- - ac_power : numeric + power_ac : numeric AC power output. [W] Notes @@ -37,9 +37,9 @@ def sandia(v_dc, p_dc, inverter): Determines the AC power output of an inverter given the DC voltage and DC power. Output AC power is bounded above by the parameter ``Paco``, to - represent inverter "clipping". When `ac_power` would be less than - parameter ``Pso`` (startup power required), then `ac_power` is set to - ``-Pnt``, representing self-consumption. `ac_power` is not adjusted for + represent inverter "clipping". When `power_ac` would be less than + parameter ``Pso`` (startup power required), then `power_ac` is set to + ``-Pnt``, representing self-consumption. `power_ac` is not adjusted for maximum power point tracking (MPPT) voltage windows or maximum current limits of the inverter. @@ -63,7 +63,7 @@ def sandia(v_dc, p_dc, inverter): with DC voltage input. [1/V] C2 Empirical coefficient allowing ``Pso`` to vary linearly with DC voltage input. [1/V] - C3 Empirical coefficient allowing Co to vary linearly with + C3 Empirical coefficient allowing ``C0`` to vary linearly with DC voltage input. [1/V] Pnt AC power consumed by the inverter at night (night tare). [W] ====== ============================================================ @@ -91,18 +91,18 @@ def sandia(v_dc, p_dc, inverter): C3 = inverter['C3'] Pnt = inverter['Pnt'] - A = Pdco * (1 + C1*(v_dc - Vdco)) - B = Pso * (1 + C2*(v_dc - Vdco)) - C = C0 * (1 + C3*(v_dc - Vdco)) + A = Pdco * (1 + C1 * (v_dc - Vdco)) + B = Pso * (1 + C2 * (v_dc - Vdco)) + C = C0 * (1 + C3 * (v_dc - Vdco)) - ac_power = (Paco/(A-B) - C*(A-B)) * (p_dc-B) + C*((p_dc-B)**2) - ac_power = np.minimum(Paco, ac_power) - ac_power = np.where(p_dc < Pso, -1.0 * abs(Pnt), ac_power) + power_ac = (Paco / (A - B) - C * (A - B)) * (p_dc - B) + C * (p_dc - B)**2 + power_ac = np.minimum(Paco, power_ac) + power_ac = np.where(p_dc < Pso, -1.0 * abs(Pnt), power_ac) if isinstance(p_dc, pd.Series): - ac_power = pd.Series(ac_power, index=p_dc.index) + power_ac = pd.Series(power_ac, index=p_dc.index) - return ac_power + return power_ac def adr(v_dc, p_dc, inverter, vtol=0.10): @@ -121,7 +121,7 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): inverter : dict-like Defines parameters for the inverter model in [1]_. See Notes for required model parameters. A parameter database is provided with pvlib - and may be read using :py:func:`pvlib.pvsystem.retrieve_sam. + and may be read using :py:func:`pvlib.pvsystem.retrieve_sam`. vtol : numeric, default 0.1 Fraction of DC voltage that determines how far the efficiency model is @@ -130,7 +130,7 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Returns ------- - ac_power : numeric + power_ac : numeric AC power output. [W] Notes @@ -140,7 +140,7 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): power. Output AC power is bounded above by the parameter ``Pacmax``, to represent inverter "clipping". AC power is bounded below by ``-Pnt`` (negative when power is consumed rather than produced) which represents - self-consumption. `ac_power` is not adjusted for maximum power point + self-consumption. `power_ac` is not adjusted for maximum power point tracking (MPPT) voltage windows or maximum current limits of the inverter. Required model parameters are: @@ -171,7 +171,8 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): of input voltage and power on inverter losses, and thereby efficiency. Corresponds to terms from [1]_ (in order): :math: `b_{0,0}, b_{1,0}, b_{2,0}, b_{0,1}, b_{1,1}, b_{2,1}, b_{0,2}, - b_{1,2}, b_{1,2}`. + b_{1,2}, b_{1,2}`. See [1]_ for the use of each coefficient + and the associated unit. Pnt AC power consumed by inverter at night (night tare) to maintain circuitry required to sense PV array voltage. [W] @@ -219,26 +220,26 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): pdc * (1. / vdc - 1), # invalid 0./0. --> nan pdc**2 * (1. / vdc - 1)]) # divide by 0 p_loss = np.dot(np.array(ce_list), poly) - ac_power = p_nom * (pdc-p_loss) + power_ac = p_nom * (pdc - p_loss) p_nt = -1 * np.absolute(p_nt) # set output to nan where input is outside of limits # errstate silences case where input is nan with np.errstate(invalid='ignore'): invalid = (v_lim_upper < v_dc) | (v_dc < v_lim_lower) - ac_power = np.where(invalid, np.nan, ac_power) + power_ac = np.where(invalid, np.nan, power_ac) # set night values - ac_power = np.where(vdc == 0, p_nt, ac_power) - ac_power = np.maximum(ac_power, p_nt) + power_ac = np.where(vdc == 0, p_nt, power_ac) + power_ac = np.maximum(power_ac, p_nt) # set max ac output - ac_power = np.minimum(ac_power, pac_max) + power_ac = np.minimum(power_ac, pac_max) if isinstance(p_dc, pd.Series): - ac_power = pd.Series(ac_power, index=pdc.index) + power_ac = pd.Series(power_ac, index=pdc.index) - return ac_power + return power_ac def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): @@ -276,7 +277,7 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): Returns ------- - pac: numeric + power_ac: numeric AC power. Same unit as ``pdc0``. References @@ -293,13 +294,13 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): eta = np.zeros_like(pdc, dtype=float) pdc_neq_0 = ~np.equal(pdc, 0) - # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541 + # eta < 0 if zeta < 0.006. power_ac is forced to be >= 0 below. GH 541 eta = eta_inv_nom / eta_inv_ref * ( -0.0162 * zeta - np.divide(0.0059, zeta, out=eta, where=pdc_neq_0) + 0.9858) # noQA: W503 - pac = eta * pdc - pac = np.minimum(pac0, pac) - pac = np.maximum(0, pac) # GH 541 + power_ac = eta * pdc + power_ac = np.minimum(pac0, power_ac) + power_ac = np.maximum(0, power_ac) # GH 541 - return pac + return power_ac diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 8ea00764ee..38f08ef290 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -495,8 +495,17 @@ def ac_model(self, model): model = model.lower() # TODO in v0.9: remove 'snlinverter', 'adrinverter' if model in ['sandia', 'snlinverter']: - self._ac_model = self.snlinverter + if model == 'snlinverter': + warnings.warn('ac_model = ''snlinverter'' is deprecated' + ' and will be removed in v0.9; use' + ' ac_model = ''sandia'' instead.', + pvlibDeprecationWarning) + self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: + warnings.warn('ac_model = \'adrinverter\' is deprecated' + ' and will be removed in v0.9; use' + ' ac_model = \'adr\' instead.', + pvlibDeprecationWarning) self._ac_model = self.adrinverter elif model in ['pvwatts']: self._ac_model = self.pvwatts_inverter From 7183c95050c69cfc570f74b5122ce988bb832223 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 15 Jun 2020 21:06:37 -0600 Subject: [PATCH 20/31] fix thedocs, error --- pvlib/inverter.py | 9 --------- pvlib/modelchain.py | 8 ++++---- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pvlib/inverter.py b/pvlib/inverter.py index efb264c99a..2fdf670aab 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -150,30 +150,21 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): ======= ============================================================ Pnom Nominal DC power, typically the DC power needed to produce maximum AC power output. [W] - Vnom Nominal DC input voltage. Typically the level at which the highest efficiency is achieved. [V] - Vmax Maximum DC input voltage. [V] - Vmin Minimum DC input voltage. [V] - Vdcmax . [V] - MPPTHi Maximum DC voltage for MPPT range. [V] - MPPTLow Minimum DC voltage for MPPT range. [V] - Pacmax Maximum AC output power, used to clip the output power if needed. [W] - ADRCoefficients A list of 9 coefficients that capture the influence of input voltage and power on inverter losses, and thereby efficiency. Corresponds to terms from [1]_ (in order): :math: `b_{0,0}, b_{1,0}, b_{2,0}, b_{0,1}, b_{1,1}, b_{2,1}, b_{0,2}, b_{1,2}, b_{1,2}`. See [1]_ for the use of each coefficient and the associated unit. - Pnt AC power consumed by inverter at night (night tare) to maintain circuitry required to sense PV array voltage. [W] diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 38f08ef290..e9aea28a76 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -502,10 +502,10 @@ def ac_model(self, model): pvlibDeprecationWarning) self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: - warnings.warn('ac_model = \'adrinverter\' is deprecated' - ' and will be removed in v0.9; use' - ' ac_model = \'adr\' instead.', - pvlibDeprecationWarning) + warnings.warn('ac_model = \'adrinverter\' is deprecated' + ' and will be removed in v0.9; use' + ' ac_model = \'adr\' instead.', + pvlibDeprecationWarning) self._ac_model = self.adrinverter elif model in ['pvwatts']: self._ac_model = self.pvwatts_inverter From 7e9532fab899e58ba195a88ccb76ba79c6b64616 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 15 Jun 2020 21:35:58 -0600 Subject: [PATCH 21/31] fix indents --- pvlib/modelchain.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index e9aea28a76..740943ecff 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -500,12 +500,13 @@ def ac_model(self, model): ' and will be removed in v0.9; use' ' ac_model = ''sandia'' instead.', pvlibDeprecationWarning) - self._ac_model = self.snlinverter + self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: - warnings.warn('ac_model = \'adrinverter\' is deprecated' - ' and will be removed in v0.9; use' - ' ac_model = \'adr\' instead.', - pvlibDeprecationWarning) + if model == 'adrinverter': + warnings.warn('ac_model = \'adrinverter\' is deprecated' + ' and will be removed in v0.9; use' + ' ac_model = \'adr\' instead.', + pvlibDeprecationWarning) self._ac_model = self.adrinverter elif model in ['pvwatts']: self._ac_model = self.pvwatts_inverter From c85ab8217f6ead2a0d36227c9dead2c36917b1ca Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 26 Jun 2020 10:04:03 -0600 Subject: [PATCH 22/31] improvements from review --- docs/sphinx/source/api.rst | 2 +- docs/sphinx/source/introtutorial.rst | 2 +- docs/sphinx/source/whatsnew/v0.8.0.rst | 5 +- docs/tutorials/forecast.ipynb | 2 +- docs/tutorials/tmy_to_power.ipynb | 4 +- pvlib/inverter.py | 76 +++++++++++++++----------- pvlib/modelchain.py | 4 +- pvlib/pvsystem.py | 9 +-- 8 files changed, 58 insertions(+), 46 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 7ec7486609..14bd4973b1 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -298,7 +298,7 @@ Functions relevant for the Pvsyst model. pvsystem.singlediode Functions relevant for the PVWatts model -------------- +---------------------------------------- .. autosummary:: :toctree: generated/ diff --git a/docs/sphinx/source/introtutorial.rst b/docs/sphinx/source/introtutorial.rst index 2ad8c967c4..31b6cd71a9 100644 --- a/docs/sphinx/source/introtutorial.rst +++ b/docs/sphinx/source/introtutorial.rst @@ -96,7 +96,7 @@ to accomplish our system modeling goal: total_irrad['poa_direct'], total_irrad['poa_diffuse'], am_abs, aoi, module) dc = pvlib.pvsystem.sapm(effective_irradiance, tcell, module) - ac = pvlib.pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter) + ac = pvlib.inverter.sandia(dc['v_mp'], dc['p_mp'], inverter) annual_energy = ac.sum() energies[name] = annual_energy diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 1a08a829af..75ebdb33d4 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -12,9 +12,10 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` * ModelChain.ac_model now accepts `'sandia'`, `'pvwatts'` and `'adr'` for the inverter models. (:pull:`886`) + API Changes ~~~~~~~~~~~ -* Removed ``run_parallel_calculations`` and ``n_workers_for_parallel_calcs`` +* Removed ``run_parallel_calculations`` and ``n_workers_for_parallel_calcs`` from :py:func:`pvlib.bifacial.pvfactors_timeseries` inputs (:issue:`902`)(:pull:`934`) Enhancements @@ -29,7 +30,7 @@ Testing ~~~~~~~ * Decorator :py:func:`pvlib.conftest.fail_on_pvlib_version` can now be applied to functions that require args or kwargs. (:pull:`973`) -* Test added for :py:meth:`ModelChain.ac_model` to confirm ValueError when +* Test added for :py:meth:`ModelChain` to confirm ValueError when ac_model is an invalid string. (:pull:`886`) Documentation diff --git a/docs/tutorials/forecast.ipynb b/docs/tutorials/forecast.ipynb index 580ca840f4..853e7f2c58 100644 --- a/docs/tutorials/forecast.ipynb +++ b/docs/tutorials/forecast.ipynb @@ -8159,7 +8159,7 @@ " solar_position_method: nrel_numpy\n", " airmass_model: kastenyoung1989\n", " dc_model: sapm\n", - " ac_model: snlinverter\n", + " ac_model: sandia\n", " aoi_model: sapm_aoi_loss\n", " spectral_model: sapm_spectral_loss\n", " temp_model: sapm_temp\n", diff --git a/docs/tutorials/tmy_to_power.ipynb b/docs/tutorials/tmy_to_power.ipynb index 4f817afa71..b4cbfcdb20 100644 --- a/docs/tutorials/tmy_to_power.ipynb +++ b/docs/tutorials/tmy_to_power.ipynb @@ -1184,8 +1184,8 @@ ], "source": [ "p_acs = pd.DataFrame()\n", - "p_acs['sapm'] = pvlib.pvsystem.snlinverter(sapm_out.v_mp, sapm_out.p_mp, sapm_inverter)\n", - "p_acs['sd'] = pvlib.pvsystem.snlinverter(single_diode_out.v_mp, single_diode_out.p_mp, sapm_inverter)\n", + "p_acs['sapm'] = pvlib.inverter.sandia(sapm_out.v_mp, sapm_out.p_mp, sapm_inverter)\n", + "p_acs['sd'] = pvlib.inverter.sandia(single_diode_out.v_mp, single_diode_out.p_mp, sapm_inverter)\n", "\n", "p_acs.plot()\n", "plt.ylabel('AC Power (W)')" diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 2fdf670aab..847ebcda1e 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -135,7 +135,6 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Notes ----- - Determines the AC power output of an inverter given the DC voltage and DC power. Output AC power is bounded above by the parameter ``Pacmax``, to represent inverter "clipping". AC power is bounded below by ``-Pnt`` @@ -145,30 +144,34 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Required model parameters are: - ======= ============================================================ - Column Description - ======= ============================================================ - Pnom Nominal DC power, typically the DC power needed to produce - maximum AC power output. [W] - Vnom Nominal DC input voltage. Typically the level at which the - highest efficiency is achieved. [V] - Vmax Maximum DC input voltage. [V] - Vmin Minimum DC input voltage. [V] - Vdcmax . [V] - MPPTHi Maximum DC voltage for MPPT range. [V] - MPPTLow Minimum DC voltage for MPPT range. [V] - Pacmax Maximum AC output power, used to clip the output power - if needed. [W] + ======= ========================================================== + Column Description + ======= ========================================================== + Pnom Nominal DC power, typically the DC power needed to produce + maximum AC power output. [W] + Vnom Nominal DC input voltage. Typically the level at which the + highest efficiency is achieved. [V] + Vmax Maximum DC input voltage. [V] + Vmin Minimum DC input voltage. [V] + Vdcmax Maximum voltage supplied from DC array. [V] + MPPTHi Maximum DC voltage for MPPT range. [V] + MPPTLow Minimum DC voltage for MPPT range. [V] + Pacmax Maximum AC output power, used to clip the output power + if needed. [W] ADRCoefficients A list of 9 coefficients that capture the influence - of input voltage and power on inverter losses, and thereby - efficiency. Corresponds to terms from [1]_ (in order): :math: - `b_{0,0}, b_{1,0}, b_{2,0}, b_{0,1}, b_{1,1}, b_{2,1}, b_{0,2}, - b_{1,2}, b_{1,2}`. See [1]_ for the use of each coefficient - and the associated unit. - Pnt AC power consumed by inverter at night (night tare) to - maintain circuitry required to sense PV array voltage. [W] - - ======= ============================================================ + of input voltage and power on inverter losses, and thereby + efficiency. Corresponds to terms from [1]_ (in order): + :math: `b_{0,0}, b_{1,0}, b_{2,0}, b_{0,1}, b_{1,1}, + b_{2,1}, b_{0,2}, b_{1,2}, b_{2,2}`. See [1]_ for the + use of each coefficient and its associated unit. + Pnt AC power consumed by inverter at night (night tare) to + maintain circuitry required to sense the PV array + voltage. [W] + ======= ========================================================== + + AC power output is set to NaN where the input DC voltage exceeds a limit + M = max(Vmax, Vdcmax, MPPTHi) x (1 + vtol), and where the input DC voltage + is less than a limit m = max(Vmin, MPPTLow) x (1 - vtol) References ---------- @@ -235,24 +238,23 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): r""" - Implements NREL's PVWatts inverter model [1]_. + Implements NREL's PVWatts inverter model. + + The PVWatts inverter model [1]_ calculates inverter efficiency :math:'\eta' + as a function of input DC power .. math:: \eta = \frac{\eta_{nom}}{\eta_{ref}} (-0.0162\zeta - \frac{0.0059} {\zeta} + 0.9858) - .. math:: + where :math:`\zeta=P_{dc}/P_{dc0}` and :math:`P_{dc0}=P_{ac0}/\eta_{nom}`. - P_{ac} = \min(\eta P_{dc}, P_{ac0}) + Output AC power is then given by - where :math:`\zeta=P_{dc}/P_{dc0}` and :math:`P_{dc0}=P_{ac0}/\eta_{nom}`. + .. math:: - Note that ``pdc0`` is also used as a symbol in - :py:func:`pvlib.pvsystem.pvwatts_dc`. ``pdc0`` in this function refers to - the DC power input limit of the inverter. ``pdc0`` in - :py:func:`pvlib.pvsystem.pvwatts_dc` refers to the DC power of the modules - at reference conditions. + P_{ac} = \min(\eta P_{dc}, P_{ac0}) Parameters ---------- @@ -271,6 +273,14 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): power_ac: numeric AC power. Same unit as ``pdc0``. + Notes + ----- + Note that ``pdc0`` is also used as a symbol in + :py:func:`pvlib.pvsystem.pvwatts_dc`. ``pdc0`` in this function refers to + the DC power input limit of the inverter. ``pdc0`` in + :py:func:`pvlib.pvsystem.pvwatts_dc` refers to the DC power of the modules + at reference conditions. + References ---------- .. [1] A. P. Dobos, "PVWatts Version 5 Manual," diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 740943ecff..8d6f30e651 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -496,9 +496,9 @@ def ac_model(self, model): # TODO in v0.9: remove 'snlinverter', 'adrinverter' if model in ['sandia', 'snlinverter']: if model == 'snlinverter': - warnings.warn('ac_model = ''snlinverter'' is deprecated' + warnings.warn('ac_model = \'snlinverter\' is deprecated' ' and will be removed in v0.9; use' - ' ac_model = ''sandia'' instead.', + ' ac_model = \'sandia\' instead.', pvlibDeprecationWarning) self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index e9f14e063b..fb8270d44b 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2441,10 +2441,11 @@ def pvwatts_dc(g_poa_effective, temp_cell, pdc0, gamma_pdc, temp_ref=25.): P_{dc} = \frac{G_{poa eff}}{1000} P_{dc0} ( 1 + \gamma_{pdc} (T_{cell} - T_{ref})) - Note that the pdc0 is also used as a symbol in :py:func:`pvwatts_ac`. pdc0 - in this function refers to the DC power of the modules at reference - conditions. pdc0 in :py:func:`pvwatts_ac` refers to the DC power input - limit of the inverter. + Note that the pdc0 is also used as a symbol in + :py:func:`pvlib.inverter.pvwatts`. pdc0 in this function refers to the DC + power of the modules at reference conditions. pdc0 in + :py:func:`pvlib.inverter.pvwatts` refers to the DC power input limit of + the inverter. Parameters ---------- From dd40006e317c85f09b4ef4145e63f22288c7e5d0 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 26 Jun 2020 10:55:44 -0600 Subject: [PATCH 23/31] more improvements from review --- docs/tutorials/forecast_to_power.ipynb | 4 ++-- docs/tutorials/pvsystem.ipynb | 8 ++++---- pvlib/inverter.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/tutorials/forecast_to_power.ipynb b/docs/tutorials/forecast_to_power.ipynb index 153bf81297..0abdd2dff9 100644 --- a/docs/tutorials/forecast_to_power.ipynb +++ b/docs/tutorials/forecast_to_power.ipynb @@ -67,7 +67,7 @@ "import matplotlib as mpl\n", "\n", "# finally, we import the pvlib library\n", - "from pvlib import solarposition,irradiance,atmosphere,pvsystem\n", + "from pvlib import solarposition, irradiance, atmosphere, pvsystem, inverter\n", "from pvlib.forecast import GFS, NAM, NDFD, RAP, HRRR" ] }, @@ -876,7 +876,7 @@ } ], "source": [ - "p_ac = pvsystem.snlinverter(sapm_out.v_mp, sapm_out.p_mp, sapm_inverter)\n", + "p_ac = inverter.sandia(sapm_out.v_mp, sapm_out.p_mp, sapm_inverter)\n", "\n", "p_ac.plot()\n", "plt.ylabel('AC Power (W)')\n", diff --git a/docs/tutorials/pvsystem.ipynb b/docs/tutorials/pvsystem.ipynb index d75c024fd5..aff47be7e4 100644 --- a/docs/tutorials/pvsystem.ipynb +++ b/docs/tutorials/pvsystem.ipynb @@ -16,7 +16,7 @@ "1. [systemdef](#systemdef)\n", "2. [Angle of Incidence Modifiers](#Angle-of-Incidence-Modifiers)\n", "2. [Sandia Cell Temp correction](#Sandia-Cell-Temp-correction)\n", - "2. [Sandia Inverter Model](#snlinverter)\n", + "2. [Sandia Inverter Model](#Sandia-inverter-model)\n", "2. [Sandia Array Performance Model](#SAPM)\n", " 1. [SAPM IV curves](#SAPM-IV-curves)\n", "2. [DeSoto Model](#desoto)\n", @@ -78,7 +78,7 @@ "outputs": [], "source": [ "import pvlib\n", - "from pvlib import pvsystem" + "from pvlib import pvsystem, inverter" ] }, { @@ -573,7 +573,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### snlinverter" + "### Sandia-inverter-model" ] }, { @@ -1356,7 +1356,7 @@ "idcs = pd.Series(np.linspace(0,11,110))\n", "pdcs = idcs * vdcs\n", "\n", - "pacs = pvsystem.snlinverter(vdcs, pdcs, inverters['ABB__MICRO_0_25_I_OUTD_US_208_208V__CEC_2014_'])\n", + "pacs = inverter.sandia(vdcs, pdcs, inverters['ABB__MICRO_0_25_I_OUTD_US_208_208V__CEC_2014_'])\n", "#pacs.plot()\n", "plt.plot(pacs, pdcs)\n", "plt.ylabel('ac power')\n", diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 847ebcda1e..4bb53a7bac 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -144,9 +144,9 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Required model parameters are: - ======= ========================================================== + ================ ========================================================== Column Description - ======= ========================================================== + ================ ========================================================== Pnom Nominal DC power, typically the DC power needed to produce maximum AC power output. [W] Vnom Nominal DC input voltage. Typically the level at which the @@ -167,7 +167,7 @@ def adr(v_dc, p_dc, inverter, vtol=0.10): Pnt AC power consumed by inverter at night (night tare) to maintain circuitry required to sense the PV array voltage. [W] - ======= ========================================================== + ================ ========================================================== AC power output is set to NaN where the input DC voltage exceeds a limit M = max(Vmax, Vdcmax, MPPTHi) x (1 + vtol), and where the input DC voltage @@ -240,7 +240,7 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): r""" Implements NREL's PVWatts inverter model. - The PVWatts inverter model [1]_ calculates inverter efficiency :math:'\eta' + The PVWatts inverter model [1]_ calculates inverter efficiency :math:`\eta` as a function of input DC power .. math:: From 7663321a3936820265b89c6c88a7c0ee60e263fa Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 6 Jul 2020 09:37:10 -0600 Subject: [PATCH 24/31] improvements from review --- docs/sphinx/source/api.rst | 1 - docs/sphinx/source/whatsnew/v0.8.0.rst | 6 ++--- pvlib/modelchain.py | 14 ++++++------ pvlib/pvsystem.py | 4 ++-- pvlib/tests/test_modelchain.py | 31 ++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 8e0d274b55..c174ef0f49 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -300,7 +300,6 @@ Functions relevant for the Pvsyst model. pvsystem.singlediode Functions relevant for the PVWatts model ----------------------------------------- .. autosummary:: :toctree: generated/ diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index c235047fc4..6119cdca82 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -10,8 +10,8 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* ModelChain.ac_model now accepts `'sandia'`, `'pvwatts'` and `'adr'` for the - inverter models. (:pull:`886`) +* `modelchain.ModelChain.ac_model` now accepts "sandia", "pvwatts" and + "adr" for the inverter models. (:pull:`886`) API Changes ~~~~~~~~~~~ @@ -21,7 +21,7 @@ API Changes Enhancements ~~~~~~~~~~~~ * Update :func:`~pvlib.bifacial.pvfactors_timeseries` to run with ``pvfactors`` v1.4.1 (:issue:`902`)(:pull:`934`) -* Add :py:func:`pvlib.iam.marion_diffuse` and +* Add :py:func:`pvlib.iam.marion_diffuse` and :py:func:`pvlib.iam.marion_integrate` to calculate IAM values for diffuse irradiance. (:pull:`984`) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 8d6f30e651..b553d093a1 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -496,19 +496,19 @@ def ac_model(self, model): # TODO in v0.9: remove 'snlinverter', 'adrinverter' if model in ['sandia', 'snlinverter']: if model == 'snlinverter': - warnings.warn('ac_model = \'snlinverter\' is deprecated' - ' and will be removed in v0.9; use' - ' ac_model = \'sandia\' instead.', + warnings.warn("ac_model = 'snlinverter' is deprecated and" + " will be removed in v0.9; use" + " ac_model = 'sandia' instead.", pvlibDeprecationWarning) self._ac_model = self.snlinverter elif model in ['adr', 'adrinverter']: if model == 'adrinverter': - warnings.warn('ac_model = \'adrinverter\' is deprecated' - ' and will be removed in v0.9; use' - ' ac_model = \'adr\' instead.', + warnings.warn("ac_model = 'adrinverter' is deprecated and" + " will be removed in v0.9; use" + " ac_model = 'adr' instead.", pvlibDeprecationWarning) self._ac_model = self.adrinverter - elif model in ['pvwatts']: + elif model == 'pvwatts': self._ac_model = self.pvwatts_inverter else: raise ValueError(model + ' is not a valid AC power model') diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index fb8270d44b..24a8f4b66e 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -838,8 +838,8 @@ 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']`. + :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. """ diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index d170e1cb02..8e02c90be3 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -478,6 +478,21 @@ def test_ac_models(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, assert mc.ac[1] < 1 +# TODO in v0.9: remove this test for a deprecation warning +@pytest.mark.parametrize('ac_model', [ + 'snlinverter', pytest.param('adrinverter', marks=requires_scipy)]) +def test_ac_models_deprecated(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, + location, ac_model, weather): + ac_systems = {'snlinverter': sapm_dc_snl_ac_system, + 'adrinverter': cec_dc_adr_ac_system} + system = ac_systems[ac_model] + warn_txt = "ac_model = '" + ac_model + "' is deprecated and will be" +\ + " removed in v0.9" + with pytest.warns(pvlibDeprecationWarning, match=warn_txt): + ModelChain(system, location, ac_model=ac_model, + aoi_model='no_loss', spectral_model='no_loss') + + def test_ac_model_user_func(pvwatts_dc_pvwatts_ac_system, location, weather, mocker): m = mocker.spy(sys.modules[__name__], 'acdc') @@ -698,6 +713,22 @@ def test_deprecated_08(): temperature_model='pvsyst', temp_model='sapm') +@fail_on_pvlib_version('0.9') +@pytest.mark.parametrize('ac_model', ['snlinverter', 'adrinverter']) +def test_deprecated_09(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, + location, ac_model, weather): + # ModelChain.ac_model = 'snlinverter' or 'adrinverter' deprecated in v0.8, + # removed in v0.9 + ac_systems = {'snlinverter': sapm_dc_snl_ac_system, + 'adrinverter': cec_dc_adr_ac_system} + system = ac_systems[ac_model] + warn_txt = "ac_model = '" + ac_model + "' is deprecated and will be" +\ + " removed in v0.9" + with pytest.warns(pvlibDeprecationWarning, match=warn_txt): + ModelChain(system, location, ac_model=ac_model, + aoi_model='no_loss', spectral_model='no_loss') + + @requires_scipy def test_basic_chain_required(sam_data, cec_inverter_parameters, sapm_temperature_cs5p_220m): From ff13e7e4920283292b9edfde1965f6d3404146e7 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 6 Jul 2020 12:08:30 -0600 Subject: [PATCH 25/31] improvements from review --- docs/sphinx/source/api.rst | 9 ++++++--- pvlib/inverter.py | 9 +++++---- pvlib/modelchain.py | 4 ++-- pvlib/tests/test_modelchain.py | 20 ++++++-------------- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index c174ef0f49..9c93af7475 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -278,7 +278,8 @@ Inverter models (DC to AC conversion) PV System Models ---------------- -Functions relevant for the Sandia array performance model (SAPM). +Sandia array performance model (SAPM) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autosummary:: :toctree: generated/ @@ -290,7 +291,8 @@ Functions relevant for the Sandia array performance model (SAPM). inverter.sandia temperature.sapm_cell -Functions relevant for the Pvsyst model. +Pvsyst model +^^^^^^^^^^^^ .. autosummary:: :toctree: generated/ @@ -299,7 +301,8 @@ Functions relevant for the Pvsyst model. pvsystem.calcparams_pvsyst pvsystem.singlediode -Functions relevant for the PVWatts model +PVWatts model +^^^^^^^^^^^^^ .. autosummary:: :toctree: generated/ diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 4bb53a7bac..57d55e10ce 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -22,10 +22,7 @@ def sandia(v_dc, p_dc, inverter): DC power input to the inverter. [W] inverter : dict-like - Defines parameters for the inverter model in [1]_. See Notes for - required model parameters. A copy of the parameter database from the - System Advisor Model (SAM) [2]_ is provided with pvlib and may be read - using :py:func:`pvlib.pvsystem.retrieve_sam`. + Defines parameters for the inverter model in [1]_. Returns ------- @@ -68,6 +65,10 @@ def sandia(v_dc, p_dc, inverter): Pnt AC power consumed by the inverter at night (night tare). [W] ====== ============================================================ + A copy of the parameter database from the System Advisor Model (SAM) [2]_ + is provided with pvlib and may be read using + :py:func:`pvlib.pvsystem.retrieve_sam`. + References ---------- .. [1] D. King, S. Gonzalez, G. Galbraith, W. Boyson, "Performance Model diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index b553d093a1..0d8e816879 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -56,8 +56,8 @@ def basic_chain(times, latitude, longitude, See temperature.sapm_cell for details. inverter_parameters : None, dict or Series - Inverter parameters as defined by the CEC. See inverter.sandia for - details. + Inverter parameters as defined by the CEC. See + :py:func:`inverter.sandia` for details. irradiance : None or DataFrame, default None If None, calculates clear sky data. diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 8e02c90be3..1ebe806a5b 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -447,23 +447,15 @@ def acdc(mc): mc.ac = mc.dc -# TODO in v0.9: remove 'snlinverter', 'adrinverter' since these values for -# ModelChain.ac_model are superseded by 'sandia' and 'adr' @pytest.mark.parametrize('ac_model', [ - 'sandia', 'snlinverter', pytest.param('adrinverter', marks=requires_scipy), - pytest.param('adr', marks=requires_scipy), - 'pvwatts']) + 'sandia', pytest.param('adr', marks=requires_scipy), 'pvwatts']) def test_ac_models(sapm_dc_snl_ac_system, cec_dc_adr_ac_system, pvwatts_dc_pvwatts_ac_system, location, ac_model, weather, mocker): - ac_systems = {'snlinverter': sapm_dc_snl_ac_system, - 'sandia': sapm_dc_snl_ac_system, - 'adrinverter': cec_dc_adr_ac_system, + ac_systems = {'sandia': sapm_dc_snl_ac_system, 'adr': cec_dc_adr_ac_system, 'pvwatts': pvwatts_dc_pvwatts_ac_system} - ac_method_name = {'snlinverter': 'snlinverter', - 'sandia': 'snlinverter', - 'adrinverter': 'adrinverter', + ac_method_name = {'sandia': 'snlinverter', 'adr': 'adrinverter', 'pvwatts': 'pvwatts_ac'} system = ac_systems[ac_model] @@ -697,19 +689,19 @@ def test_deprecated_08(): warn_txt = 'temp_model keyword argument is deprecated' with pytest.warns(pvlibDeprecationWarning, match=warn_txt): ModelChain(system, location, dc_model='desoto', aoi_model='no_loss', - spectral_model='no_loss', ac_model='snlinverter', + spectral_model='no_loss', ac_model='sandia', temp_model='sapm') # provide both temp_model and temperature_model kwargs warn_txt = 'Provide only one of temperature_model' with pytest.warns(pvlibDeprecationWarning, match=warn_txt): ModelChain(system, location, dc_model='desoto', aoi_model='no_loss', - spectral_model='no_loss', ac_model='snlinverter', + spectral_model='no_loss', ac_model='sandia', temperature_model='sapm', temp_model='sapm') # conflicting temp_model and temperature_model kwargs exc_text = 'Conflicting temperature_model' with pytest.raises(ValueError, match=exc_text): ModelChain(system, location, dc_model='desoto', aoi_model='no_loss', - spectral_model='no_loss', ac_model='snlinverter', + spectral_model='no_loss', ac_model='sandia', temperature_model='pvsyst', temp_model='sapm') From 75d818b754574b6ab1383dc82582fe6f3691da94 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 10:00:08 -0600 Subject: [PATCH 26/31] last cleanup --- docs/sphinx/source/whatsnew/v0.8.0.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index e4bf03e2c8..b001ea5f68 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -10,8 +10,8 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* `modelchain.ModelChain.ac_model` now accepts "sandia", "pvwatts" and - "adr" for the inverter models. (:pull:`886`) +* `modelchain.ModelChain.ac_model` now accepts ''sandia'', ''pvwatts'' and + ''adr'' for the inverter models. (:pull:`886`) API Changes ~~~~~~~~~~~ From 9a9f105f192090747145a5b90f6ca55969f3ebbc Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 10:27:12 -0600 Subject: [PATCH 27/31] last cleanup part 2 --- docs/sphinx/source/whatsnew/v0.8.0.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index b001ea5f68..b163053c29 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -10,8 +10,8 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* `modelchain.ModelChain.ac_model` now accepts ''sandia'', ''pvwatts'' and - ''adr'' for the inverter models. (:pull:`886`) +* `modelchain.ModelChain.ac_model` now accepts ``sandia``, ``pvwatts`` and + ``adr`` for the inverter models. (:pull:`886`) API Changes ~~~~~~~~~~~ From 9be21e405777281388f7a22337d15f7fff25251a Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 10:53:55 -0600 Subject: [PATCH 28/31] last cleanup part 3 --- docs/sphinx/source/whatsnew/v0.8.0.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index b163053c29..a7f34bad2a 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -10,8 +10,8 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* `modelchain.ModelChain.ac_model` now accepts ``sandia``, ``pvwatts`` and - ``adr`` for the inverter models. (:pull:`886`) +* Method :py:meth:`modelchain.ModelChain.ac_model` now accepts ``sandia``, + ``pvwatts`` and ``adr`` for the inverter models. (:pull:`886`) API Changes ~~~~~~~~~~~ From 33cddd204f993887935872e9799f529f977292a7 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 13:15:33 -0600 Subject: [PATCH 29/31] py:attribute in whatsnew --- docs/sphinx/source/whatsnew/v0.8.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index a7f34bad2a..b59cfee6eb 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -10,7 +10,7 @@ API Changes with Deprecations - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* Method :py:meth:`modelchain.ModelChain.ac_model` now accepts ``sandia``, +* Attribute :py:attribute:`modelchain.ModelChain.ac_model` now accepts ``sandia``, ``pvwatts`` and ``adr`` for the inverter models. (:pull:`886`) API Changes From 1e073513ac7ad338440996396155c4ae81df517d Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 13:50:45 -0600 Subject: [PATCH 30/31] docstring improvements --- docs/sphinx/source/whatsnew/v0.8.0.rst | 8 ++++---- pvlib/inverter.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index b59cfee6eb..788a222d5c 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -5,13 +5,13 @@ v0.8.0 (Month day, year) API Changes with Deprecations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* Moved functions related to inverters from `pvsystem.py` to `inverter.py`. +* Moved functions related to inverters from ``pvsystem.py`` to ``inverter.py``. Functions are renamed to follow a more consistent pattern, as follows (:pull:`886`): - :py:func:`pvlib.pvsystem.snlinverter` is now :py:func:`pvlib.inverter.sandia` - :py:func:`pvlib.pvsystem.pvwatts_ac` is now :py:func:`pvlib.inverter.pvwatts` - :py:func:`pvlib.pvsystem.adrinverter` is now :py:func:`pvlib.inverter.adr` -* Attribute :py:attribute:`modelchain.ModelChain.ac_model` now accepts ``sandia``, - ``pvwatts`` and ``adr`` for the inverter models. (:pull:`886`) +* Argument ``ac_model`` for :py:class:`pvlib.modelchain.ModelChain` now accepts + ``'sandia'``, ``'pvwatts'`` and ``'adr'`` for the inverter models. (:pull:`886`) API Changes ~~~~~~~~~~~ @@ -33,7 +33,7 @@ Testing ~~~~~~~ * Decorator :py:func:`pvlib.conftest.fail_on_pvlib_version` can now be applied to functions that require args or kwargs. (:pull:`973`) -* Test added for :py:meth:`ModelChain` to confirm ValueError when +* Test added for :py:class:`pvlib.modelchain.ModelChain` to confirm ValueError when ac_model is an invalid string. (:pull:`886`) Documentation diff --git a/pvlib/inverter.py b/pvlib/inverter.py index 57d55e10ce..514be06e88 100644 --- a/pvlib/inverter.py +++ b/pvlib/inverter.py @@ -109,7 +109,7 @@ def sandia(v_dc, p_dc, inverter): def adr(v_dc, p_dc, inverter, vtol=0.10): r''' Converts DC power and voltage to AC power using Anton Driesse's - Grid-Connected PV Inverter efficiency model + grid-connected inverter efficiency model. Parameters ---------- From 6ba55aac8d3f6ca73c6bafc47b656279ab8ece3e Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Tue, 7 Jul 2020 14:17:00 -0600 Subject: [PATCH 31/31] one more --- docs/sphinx/source/whatsnew/v0.8.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 788a222d5c..f901add383 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -34,7 +34,7 @@ Testing * Decorator :py:func:`pvlib.conftest.fail_on_pvlib_version` can now be applied to functions that require args or kwargs. (:pull:`973`) * Test added for :py:class:`pvlib.modelchain.ModelChain` to confirm ValueError when - ac_model is an invalid string. (:pull:`886`) + ``ac_model`` is an invalid string. (:pull:`886`) Documentation ~~~~~~~~~~~~~