From acb9ff27b0c089a0c619a1373673ca1b2da1636b Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 10 Aug 2020 20:10:36 -0700 Subject: [PATCH 01/12] PVWatts(ModelChain) --- pvlib/modelchain.py | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 0d8e816879..44ee98bbd9 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -978,3 +978,79 @@ def run_model(self, weather, times=None): self.ac_model() return self + + +PVWATTS_CONFIG = dict( + dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts', + transposition_model='perez', aoi_model='physical', + spectral_model='no_loss' +) + + +class PVWatts(ModelChain): + """ + PVWatts version of ModelChain. + + Parameters + ---------- + system : PVSystem + A :py:class:`~pvlib.pvsystem.PVSystem` object that represents + the connected set of modules, inverters, etc. + + location : Location + A :py:class:`~pvlib.location.Location` object that represents + the physical location at which to evaluate the model. + + orientation_strategy : None or str, default None + The strategy for aligning the modules. If not None, sets the + ``surface_azimuth`` and ``surface_tilt`` properties of the + ``system``. Allowed strategies include 'flat', + 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. + + clearsky_model : str, default 'ineichen' + Passed to location.get_clearsky. + + airmass_model : str, default 'kastenyoung1989' + Passed to location.get_airmass. + + temperature_model: None, str or function, default None + Valid strings are 'sapm', 'pvsyst', and 'faiman'. The ModelChain + instance will be passed as the first argument to a user-defined + function. + + name: None or str, default None + Name of ModelChain instance. + + **kwargs + Arbitrary keyword arguments. Included for compatibility, but not + used. + + Examples + -------- + >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=1) + >>> inverter_parameters = dict(pac0=1) + >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, + ... module_parameters=module_parameters, + ... inverter_parameters=inverter_parameters) + >>> location = Location(32.2, -110.9) + >>> PVWatts(system, location) + """ + + def __init__(self, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + airmass_model='kastenyoung1989', + temperature_model=None, + name=None, + **kwargs): + + kwargs.update(PVWATTS_CONFIG) + super().__init__( + system, location, + orientation_strategy=orientation_strategy, + clearsky_model=clearsky_model, + airmass_model=airmass_model, + temperature_model=temperature_model, + name=name, + **kwargs + ) From e38771fbec6b7017268de8a59e62481fcd1ef36a Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Tue, 11 Aug 2020 09:53:40 -0700 Subject: [PATCH 02/12] make_chain_pvwatts classmethod --- pvlib/modelchain.py | 82 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 44ee98bbd9..5f722d32b0 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -18,6 +18,14 @@ from pvlib._deprecation import pvlibDeprecationWarning from pvlib.tools import _build_kwargs + +PVWATTS_CONFIG = dict( + dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts', + transposition_model='perez', aoi_model='physical', + spectral_model='no_loss' +) + + def basic_chain(times, latitude, longitude, module_parameters, temperature_model_parameters, inverter_parameters, @@ -349,6 +357,73 @@ def __init__(self, system, location, self.times = None self.solar_position = None + @classmethod + def make_chain_pvwatts(cls, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + airmass_model='kastenyoung1989', + temperature_model=None, + name=None, + **kwargs): + """ + PVWatts version of ModelChain. + + Parameters + ---------- + system : PVSystem + A :py:class:`~pvlib.pvsystem.PVSystem` object that represents + the connected set of modules, inverters, etc. + + location : Location + A :py:class:`~pvlib.location.Location` object that represents + the physical location at which to evaluate the model. + + orientation_strategy : None or str, default None + The strategy for aligning the modules. If not None, sets the + ``surface_azimuth`` and ``surface_tilt`` properties of the + ``system``. Allowed strategies include 'flat', + 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. + + clearsky_model : str, default 'ineichen' + Passed to location.get_clearsky. + + airmass_model : str, default 'kastenyoung1989' + Passed to location.get_airmass. + + temperature_model: None, str or function, default None + Valid strings are 'sapm', 'pvsyst', and 'faiman'. The ModelChain + instance will be passed as the first argument to a user-defined + function. + + name: None or str, default None + Name of ModelChain instance. + + **kwargs + Arbitrary keyword arguments. Included for compatibility, but not + used. + + Examples + -------- + >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=1) + >>> inverter_parameters = dict(pac0=1) + >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, + ... module_parameters=module_parameters, + ... inverter_parameters=inverter_parameters) + >>> location = Location(32.2, -110.9) + >>> ModelChain.make_chain_pvwatts(system, location) + """ + + kwargs.update(PVWATTS_CONFIG) + return ModelChain( + system, location, + orientation_strategy=orientation_strategy, + clearsky_model=clearsky_model, + airmass_model=airmass_model, + temperature_model=temperature_model, + name=name, + **kwargs + ) + def __repr__(self): attrs = [ 'name', 'orientation_strategy', 'clearsky_model', @@ -980,13 +1055,6 @@ def run_model(self, weather, times=None): return self -PVWATTS_CONFIG = dict( - dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts', - transposition_model='perez', aoi_model='physical', - spectral_model='no_loss' -) - - class PVWatts(ModelChain): """ PVWatts version of ModelChain. From e130b699a716370ef83fcb53e26402fca4ebb958 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Tue, 11 Aug 2020 10:13:36 -0700 Subject: [PATCH 03/12] sapm --- pvlib/modelchain.py | 106 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 5f722d32b0..320ab3a554 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -25,6 +25,11 @@ spectral_model='no_loss' ) +SAPM_CONFIG = dict( + dc_model='sapm', ac_model='sandia', losses_model='no_loss', + aoi_model='sapm', spectral_model='sapm' +) + def basic_chain(times, latitude, longitude, module_parameters, temperature_model_parameters, @@ -366,7 +371,7 @@ def make_chain_pvwatts(cls, system, location, name=None, **kwargs): """ - PVWatts version of ModelChain. + ModelChain that follows the PVWatts methods. Parameters ---------- @@ -411,6 +416,19 @@ def make_chain_pvwatts(cls, system, location, ... inverter_parameters=inverter_parameters) >>> location = Location(32.2, -110.9) >>> ModelChain.make_chain_pvwatts(system, location) + ModelChain: + name: None + orientation_strategy: None + clearsky_model: ineichen + transposition_model: perez + solar_position_method: nrel_numpy + airmass_model: kastenyoung1989 + dc_model: pvwatts_dc + ac_model: pvwatts_inverter + aoi_model: physical_aoi_loss + spectral_model: no_spectral_loss + temperature_model: sapm_temp + losses_model: pvwatts_losses """ kwargs.update(PVWATTS_CONFIG) @@ -424,6 +442,92 @@ def make_chain_pvwatts(cls, system, location, **kwargs ) + @classmethod + def make_chain_sapm(cls, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + transposition_model='haydavies', + solar_position_method='nrel_numpy', + airmass_model='kastenyoung1989', + name=None, + **kwargs): + """ + ModelChain that follows the Sandia Array Performance Model + (SAPM) methods. + + Parameters + ---------- + system : PVSystem + A :py:class:`~pvlib.pvsystem.PVSystem` object that represents + the connected set of modules, inverters, etc. + + location : Location + A :py:class:`~pvlib.location.Location` object that represents + the physical location at which to evaluate the model. + + orientation_strategy : None or str, default None + The strategy for aligning the modules. If not None, sets the + ``surface_azimuth`` and ``surface_tilt`` properties of the + ``system``. Allowed strategies include 'flat', + 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. + + clearsky_model : str, default 'ineichen' + Passed to location.get_clearsky. + + transposition_model : str, default 'haydavies' + Passed to system.get_irradiance. + + solar_position_method : str, default 'nrel_numpy' + Passed to location.get_solarposition. + + airmass_model : str, default 'kastenyoung1989' + Passed to location.get_airmass. + + name: None or str, default None + Name of ModelChain instance. + + **kwargs + Arbitrary keyword arguments. Included for compatibility, but not + used. + + Examples + -------- + >>> mods = pvlib.pvsystem.retrieve_sam('sandiamod') + >>> invs = pvlib.pvsystem.retrieve_sam('cecinverter') + >>> module_parameters = mods['Canadian_Solar_CS5P_220M___2009_'] + >>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_'] + >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, + ... module_parameters=module_parameters, + ... inverter_parameters=inverter_parameters) + >>> location = Location(32.2, -110.9) + >>> ModelChain.make_chain_sapm(system, location) + ModelChain: + name: None + orientation_strategy: None + clearsky_model: ineichen + transposition_model: haydavies + solar_position_method: nrel_numpy + airmass_model: kastenyoung1989 + dc_model: sapm + ac_model: snlinverter + aoi_model: sapm_aoi_loss + spectral_model: sapm_spectral_loss + temperature_model: sapm_temp + losses_model: no_extra_losses + """ + + kwargs.update(SAPM_CONFIG) + return ModelChain( + system, location, + orientation_strategy=orientation_strategy, + clearsky_model=clearsky_model, + transposition_model=transposition_model, + solar_position_method=solar_position_method, + airmass_model=airmass_model, + name=name, + **kwargs + ) + def __repr__(self): attrs = [ 'name', 'orientation_strategy', 'clearsky_model', From 37f726f22aafbcb56c417e5d0cbdd998b6463e6e Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Wed, 12 Aug 2020 08:59:46 -0700 Subject: [PATCH 04/12] method names, comment --- pvlib/modelchain.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 320ab3a554..034533cbf1 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -363,13 +363,13 @@ def __init__(self, system, location, self.solar_position = None @classmethod - def make_chain_pvwatts(cls, system, location, - orientation_strategy=None, - clearsky_model='ineichen', - airmass_model='kastenyoung1989', - temperature_model=None, - name=None, - **kwargs): + def with_pvwatts(cls, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + airmass_model='kastenyoung1989', + temperature_model=None, + name=None, + **kwargs): """ ModelChain that follows the PVWatts methods. @@ -415,7 +415,7 @@ def make_chain_pvwatts(cls, system, location, ... module_parameters=module_parameters, ... inverter_parameters=inverter_parameters) >>> location = Location(32.2, -110.9) - >>> ModelChain.make_chain_pvwatts(system, location) + >>> ModelChain.with_pvwatts(system, location) ModelChain: name: None orientation_strategy: None @@ -443,14 +443,14 @@ def make_chain_pvwatts(cls, system, location, ) @classmethod - def make_chain_sapm(cls, system, location, - orientation_strategy=None, - clearsky_model='ineichen', - transposition_model='haydavies', - solar_position_method='nrel_numpy', - airmass_model='kastenyoung1989', - name=None, - **kwargs): + def with_sapm(cls, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + transposition_model='haydavies', + solar_position_method='nrel_numpy', + airmass_model='kastenyoung1989', + name=None, + **kwargs): """ ModelChain that follows the Sandia Array Performance Model (SAPM) methods. @@ -500,7 +500,7 @@ def make_chain_sapm(cls, system, location, ... module_parameters=module_parameters, ... inverter_parameters=inverter_parameters) >>> location = Location(32.2, -110.9) - >>> ModelChain.make_chain_sapm(system, location) + >>> ModelChain.with_sapm(system, location) ModelChain: name: None orientation_strategy: None @@ -1159,6 +1159,7 @@ def run_model(self, weather, times=None): return self +# delete this if we agree factory methods are preferable class PVWatts(ModelChain): """ PVWatts version of ModelChain. From dfb0f4395bf2076de56c25948337a60f4351effc Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Wed, 12 Aug 2020 12:56:17 -0700 Subject: [PATCH 05/12] remove class, add pvsyst stub --- pvlib/modelchain.py | 166 +++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 71 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 034533cbf1..d8bcd1cd0b 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -19,16 +19,23 @@ from pvlib.tools import _build_kwargs +# these dictionaries contain the default configuration for following +# established modeling sequences. They can be used in combination with +# basic_chain and ModelChain. They are used by the ModelChain methods +# ModelChain.with_pvwatts, ModelChain.with_sapm, etc. PVWATTS_CONFIG = dict( dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts', transposition_model='perez', aoi_model='physical', spectral_model='no_loss' ) - SAPM_CONFIG = dict( dc_model='sapm', ac_model='sandia', losses_model='no_loss', aoi_model='sapm', spectral_model='sapm' ) +# update when full pvsyst models are known +PVSYST_CONFIG = dict( + dc_model='pvsyst' +) def basic_chain(times, latitude, longitude, @@ -528,6 +535,93 @@ def with_sapm(cls, system, location, **kwargs ) + # update when full pvsyst models are known + @classmethod + def with_pvsyst(cls, system, location, + orientation_strategy=None, + clearsky_model='ineichen', + transposition_model='haydavies', + solar_position_method='nrel_numpy', + airmass_model='kastenyoung1989', + name=None, + **kwargs): + """ + ModelChain that follows the Sandia Array Performance Model + (SAPM) methods. + + Parameters + ---------- + system : PVSystem + A :py:class:`~pvlib.pvsystem.PVSystem` object that represents + the connected set of modules, inverters, etc. + + location : Location + A :py:class:`~pvlib.location.Location` object that represents + the physical location at which to evaluate the model. + + orientation_strategy : None or str, default None + The strategy for aligning the modules. If not None, sets the + ``surface_azimuth`` and ``surface_tilt`` properties of the + ``system``. Allowed strategies include 'flat', + 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. + + clearsky_model : str, default 'ineichen' + Passed to location.get_clearsky. + + transposition_model : str, default 'haydavies' + Passed to system.get_irradiance. + + solar_position_method : str, default 'nrel_numpy' + Passed to location.get_solarposition. + + airmass_model : str, default 'kastenyoung1989' + Passed to location.get_airmass. + + name: None or str, default None + Name of ModelChain instance. + + **kwargs + Arbitrary keyword arguments. Included for compatibility, but not + used. + + Examples + -------- + >>> mods = pvlib.pvsystem.retrieve_sam('sandiamod') + >>> invs = pvlib.pvsystem.retrieve_sam('cecinverter') + >>> module_parameters = mods['Canadian_Solar_CS5P_220M___2009_'] + >>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_'] + >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, + ... module_parameters=module_parameters, + ... inverter_parameters=inverter_parameters) + >>> location = Location(32.2, -110.9) + >>> ModelChain.with_pvsyst(system, location) + ModelChain: + name: None + orientation_strategy: None + clearsky_model: ineichen + transposition_model: haydavies + solar_position_method: nrel_numpy + airmass_model: kastenyoung1989 + dc_model: sapm + ac_model: snlinverter + aoi_model: sapm_aoi_loss + spectral_model: sapm_spectral_loss + temperature_model: sapm_temp + losses_model: no_extra_losses + """ + + kwargs.update(PVSYST_CONFIG) + return ModelChain( + system, location, + orientation_strategy=orientation_strategy, + clearsky_model=clearsky_model, + transposition_model=transposition_model, + solar_position_method=solar_position_method, + airmass_model=airmass_model, + name=name, + **kwargs + ) + def __repr__(self): attrs = [ 'name', 'orientation_strategy', 'clearsky_model', @@ -1157,73 +1251,3 @@ def run_model(self, weather, times=None): self.ac_model() return self - - -# delete this if we agree factory methods are preferable -class PVWatts(ModelChain): - """ - PVWatts version of ModelChain. - - Parameters - ---------- - system : PVSystem - A :py:class:`~pvlib.pvsystem.PVSystem` object that represents - the connected set of modules, inverters, etc. - - location : Location - A :py:class:`~pvlib.location.Location` object that represents - the physical location at which to evaluate the model. - - orientation_strategy : None or str, default None - The strategy for aligning the modules. If not None, sets the - ``surface_azimuth`` and ``surface_tilt`` properties of the - ``system``. Allowed strategies include 'flat', - 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. - - clearsky_model : str, default 'ineichen' - Passed to location.get_clearsky. - - airmass_model : str, default 'kastenyoung1989' - Passed to location.get_airmass. - - temperature_model: None, str or function, default None - Valid strings are 'sapm', 'pvsyst', and 'faiman'. The ModelChain - instance will be passed as the first argument to a user-defined - function. - - name: None or str, default None - Name of ModelChain instance. - - **kwargs - Arbitrary keyword arguments. Included for compatibility, but not - used. - - Examples - -------- - >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=1) - >>> inverter_parameters = dict(pac0=1) - >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, - ... module_parameters=module_parameters, - ... inverter_parameters=inverter_parameters) - >>> location = Location(32.2, -110.9) - >>> PVWatts(system, location) - """ - - def __init__(self, system, location, - orientation_strategy=None, - clearsky_model='ineichen', - airmass_model='kastenyoung1989', - temperature_model=None, - name=None, - **kwargs): - - kwargs.update(PVWATTS_CONFIG) - super().__init__( - system, location, - orientation_strategy=orientation_strategy, - clearsky_model=clearsky_model, - airmass_model=airmass_model, - temperature_model=temperature_model, - name=name, - **kwargs - ) From 00108d91a590972c8ba7a5d667a57b1d5beb5c3e Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 17 Aug 2020 19:44:05 -0700 Subject: [PATCH 06/12] fix dict update, a couple of tests --- pvlib/modelchain.py | 35 ++++++++++++++++++---------------- pvlib/tests/test_modelchain.py | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index d8bcd1cd0b..2bad2ded95 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -34,7 +34,7 @@ ) # update when full pvsyst models are known PVSYST_CONFIG = dict( - dc_model='pvsyst' + dc_model='pvsyst', spectral_model='no_loss' ) @@ -411,8 +411,9 @@ def with_pvwatts(cls, system, location, Name of ModelChain instance. **kwargs - Arbitrary keyword arguments. Included for compatibility, but not - used. + Parameters supplied here are passed to the ModelChain + constructor and take precedence over the default + configuration. Examples -------- @@ -437,8 +438,8 @@ def with_pvwatts(cls, system, location, temperature_model: sapm_temp losses_model: pvwatts_losses """ - - kwargs.update(PVWATTS_CONFIG) + config = PVWATTS_CONFIG.copy() + config.update(kwargs) return ModelChain( system, location, orientation_strategy=orientation_strategy, @@ -446,7 +447,7 @@ def with_pvwatts(cls, system, location, airmass_model=airmass_model, temperature_model=temperature_model, name=name, - **kwargs + **config ) @classmethod @@ -494,8 +495,9 @@ def with_sapm(cls, system, location, Name of ModelChain instance. **kwargs - Arbitrary keyword arguments. Included for compatibility, but not - used. + Parameters supplied here are passed to the ModelChain + constructor and take precedence over the default + configuration. Examples -------- @@ -522,8 +524,8 @@ def with_sapm(cls, system, location, temperature_model: sapm_temp losses_model: no_extra_losses """ - - kwargs.update(SAPM_CONFIG) + config = SAPM_CONFIG.copy() + config.update(kwargs) return ModelChain( system, location, orientation_strategy=orientation_strategy, @@ -532,7 +534,7 @@ def with_sapm(cls, system, location, solar_position_method=solar_position_method, airmass_model=airmass_model, name=name, - **kwargs + **config ) # update when full pvsyst models are known @@ -581,8 +583,9 @@ def with_pvsyst(cls, system, location, Name of ModelChain instance. **kwargs - Arbitrary keyword arguments. Included for compatibility, but not - used. + Parameters supplied here are passed to the ModelChain + constructor and take precedence over the default + configuration. Examples -------- @@ -609,8 +612,8 @@ def with_pvsyst(cls, system, location, temperature_model: sapm_temp losses_model: no_extra_losses """ - - kwargs.update(PVSYST_CONFIG) + config = PVSYST_CONFIG.copy() + config.update(kwargs) return ModelChain( system, location, orientation_strategy=orientation_strategy, @@ -619,7 +622,7 @@ def with_pvsyst(cls, system, location, solar_position_method=solar_position_method, airmass_model=airmass_model, name=name, - **kwargs + **config ) def __repr__(self): diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index bba8a711a0..570586af55 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -170,6 +170,21 @@ def test_ModelChain_creation(sapm_dc_snl_ac_system, location): ModelChain(sapm_dc_snl_ac_system, location) +def test_with_pvsyst(pvsyst_dc_snl_ac_system, location): + mc = ModelChain.with_pvsyst(pvsyst_dc_snl_ac_system, location) + assert mc.dc_model == mc.pvsyst + + +def test_with_sapm(sapm_dc_snl_ac_system, location): + mc = ModelChain.with_sapm(sapm_dc_snl_ac_system, location) + assert mc.dc_model == mc.sapm + + +def test_with_pvwatts(pvwatts_dc_pvwatts_ac_system, location): + mc = ModelChain.with_pvwatts(pvwatts_dc_pvwatts_ac_system, location) + assert mc.dc_model == mc.pvwatts_dc + + @pytest.mark.parametrize('strategy, expected', [ (None, (32.2, 180)), ('None', (32.2, 180)), ('flat', (0, 180)), ('south_at_latitude_tilt', (32.2, 180)) From 368fceb475223ac86c1ce49184f58fe677a68919 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 17 Aug 2020 19:49:48 -0700 Subject: [PATCH 07/12] documentation --- docs/sphinx/source/api.rst | 3 +++ docs/sphinx/source/whatsnew/v0.8.0.rst | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index dd7c618646..06fa2d62e0 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -489,6 +489,9 @@ Creating a ModelChain object. :toctree: generated/ modelchain.ModelChain + modelchain.ModelChain.with_pvsyst + modelchain.ModelChain.with_pvwatts + modelchain.ModelChain.with_sapm Running ------- diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 2aa1ebfb67..50938d437c 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -40,6 +40,13 @@ Enhancements diffuse irradiance. (:pull:`984`) * Add :py:func:`pvlib.inverter.fit_sandia` that fits the Sandia inverter model to a set of inverter efficiency curves. (:pull:`1011`) +* Add factory methods :py:meth:`~pvlib.modelchain.ModelChain.with_pvsyst`, + :py:meth:`~pvlib.modelchain.ModelChain.with_pvwatts`, and + :py:meth:`~pvlib.modelchain.ModelChain.with_sapm` to create ``ModelChain`` + objects configured for the respective modeling paradigms. The + configurations are defined in ``modelchain.PVSYST_CONFIG``, + ``modelchain.PVWATTS_CONFIG``, and ``modelchain.SAPM_CONFIG``. + (:issue:`1013`, :pull:`1022`) Bug fixes ~~~~~~~~~ From 600c6a53748cf73d318fb47f495b69b1bbd805b9 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 24 Aug 2020 15:27:17 -0700 Subject: [PATCH 08/12] remove incomplete with_pvsyst --- pvlib/modelchain.py | 92 ---------------------------------- pvlib/tests/test_modelchain.py | 5 -- 2 files changed, 97 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 2bad2ded95..2fa9c951c3 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -32,10 +32,6 @@ dc_model='sapm', ac_model='sandia', losses_model='no_loss', aoi_model='sapm', spectral_model='sapm' ) -# update when full pvsyst models are known -PVSYST_CONFIG = dict( - dc_model='pvsyst', spectral_model='no_loss' -) def basic_chain(times, latitude, longitude, @@ -537,94 +533,6 @@ def with_sapm(cls, system, location, **config ) - # update when full pvsyst models are known - @classmethod - def with_pvsyst(cls, system, location, - orientation_strategy=None, - clearsky_model='ineichen', - transposition_model='haydavies', - solar_position_method='nrel_numpy', - airmass_model='kastenyoung1989', - name=None, - **kwargs): - """ - ModelChain that follows the Sandia Array Performance Model - (SAPM) methods. - - Parameters - ---------- - system : PVSystem - A :py:class:`~pvlib.pvsystem.PVSystem` object that represents - the connected set of modules, inverters, etc. - - location : Location - A :py:class:`~pvlib.location.Location` object that represents - the physical location at which to evaluate the model. - - orientation_strategy : None or str, default None - The strategy for aligning the modules. If not None, sets the - ``surface_azimuth`` and ``surface_tilt`` properties of the - ``system``. Allowed strategies include 'flat', - 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. - - clearsky_model : str, default 'ineichen' - Passed to location.get_clearsky. - - transposition_model : str, default 'haydavies' - Passed to system.get_irradiance. - - solar_position_method : str, default 'nrel_numpy' - Passed to location.get_solarposition. - - airmass_model : str, default 'kastenyoung1989' - Passed to location.get_airmass. - - name: None or str, default None - Name of ModelChain instance. - - **kwargs - Parameters supplied here are passed to the ModelChain - constructor and take precedence over the default - configuration. - - Examples - -------- - >>> mods = pvlib.pvsystem.retrieve_sam('sandiamod') - >>> invs = pvlib.pvsystem.retrieve_sam('cecinverter') - >>> module_parameters = mods['Canadian_Solar_CS5P_220M___2009_'] - >>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_'] - >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, - ... module_parameters=module_parameters, - ... inverter_parameters=inverter_parameters) - >>> location = Location(32.2, -110.9) - >>> ModelChain.with_pvsyst(system, location) - ModelChain: - name: None - orientation_strategy: None - clearsky_model: ineichen - transposition_model: haydavies - solar_position_method: nrel_numpy - airmass_model: kastenyoung1989 - dc_model: sapm - ac_model: snlinverter - aoi_model: sapm_aoi_loss - spectral_model: sapm_spectral_loss - temperature_model: sapm_temp - losses_model: no_extra_losses - """ - config = PVSYST_CONFIG.copy() - config.update(kwargs) - return ModelChain( - system, location, - orientation_strategy=orientation_strategy, - clearsky_model=clearsky_model, - transposition_model=transposition_model, - solar_position_method=solar_position_method, - airmass_model=airmass_model, - name=name, - **config - ) - def __repr__(self): attrs = [ 'name', 'orientation_strategy', 'clearsky_model', diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 570586af55..51f18da730 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -170,11 +170,6 @@ def test_ModelChain_creation(sapm_dc_snl_ac_system, location): ModelChain(sapm_dc_snl_ac_system, location) -def test_with_pvsyst(pvsyst_dc_snl_ac_system, location): - mc = ModelChain.with_pvsyst(pvsyst_dc_snl_ac_system, location) - assert mc.dc_model == mc.pvsyst - - def test_with_sapm(sapm_dc_snl_ac_system, location): mc = ModelChain.with_sapm(sapm_dc_snl_ac_system, location) assert mc.dc_model == mc.sapm From 1df7e9a3f6cbfacc551f1deab77f42cf167febc8 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 24 Aug 2020 19:22:59 -0700 Subject: [PATCH 09/12] fix temperature model issues --- pvlib/modelchain.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 2fa9c951c3..267cda0a8e 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -23,14 +23,22 @@ # established modeling sequences. They can be used in combination with # basic_chain and ModelChain. They are used by the ModelChain methods # ModelChain.with_pvwatts, ModelChain.with_sapm, etc. + +# pvwatts documentation states that it uses the following reference for +# a temperature model: Fuentes, M. K. (1987). A Simplified Thermal Model +# for Flat-Plate Photovoltaic Arrays. SAND85-0330. Albuquerque, NM: +# Sandia National Laboratories. Accessed September 3, 2013: +# http://prod.sandia.gov/techlib/access-control.cgi/1985/850330.pdf +# pvlib python does not implement that model, so use the SAPM instead. PVWATTS_CONFIG = dict( dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts', transposition_model='perez', aoi_model='physical', - spectral_model='no_loss' + spectral_model='no_loss', temperature_model='sapm' ) + SAPM_CONFIG = dict( dc_model='sapm', ac_model='sandia', losses_model='no_loss', - aoi_model='sapm', spectral_model='sapm' + aoi_model='sapm', spectral_model='sapm', temperature_model='sapm' ) @@ -370,7 +378,6 @@ def with_pvwatts(cls, system, location, orientation_strategy=None, clearsky_model='ineichen', airmass_model='kastenyoung1989', - temperature_model=None, name=None, **kwargs): """ @@ -398,11 +405,6 @@ def with_pvwatts(cls, system, location, airmass_model : str, default 'kastenyoung1989' Passed to location.get_airmass. - temperature_model: None, str or function, default None - Valid strings are 'sapm', 'pvsyst', and 'faiman'. The ModelChain - instance will be passed as the first argument to a user-defined - function. - name: None or str, default None Name of ModelChain instance. @@ -413,11 +415,12 @@ def with_pvwatts(cls, system, location, Examples -------- - >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=1) - >>> inverter_parameters = dict(pac0=1) + >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=4500) + >>> inverter_parameters = dict(pac0=4000) >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, ... module_parameters=module_parameters, - ... inverter_parameters=inverter_parameters) + ... inverter_parameters=inverter_parameters, + ... temperature_parameters='open_rack_glass_glass') >>> location = Location(32.2, -110.9) >>> ModelChain.with_pvwatts(system, location) ModelChain: @@ -441,7 +444,6 @@ def with_pvwatts(cls, system, location, orientation_strategy=orientation_strategy, clearsky_model=clearsky_model, airmass_model=airmass_model, - temperature_model=temperature_model, name=name, **config ) @@ -503,7 +505,8 @@ def with_sapm(cls, system, location, >>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_'] >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, ... module_parameters=module_parameters, - ... inverter_parameters=inverter_parameters) + ... inverter_parameters=inverter_parameters, + ... temperature_parameters='open_rack_glass_glass') >>> location = Location(32.2, -110.9) >>> ModelChain.with_sapm(system, location) ModelChain: From affdb042012e05bb936593ba47dcd8f418b79c86 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 24 Aug 2020 19:26:27 -0700 Subject: [PATCH 10/12] fix temp model kwarg. run_model in test --- pvlib/tests/test_modelchain.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 51f18da730..e6d8f70083 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -170,14 +170,17 @@ def test_ModelChain_creation(sapm_dc_snl_ac_system, location): ModelChain(sapm_dc_snl_ac_system, location) -def test_with_sapm(sapm_dc_snl_ac_system, location): +def test_with_sapm(sapm_dc_snl_ac_system, location, weather): mc = ModelChain.with_sapm(sapm_dc_snl_ac_system, location) assert mc.dc_model == mc.sapm + mc.run_model(weather) -def test_with_pvwatts(pvwatts_dc_pvwatts_ac_system, location): +def test_with_pvwatts(pvwatts_dc_pvwatts_ac_system, location, weather): mc = ModelChain.with_pvwatts(pvwatts_dc_pvwatts_ac_system, location) assert mc.dc_model == mc.pvwatts_dc + assert mc.temperature_model == mc.sapm_temp + mc.run_model(weather) @pytest.mark.parametrize('strategy, expected', [ From c8be8fb5729774b065c250ffd4365962d4fda38f Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Mon, 24 Aug 2020 20:08:31 -0700 Subject: [PATCH 11/12] complicated code is bad --- pvlib/modelchain.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 267cda0a8e..2479f16118 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -417,10 +417,11 @@ def with_pvwatts(cls, system, location, -------- >>> module_parameters = dict(gamma_pdc=-0.003, pdc0=4500) >>> inverter_parameters = dict(pac0=4000) + >>> tparams = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass'] >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, ... module_parameters=module_parameters, ... inverter_parameters=inverter_parameters, - ... temperature_parameters='open_rack_glass_glass') + ... temperature_model_parameters=tparams) >>> location = Location(32.2, -110.9) >>> ModelChain.with_pvwatts(system, location) ModelChain: @@ -436,7 +437,7 @@ def with_pvwatts(cls, system, location, spectral_model: no_spectral_loss temperature_model: sapm_temp losses_model: pvwatts_losses - """ + """ # noqa: E501 config = PVWATTS_CONFIG.copy() config.update(kwargs) return ModelChain( @@ -503,10 +504,11 @@ def with_sapm(cls, system, location, >>> invs = pvlib.pvsystem.retrieve_sam('cecinverter') >>> module_parameters = mods['Canadian_Solar_CS5P_220M___2009_'] >>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_'] + >>> tparams = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass'] >>> system = PVSystem(surface_tilt=30, surface_azimuth=180, ... module_parameters=module_parameters, ... inverter_parameters=inverter_parameters, - ... temperature_parameters='open_rack_glass_glass') + ... temperature_model_parameters=tparams) >>> location = Location(32.2, -110.9) >>> ModelChain.with_sapm(system, location) ModelChain: @@ -522,7 +524,7 @@ def with_sapm(cls, system, location, spectral_model: sapm_spectral_loss temperature_model: sapm_temp losses_model: no_extra_losses - """ + """ # noqa: E501 config = SAPM_CONFIG.copy() config.update(kwargs) return ModelChain( From 17637d23cdb1269ad98f3dfaab1317210619b201 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Tue, 25 Aug 2020 11:55:47 -0700 Subject: [PATCH 12/12] remove with_pvsyst from docs --- docs/sphinx/source/api.rst | 1 - docs/sphinx/source/whatsnew/v0.8.0.rst | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 983c681a94..91c7662a0a 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -495,7 +495,6 @@ Creating a ModelChain object. :toctree: generated/ modelchain.ModelChain - modelchain.ModelChain.with_pvsyst modelchain.ModelChain.with_pvwatts modelchain.ModelChain.with_sapm diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index ce76a838a9..b87f79067b 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -44,13 +44,11 @@ Enhancements (:pull:`1017`) * Add :py:func:`pvlib.inverter.fit_sandia` that fits the Sandia inverter model to a set of inverter efficiency curves. (:pull:`1011`) -* Add factory methods :py:meth:`~pvlib.modelchain.ModelChain.with_pvsyst`, - :py:meth:`~pvlib.modelchain.ModelChain.with_pvwatts`, and +* Add factory methods :py:meth:`~pvlib.modelchain.ModelChain.with_pvwatts` :py:meth:`~pvlib.modelchain.ModelChain.with_sapm` to create ``ModelChain`` objects configured for the respective modeling paradigms. The - configurations are defined in ``modelchain.PVSYST_CONFIG``, - ``modelchain.PVWATTS_CONFIG``, and ``modelchain.SAPM_CONFIG``. - (:issue:`1013`, :pull:`1022`) + configurations are defined in ``modelchain.PVWATTS_CONFIG``, and + ``modelchain.SAPM_CONFIG``. (:issue:`1013`, :pull:`1022`) * Added *racking_model*, *module_type*, and *temperature_model_parameters* to PVSystem, LocalizedPVSystem, SingleAxisTracker, and LocalizedSingleAxisTracker repr methods. (:issue:`1027`)