From 9f97e508637bd439fd269b04d82b88208e90af47 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 1 Sep 2016 11:44:56 +0200 Subject: [PATCH 01/35] try to use weather DataFrame for irradiance if irradiance DataFrame is None --- pvlib/modelchain.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 47b6b30992..2948235f7b 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -637,12 +637,16 @@ def prepare_inputs(self, times, irradiance=None, weather=None): self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'], self.solar_position['azimuth']) - if irradiance is None: - irradiance = self.location.get_clearsky( + if irradiance: + self.irradiance = irradiance + else: + self.irradiance = weather + + if not self.irradiance: + self.irradiance = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, zenith_data=self.solar_position['apparent_zenith'], airmass_data=self.airmass['airmass_absolute']) - self.irradiance = irradiance # PVSystem.get_irradiance and SingleAxisTracker.get_irradiance # have different method signatures, so use partial to handle From d99ee1852444dfd94a5dca31c5ae90a7ecb2633f Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 1 Sep 2016 11:47:00 +0200 Subject: [PATCH 02/35] try to determine missing columns of the irradiance DataFrame --- pvlib/modelchain.py | 55 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 2948235f7b..dcfd315493 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -10,7 +10,8 @@ import pandas as pd -from pvlib import solarposition, pvsystem, clearsky, atmosphere +from pvlib import (solarposition, pvsystem, clearsky, atmosphere, tools, + irradiance) from pvlib.tracking import SingleAxisTracker import pvlib.irradiance # avoid name conflict with full import @@ -602,7 +603,54 @@ def effective_irradiance_model(self): fd*self.total_irrad['poa_diffuse']) return self - def prepare_inputs(self, times, irradiance=None, weather=None): + def prepare_irradiance(self, dni_determination_method='dirint'): + """ + + Parameters + ---------- + dni_determination_method : string + something.... + + Returns + ------- + + """ + if tools.check_df(self.irradiance, ['ghi'], not_exist=['dhi', 'dni']): + if dni_determination_method == 'dirint': + return_value = irradiance.dirint(self.irradiance.ghi, + self.solar_position.zenith, + self.times) + self.irradiance['dhi'] = return_value + elif dni_determination_method == 'disc': + return_value = irradiance.disc(self.irradiance.ghi, + self.solar_position.zenith, + self.times) + self.irradiance['dni'] = return_value.dni + elif dni_determination_method == 'erbs': + return_value = irradiance.erbs(self.irradiance.ghi, + self.solar_position.zenith, + self.times) + self.irradiance['dni'] = return_value.dni + self.irradiance['dhi'] = return_value.dhi + + + if tools.check_df(self.irradiance, ['ghi', 'dhi'], not_exist=['dni']): + self.irradiance['dni'] = ((self.irradiance.ghi - + self.irradiance.dhi) / + tools.cosd(self.solar_position.zenith)) + + elif tools.check_df(self.irradiance, ['dni', 'dhi'], not_exist=['ghi']): + self.irradiance['ghi'] = (self.irradiance.dni * + tools.cosd(self.solar_position.zenith) + + self.irradiance.dhi) + elif tools.check_df(self.irradiance, ['dni', 'ghi'], not_exist=['dhi']): + self.irradiance['dhi'] = (self.irradiance.ghi - + self.irradiance.dni * + tools.cosd(self.solar_position.zenith)) + else: + self.irradiance = None + + def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): """ Prepare the solar position, irradiance, and weather inputs to the model. @@ -642,6 +690,9 @@ def prepare_inputs(self, times, irradiance=None, weather=None): else: self.irradiance = weather + if self.irradiance: + self.prepare_irradiance(**kwargs) + if not self.irradiance: self.irradiance = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, From 0c831996b71ad2bea23493c86f90e27e72a13ddc Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:54:06 +0200 Subject: [PATCH 03/35] remove prepare_irradiance call from run_model --- pvlib/modelchain.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index dcfd315493..ae90f09d27 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -685,14 +685,6 @@ def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'], self.solar_position['azimuth']) - if irradiance: - self.irradiance = irradiance - else: - self.irradiance = weather - - if self.irradiance: - self.prepare_irradiance(**kwargs) - if not self.irradiance: self.irradiance = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, From 9ffa138a7842eae331aff1daafa14b2db7368f98 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:56:57 +0200 Subject: [PATCH 04/35] replace irradiance DF with weather DF without breaking the API --- pvlib/modelchain.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index ae90f09d27..e1658827df 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -7,7 +7,7 @@ """ from functools import partial - +import warnings import pandas as pd from pvlib import (solarposition, pvsystem, clearsky, atmosphere, tools, @@ -317,6 +317,8 @@ def __init__(self, system, location, self.losses_model = losses_model self.orientation_strategy = orientation_strategy + self.weather = pd.DataFrame() + def __repr__(self): return ('ModelChain for: ' + str(self.system) + ' orientation_startegy: ' + str(self.orientation_strategy) + @@ -650,7 +652,7 @@ def prepare_irradiance(self, dni_determination_method='dirint'): else: self.irradiance = None - def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): + def prepare_inputs(self, times, irradiance=None, weather=None): """ Prepare the solar position, irradiance, and weather inputs to the model. @@ -674,6 +676,19 @@ def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): Assigns attributes: times, solar_position, airmass, irradiance, total_irrad, weather, aoi """ + # The following part could be removed together with the irradiance + # parameter at version v0.5 or v0.6. + # **** Begin **** + if irradiance is not None: + for column in irradiance.columns: + weather[column] = irradiance.pop(column) + # **** End **** + + # Add columns that does not exist and overwrite existing columns + # Maybe there is a more elegant way to do this. Any ideas? + if weather is not None: + self.weather = self.weather.combine_first(weather) + self.weather.update(weather) self.times = times @@ -685,8 +700,9 @@ def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'], self.solar_position['azimuth']) - if not self.irradiance: - self.irradiance = self.location.get_clearsky( + if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): + print('any is True') + self.weather[['ghi', 'dni', 'dhi']] = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, zenith_data=self.solar_position['apparent_zenith'], airmass_data=self.airmass['airmass_absolute']) @@ -717,16 +733,16 @@ def prepare_inputs(self, times, irradiance=None, weather=None, **kwargs): self.solar_position['azimuth']) self.total_irrad = get_irradiance( - self.irradiance['dni'], - self.irradiance['ghi'], - self.irradiance['dhi'], + self.weather['dni'], + self.weather['ghi'], + self.weather['dhi'], airmass=self.airmass['airmass_relative'], model=self.transposition_model) - if weather is None: - weather = {'wind_speed': 0, 'temp_air': 20} - self.weather = weather - + if self.weather.get('wind_speed') is None: + self.weather['wind_speed'] = 0 + if self.weather.get('temp_air') is None: + self.weather['temp_air'] = 20 return self def run_model(self, times, irradiance=None, weather=None): From 2aae90cc09a41dd93949f4f51f0c3c51f49bd3e4 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:57:22 +0200 Subject: [PATCH 05/35] add future warning --- pvlib/modelchain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index e1658827df..cc0290cba0 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -679,7 +679,11 @@ def prepare_inputs(self, times, irradiance=None, weather=None): # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. # **** Begin **** + wrn_txt = "The irradiance parameter will be removed soon." + wrn_txt += "Please use the weather parameter to pass a DataFrame with " + wrn_txt += "irradiance (ghi, dni, dhi), wind speed and temp_air" if irradiance is not None: + warnings.warn(wrn_txt, FutureWarning) for column in irradiance.columns: weather[column] = irradiance.pop(column) # **** End **** From 326dc11dfbeaf401e6586ebd6ae50e4b969e5cc6 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:57:50 +0200 Subject: [PATCH 06/35] add error if irradiation data is incomplete --- pvlib/modelchain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index cc0290cba0..44042839c8 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -711,6 +711,10 @@ def prepare_inputs(self, times, irradiance=None, weather=None): zenith_data=self.solar_position['apparent_zenith'], airmass_data=self.airmass['airmass_absolute']) + if not {'ghi', 'dni', 'dhi'} <= set(self.weather.columns): + ValueError( + "Uncompleted irradiance data set. Please check you input data") + # PVSystem.get_irradiance and SingleAxisTracker.get_irradiance # have different method signatures, so use partial to handle # the differences. From f1e17eecc511be428ab2abfb6b9cd234a3088a39 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:58:38 +0200 Subject: [PATCH 07/35] rename method --- pvlib/modelchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 44042839c8..71dde89721 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -605,7 +605,7 @@ def effective_irradiance_model(self): fd*self.total_irrad['poa_diffuse']) return self - def prepare_irradiance(self, dni_determination_method='dirint'): + def complete_irradiance(self, dni_determination_method='dirint'): """ Parameters From 933e57b67e4c8dfa5335f02b34bffd35b8df65ac Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 13:59:31 +0200 Subject: [PATCH 08/35] replace non existing function with set set comparison --- pvlib/modelchain.py | 48 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 71dde89721..ad8fcba357 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -617,40 +617,38 @@ def complete_irradiance(self, dni_determination_method='dirint'): ------- """ - if tools.check_df(self.irradiance, ['ghi'], not_exist=['dhi', 'dni']): + icolumns = self.weather.columns + + if {'ghi'} <= icolumns and not {'dhi', 'dni'} <= icolumns: if dni_determination_method == 'dirint': - return_value = irradiance.dirint(self.irradiance.ghi, + return_value = irradiance.dirint(self.weather.ghi, self.solar_position.zenith, self.times) - self.irradiance['dhi'] = return_value + self.weather['dhi'] = return_value elif dni_determination_method == 'disc': - return_value = irradiance.disc(self.irradiance.ghi, + return_value = irradiance.disc(self.weather.ghi, self.solar_position.zenith, self.times) - self.irradiance['dni'] = return_value.dni + self.weather['dni'] = return_value.dni elif dni_determination_method == 'erbs': - return_value = irradiance.erbs(self.irradiance.ghi, + return_value = irradiance.erbs(self.weather.ghi, self.solar_position.zenith, self.times) - self.irradiance['dni'] = return_value.dni - self.irradiance['dhi'] = return_value.dhi - - - if tools.check_df(self.irradiance, ['ghi', 'dhi'], not_exist=['dni']): - self.irradiance['dni'] = ((self.irradiance.ghi - - self.irradiance.dhi) / - tools.cosd(self.solar_position.zenith)) - - elif tools.check_df(self.irradiance, ['dni', 'dhi'], not_exist=['ghi']): - self.irradiance['ghi'] = (self.irradiance.dni * - tools.cosd(self.solar_position.zenith) + - self.irradiance.dhi) - elif tools.check_df(self.irradiance, ['dni', 'ghi'], not_exist=['dhi']): - self.irradiance['dhi'] = (self.irradiance.ghi - - self.irradiance.dni * - tools.cosd(self.solar_position.zenith)) - else: - self.irradiance = None + self.weather['dni'] = return_value.dni + self.weather['dhi'] = return_value.dhi + + if {'ghi', 'dhi'} <= icolumns and not {'dni'} <= icolumns: + self.weather['dni'] = ((self.weather.ghi - + self.weather.dhi) / + tools.cosd(self.solar_position.zenith)) + elif {'dni', 'dhi'} <= icolumns and not {'ghi'} <= icolumns: + self.weather['ghi'] = (self.weather.dni * + tools.cosd(self.solar_position.zenith) + + self.weather.dhi) + elif {'dni', 'ghi'} <= icolumns and not {'dhi'} <= icolumns: + self.weather['dhi'] = (self.weather.ghi - + self.weather.dni * + tools.cosd(self.solar_position.zenith)) def prepare_inputs(self, times, irradiance=None, weather=None): """ From 00e0e7209359ec9ca7dea68f059ec4e5eb7738ee Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 14:54:45 +0200 Subject: [PATCH 09/35] fix assigned attributes in the docstring --- pvlib/modelchain.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index ad8fcba357..dde70c5930 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -671,8 +671,7 @@ def prepare_inputs(self, times, irradiance=None, weather=None): ------- self - Assigns attributes: times, solar_position, airmass, irradiance, - total_irrad, weather, aoi + Assigns attributes: times, solar_position, airmass, total_irrad, aoi """ # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. From 0abdde4e20898fd3d5c812735f51cc79fbd8ed92 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 14:56:27 +0200 Subject: [PATCH 10/35] fix self.weather assignment --- pvlib/modelchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index dde70c5930..65e9eb1145 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -682,7 +682,7 @@ def prepare_inputs(self, times, irradiance=None, weather=None): if irradiance is not None: warnings.warn(wrn_txt, FutureWarning) for column in irradiance.columns: - weather[column] = irradiance.pop(column) + self.weather[column] = irradiance.pop(column) # **** End **** # Add columns that does not exist and overwrite existing columns From ec5ed5f6c269e156bc9dd5ac3309b47047ecac33 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 8 Sep 2016 14:56:36 +0200 Subject: [PATCH 11/35] fix layout --- pvlib/modelchain.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 65e9eb1145..2559b5b9a5 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -676,7 +676,7 @@ def prepare_inputs(self, times, irradiance=None, weather=None): # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. # **** Begin **** - wrn_txt = "The irradiance parameter will be removed soon." + wrn_txt = "The irradiance parameter will be removed soon.\n" wrn_txt += "Please use the weather parameter to pass a DataFrame with " wrn_txt += "irradiance (ghi, dni, dhi), wind speed and temp_air" if irradiance is not None: @@ -702,7 +702,6 @@ def prepare_inputs(self, times, irradiance=None, weather=None): self.solar_position['azimuth']) if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): - print('any is True') self.weather[['ghi', 'dni', 'dhi']] = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, zenith_data=self.solar_position['apparent_zenith'], From 4d8feaf121704189219fffec1a5589b76905dec8 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:07:09 +0200 Subject: [PATCH 12/35] change existing tests to new API --- pvlib/test/test_modelchain.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/test/test_modelchain.py b/pvlib/test/test_modelchain.py index 1d05e1a5ee..1cc7f3f60b 100644 --- a/pvlib/test/test_modelchain.py +++ b/pvlib/test/test_modelchain.py @@ -102,7 +102,7 @@ def test_run_model_with_irradiance(system, location): times = pd.date_range('20160101 1200-0700', periods=2, freq='6H') irradiance = pd.DataFrame({'dni':900, 'ghi':600, 'dhi':150}, index=times) - ac = mc.run_model(times, irradiance=irradiance).ac + ac = mc.run_model(times, weather=irradiance).ac expected = pd.Series(np.array([ 1.90054749e+02, -2.00000000e-02]), index=times) @@ -114,7 +114,7 @@ def test_run_model_perez(system, location): times = pd.date_range('20160101 1200-0700', periods=2, freq='6H') irradiance = pd.DataFrame({'dni':900, 'ghi':600, 'dhi':150}, index=times) - ac = mc.run_model(times, irradiance=irradiance).ac + ac = mc.run_model(times, weather=irradiance).ac expected = pd.Series(np.array([ 190.194545796, -2.00000000e-02]), index=times) @@ -127,7 +127,7 @@ def test_run_model_gueymard_perez(system, location): times = pd.date_range('20160101 1200-0700', periods=2, freq='6H') irradiance = pd.DataFrame({'dni':900, 'ghi':600, 'dhi':150}, index=times) - ac = mc.run_model(times, irradiance=irradiance).ac + ac = mc.run_model(times, weather=irradiance).ac expected = pd.Series(np.array([ 190.194760203, -2.00000000e-02]), index=times) From c572a075d88e7a4d3fad4e6e6decbf266a54977e Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:07:52 +0200 Subject: [PATCH 13/35] add new tests --- pvlib/test/test_modelchain.py | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pvlib/test/test_modelchain.py b/pvlib/test/test_modelchain.py index 1cc7f3f60b..9d7ad8428b 100644 --- a/pvlib/test/test_modelchain.py +++ b/pvlib/test/test_modelchain.py @@ -415,3 +415,60 @@ def test_ModelChain___repr__(system, location): 'orientation_startegy: south_at_latitude_tilt clearsky_model: '+ 'ineichen transposition_model: haydavies solar_position_method: '+ 'nrel_numpy airmass_model: kastenyoung1989') + + +@requires_scipy +def test_weather_irradiance_input(system, location): + """Test will raise a warning and should be removed in future versions.""" + mc = ModelChain(system, location) + times = pd.date_range('2012-06-01 12:00:00', periods=2, freq='H') + i = pd.DataFrame({'dni': [2, 3], 'dhi': [4, 6], 'ghi': [9, 5]}, index=times) + w = pd.DataFrame({'wind_speed': [11, 5], 'temp_air': [30, 32]}, index=times) + mc.run_model(times, irradiance=i, weather=w) + + assert_series_equal(mc.weather['dni'], + pd.Series([2, 3], index=times, name='dni')) + assert_series_equal(mc.weather['wind_speed'], + pd.Series([11, 5], index=times, name='wind_speed')) + + +@requires_scipy +def test_complete_irradiance_clean_run(system, location): + """The DataFrame should not change if all columns are passed""" + mc = ModelChain(system, location) + times = pd.date_range('2010-07-05 9:00:00', periods=2, freq='H') + i = pd.DataFrame({'dni': [2, 3], 'dhi': [4, 6], 'ghi': [9, 5]}, index=times) + + mc.complete_irradiance(times, weather=i) + + assert_series_equal(mc.weather['dni'], + pd.Series([2, 3], index=times, name='dni')) + assert_series_equal(mc.weather['dhi'], + pd.Series([4, 6], index=times, name='dhi')) + assert_series_equal(mc.weather['ghi'], + pd.Series([9, 5], index=times, name='ghi')) + + +@requires_scipy +def test_complete_irradiance(system, location): + """Check calculations""" + mc = ModelChain(system, location) + times = pd.date_range('2010-07-05 9:00:00', periods=2, freq='H') + i = pd.DataFrame({'dni': [30.354455, 77.22822], + 'dhi': [372.103976116, 497.087579068], + 'ghi': [356.543700, 465.44400]}, index=times) + + mc.complete_irradiance(times, weather=i[['ghi', 'dni']]) + assert_series_equal(mc.weather['dhi'], + pd.Series([372.103976116, 497.087579068], + index=times, name='dhi')) + + mc.complete_irradiance(times, weather=i[['dhi', 'dni']]) + assert_series_equal(mc.weather['ghi'], + pd.Series([356.543700, 465.44400], + index=times, name='ghi')) + + mc.complete_irradiance(times, weather=i[['dhi', 'ghi']]) + assert_series_equal(mc.weather['dni'], + pd.Series([30.354455, 77.22822], + index=times, name='dni')) From 9dac5cf46f7a72667deda336b71d67a9d87ec64b Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:11:01 +0200 Subject: [PATCH 14/35] add columns or update columns of existing weather data --- pvlib/modelchain.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 2559b5b9a5..75f5bf52e6 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -673,6 +673,12 @@ def prepare_inputs(self, times, irradiance=None, weather=None): Assigns attributes: times, solar_position, airmass, total_irrad, aoi """ + # Add columns that does not exist and overwrite existing columns + # Maybe there is a more elegant way to do this. Any ideas? + if weather is not None: + self.weather = self.weather.combine_first(weather) + self.weather.update(weather) + # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. # **** Begin **** From 7fda2181a2fd632dfb8a5b2f836f3aecc8be7a78 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:14:48 +0200 Subject: [PATCH 15/35] add attributes to class --- pvlib/modelchain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 75f5bf52e6..43fbd1b176 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -318,6 +318,8 @@ def __init__(self, system, location, self.orientation_strategy = orientation_strategy self.weather = pd.DataFrame() + self.times = None + self.solar_position = None def __repr__(self): return ('ModelChain for: ' + str(self.system) + From 7e0b6267abf4cad853622daa684aefd8a8adf3b0 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:17:49 +0200 Subject: [PATCH 16/35] adapt docstrings --- pvlib/modelchain.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 43fbd1b176..e197b300e6 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -660,14 +660,16 @@ def prepare_inputs(self, times, irradiance=None, weather=None): Parameters ---------- times : DatetimeIndex - Times at which to evaluate the model. - irradiance : None or DataFrame - If None, calculates clear sky data. - Columns must be 'dni', 'ghi', 'dhi'. + Times at which to evaluate the model. Can be None if attribute + `times` is already set. weather : None or DataFrame - If None, assumes air temperature is 20 C and - wind speed is 0 m/s. - Columns must be 'wind_speed', 'temp_air'. + If None, assumes air temperature is 20 C, wind speed is 0 m/s and + irradiation calculated from clear sky data. + Column names must be 'wind_speed', 'temp_air', 'dni', 'ghi', 'dhi'. + Do not pass incomplete irradiation data. + Use method + :py:meth:`~pvlib.modelchain.ModelChain.complete_irradiance` + instead. Returns ------- @@ -765,15 +767,14 @@ def run_model(self, times, irradiance=None, weather=None): ---------- times : DatetimeIndex Times at which to evaluate the model. - - irradiance : None or DataFrame - If None, calculates clear sky data. - Columns must be 'dni', 'ghi', 'dhi'. - weather : None or DataFrame - If None, assumes air temperature is 20 C and - wind speed is 0 m/s. - Columns must be 'wind_speed', 'temp_air'. + If None, assumes air temperature is 20 C, wind speed is 0 m/s and + irradiation calculated from clear sky data. + Column names must be 'wind_speed', 'temp_air', 'dni', 'ghi', 'dhi'. + Do not pass incomplete irradiation data. + Use method + :py:meth:`~pvlib.modelchain.ModelChain.complete_irradiance` + instead. Returns ------- From 300678c459526b9e65a3d86702ad9df5a2747851 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:19:14 +0200 Subject: [PATCH 17/35] make time an optional argument if self.times is already set --- pvlib/modelchain.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index e197b300e6..a91e4997d4 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -652,7 +652,7 @@ def complete_irradiance(self, dni_determination_method='dirint'): self.weather.dni * tools.cosd(self.solar_position.zenith)) - def prepare_inputs(self, times, irradiance=None, weather=None): + def prepare_inputs(self, times=None, irradiance=None, weather=None): """ Prepare the solar position, irradiance, and weather inputs to the model. @@ -695,13 +695,8 @@ def prepare_inputs(self, times, irradiance=None, weather=None): self.weather[column] = irradiance.pop(column) # **** End **** - # Add columns that does not exist and overwrite existing columns - # Maybe there is a more elegant way to do this. Any ideas? - if weather is not None: - self.weather = self.weather.combine_first(weather) - self.weather.update(weather) - - self.times = times + if times is not None: + self.times = times self.solar_position = self.location.get_solarposition(self.times) From c74f9774d11dcb6ff0b592140d39f96ee87e6cb4 Mon Sep 17 00:00:00 2001 From: uwe Date: Thu, 13 Oct 2016 20:20:32 +0200 Subject: [PATCH 18/35] complete temporary version (beta) of "complete_irradiance" --- pvlib/modelchain.py | 75 ++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index a91e4997d4..56b90929ca 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -7,6 +7,7 @@ """ from functools import partial +import logging import warnings import pandas as pd @@ -607,50 +608,54 @@ def effective_irradiance_model(self): fd*self.total_irrad['poa_diffuse']) return self - def complete_irradiance(self, dni_determination_method='dirint'): + def complete_irradiance(self, times, weather): """ + Determine the missing irradiation columns. Only two of the following + data columns (dni, ghi, dhi) are needed to calculate the missing data. + + This function is not save at the moment. Results can be too high or + negative. Please contribute and help to improve this function on + https://github.com/pvlib/pvlib-python Parameters ---------- - dni_determination_method : string - something.... + times : datetime index + Date and time index of the irradiation data + weather : pandas.DataFrame + Table with at least two columns containing one of the following data + sets: dni, dhi, ghi Returns ------- + pandas.DataFrame + Containing the missing column of the data sets passed with the + weather DataFrame. """ - icolumns = self.weather.columns - - if {'ghi'} <= icolumns and not {'dhi', 'dni'} <= icolumns: - if dni_determination_method == 'dirint': - return_value = irradiance.dirint(self.weather.ghi, - self.solar_position.zenith, - self.times) - self.weather['dhi'] = return_value - elif dni_determination_method == 'disc': - return_value = irradiance.disc(self.weather.ghi, - self.solar_position.zenith, - self.times) - self.weather['dni'] = return_value.dni - elif dni_determination_method == 'erbs': - return_value = irradiance.erbs(self.weather.ghi, - self.solar_position.zenith, - self.times) - self.weather['dni'] = return_value.dni - self.weather['dhi'] = return_value.dhi - - if {'ghi', 'dhi'} <= icolumns and not {'dni'} <= icolumns: - self.weather['dni'] = ((self.weather.ghi - - self.weather.dhi) / - tools.cosd(self.solar_position.zenith)) - elif {'dni', 'dhi'} <= icolumns and not {'ghi'} <= icolumns: - self.weather['ghi'] = (self.weather.dni * - tools.cosd(self.solar_position.zenith) + - self.weather.dhi) - elif {'dni', 'ghi'} <= icolumns and not {'dhi'} <= icolumns: - self.weather['dhi'] = (self.weather.ghi - - self.weather.dni * - tools.cosd(self.solar_position.zenith)) + self.weather = weather + self.times = times + self.solar_position = self.location.get_solarposition(self.times) + icolumns = set(self.weather.columns) + wrn_txt = "This function is not save at the moment.\n" + wrn_txt += "Results can be too high or negative.\n" + wrn_txt += "Help to improve this function on github." + wrn_txt += "https://github.com/pvlib/pvlib-python" + warnings.warn(wrn_txt, UserWarning) + if {'ghi', 'dhi'} <= icolumns and 'dni' not in icolumns: + logging.debug('Estimate dni from ghi and dhi') + self.weather.loc[:, 'dni'] = ( + (self.weather.loc[:, 'ghi'] - self.weather.loc[:, 'dhi']) / + tools.cosd(self.solar_position.loc[:, 'zenith'])) + elif {'dni', 'dhi'} <= icolumns and 'ghi' not in icolumns: + logging.debug('Estimate ghi from dni and dhi') + self.weather.loc[:, 'ghi'] = ( + self.weather.dni * tools.cosd(self.solar_position.zenith) + + self.weather.dhi) + elif {'dni', 'ghi'} <= icolumns and 'dhi' not in icolumns: + logging.debug('Estimate dhi from dni and ghi') + self.weather.loc[:, 'dhi'] = ( + self.weather.ghi - self.weather.dni * + tools.cosd(self.solar_position.zenith)) def prepare_inputs(self, times=None, irradiance=None, weather=None): """ From ef5520e2e5c2abfd3197adae8f1f8167282ea0c3 Mon Sep 17 00:00:00 2001 From: uwe Date: Fri, 14 Oct 2016 13:59:07 +0200 Subject: [PATCH 19/35] remove duplicate import --- pvlib/modelchain.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 56b90929ca..024d381dd9 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -11,8 +11,7 @@ import warnings import pandas as pd -from pvlib import (solarposition, pvsystem, clearsky, atmosphere, tools, - irradiance) +from pvlib import (solarposition, pvsystem, clearsky, atmosphere, tools) from pvlib.tracking import SingleAxisTracker import pvlib.irradiance # avoid name conflict with full import From dfe04b19311f5272e207842c176574a0c7eeef0b Mon Sep 17 00:00:00 2001 From: uwe Date: Fri, 14 Oct 2016 14:01:28 +0200 Subject: [PATCH 20/35] update docstring --- pvlib/modelchain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 024d381dd9..8f72429bd3 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -667,7 +667,8 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): Times at which to evaluate the model. Can be None if attribute `times` is already set. weather : None or DataFrame - If None, assumes air temperature is 20 C, wind speed is 0 m/s and + If None, the weather attribute is used. If the weather attribute is + also None assumes air temperature is 20 C, wind speed is 0 m/s and irradiation calculated from clear sky data. Column names must be 'wind_speed', 'temp_air', 'dni', 'ghi', 'dhi'. Do not pass incomplete irradiation data. From b691358b6d9e47cd7e45bdce62ebdc8edf216336 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:02:17 +0200 Subject: [PATCH 21/35] fix typo --- pvlib/modelchain.py | 2 +- pvlib/test/test_modelchain.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 8f72429bd3..aaddd39bd4 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -323,7 +323,7 @@ def __init__(self, system, location, def __repr__(self): return ('ModelChain for: ' + str(self.system) + - ' orientation_startegy: ' + str(self.orientation_strategy) + + ' orientation_strategy: ' + str(self.orientation_strategy) + ' clearsky_model: ' + str(self.clearsky_model) + ' transposition_model: ' + str(self.transposition_model) + ' solar_position_method: ' + str(self.solar_position_method) + diff --git a/pvlib/test/test_modelchain.py b/pvlib/test/test_modelchain.py index 9d7ad8428b..40fd7f32a8 100644 --- a/pvlib/test/test_modelchain.py +++ b/pvlib/test/test_modelchain.py @@ -412,7 +412,7 @@ def test_ModelChain___repr__(system, location): assert mc.__repr__() == ('ModelChain for: PVSystem with tilt:32.2 and '+ 'azimuth: 180 with Module: None and Inverter: None '+ - 'orientation_startegy: south_at_latitude_tilt clearsky_model: '+ + 'orientation_strategy: south_at_latitude_tilt clearsky_model: '+ 'ineichen transposition_model: haydavies solar_position_method: '+ 'nrel_numpy airmass_model: kastenyoung1989') From 5f8ce92b28a263f23018598993404c33ff4e1230 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:04:27 +0200 Subject: [PATCH 22/35] add deprecated parameter to docstring --- pvlib/modelchain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index aaddd39bd4..52ba45b9ce 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -666,6 +666,8 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): times : DatetimeIndex Times at which to evaluate the model. Can be None if attribute `times` is already set. + irradiance : None or DataFrame + This parameter is deprecated. Please use `weather` instead. weather : None or DataFrame If None, the weather attribute is used. If the weather attribute is also None assumes air temperature is 20 C, wind speed is 0 m/s and From 1bff19f3215a161d938e73e194a505b389827233 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:08:43 +0200 Subject: [PATCH 23/35] set default self.weather to None instead of empty DataFrame --- pvlib/modelchain.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 52ba45b9ce..d35196c2ad 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -317,7 +317,7 @@ def __init__(self, system, location, self.losses_model = losses_model self.orientation_strategy = orientation_strategy - self.weather = pd.DataFrame() + self.weather = None self.times = None self.solar_position = None @@ -687,8 +687,11 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): # Add columns that does not exist and overwrite existing columns # Maybe there is a more elegant way to do this. Any ideas? if weather is not None: - self.weather = self.weather.combine_first(weather) - self.weather.update(weather) + if self.weather is None: + self.weather = weather + else: + self.weather = self.weather.combine_first(weather) + self.weather.update(weather) # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. @@ -713,7 +716,15 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'], self.solar_position['azimuth']) - if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): + use_clearsky = False + if self.weather is None: + use_clearsky = True + self.weather = pd.DataFrame() + else: + if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): + use_clearsky = True + + if use_clearsky: self.weather[['ghi', 'dni', 'dhi']] = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, zenith_data=self.solar_position['apparent_zenith'], From 721743d972f442f2120f51aee6cf45ff47e31633 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:33:05 +0200 Subject: [PATCH 24/35] fix typos, layout changes --- pvlib/modelchain.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index d35196c2ad..e243373810 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -612,13 +612,13 @@ def complete_irradiance(self, times, weather): Determine the missing irradiation columns. Only two of the following data columns (dni, ghi, dhi) are needed to calculate the missing data. - This function is not save at the moment. Results can be too high or + This function is not safe at the moment. Results can be too high or negative. Please contribute and help to improve this function on https://github.com/pvlib/pvlib-python Parameters ---------- - times : datetime index + times : DatetimeIndex Date and time index of the irradiation data weather : pandas.DataFrame Table with at least two columns containing one of the following data @@ -629,16 +629,15 @@ def complete_irradiance(self, times, weather): pandas.DataFrame Containing the missing column of the data sets passed with the weather DataFrame. - """ self.weather = weather self.times = times self.solar_position = self.location.get_solarposition(self.times) icolumns = set(self.weather.columns) - wrn_txt = "This function is not save at the moment.\n" - wrn_txt += "Results can be too high or negative.\n" - wrn_txt += "Help to improve this function on github." - wrn_txt += "https://github.com/pvlib/pvlib-python" + wrn_txt = ("This function is not safe at the moment.\n" + + "Results can be too high or negative.\n" + + "Help to improve this function on github:\n" + + "https://github.com/pvlib/pvlib-python \n") warnings.warn(wrn_txt, UserWarning) if {'ghi', 'dhi'} <= icolumns and 'dni' not in icolumns: logging.debug('Estimate dni from ghi and dhi') @@ -696,9 +695,10 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. # **** Begin **** - wrn_txt = "The irradiance parameter will be removed soon.\n" - wrn_txt += "Please use the weather parameter to pass a DataFrame with " - wrn_txt += "irradiance (ghi, dni, dhi), wind speed and temp_air" + wrn_txt = ("The irradiance parameter will be removed soon.\n" + + "Please use the weather parameter to pass a DataFrame " + + "with irradiance (ghi, dni, dhi), wind speed and " + + "temp_air.\n") if irradiance is not None: warnings.warn(wrn_txt, FutureWarning) for column in irradiance.columns: From 6a1a61dfd2bbf7179571131c2b126fea5c080257 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:34:51 +0200 Subject: [PATCH 25/35] avoid mutation of input data (irradiance) --- pvlib/modelchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index e243373810..53e24a3b53 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -702,7 +702,7 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): if irradiance is not None: warnings.warn(wrn_txt, FutureWarning) for column in irradiance.columns: - self.weather[column] = irradiance.pop(column) + self.weather[column] = irradiance[column] # **** End **** if times is not None: From f702c73ef4ddadf6e19ac683861030f4a3987060 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:36:33 +0200 Subject: [PATCH 26/35] overwrite self.weather completly with its parameter instead of column-wise --- pvlib/modelchain.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 53e24a3b53..df6dc5474d 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -686,11 +686,7 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): # Add columns that does not exist and overwrite existing columns # Maybe there is a more elegant way to do this. Any ideas? if weather is not None: - if self.weather is None: - self.weather = weather - else: - self.weather = self.weather.combine_first(weather) - self.weather.update(weather) + self.weather = weather # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. From 82a43663212cd211f4cd6587f38e827df7d8b14e Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:46:09 +0200 Subject: [PATCH 27/35] add more IDE config files to gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a8304db0b7..658fe2d026 100644 --- a/.gitignore +++ b/.gitignore @@ -52,10 +52,12 @@ coverage.xml # Translations *.mo -# Mr Developer +# IDE's (Mr Developer, pydev, pycharm...) .mr.developer.cfg .project .pydevproject +.spyderproject +.idea/ # Rope .ropeproject From 34166c883601fcef29751529472c0a58ca6ddcc4 Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 11:58:30 +0200 Subject: [PATCH 28/35] add whatsnew entry --- docs/sphinx/source/whatsnew.rst | 1 + docs/sphinx/source/whatsnew/v0.4.2.txt | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 docs/sphinx/source/whatsnew/v0.4.2.txt diff --git a/docs/sphinx/source/whatsnew.rst b/docs/sphinx/source/whatsnew.rst index e2439657bb..9b69bd4303 100644 --- a/docs/sphinx/source/whatsnew.rst +++ b/docs/sphinx/source/whatsnew.rst @@ -6,6 +6,7 @@ What's New These are new features and improvements of note in each release. +.. include:: whatsnew/v0.4.2.txt .. include:: whatsnew/v0.4.1.txt .. include:: whatsnew/v0.4.0.txt .. include:: whatsnew/v0.3.3.txt diff --git a/docs/sphinx/source/whatsnew/v0.4.2.txt b/docs/sphinx/source/whatsnew/v0.4.2.txt new file mode 100644 index 0000000000..26f3895176 --- /dev/null +++ b/docs/sphinx/source/whatsnew/v0.4.2.txt @@ -0,0 +1,24 @@ +.. _whatsnew_0420: + +v0.4.2 () +------------------------ + +This is a minor release from 0.4.0. .... + + +API Changes +~~~~~~~~~~~ + +* The run_model method of the ModelChain will use the weather parameter of all weather data instead of splitting it to irradiation and weather. The irradiation parameter still works but will be removed soon.(:issue:`239`) + + +Enhancements +~~~~~~~~~~~~ + +* Adding a complete_irradiance method to the ModelChain to make it possible to calculate missing irradiation data from the existing columns [beta] (:issue:`239`) + + +Code Contributors +~~~~~~~~~~~~~~~~~ + +* Uwe Krien From 9ff9fe426e8568ebcb0f99f25466b8c3e7b44a9b Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 15:46:09 +0200 Subject: [PATCH 29/35] copy doctstring changes to run_model method --- pvlib/modelchain.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index df6dc5474d..34fb2155f9 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -768,14 +768,17 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): self.weather['temp_air'] = 20 return self - def run_model(self, times, irradiance=None, weather=None): + def run_model(self, times=None, irradiance=None, weather=None): """ Run the model. Parameters ---------- times : DatetimeIndex - Times at which to evaluate the model. + Times at which to evaluate the model. Can be None if attribute + `times` is already set. + irradiance : None or DataFrame + This parameter is deprecated. Please use `weather` instead. weather : None or DataFrame If None, assumes air temperature is 20 C, wind speed is 0 m/s and irradiation calculated from clear sky data. From 76d89c365940dca29e509b3cdf3d5fd01634672f Mon Sep 17 00:00:00 2001 From: Uwe Krien Date: Mon, 17 Oct 2016 16:22:33 +0200 Subject: [PATCH 30/35] make parameters optional if attributes are already set --- pvlib/modelchain.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 34fb2155f9..b69b71f67b 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -607,7 +607,7 @@ def effective_irradiance_model(self): fd*self.total_irrad['poa_diffuse']) return self - def complete_irradiance(self, times, weather): + def complete_irradiance(self, times=None, weather=None): """ Determine the missing irradiation columns. Only two of the following data columns (dni, ghi, dhi) are needed to calculate the missing data. @@ -619,10 +619,12 @@ def complete_irradiance(self, times, weather): Parameters ---------- times : DatetimeIndex - Date and time index of the irradiation data + Times at which to evaluate the model. Can be None if attribute + `times` is already set. weather : pandas.DataFrame Table with at least two columns containing one of the following data - sets: dni, dhi, ghi + sets: dni, dhi, ghi. Can be None if attribute `weather` is already + set. Returns ------- @@ -630,8 +632,10 @@ def complete_irradiance(self, times, weather): Containing the missing column of the data sets passed with the weather DataFrame. """ - self.weather = weather - self.times = times + if weather is not None: + self.weather = weather + if times is not None: + self.times = times self.solar_position = self.location.get_solarposition(self.times) icolumns = set(self.weather.columns) wrn_txt = ("This function is not safe at the moment.\n" + From a63a48fc76c7ff5708b487382a0fdf1e50720d0b Mon Sep 17 00:00:00 2001 From: uwe Date: Tue, 18 Oct 2016 10:39:49 +0200 Subject: [PATCH 31/35] add example to docstring (not working and excluded from doctest) --- pvlib/modelchain.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index b69b71f67b..d0406ab3d7 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -631,6 +631,22 @@ def complete_irradiance(self, times=None, weather=None): pandas.DataFrame Containing the missing column of the data sets passed with the weather DataFrame. + Examples + -------- + This example does not work until the parameters `my_system`, + `my_location`, `my_datetime` and `my_weather` are not defined properly + but shows the basic idea how this method can be used. + + >>> from pvlib.modelchain import ModelChain + + >>> # my_weather containing 'dhi' and 'ghi'. + >>> mc = ModelChain(my_system, my_location) # doctest: +SKIP + >>> mc.complete_irradiance(my_datetime, my_weather) # doctest: +SKIP + >>> mc.run_model() # doctest: +SKIP + + >>> # my_weather containing 'dhi', 'ghi' and 'dni'. + >>> mc = ModelChain(my_system, my_location) # doctest: +SKIP + >>> mc.run_model(my_datetime, my_weather) # doctest: +SKIP """ if weather is not None: self.weather = weather From 6097d753ee00415343ec6ef6d6d3a620de77b53f Mon Sep 17 00:00:00 2001 From: uwe Date: Tue, 18 Oct 2016 10:40:23 +0200 Subject: [PATCH 32/35] return self and describe it in the docstring --- pvlib/modelchain.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index d0406ab3d7..9f1514ca64 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -628,9 +628,10 @@ def complete_irradiance(self, times=None, weather=None): Returns ------- - pandas.DataFrame - Containing the missing column of the data sets passed with the - weather DataFrame. + self + + Assigns attributes: times, weather + Examples -------- This example does not work until the parameters `my_system`, @@ -675,6 +676,8 @@ def complete_irradiance(self, times=None, weather=None): self.weather.ghi - self.weather.dni * tools.cosd(self.solar_position.zenith)) + return self + def prepare_inputs(self, times=None, irradiance=None, weather=None): """ Prepare the solar position, irradiance, and weather inputs to From da8076dfd0c01b3191bc1c5355a6c6f16b9d393c Mon Sep 17 00:00:00 2001 From: uwe Date: Tue, 18 Oct 2016 10:45:54 +0200 Subject: [PATCH 33/35] add bug fix to whatsnew --- docs/sphinx/source/whatsnew/v0.4.2.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.4.2.txt b/docs/sphinx/source/whatsnew/v0.4.2.txt index 26f3895176..9569a42db8 100644 --- a/docs/sphinx/source/whatsnew/v0.4.2.txt +++ b/docs/sphinx/source/whatsnew/v0.4.2.txt @@ -6,6 +6,12 @@ v0.4.2 () This is a minor release from 0.4.0. .... +Bug fixes +~~~~~~~~~ + +* Fixed typo in __repr__ method of ModelChain and in its regarding test. (commit: b691358b) + + API Changes ~~~~~~~~~~~ From d4ff3647c4fa4d3fd3f2b5b7512741fe18f5d1b3 Mon Sep 17 00:00:00 2001 From: uwe Date: Tue, 18 Oct 2016 11:07:37 +0200 Subject: [PATCH 34/35] add empty DataFrame directly to avoid if clauses --- pvlib/modelchain.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 9f1514ca64..fdde4f06fd 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -706,10 +706,10 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): Assigns attributes: times, solar_position, airmass, total_irrad, aoi """ - # Add columns that does not exist and overwrite existing columns - # Maybe there is a more elegant way to do this. Any ideas? if weather is not None: self.weather = weather + if self.weather is None: + self.weather = pd.DataFrame() # The following part could be removed together with the irradiance # parameter at version v0.5 or v0.6. @@ -735,15 +735,7 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'], self.solar_position['azimuth']) - use_clearsky = False - if self.weather is None: - use_clearsky = True - self.weather = pd.DataFrame() - else: - if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): - use_clearsky = True - - if use_clearsky: + if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]): self.weather[['ghi', 'dni', 'dhi']] = self.location.get_clearsky( self.solar_position.index, self.clearsky_model, zenith_data=self.solar_position['apparent_zenith'], From bfb23505a498f916b77921e0c30267a6bcc79b9e Mon Sep 17 00:00:00 2001 From: uwe Date: Tue, 18 Oct 2016 11:08:04 +0200 Subject: [PATCH 35/35] make error message clearer --- pvlib/modelchain.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index fdde4f06fd..e3625c3651 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -742,8 +742,10 @@ def prepare_inputs(self, times=None, irradiance=None, weather=None): airmass_data=self.airmass['airmass_absolute']) if not {'ghi', 'dni', 'dhi'} <= set(self.weather.columns): - ValueError( - "Uncompleted irradiance data set. Please check you input data") + raise ValueError( + "Uncompleted irradiance data set. Please check you input " + + "data.\nData set needs to have 'dni', 'dhi' and 'ghi'.\n" + + "Detected data: {0}".format(list(self.weather.columns))) # PVSystem.get_irradiance and SingleAxisTracker.get_irradiance # have different method signatures, so use partial to handle