diff --git a/docs/sphinx/source/whatsnew/v0.3.3.txt b/docs/sphinx/source/whatsnew/v0.3.3.txt index a6e05fd827..2a3ac63745 100644 --- a/docs/sphinx/source/whatsnew/v0.3.3.txt +++ b/docs/sphinx/source/whatsnew/v0.3.3.txt @@ -12,6 +12,8 @@ Enhancements * Adds the Erbs model. (:issue:`2`) * Adds the ``scale_voltage_current_power`` function and ``PVSystem`` method to support simple array modeling. (:issue:`159`) +* Adds support for ``SingleAxisTracker`` objects in ``ModelChain``. + (:issue:`169`) Bug fixes diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index d3714a6488..cedffce9fc 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -6,9 +6,12 @@ the time to read the source code for the module. """ +from functools import partial + import pandas as pd from pvlib import solarposition, pvsystem, clearsky, atmosphere +from pvlib.tracking import SingleAxisTracker import pvlib.irradiance # avoid name conflict with full import @@ -317,9 +320,32 @@ def run_model(self, times, irradiance=None, weather=None): airmass_data=self.airmass['airmass_absolute']) self.irradiance = irradiance - self.total_irrad = self.system.get_irradiance( - self.solar_position['apparent_zenith'], - self.solar_position['azimuth'], + # PVSystem.get_irradiance and SingleAxisTracker.get_irradiance + # have different method signatures, so use partial to handle + # the differences. + if isinstance(self.system, SingleAxisTracker): + self.tracking = self.system.singleaxis( + self.solar_position['apparent_zenith'], + self.solar_position['azimuth']) + self.tracking['surface_tilt'] = ( + self.tracking['surface_tilt'] + .fillna(self.system.axis_tilt)) + self.tracking['surface_azimuth'] = ( + self.tracking['surface_azimuth'] + .fillna(self.system.axis_azimuth)) + get_irradiance = partial( + self.system.get_irradiance, + surface_tilt=self.tracking['surface_tilt'], + surface_azimuth=self.tracking['surface_azimuth'], + solar_zenith=self.solar_position['apparent_zenith'], + solar_azimuth=self.solar_position['azimuth']) + else: + get_irradiance = partial( + self.system.get_irradiance, + self.solar_position['apparent_zenith'], + self.solar_position['azimuth']) + + self.total_irrad = get_irradiance( self.irradiance['dni'], self.irradiance['ghi'], self.irradiance['dhi'], diff --git a/pvlib/test/test_modelchain.py b/pvlib/test/test_modelchain.py index 56d2aef89e..e590325113 100644 --- a/pvlib/test/test_modelchain.py +++ b/pvlib/test/test_modelchain.py @@ -1,9 +1,11 @@ import numpy as np import pandas as pd +from numpy import nan from pvlib import modelchain, pvsystem from pvlib.modelchain import ModelChain from pvlib.pvsystem import PVSystem +from pvlib.tracking import SingleAxisTracker from pvlib.location import Location from pandas.util.testing import assert_series_equal, assert_frame_equal @@ -100,6 +102,26 @@ def test_run_model_with_weather(): assert_series_equal(ac, expected) +def test_run_model_tracker(): + system, location = mc_setup() + system = SingleAxisTracker(module_parameters=system.module_parameters, + inverter_parameters=system.inverter_parameters) + mc = ModelChain(system, location) + times = pd.date_range('20160101 1200-0700', periods=2, freq='6H') + ac = mc.run_model(times).ac + + expected = pd.Series(np.array([ 121.421719, -2.00000000e-02]), + index=times) + assert_series_equal(ac, expected) + + expected = pd.DataFrame(np. + array([[ 54.82513187, 90. , 11.0039221 , 11.0039221 ], + [ nan, 0. , 0. , nan]]), + columns=['aoi', 'surface_azimuth', 'surface_tilt', 'tracker_theta'], + index=times) + assert_frame_equal(mc.tracking, expected) + + @raises(ValueError) def test_bad_get_orientation(): modelchain.get_orientation('bad value')