From 036511705daf72d72c25bd5a19d0e04804e180ed Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:18:06 -0700 Subject: [PATCH 01/13] remove unused pvsyst_celltemp parameter docs --- pvlib/pvsystem.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index d9a24b9b52..49054013c7 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -600,13 +600,6 @@ def pvsyst_celltemp(self, poa_global, temp_air, wind_speed=1.0): loss factor was determined. The default value is 1.0, which is the wind speed at module height used to determine NOCT. - eta_m : numeric, default 0.1 - Module external efficiency as a fraction, i.e., - DC power / poa_global. - - alpha_absorption : numeric, default 0.9 - Absorption coefficient - Returns ------- numeric, values in degrees C. From 857e63cb04aa033c2f0657d08ec8c6a9b77ea806 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:24:36 -0700 Subject: [PATCH 02/13] fix up temperature.faiman docstring formatting --- pvlib/temperature.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pvlib/temperature.py b/pvlib/temperature.py index fed5cdca89..6aceba1532 100644 --- a/pvlib/temperature.py +++ b/pvlib/temperature.py @@ -274,8 +274,8 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0, def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84): ''' Calculate cell or module temperature using an empirical heat loss factor - model as proposed by Faiman [1] and adopted in the IEC 61853 - standards [2] and [3]. + model as proposed by Faiman [1]_ and adopted in the IEC 61853 + standards [2]_ and [3]_. Usage of this model in the IEC 61853 standard does not distinguish between cell and module temperature. @@ -312,15 +312,15 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84): References ---------- - [1] Faiman, D. (2008). "Assessing the outdoor operating temperature of - photovoltaic modules." Progress in Photovoltaics 16(4): 307-315. + .. [1] Faiman, D. (2008). "Assessing the outdoor operating temperature of + photovoltaic modules." Progress in Photovoltaics 16(4): 307-315. - [2] "IEC 61853-2 Photovoltaic (PV) module performance testing and energy - rating - Part 2: Spectral responsivity, incidence angle and module - operating temperature measurements". IEC, Geneva, 2018. + .. [2] "IEC 61853-2 Photovoltaic (PV) module performance testing and energy + rating - Part 2: Spectral responsivity, incidence angle and module + operating temperature measurements". IEC, Geneva, 2018. - [3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy - rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018. + .. [3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy + rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018. ''' # Contributed by Anton Driesse (@adriesse), PV Performance Labs. Dec., 2019 From 88e76459a1ac12d9433e6bdf75b2b28ff272507d Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:36:06 -0700 Subject: [PATCH 03/13] add pvsystem.PVSystem.faiman_celltemp --- pvlib/pvsystem.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 49054013c7..59260c0da8 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -611,6 +611,32 @@ def pvsyst_celltemp(self, poa_global, temp_air, wind_speed=1.0): return temperature.pvsyst_cell(poa_global, temp_air, wind_speed, **kwargs) + def faiman_celltemp(self, poa_global, temp_air, wind_speed=1.0): + """ + Use :py:func:`temperature.faiman` to calculate cell temperature. + + Parameters + ---------- + poa_global : numeric + Total incident irradiance [W/m^2]. + + temp_air : numeric + Ambient dry bulb temperature [C]. + + wind_speed : numeric, default 1.0 + Wind speed in m/s measured at the same height for which the wind + loss factor was determined. The default value 1.0 m/s is the wind + speed at module height used to determine NOCT. [m/s] + + Returns + ------- + numeric, values in degrees C. + """ + kwargs = _build_kwargs(['u0', 'u1'], + self.temperature_model_parameters) + return temperature.pvsyst_cell(poa_global, temp_air, wind_speed, + **kwargs) + def first_solar_spectral_loss(self, pw, airmass_absolute): """ From 229c3ae2729f2d73e82b8bb25b725df67ec428e7 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:36:47 -0700 Subject: [PATCH 04/13] add faiman model to ModelChain --- pvlib/modelchain.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index 45a9f5ca98..dea4cc0ac3 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -282,8 +282,9 @@ class ModelChain(object): as the first argument to a user-defined function. temperature_model: None, str or function, default None - Valid strings are 'sapm' and 'pvsyst'. The ModelChain instance will be - passed as the first argument to a user-defined function. + Valid strings are 'sapm', 'pvsyst', and 'faiman'. The ModelChain + instance will be passed as the first argument to a user-defined + function. losses_model: str or function, default 'no_loss' Valid strings are 'pvwatts', 'no_loss'. The ModelChain instance @@ -660,6 +661,8 @@ def temperature_model(self, model): self._temperature_model = self.sapm_temp elif model == 'pvsyst': self._temperature_model = self.pvsyst_temp + elif model == 'faiman': + self._temperature_model = self.faiman_temp else: raise ValueError(model + ' is not a valid temperature model') # check system.temperature_model_parameters for consistency @@ -679,6 +682,8 @@ def infer_temperature_model(self): return self.sapm_temp elif set(['u_c', 'u_v']) <= params: return self.pvsyst_temp + elif set(['u0', 'u1']) <= params: + return self.faiman_temp else: raise ValueError('could not infer temperature model from ' 'system.temperature_module_parameters {}.' @@ -696,6 +701,12 @@ def pvsyst_temp(self): self.weather['wind_speed']) return self + def faiman_temp(self): + self.cell_temperature = self.system.faiman_celltemp( + self.total_irrad['poa_global'], self.weather['temp_air'], + self.weather['wind_speed']) + return self + @property def losses_model(self): return self._losses_model From e0fbfc369e96e80d3c5cbd4b79aea11ccbabcc98 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:51:45 -0700 Subject: [PATCH 05/13] fix copy/paste error --- pvlib/pvsystem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 59260c0da8..8b5f868321 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -634,8 +634,8 @@ def faiman_celltemp(self, poa_global, temp_air, wind_speed=1.0): """ kwargs = _build_kwargs(['u0', 'u1'], self.temperature_model_parameters) - return temperature.pvsyst_cell(poa_global, temp_air, wind_speed, - **kwargs) + return temperature.faiman(poa_global, temp_air, wind_speed, + **kwargs) def first_solar_spectral_loss(self, pw, airmass_absolute): From 532bfd60163ee6c40b74446a44607f7901ce782a Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:51:59 -0700 Subject: [PATCH 06/13] add test --- pvlib/tests/test_pvsystem.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 97a60e4c19..6fe045a147 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -434,6 +434,19 @@ def test_PVSystem_pvsyst_celltemp_kwargs(mocker): assert (out < 90) and (out > 70) +def test_PVSystem_faiman_celltemp(mocker): + u0, u1 = 25.0, 6.84 # default values + temp_model_params = {'u0': u0, 'u1': u1} + system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params) + mocker.spy(temperature, 'faiman') + temps = 25 + irrads = 1000 + winds = 1 + out = system.faiman_celltemp(irrads, temps, winds) + temperature.faiman.assert_called_once_with(irrads, temps, winds, u0, u1) + assert_allclose(out, 56.4, atol=1) + + def test__infer_temperature_model_params(): system = pvsystem.PVSystem(module_parameters={}, racking_model='open_rack', From 2dbf15aeaa03775ac303ed5f9e2e7b3b933d854c Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 20:54:48 -0700 Subject: [PATCH 07/13] whatsnew --- docs/sphinx/source/whatsnew/v0.7.2.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.7.2.rst b/docs/sphinx/source/whatsnew/v0.7.2.rst index abd4771101..55b8a57dd3 100644 --- a/docs/sphinx/source/whatsnew/v0.7.2.rst +++ b/docs/sphinx/source/whatsnew/v0.7.2.rst @@ -8,6 +8,8 @@ Enhancements * TMY3 dataframe returned by :py:func:`~pvlib.iotools.read_tmy3` now contains the original ``Date (MM/DD/YYYY)`` and ``Time (HH:MM)`` columns that the indices were parsed from (:pull:`866`) +* Add :py:func:`~pvlib.pvsystem.PVSystem.faiman` and added + ``temperature_model='faiman'`` option to :py:class:`pvlib.modelchain.ModelChain`. Bug fixes ~~~~~~~~~ @@ -21,3 +23,4 @@ Documentation Contributors ~~~~~~~~~~~~ * Mark Mikofski (:ghuser:`mikofski`) +* Kevin Anderson (:ghuser:`kanderso-nrel`) From ae9f970e1327207e948182f1cfc9a61c005f16c9 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 21:13:46 -0700 Subject: [PATCH 08/13] fix whatsnew --- docs/sphinx/source/whatsnew/v0.7.2.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.7.2.rst b/docs/sphinx/source/whatsnew/v0.7.2.rst index f7c66bae0d..49fe23e7ec 100644 --- a/docs/sphinx/source/whatsnew/v0.7.2.rst +++ b/docs/sphinx/source/whatsnew/v0.7.2.rst @@ -40,7 +40,6 @@ Requirements Contributors ~~~~~~~~~~~~ * Mark Mikofski (:ghuser:`mikofski`) -* Kevin Anderson (:ghuser:`kanderso-nrel`) * Cliff Hansen (:ghuser:`cwhanse`) * Cameron T. Stark (:ghuser:`camerontstark`) * Will Holmgren (:ghuser:`wholmgren`) From de60912120cd0cbd6ebb9243b3009e71306a4416 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Thu, 20 Feb 2020 21:22:52 -0700 Subject: [PATCH 09/13] add GH links to whatsnew entry --- docs/sphinx/source/whatsnew/v0.7.2.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.7.2.rst b/docs/sphinx/source/whatsnew/v0.7.2.rst index 49fe23e7ec..8d73b7f37f 100644 --- a/docs/sphinx/source/whatsnew/v0.7.2.rst +++ b/docs/sphinx/source/whatsnew/v0.7.2.rst @@ -14,7 +14,8 @@ Enhancements the original ``Date (MM/DD/YYYY)`` and ``Time (HH:MM)`` columns that the indices were parsed from (:pull:`866`) * Add :py:func:`~pvlib.pvsystem.PVSystem.faiman` and added - ``temperature_model='faiman'`` option to :py:class:`pvlib.modelchain.ModelChain`. + ``temperature_model='faiman'`` option to :py:class:`~pvlib.modelchain.ModelChain` + (:pull:`897`) (:issue:`836`). * Add Kimber soiling model :py:func:`pvlib.losses.soiling_kimber` (:pull:`860`) Bug fixes From b86fbbeaa94ad76e6af1beffe464aa6a568820e8 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Sat, 22 Feb 2020 09:56:55 -0700 Subject: [PATCH 10/13] split up MC cell temp tests; add faiman test --- pvlib/tests/test_modelchain.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index b48a3e05ba..1cd899fa91 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -230,10 +230,10 @@ def test_run_model_gueymard_perez(system, location): assert_series_equal(ac, expected) -def test_run_model_with_weather(system, location, weather, mocker): +def test_run_model_with_weather_sapm_temp(system, location, weather, mocker): + # test with sapm cell temperature model weather['wind_speed'] = 5 weather['temp_air'] = 10 - # test with sapm cell temperature model system.racking_model = 'open_rack' system.module_type = 'glass_glass' mc = ModelChain(system, location) @@ -246,7 +246,12 @@ def test_run_model_with_weather(system, location, weather, mocker): assert_series_equal(m_sapm.call_args[0][1], weather['temp_air']) # temp assert_series_equal(m_sapm.call_args[0][2], weather['wind_speed']) # wind assert not mc.ac.empty + + +def test_run_model_with_weather_pvsyst_temp(system, location, weather, mocker): # test with pvsyst cell temperature model + weather['wind_speed'] = 5 + weather['temp_air'] = 10 system.racking_model = 'freestanding' system.temperature_model_parameters = \ temperature._temperature_model_params('pvsyst', 'freestanding') @@ -260,6 +265,21 @@ def test_run_model_with_weather(system, location, weather, mocker): assert not mc.ac.empty +def test_run_model_with_weather_faiman_temp(system, location, weather, mocker): + # test with faiman cell temperature model + weather['wind_speed'] = 5 + weather['temp_air'] = 10 + system.temperature_model_parameters = {'u0': 25.0, 'u1': 6.84} + mc = ModelChain(system, location) + mc.temperature_model = 'faiman' + m_faiman = mocker.spy(system, 'faiman_celltemp') + mc.run_model(weather) + assert m_faiman.call_count == 1 + assert_series_equal(m_faiman.call_args[0][1], weather['temp_air']) + assert_series_equal(m_faiman.call_args[0][2], weather['wind_speed']) + assert not mc.ac.empty + + def test_run_model_tracker(system, location, weather, mocker): system = SingleAxisTracker( module_parameters=system.module_parameters, From 14bcacd684fd881eea729058d57a7d2516ebf4e5 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Sat, 22 Feb 2020 10:18:57 -0700 Subject: [PATCH 11/13] add faiman to MC infer_temp_model test; change test to check inferred model --- pvlib/tests/test_modelchain.py | 38 ++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 1cd899fa91..852a58a085 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -113,6 +113,31 @@ def pvwatts_dc_pvwatts_ac_system(sapm_temperature_cs5p_220m): return system +@pytest.fixture(scope="function") +def pvwatts_dc_pvwatts_ac_faiman_temp_system(): + module_parameters = {'pdc0': 220, 'gamma_pdc': -0.003} + temp_model_params = {'u0': 25.0, 'u1': 6.84} + inverter_parameters = {'pdc0': 220, 'eta_inv_nom': 0.95} + system = PVSystem(surface_tilt=32.2, surface_azimuth=180, + module_parameters=module_parameters, + temperature_model_parameters=temp_model_params, + inverter_parameters=inverter_parameters) + return system + + +@pytest.fixture(scope="function") +def pvwatts_dc_pvwatts_ac_pvsyst_temp_system(): + module_parameters = {'pdc0': 220, 'gamma_pdc': -0.003} + temp_model_params = {'u_c': 29.0, 'u_v': 0.0, 'eta_m': 0.1, + 'alpha_absorption': 0.9} + inverter_parameters = {'pdc0': 220, 'eta_inv_nom': 0.95} + system = PVSystem(surface_tilt=32.2, surface_azimuth=180, + module_parameters=module_parameters, + temperature_model_parameters=temp_model_params, + inverter_parameters=inverter_parameters) + return system + + @pytest.fixture(scope="function") def system_no_aoi(cec_module_cs5p_220m, sapm_temperature_cs5p_220m, cec_inverter_parameters): @@ -361,15 +386,20 @@ def test_infer_spectral_model(location, system, cec_dc_snl_ac_system, @pytest.mark.parametrize('temp_model', [ - 'sapm', pytest.param('pvsyst', marks=requires_scipy)]) -def test_infer_temp_model(location, system, pvsyst_dc_snl_ac_system, + 'sapm_temp', 'faiman_temp', + pytest.param('pvsyst_temp', marks=requires_scipy)]) +def test_infer_temp_model(location, system, + pvwatts_dc_pvwatts_ac_pvsyst_temp_system, + pvwatts_dc_pvwatts_ac_faiman_temp_system, temp_model): - dc_systems = {'sapm': system, - 'pvsyst': pvsyst_dc_snl_ac_system} + dc_systems = {'sapm_temp': system, + 'pvsyst_temp': pvwatts_dc_pvwatts_ac_pvsyst_temp_system, + 'faiman_temp': pvwatts_dc_pvwatts_ac_faiman_temp_system} system = dc_systems[temp_model] mc = ModelChain(system, location, orientation_strategy='None', aoi_model='physical', spectral_model='no_loss') + assert temp_model == mc.temperature_model.__name__ assert isinstance(mc, ModelChain) From f668a5d47718d0596b1f961105d1013043078cf8 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Sat, 22 Feb 2020 12:16:19 -0700 Subject: [PATCH 12/13] add MC.faiman_temp to api.rst --- docs/sphinx/source/api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 8237e3908a..e13eff32e2 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -524,6 +524,7 @@ ModelChain model definitions. modelchain.ModelChain.no_spectral_loss modelchain.ModelChain.sapm_temp modelchain.ModelChain.pvsyst_temp + modelchain.ModelChain.faiman_temp modelchain.ModelChain.pvwatts_losses modelchain.ModelChain.no_extra_losses From 645698cc6c23f2f4ac686f28bf9f4277135fd7c0 Mon Sep 17 00:00:00 2001 From: kanderso-nrel Date: Sun, 23 Feb 2020 20:56:48 -0700 Subject: [PATCH 13/13] delete duplicate pvsystem test --- pvlib/tests/test_pvsystem.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 6fe045a147..51767885b4 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -415,25 +415,6 @@ def test_PVSystem_pvsyst_celltemp(mocker): assert (out < 90) and (out > 70) -def test_PVSystem_pvsyst_celltemp_kwargs(mocker): - temp_model_params = temperature.TEMPERATURE_MODEL_PARAMETERS['pvsyst'][ - 'insulated'] - alpha_absorption = 0.85 - eta_m = 0.17 - module_parameters = {'alpha_absorption': alpha_absorption, 'eta_m': eta_m} - system = pvsystem.PVSystem(module_parameters=module_parameters, - temperature_model_parameters=temp_model_params) - mocker.spy(temperature, 'pvsyst_cell') - irrad = 800 - temp = 45 - wind = 0.5 - out = system.pvsyst_celltemp(irrad, temp, wind_speed=wind) - temperature.pvsyst_cell.assert_called_once_with( - irrad, temp, wind, temp_model_params['u_c'], temp_model_params['u_v'], - eta_m, alpha_absorption) - assert (out < 90) and (out > 70) - - def test_PVSystem_faiman_celltemp(mocker): u0, u1 = 25.0, 6.84 # default values temp_model_params = {'u0': u0, 'u1': u1}