From 693e60d1cc33b767d2ba6be94475ea779e5101be Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Wed, 8 Jul 2020 10:34:28 -0500 Subject: [PATCH 01/30] Added irradiance_loss_pvsyst function to pvsystem module and method to pvsystem class. --- pvlib/pvsystem.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 24a8f4b66e..bf97202f1a 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -848,6 +848,22 @@ def pvwatts_ac(self, pdc): return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], **kwargs) + + def irradiance_loss_pvsyst(self, effective_irradiance, + irradiance_shading_loss, irradiance_snow_loss, + irradiance_soiling_loss): + """ + Calculates plane of array irradiance losses using a model based on the + PVSyst methodology. A wrapper for + :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst`. + + See :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst` for details. + """ + + return irradiance_loss_pvsyst(effective_irradiance, + irradiance_shading_loss, + irradiance_snow_loss, + irradiance_soiling_loss) def localize(self, location=None, latitude=None, longitude=None, **kwargs): @@ -2536,6 +2552,73 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, return losses + +def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, + irradiance_snow_loss, irradiance_soiling_loss): + """ + Calculates plane of array irradiance losses using a model based on the + PVSyst methodology [1]_ of linearly reducing the effective irradiance on a + module. This doesn't account for the electrical losses due to irregular + irradiance on different solar cell strings but rather reduces the + irradiance input to the single diode equation. + + The losses are compounded using the following equation: + .. math:: + + L_{total}(\%) = 100 [ 1 - \Pi_i ( 1 - \frac{L_i}{100} ) ] + + Note the parameters must each be a series with a DatetimeIndex. The + index of the returned series will be the same as the effective_irradiance + index. All other parameters will be resampled to match this index with + a "fill forward" method for filling holes. + + Parameters + ---------- + effective_irradiance : Series + The irradiance (W/m2) that is to be reduced. Plane-of-array + irradiance that already accounts for Angle of Incidence and + Spectral losses. + + irradiance_shading_loss : Series + The fraction of the solar panel that is shaded. + + irradiance_snow_loss : Series + The fraction of the solar panel that is covered with snow. + + irradiance_soiling_loss : Series + The fraction of the irradiance prevented from reaching the solar + cells due to soiling of the solar panel. + + Returns + ------- + losses: Series + Irradiance (W/m2) reduction due to compounded losses. + + References + ---------- + .. [1] "Simulation process: Irradiances and PV-array" + https://www.pvsyst.com/help/simulation_process.htm + (2020). + + """ + + fill_method = 'ffill' + + shading_loss = irradiance_shading_loss.reindex_like(effective_irradiance, + method = fill_method) + + snow_loss = irradiance_snow_loss.reindex_like(effective_irradiance, + method = fill_method) + + soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, + method = fill_method) + + irradiance_losses = effective_irradiance * (1 - (1 - shading_loss) * + (1 - snow_loss) * + (1 - soiling_loss)) + + return irradiance_losses + ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', removal='0.8')(iam.ashrae) From ad09984c30d4cb9e9e5715652edc6551cc9685ef Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Thu, 9 Jul 2020 14:17:14 -0500 Subject: [PATCH 02/30] Updated formatting --- pvlib/pvsystem.py | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index bf97202f1a..83150d290c 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -848,7 +848,7 @@ def pvwatts_ac(self, pdc): return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], **kwargs) - + def irradiance_loss_pvsyst(self, effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, irradiance_soiling_loss): @@ -859,7 +859,7 @@ def irradiance_loss_pvsyst(self, effective_irradiance, See :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst` for details. """ - + return irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, @@ -2552,7 +2552,7 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, return losses - + def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, irradiance_soiling_loss): """ @@ -2561,34 +2561,35 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, module. This doesn't account for the electrical losses due to irregular irradiance on different solar cell strings but rather reduces the irradiance input to the single diode equation. - + The losses are compounded using the following equation: + .. math:: L_{total}(\%) = 100 [ 1 - \Pi_i ( 1 - \frac{L_i}{100} ) ] - + Note the parameters must each be a series with a DatetimeIndex. The index of the returned series will be the same as the effective_irradiance index. All other parameters will be resampled to match this index with a "fill forward" method for filling holes. - + Parameters ---------- effective_irradiance : Series The irradiance (W/m2) that is to be reduced. Plane-of-array irradiance that already accounts for Angle of Incidence and Spectral losses. - + irradiance_shading_loss : Series The fraction of the solar panel that is shaded. - + irradiance_snow_loss : Series The fraction of the solar panel that is covered with snow. - + irradiance_soiling_loss : Series The fraction of the irradiance prevented from reaching the solar cells due to soiling of the solar panel. - + Returns ------- losses: Series @@ -2599,24 +2600,24 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, .. [1] "Simulation process: Irradiances and PV-array" https://www.pvsyst.com/help/simulation_process.htm (2020). - + """ - + fill_method = 'ffill' - + shading_loss = irradiance_shading_loss.reindex_like(effective_irradiance, - method = fill_method) - + method=fill_method) + snow_loss = irradiance_snow_loss.reindex_like(effective_irradiance, - method = fill_method) - + method=fill_method) + soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, - method = fill_method) - - irradiance_losses = effective_irradiance * (1 - (1 - shading_loss) * - (1 - snow_loss) * - (1 - soiling_loss)) - + method=fill_method) + + irradiance_losses = effective_irradiance * (1 - (1 - shading_loss) + * (1 - snow_loss) + * (1 - soiling_loss)) + return irradiance_losses From 896e71f979bdb7e692e066219462621487dea883 Mon Sep 17 00:00:00 2001 From: btaute Date: Fri, 10 Jul 2020 09:07:55 -0500 Subject: [PATCH 03/30] fixing loss equation formatting Co-authored-by: Cliff Hansen --- pvlib/pvsystem.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 83150d290c..f9e858915a 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2614,9 +2614,8 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, method=fill_method) - irradiance_losses = effective_irradiance * (1 - (1 - shading_loss) - * (1 - snow_loss) - * (1 - soiling_loss)) + irradiance_losses = effective_irradiance * ( + 1 - (1 - shading_loss) * (1 - snow_loss) * (1 - soiling_loss)) return irradiance_losses From 430ab3d411a0794640673b162ff15afb19fb3e4c Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 09:12:10 -0500 Subject: [PATCH 04/30] Fix math formatting --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index f9e858915a..df2a3d980c 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2555,7 +2555,7 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, irradiance_soiling_loss): - """ + r""" Calculates plane of array irradiance losses using a model based on the PVSyst methodology [1]_ of linearly reducing the effective irradiance on a module. This doesn't account for the electrical losses due to irregular From 06efce1d20103cc6416f38e769da53211c504463 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 11:35:29 -0500 Subject: [PATCH 05/30] Added Tests --- pvlib/tests/test_pvsystem.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 81aca6cf9e..bb935e7596 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1347,6 +1347,38 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): assert out < pdc +def make_irradiance_loss_pvsyst_test_series(): + final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') + effective_irradiance = pd.Series(1000, index = final_index) + shading = pd.Series(.1, index = final_index) + snow = pd.Series(.05, index = pd.date_range(start='1/1/1990 12:00', + periods=365*2, freq='D')) + soiling = pd.Series(.02, index = pd.date_range(start='1/1/1990', + periods=12, freq='MS')) + expected = pd.Series(162.1, index = final_index) + + return {'effective_irradiance': effective_irradiance, + 'shading': shading, 'snow': snow, + 'soiling': soiling, 'expected': expected} + + +def test_irradiance_loss_pvsyst(): + params = make_irradiance_loss_pvsyst_test_series() + out = irradiance_loss_pvsyst(params['effective_irradiance'], + params['shading'], params['snow'], + params['soiling']) + assert_series_equal(params['expected'], out) + + +def test_PVSystem_irradiance_loss_pvsyst(): + system = pvsystem.PVSystem() + params = make_irradiance_loss_pvsyst_test_series() + out = system.irradiance_loss_pvsyst(params['effective_irradiance'], + params['shading'], params['snow'], + params['soiling']) + assert_series_equal(params['expected'], out) + + @fail_on_pvlib_version('0.8') def test_deprecated_08(): # deprecated function pvsystem.sapm_celltemp From 43ac80e38cf0b50d65cee7e8dcecc5794ded0717 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 11:39:08 -0500 Subject: [PATCH 06/30] fix formatting in tests --- pvlib/tests/test_pvsystem.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index bb935e7596..b0f9b5f549 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1349,13 +1349,13 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): def make_irradiance_loss_pvsyst_test_series(): final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') - effective_irradiance = pd.Series(1000, index = final_index) - shading = pd.Series(.1, index = final_index) - snow = pd.Series(.05, index = pd.date_range(start='1/1/1990 12:00', - periods=365*2, freq='D')) - soiling = pd.Series(.02, index = pd.date_range(start='1/1/1990', - periods=12, freq='MS')) - expected = pd.Series(162.1, index = final_index) + effective_irradiance = pd.Series(1000, index=final_index) + shading = pd.Series(.1, index=final_index) + snow = pd.Series(.05, index=pd.date_range(start='1/1/1990 12:00', + periods=365*2, freq='D')) + soiling = pd.Series(.02, index=pd.date_range(start='1/1/1990', + periods=12, freq='MS')) + expected = pd.Series(162.1, index=final_index) return {'effective_irradiance': effective_irradiance, 'shading': shading, 'snow': snow, @@ -1364,7 +1364,7 @@ def make_irradiance_loss_pvsyst_test_series(): def test_irradiance_loss_pvsyst(): params = make_irradiance_loss_pvsyst_test_series() - out = irradiance_loss_pvsyst(params['effective_irradiance'], + out = pvsystem.irradiance_loss_pvsyst(params['effective_irradiance'], params['shading'], params['snow'], params['soiling']) assert_series_equal(params['expected'], out) From 1bd866bca50fce17c4a62798bf6f352ee1de7c02 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 11:41:27 -0500 Subject: [PATCH 07/30] more test formatting fixes --- pvlib/tests/test_pvsystem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index b0f9b5f549..0243da436f 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1365,8 +1365,8 @@ def make_irradiance_loss_pvsyst_test_series(): def test_irradiance_loss_pvsyst(): params = make_irradiance_loss_pvsyst_test_series() out = pvsystem.irradiance_loss_pvsyst(params['effective_irradiance'], - params['shading'], params['snow'], - params['soiling']) + params['shading'], params['snow'], + params['soiling']) assert_series_equal(params['expected'], out) From 7969ce525eb3b35e8bc2fd8f37ea6ec01f0cc695 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 11:55:48 -0500 Subject: [PATCH 08/30] Updated v0.8.0 What's New --- docs/sphinx/source/whatsnew/v0.8.0.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index f901add383..06161c82ff 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -24,6 +24,9 @@ Enhancements * Add :py:func:`pvlib.iam.marion_diffuse` and :py:func:`pvlib.iam.marion_integrate` to calculate IAM values for diffuse irradiance. (:pull:`984`) +* Add :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and + :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` to calculate + cumulative losses on the effective irradiance with a style similar to PVSyst. Bug fixes ~~~~~~~~~ @@ -35,6 +38,8 @@ Testing applied to functions that require args or kwargs. (:pull:`973`) * Test added for :py:class:`pvlib.modelchain.ModelChain` to confirm ValueError when ``ac_model`` is an invalid string. (:pull:`886`) +* Tests added for :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and + :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` Documentation ~~~~~~~~~~~~~ From 8b617b70de596df693cddd5405668e39d22b2d27 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Fri, 10 Jul 2020 12:01:19 -0500 Subject: [PATCH 09/30] Added Issue Number to v0.8.0 What's New --- docs/sphinx/source/whatsnew/v0.8.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 06161c82ff..ee62879dd8 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -27,6 +27,7 @@ Enhancements * Add :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` to calculate cumulative losses on the effective irradiance with a style similar to PVSyst. + Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` Bug fixes ~~~~~~~~~ From 2361db263835f9beacf610bf2581646083c06c96 Mon Sep 17 00:00:00 2001 From: btaute Date: Tue, 21 Jul 2020 15:02:55 -0500 Subject: [PATCH 10/30] Update pvlib/pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/pvsystem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index df2a3d980c..f4f72f8b39 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2556,11 +2556,11 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, irradiance_soiling_loss): r""" - Calculates plane of array irradiance losses using a model based on the - PVSyst methodology [1]_ of linearly reducing the effective irradiance on a - module. This doesn't account for the electrical losses due to irregular - irradiance on different solar cell strings but rather reduces the - irradiance input to the single diode equation. + Calculates irradiance losses using a model based on PVsyst. + + The PVsyst method [1]_ linearly reduces the effective irradiance to + account for the effects of shading, snow and soiling. The separate + loss factors are compounded to calculate a single loss factor. The losses are compounded using the following equation: From e0e168cbb8b4053860e02f9b1f79f6e308eb1035 Mon Sep 17 00:00:00 2001 From: btaute Date: Tue, 21 Jul 2020 15:03:22 -0500 Subject: [PATCH 11/30] Update pvlib/pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index f4f72f8b39..7a84993378 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2562,7 +2562,7 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, account for the effects of shading, snow and soiling. The separate loss factors are compounded to calculate a single loss factor. - The losses are compounded using the following equation: + The separate losses are compounded using the following equation: .. math:: From b7169bdddc9cf1be4af1c4d0009001af9f9bb71c Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 22 Jul 2020 09:55:57 -0500 Subject: [PATCH 12/30] Update pvlib/pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 7a84993378..ccb8dd6956 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2593,7 +2593,7 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, Returns ------- losses: Series - Irradiance (W/m2) reduction due to compounded losses. + Irradiance reduction due to compounded losses. [%] References ---------- From 607bdb9fe5ae6ea0563e3cff685dea1b68311214 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 22 Jul 2020 09:56:11 -0500 Subject: [PATCH 13/30] Update pvlib/tests/test_pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/tests/test_pvsystem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 0243da436f..507ff2e719 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1347,7 +1347,8 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): assert out < pdc -def make_irradiance_loss_pvsyst_test_series(): +@pytest.fixture() +def irradiance_loss_pvsyst(): final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') effective_irradiance = pd.Series(1000, index=final_index) shading = pd.Series(.1, index=final_index) From 6c408f5c5bc79848070047fd719076c5fa3b3a86 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 22 Jul 2020 09:56:31 -0500 Subject: [PATCH 14/30] Update pvlib/tests/test_pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/tests/test_pvsystem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 507ff2e719..48fb3ded95 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1363,8 +1363,7 @@ def irradiance_loss_pvsyst(): 'soiling': soiling, 'expected': expected} -def test_irradiance_loss_pvsyst(): - params = make_irradiance_loss_pvsyst_test_series() +def test_irradiance_loss_pvsyst(irradiance_loss_pvsyst): out = pvsystem.irradiance_loss_pvsyst(params['effective_irradiance'], params['shading'], params['snow'], params['soiling']) From 4b33177623f95f459cf0c2a4de7ac04fe0b10aa1 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 22 Jul 2020 09:56:59 -0500 Subject: [PATCH 15/30] Update pvlib/tests/test_pvsystem.py Co-authored-by: Cliff Hansen --- pvlib/tests/test_pvsystem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 48fb3ded95..cbba61fc4b 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1364,10 +1364,10 @@ def irradiance_loss_pvsyst(): def test_irradiance_loss_pvsyst(irradiance_loss_pvsyst): - out = pvsystem.irradiance_loss_pvsyst(params['effective_irradiance'], - params['shading'], params['snow'], - params['soiling']) - assert_series_equal(params['expected'], out) + out = pvsystem.irradiance_loss_pvsyst( + irradiance_loss_pvsyst['effective_irradiance'], irradiance_loss_pvsyst['shading'], + irradiance_loss_pvsyst['snow'], irradiance_loss_pvsyst['soiling']) + assert_series_equal(irradiance_loss_pvsyst['expected'], out) def test_PVSystem_irradiance_loss_pvsyst(): From 29cccdd128251c86730457a6f24a02091835827e Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Wed, 22 Jul 2020 10:38:47 -0500 Subject: [PATCH 16/30] Updated params and output to be percents --- pvlib/pvsystem.py | 24 ++++++++++++------------ pvlib/tests/test_pvsystem.py | 25 +++++++++++++------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index ccb8dd6956..036526bfc2 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2557,9 +2557,9 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, irradiance_snow_loss, irradiance_soiling_loss): r""" Calculates irradiance losses using a model based on PVsyst. - + The PVsyst method [1]_ linearly reduces the effective irradiance to - account for the effects of shading, snow and soiling. The separate + account for the effects of shading, snow, and soiling. The separate loss factors are compounded to calculate a single loss factor. The separate losses are compounded using the following equation: @@ -2568,6 +2568,9 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, L_{total}(\%) = 100 [ 1 - \Pi_i ( 1 - \frac{L_i}{100} ) ] + :math:L_{total} is the total irradiance loss resulting from the effects of + shading, snow, and soiling. + Note the parameters must each be a series with a DatetimeIndex. The index of the returned series will be the same as the effective_irradiance index. All other parameters will be resampled to match this index with @@ -2576,24 +2579,21 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, Parameters ---------- effective_irradiance : Series - The irradiance (W/m2) that is to be reduced. Plane-of-array - irradiance that already accounts for Angle of Incidence and - Spectral losses. + The plane-of-array irradiance (W/m2) that is to be reduced. irradiance_shading_loss : Series - The fraction of the solar panel that is shaded. + The percent reduction in irradiance due to shading. [%] irradiance_snow_loss : Series - The fraction of the solar panel that is covered with snow. + The percent reduction in irradiance due to snow coverage. [%] irradiance_soiling_loss : Series - The fraction of the irradiance prevented from reaching the solar - cells due to soiling of the solar panel. + The percent reduction in irradiance due to soiling. [%] Returns ------- losses: Series - Irradiance reduction due to compounded losses. [%] + The percent reduction in irradiance due to compounded losses. [%] References ---------- @@ -2614,8 +2614,8 @@ def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, method=fill_method) - irradiance_losses = effective_irradiance * ( - 1 - (1 - shading_loss) * (1 - snow_loss) * (1 - soiling_loss)) + irradiance_losses = 100 * (1 - ( + (1 - shading_loss/100) * (1 - snow_loss/100) * (1 - soiling_loss/100))) return irradiance_losses diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index cbba61fc4b..14ff412fcc 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1351,12 +1351,12 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): def irradiance_loss_pvsyst(): final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') effective_irradiance = pd.Series(1000, index=final_index) - shading = pd.Series(.1, index=final_index) - snow = pd.Series(.05, index=pd.date_range(start='1/1/1990 12:00', + shading = pd.Series(10, index=final_index) + snow = pd.Series(5, index=pd.date_range(start='1/1/1990 12:00', periods=365*2, freq='D')) - soiling = pd.Series(.02, index=pd.date_range(start='1/1/1990', + soiling = pd.Series(2, index=pd.date_range(start='1/1/1990', periods=12, freq='MS')) - expected = pd.Series(162.1, index=final_index) + expected = pd.Series(16.21, index=final_index) return {'effective_irradiance': effective_irradiance, 'shading': shading, 'snow': snow, @@ -1365,18 +1365,19 @@ def irradiance_loss_pvsyst(): def test_irradiance_loss_pvsyst(irradiance_loss_pvsyst): out = pvsystem.irradiance_loss_pvsyst( - irradiance_loss_pvsyst['effective_irradiance'], irradiance_loss_pvsyst['shading'], - irradiance_loss_pvsyst['snow'], irradiance_loss_pvsyst['soiling']) + irradiance_loss_pvsyst['effective_irradiance'], + irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], + irradiance_loss_pvsyst['soiling']) assert_series_equal(irradiance_loss_pvsyst['expected'], out) -def test_PVSystem_irradiance_loss_pvsyst(): +def test_PVSystem_irradiance_loss_pvsyst(irradiance_loss_pvsyst): system = pvsystem.PVSystem() - params = make_irradiance_loss_pvsyst_test_series() - out = system.irradiance_loss_pvsyst(params['effective_irradiance'], - params['shading'], params['snow'], - params['soiling']) - assert_series_equal(params['expected'], out) + out = system.irradiance_loss_pvsyst( + irradiance_loss_pvsyst['effective_irradiance'], + irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], + irradiance_loss_pvsyst['soiling']) + assert_series_equal(irradiance_loss_pvsyst['expected'], out) @fail_on_pvlib_version('0.8') From 25fc4240d5b7bc5b352edf22a843d7a6ead38112 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Wed, 22 Jul 2020 10:42:05 -0500 Subject: [PATCH 17/30] fix indents --- pvlib/tests/test_pvsystem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 14ff412fcc..2201f755bd 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1353,9 +1353,9 @@ def irradiance_loss_pvsyst(): effective_irradiance = pd.Series(1000, index=final_index) shading = pd.Series(10, index=final_index) snow = pd.Series(5, index=pd.date_range(start='1/1/1990 12:00', - periods=365*2, freq='D')) + periods=365*2, freq='D')) soiling = pd.Series(2, index=pd.date_range(start='1/1/1990', - periods=12, freq='MS')) + periods=12, freq='MS')) expected = pd.Series(16.21, index=final_index) return {'effective_irradiance': effective_irradiance, From 5d488e75033d4cb6fc6d20991a8fece3564d93cf Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 14:06:50 -0500 Subject: [PATCH 18/30] Changed function to generic combine_loss_factors --- docs/sphinx/source/api.rst | 7 +++ docs/sphinx/source/whatsnew/v0.8.0.rst | 7 +-- pvlib/pvsystem.py | 85 +++++++------------------- pvlib/tests/test_pvsystem.py | 37 +++-------- 4 files changed, 39 insertions(+), 97 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 9c93af7475..a9dae2435a 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -311,6 +311,13 @@ PVWatts model inverter.pvwatts pvsystem.pvwatts_losses +Loss models +^^^^^^^^^^^ +.. autosummary:: + :toctree: generated/ + + pvsystem.combine_loss_factors + Functions for fitting diode models ---------------------------------- diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index ee62879dd8..9d56c184e5 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -24,9 +24,8 @@ Enhancements * Add :py:func:`pvlib.iam.marion_diffuse` and :py:func:`pvlib.iam.marion_integrate` to calculate IAM values for diffuse irradiance. (:pull:`984`) -* Add :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and - :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` to calculate - cumulative losses on the effective irradiance with a style similar to PVSyst. +* Add :py:func:`pvlib.pvsystem.combine_loss_factors` as general purpose + function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` Bug fixes @@ -39,8 +38,6 @@ Testing applied to functions that require args or kwargs. (:pull:`973`) * Test added for :py:class:`pvlib.modelchain.ModelChain` to confirm ValueError when ``ac_model`` is an invalid string. (:pull:`886`) -* Tests added for :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and - :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` Documentation ~~~~~~~~~~~~~ diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 036526bfc2..e8e233de0f 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -849,22 +849,6 @@ def pvwatts_ac(self, pdc): return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], **kwargs) - def irradiance_loss_pvsyst(self, effective_irradiance, - irradiance_shading_loss, irradiance_snow_loss, - irradiance_soiling_loss): - """ - Calculates plane of array irradiance losses using a model based on the - PVSyst methodology. A wrapper for - :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst`. - - See :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst` for details. - """ - - return irradiance_loss_pvsyst(effective_irradiance, - irradiance_shading_loss, - irradiance_snow_loss, - irradiance_soiling_loss) - def localize(self, location=None, latitude=None, longitude=None, **kwargs): """Creates a LocalizedPVSystem object using this object @@ -2553,71 +2537,46 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, return losses -def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, - irradiance_snow_loss, irradiance_soiling_loss): +def combine_loss_factors(index, *losses, fill_method='ffill'): r""" - Calculates irradiance losses using a model based on PVsyst. - - The PVsyst method [1]_ linearly reduces the effective irradiance to - account for the effects of shading, snow, and soiling. The separate - loss factors are compounded to calculate a single loss factor. + Combines Series loss fractions while setting a common index. The separate losses are compounded using the following equation: .. math:: - L_{total}(\%) = 100 [ 1 - \Pi_i ( 1 - \frac{L_i}{100} ) ] + L_{total} = 1 - [ 1 - \Pi_i ( 1 - L_i ) ] - :math:L_{total} is the total irradiance loss resulting from the effects of - shading, snow, and soiling. + :math:L_{total} is the total loss returned + :math:L_i is each individual loss factor input - Note the parameters must each be a series with a DatetimeIndex. The - index of the returned series will be the same as the effective_irradiance - index. All other parameters will be resampled to match this index with - a "fill forward" method for filling holes. + Note the losses must each be a series with a DatetimeIndex. + All losses will be resampled to match the index parameter using + the fill method specified (defaults to "fill forward"). Parameters ---------- - effective_irradiance : Series - The plane-of-array irradiance (W/m2) that is to be reduced. + index : DatetimeIndex + The index of the returned loss factors - irradiance_shading_loss : Series - The percent reduction in irradiance due to shading. [%] + *losses : Series + Each parameter is a series of fractions to be compounded - irradiance_snow_loss : Series - The percent reduction in irradiance due to snow coverage. [%] - - irradiance_soiling_loss : Series - The percent reduction in irradiance due to soiling. [%] + fill_method : {None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’} + Method to use for filling holes in reindexed DataFrame Returns ------- - losses: Series - The percent reduction in irradiance due to compounded losses. [%] - - References - ---------- - .. [1] "Simulation process: Irradiances and PV-array" - https://www.pvsyst.com/help/simulation_process.htm - (2020). - + Series + Fractions resulting from the combination of each loss factor """ + combined_factor = 1 + + for loss in losses: + loss = loss.reindex(index, method=fill_method) + combined_factor *= (1 - loss) - fill_method = 'ffill' - - shading_loss = irradiance_shading_loss.reindex_like(effective_irradiance, - method=fill_method) - - snow_loss = irradiance_snow_loss.reindex_like(effective_irradiance, - method=fill_method) - - soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, - method=fill_method) - - irradiance_losses = 100 * (1 - ( - (1 - shading_loss/100) * (1 - snow_loss/100) * (1 - soiling_loss/100))) - - return irradiance_losses + return 1 - combined_factor ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 2201f755bd..494ced5992 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1347,37 +1347,16 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): assert out < pdc -@pytest.fixture() -def irradiance_loss_pvsyst(): - final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') - effective_irradiance = pd.Series(1000, index=final_index) - shading = pd.Series(10, index=final_index) - snow = pd.Series(5, index=pd.date_range(start='1/1/1990 12:00', +def test_combine_loss_factors(): + index = pd.date_range(start='1990/01/01T12:00', periods=365, freq='D') + loss_1 = pd.Series(.10, index=final_index) + loss_2 = pd.Series(.05, index=pd.date_range(start='1990/01/01T12:00', periods=365*2, freq='D')) - soiling = pd.Series(2, index=pd.date_range(start='1/1/1990', + loss_3 = pd.Series(.02, index=pd.date_range(start='1990/01/01', periods=12, freq='MS')) - expected = pd.Series(16.21, index=final_index) - - return {'effective_irradiance': effective_irradiance, - 'shading': shading, 'snow': snow, - 'soiling': soiling, 'expected': expected} - - -def test_irradiance_loss_pvsyst(irradiance_loss_pvsyst): - out = pvsystem.irradiance_loss_pvsyst( - irradiance_loss_pvsyst['effective_irradiance'], - irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], - irradiance_loss_pvsyst['soiling']) - assert_series_equal(irradiance_loss_pvsyst['expected'], out) - - -def test_PVSystem_irradiance_loss_pvsyst(irradiance_loss_pvsyst): - system = pvsystem.PVSystem() - out = system.irradiance_loss_pvsyst( - irradiance_loss_pvsyst['effective_irradiance'], - irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], - irradiance_loss_pvsyst['soiling']) - assert_series_equal(irradiance_loss_pvsyst['expected'], out) + expected = pd.Series(.1621, index=final_index) + out = combine_loss_factors(index, loss_1, loss_2, loss_3) + assert_series_equal(expected, out) @fail_on_pvlib_version('0.8') From 6f2f97658c5b1348e85e3419bde65ccfb8fe5293 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 14:06:50 -0500 Subject: [PATCH 19/30] Changed function to generic combine_loss_factors --- docs/sphinx/source/api.rst | 7 +++ docs/sphinx/source/whatsnew/v0.8.0.rst | 7 +-- pvlib/pvsystem.py | 85 +++++++------------------- pvlib/tests/test_pvsystem.py | 41 +++---------- 4 files changed, 41 insertions(+), 99 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 9c93af7475..a9dae2435a 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -311,6 +311,13 @@ PVWatts model inverter.pvwatts pvsystem.pvwatts_losses +Loss models +^^^^^^^^^^^ +.. autosummary:: + :toctree: generated/ + + pvsystem.combine_loss_factors + Functions for fitting diode models ---------------------------------- diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index ee62879dd8..9d56c184e5 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -24,9 +24,8 @@ Enhancements * Add :py:func:`pvlib.iam.marion_diffuse` and :py:func:`pvlib.iam.marion_integrate` to calculate IAM values for diffuse irradiance. (:pull:`984`) -* Add :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and - :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` to calculate - cumulative losses on the effective irradiance with a style similar to PVSyst. +* Add :py:func:`pvlib.pvsystem.combine_loss_factors` as general purpose + function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` Bug fixes @@ -39,8 +38,6 @@ Testing applied to functions that require args or kwargs. (:pull:`973`) * Test added for :py:class:`pvlib.modelchain.ModelChain` to confirm ValueError when ``ac_model`` is an invalid string. (:pull:`886`) -* Tests added for :py:func:`pvlib.pvsystem.irradiance_losses_pvsyst` and - :py:meth:`pvlib.pvsystem.PVSystem.irradiance_losses_pvsyst` Documentation ~~~~~~~~~~~~~ diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 036526bfc2..e8e233de0f 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -849,22 +849,6 @@ def pvwatts_ac(self, pdc): return inverter.pvwatts(pdc, self.inverter_parameters['pdc0'], **kwargs) - def irradiance_loss_pvsyst(self, effective_irradiance, - irradiance_shading_loss, irradiance_snow_loss, - irradiance_soiling_loss): - """ - Calculates plane of array irradiance losses using a model based on the - PVSyst methodology. A wrapper for - :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst`. - - See :py:func:`pvlib.pvsystem.irradiance_loss_pvsyst` for details. - """ - - return irradiance_loss_pvsyst(effective_irradiance, - irradiance_shading_loss, - irradiance_snow_loss, - irradiance_soiling_loss) - def localize(self, location=None, latitude=None, longitude=None, **kwargs): """Creates a LocalizedPVSystem object using this object @@ -2553,71 +2537,46 @@ def pvwatts_losses(soiling=2, shading=3, snow=0, mismatch=2, wiring=2, return losses -def irradiance_loss_pvsyst(effective_irradiance, irradiance_shading_loss, - irradiance_snow_loss, irradiance_soiling_loss): +def combine_loss_factors(index, *losses, fill_method='ffill'): r""" - Calculates irradiance losses using a model based on PVsyst. - - The PVsyst method [1]_ linearly reduces the effective irradiance to - account for the effects of shading, snow, and soiling. The separate - loss factors are compounded to calculate a single loss factor. + Combines Series loss fractions while setting a common index. The separate losses are compounded using the following equation: .. math:: - L_{total}(\%) = 100 [ 1 - \Pi_i ( 1 - \frac{L_i}{100} ) ] + L_{total} = 1 - [ 1 - \Pi_i ( 1 - L_i ) ] - :math:L_{total} is the total irradiance loss resulting from the effects of - shading, snow, and soiling. + :math:L_{total} is the total loss returned + :math:L_i is each individual loss factor input - Note the parameters must each be a series with a DatetimeIndex. The - index of the returned series will be the same as the effective_irradiance - index. All other parameters will be resampled to match this index with - a "fill forward" method for filling holes. + Note the losses must each be a series with a DatetimeIndex. + All losses will be resampled to match the index parameter using + the fill method specified (defaults to "fill forward"). Parameters ---------- - effective_irradiance : Series - The plane-of-array irradiance (W/m2) that is to be reduced. + index : DatetimeIndex + The index of the returned loss factors - irradiance_shading_loss : Series - The percent reduction in irradiance due to shading. [%] + *losses : Series + Each parameter is a series of fractions to be compounded - irradiance_snow_loss : Series - The percent reduction in irradiance due to snow coverage. [%] - - irradiance_soiling_loss : Series - The percent reduction in irradiance due to soiling. [%] + fill_method : {None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’} + Method to use for filling holes in reindexed DataFrame Returns ------- - losses: Series - The percent reduction in irradiance due to compounded losses. [%] - - References - ---------- - .. [1] "Simulation process: Irradiances and PV-array" - https://www.pvsyst.com/help/simulation_process.htm - (2020). - + Series + Fractions resulting from the combination of each loss factor """ + combined_factor = 1 + + for loss in losses: + loss = loss.reindex(index, method=fill_method) + combined_factor *= (1 - loss) - fill_method = 'ffill' - - shading_loss = irradiance_shading_loss.reindex_like(effective_irradiance, - method=fill_method) - - snow_loss = irradiance_snow_loss.reindex_like(effective_irradiance, - method=fill_method) - - soiling_loss = irradiance_soiling_loss.reindex_like(effective_irradiance, - method=fill_method) - - irradiance_losses = 100 * (1 - ( - (1 - shading_loss/100) * (1 - snow_loss/100) * (1 - soiling_loss/100))) - - return irradiance_losses + return 1 - combined_factor ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 2201f755bd..465b287da3 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1347,37 +1347,16 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): assert out < pdc -@pytest.fixture() -def irradiance_loss_pvsyst(): - final_index = pd.date_range(start='1/1/1990 12:00', periods=365, freq='D') - effective_irradiance = pd.Series(1000, index=final_index) - shading = pd.Series(10, index=final_index) - snow = pd.Series(5, index=pd.date_range(start='1/1/1990 12:00', - periods=365*2, freq='D')) - soiling = pd.Series(2, index=pd.date_range(start='1/1/1990', - periods=12, freq='MS')) - expected = pd.Series(16.21, index=final_index) - - return {'effective_irradiance': effective_irradiance, - 'shading': shading, 'snow': snow, - 'soiling': soiling, 'expected': expected} - - -def test_irradiance_loss_pvsyst(irradiance_loss_pvsyst): - out = pvsystem.irradiance_loss_pvsyst( - irradiance_loss_pvsyst['effective_irradiance'], - irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], - irradiance_loss_pvsyst['soiling']) - assert_series_equal(irradiance_loss_pvsyst['expected'], out) - - -def test_PVSystem_irradiance_loss_pvsyst(irradiance_loss_pvsyst): - system = pvsystem.PVSystem() - out = system.irradiance_loss_pvsyst( - irradiance_loss_pvsyst['effective_irradiance'], - irradiance_loss_pvsyst['shading'], irradiance_loss_pvsyst['snow'], - irradiance_loss_pvsyst['soiling']) - assert_series_equal(irradiance_loss_pvsyst['expected'], out) +def test_combine_loss_factors(): + test_index = pd.date_range(start='1990/01/01T12:00', periods=365, freq='D') + loss_1 = pd.Series(.10, index=test_index) + loss_2 = pd.Series(.05, index=pd.date_range(start='1990/01/01T12:00', + periods=365*2, freq='D')) + loss_3 = pd.Series(.02, index=pd.date_range(start='1990/01/01', + periods=12, freq='MS')) + expected = pd.Series(.1621, index=test_index) + out = pvsystem.combine_loss_factors(index, loss_1, loss_2, loss_3) + assert_series_equal(expected, out) @fail_on_pvlib_version('0.8') From 6c5e5a9c3cde2f45ac4c782d00ccc9172367418d Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 14:16:05 -0500 Subject: [PATCH 20/30] fixed test typo --- pvlib/tests/test_pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 465b287da3..89bf61d72f 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1355,7 +1355,7 @@ def test_combine_loss_factors(): loss_3 = pd.Series(.02, index=pd.date_range(start='1990/01/01', periods=12, freq='MS')) expected = pd.Series(.1621, index=test_index) - out = pvsystem.combine_loss_factors(index, loss_1, loss_2, loss_3) + out = pvsystem.combine_loss_factors(test_index, loss_1, loss_2, loss_3) assert_series_equal(expected, out) From 49a7f045ff2d673f5bb9f7c4336b17e529b93320 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 14:41:49 -0500 Subject: [PATCH 21/30] indentation fix --- pvlib/pvsystem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index e8e233de0f..5c787d5fe2 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2570,13 +2570,13 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): Series Fractions resulting from the combination of each loss factor """ - combined_factor = 1 + combined_factor = 1 - for loss in losses: - loss = loss.reindex(index, method=fill_method) - combined_factor *= (1 - loss) + for loss in losses: + loss = loss.reindex(index, method=fill_method) + combined_factor *= (1 - loss) - return 1 - combined_factor + return 1 - combined_factor ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', From 50590d331fffdc3645de5768d39b2eae1367c796 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 14:43:01 -0500 Subject: [PATCH 22/30] whitespace fix --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 5c787d5fe2..13139b8c09 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2571,7 +2571,7 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): Fractions resulting from the combination of each loss factor """ combined_factor = 1 - + for loss in losses: loss = loss.reindex(index, method=fill_method) combined_factor *= (1 - loss) From 48fd3b431bbb8bb5bb751d76748fcedd64079605 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 16:44:43 -0500 Subject: [PATCH 23/30] Moved combine_loss_factors to PV System Effects --- docs/sphinx/source/api.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index a9dae2435a..f69648739b 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -311,13 +311,6 @@ PVWatts model inverter.pvwatts pvsystem.pvwatts_losses -Loss models -^^^^^^^^^^^ -.. autosummary:: - :toctree: generated/ - - pvsystem.combine_loss_factors - Functions for fitting diode models ---------------------------------- @@ -342,6 +335,13 @@ Other Effects on PV System Output =========================== +Loss models +^^^^^^^^^^^ +.. autosummary:: + :toctree: generated/ + + pvsystem.combine_loss_factors + .. autosummary:: :toctree: generated/ From 7107119498f9199c3bfec9eeb1d17a6b521365a9 Mon Sep 17 00:00:00 2001 From: btaute Date: Tue, 4 Aug 2020 16:46:37 -0500 Subject: [PATCH 24/30] Apply suggestions from code review Co-authored-by: Cliff Hansen --- pvlib/pvsystem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 13139b8c09..2579ceeda1 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2547,8 +2547,8 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): L_{total} = 1 - [ 1 - \Pi_i ( 1 - L_i ) ] - :math:L_{total} is the total loss returned - :math:L_i is each individual loss factor input + :math:`L_{total}` is the total loss returned + :math:`L_i` is each individual loss factor input Note the losses must each be a series with a DatetimeIndex. All losses will be resampled to match the index parameter using @@ -2560,7 +2560,7 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): The index of the returned loss factors *losses : Series - Each parameter is a series of fractions to be compounded + One or more Series of fractions to be compounded fill_method : {None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’} Method to use for filling holes in reindexed DataFrame From 0b6ae0456bc3ced5ea685430b1ccce5311d158b7 Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 16:49:27 -0500 Subject: [PATCH 25/30] fill_method docstring update --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 13139b8c09..9b400b78ff 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2562,7 +2562,7 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): *losses : Series Each parameter is a series of fractions to be compounded - fill_method : {None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’} + fill_method : {'ffill'/'pad', 'backfill'/'bfill', 'nearest'}, default 'ffill' Method to use for filling holes in reindexed DataFrame Returns From 62e9af38675cd26b931fac8d54ae6ae51814012d Mon Sep 17 00:00:00 2001 From: Brock Taute Date: Tue, 4 Aug 2020 16:54:18 -0500 Subject: [PATCH 26/30] fill_method docstring update --- pvlib/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index f60a165adb..7b3c99c7ae 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2562,7 +2562,7 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): *losses : Series One or more Series of fractions to be compounded - fill_method : {'ffill'/'pad', 'backfill'/'bfill', 'nearest'}, default 'ffill' + fill_method : {'ffill', 'bfill', 'nearest'}, default 'ffill' Method to use for filling holes in reindexed DataFrame Returns From d8abcfee16733349a1271a692c46fcafdcfac168 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 2 Sep 2020 15:13:21 -0500 Subject: [PATCH 27/30] Update v0.8.0.rst --- docs/sphinx/source/whatsnew/v0.8.0.rst | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index 5096fb2a97..f878038eab 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -78,23 +78,6 @@ Enhancements * Add :py:func:`pvlib.pvsystem.combine_loss_factors` as general purpose function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` -* Add :py:func:`pvlib.shading.sky_diffuse_passias`, - :py:func:`pvlib.shading.masking_angle_passias`, and - :py:func:`pvlib.shading.masking_angle` to model diffuse shading loss. - (: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 :py:func:`pvlib.ivtools.sdm.fit_pvsyst_sandia` and :py:func:`pvlib.ivtools.sdm.fit_desoto_sandia` - for fitting the Pvsyst and De Soto models to IV curve data (:issue:`227`)(:pull:`708`) -* 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.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`) -* Added ability for :py:func:`pvlib.soiling.hsu` to accept arbitrary time intervals. (:pull:`980`) Bug fixes ~~~~~~~~~ From 43915406cdd550b144e735fd4db9409fca765801 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 2 Sep 2020 15:14:21 -0500 Subject: [PATCH 28/30] Update pvsystem.py --- pvlib/pvsystem.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index f658dac2fa..2134801c8d 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2352,18 +2352,6 @@ def combine_loss_factors(index, *losses, fill_method='ffill'): return 1 - combined_factor -ashraeiam = deprecated('0.7', alternative='iam.ashrae', name='ashraeiam', - removal='0.8')(iam.ashrae) - - -physicaliam = deprecated('0.7', alternative='iam.physical', name='physicaliam', - removal='0.8')(iam.physical) - - -sapm_aoi_loss = deprecated('0.7', alternative='iam.sapm', name='sapm_aoi_loss', - removal='0.8')(iam.sapm) - - snlinverter = deprecated('0.8', alternative='inverter.sandia', name='snlinverter', removal='0.9')(inverter.sandia) From 1af48540977cbe512c3178d3c62bec5fb5f9b504 Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 2 Sep 2020 15:15:28 -0500 Subject: [PATCH 29/30] Update test_pvsystem.py --- pvlib/tests/test_pvsystem.py | 88 ------------------------------------ 1 file changed, 88 deletions(-) diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index f39d633c25..2ad26937b4 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -1311,94 +1311,6 @@ def test_combine_loss_factors(): assert_series_equal(expected, out) -@fail_on_pvlib_version('0.8') -def test_deprecated_08(): - # deprecated function pvsystem.sapm_celltemp - with pytest.warns(pvlibDeprecationWarning): - pvsystem.sapm_celltemp(1000, 25, 1) - # deprecated function pvsystem.pvsyst_celltemp - with pytest.warns(pvlibDeprecationWarning): - pvsystem.pvsyst_celltemp(1000, 25) - module_parameters = {'R_sh_ref': 1, 'a_ref': 1, 'I_o_ref': 1, - 'alpha_sc': 1, 'I_L_ref': 1, 'R_s': 1, - 'B5': 0.0, 'B4': 0.0, 'B3': 0.0, 'B2': 0.0, - 'B1': 0.0, 'B0': 1.0, - 'b': 0.05, 'K': 4, 'L': 0.002, 'n': 1.526, - 'a_r': 0.16} - temp_model_params = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][ - 'open_rack_glass_glass'] - # for missing temperature_model_parameters - with pytest.warns(pvlibDeprecationWarning): - pvsystem.PVSystem(module_parameters=module_parameters, - racking_model='open', module_type='glass_glass') - pv = pvsystem.PVSystem(module_parameters=module_parameters, - temperature_model_parameters=temp_model_params, - racking_model='open', module_type='glass_glass') - # deprecated method PVSystem.ashraeiam - with pytest.warns(pvlibDeprecationWarning): - pv.ashraeiam(45) - # deprecated function ashraeiam - with pytest.warns(pvlibDeprecationWarning): - pvsystem.ashraeiam(45) - # deprecated method PVSystem.physicaliam - with pytest.warns(pvlibDeprecationWarning): - pv.physicaliam(45) - # deprecated function physicaliam - with pytest.warns(pvlibDeprecationWarning): - pvsystem.physicaliam(45) - # deprecated method PVSystem.sapm_aoi_loss - with pytest.warns(pvlibDeprecationWarning): - pv.sapm_aoi_loss(45) - # deprecated function sapm_aoi_loss - with pytest.warns(pvlibDeprecationWarning): - pvsystem.sapm_aoi_loss(45, {'B5': 0.0, 'B4': 0.0, 'B3': 0.0, 'B2': 0.0, - 'B1': 0.0, 'B0': 1.0}) - - -@fail_on_pvlib_version('0.8') -def test__pvsyst_celltemp_translator(): - result = pvsystem._pvsyst_celltemp_translator(900, 20, 5) - assert_allclose(result, 45.137, 0.001) - result = pvsystem._pvsyst_celltemp_translator(900, 20, 5, 0.1, 0.9, - [29.0, 0.0]) - assert_allclose(result, 45.137, 0.001) - result = pvsystem._pvsyst_celltemp_translator(poa_global=900, temp_air=20, - wind_speed=5) - assert_allclose(result, 45.137, 0.001) - result = pvsystem._pvsyst_celltemp_translator(900, 20, wind_speed=5) - assert_allclose(result, 45.137, 0.001) - result = pvsystem._pvsyst_celltemp_translator(900, 20, wind_speed=5.0, - u_c=23.5, u_v=6.25, - eta_m=0.1) - assert_allclose(result, 33.315, 0.001) - result = pvsystem._pvsyst_celltemp_translator(900, 20, wind_speed=5.0, - eta_m=0.1, - model_params=[23.5, 6.25]) - assert_allclose(result, 33.315, 0.001) - result = pvsystem._pvsyst_celltemp_translator(900, 20, wind_speed=5.0, - eta_m=0.1, - model_params=(23.5, 6.25)) - assert_allclose(result, 33.315, 0.001) - - -@fail_on_pvlib_version('0.8') -def test__sapm_celltemp_translator(): - result = pvsystem._sapm_celltemp_translator(900, 5, 20, - 'open_rack_glass_glass') - assert_allclose(result, 43.509, 3) - result = pvsystem._sapm_celltemp_translator(900, 5, temp_air=20, - model='open_rack_glass_glass') - assert_allclose(result, 43.509, 3) - params = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][ - 'open_rack_glass_glass'] - result = pvsystem._sapm_celltemp_translator(900, 5, 20, params) - assert_allclose(result, 43.509, 3) - result = pvsystem._sapm_celltemp_translator(900, 5, 20, - [params['a'], params['b'], - params['deltaT']]) - assert_allclose(result, 43.509, 3) - - @fail_on_pvlib_version('0.9') def test_deprecated_09(cec_inverter_parameters, adr_inverter_parameters): # deprecated function pvsystem.snlinverter From 70f2fa83c98683eb2b6004e12acbd25a15727b6c Mon Sep 17 00:00:00 2001 From: btaute Date: Wed, 2 Sep 2020 16:36:05 -0500 Subject: [PATCH 30/30] Update v0.8.0.rst --- docs/sphinx/source/whatsnew/v0.8.0.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index f878038eab..b64c839a29 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -75,6 +75,23 @@ Enhancements * Add :py:func:`pvlib.iam.marion_diffuse` and :py:func:`pvlib.iam.marion_integrate` to calculate IAM values for diffuse irradiance. (:pull:`984`) +* Add :py:func:`pvlib.shading.sky_diffuse_passias`, + :py:func:`pvlib.shading.masking_angle_passias`, and + :py:func:`pvlib.shading.masking_angle` to model diffuse shading loss. + (: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 :py:func:`pvlib.ivtools.sdm.fit_pvsyst_sandia` and :py:func:`pvlib.ivtools.sdm.fit_desoto_sandia` + for fitting the Pvsyst and De Soto models to IV curve data (:issue:`227`)(:pull:`708`) +* 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.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`) +* Added ability for :py:func:`pvlib.soiling.hsu` to accept arbitrary time intervals. (:pull:`980`) * Add :py:func:`pvlib.pvsystem.combine_loss_factors` as general purpose function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute`