From d8a88369d32cf477d5f0fc107c49bd9a67d840d9 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 11:31:48 -0600 Subject: [PATCH 01/11] change sapm effective_irradiance to W/m2 --- pvlib/pvsystem.py | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 332a43b9a0..b0972cc0e3 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -404,21 +404,12 @@ def sapm(self, effective_irradiance, temp_cell, **kwargs): Parameters ---------- - poa_direct : Series - The direct irradiance incident upon the module (W/m^2). - - poa_diffuse : Series - The diffuse irradiance incident on module. + effective_irradiance : Series + The effective irradiance incident upon the module (W/m^2). temp_cell : Series The cell temperature (degrees C). - airmass_absolute : Series - Absolute airmass. - - aoi : Series - Angle of incidence (degrees). - **kwargs See pvsystem.sapm for details @@ -505,7 +496,7 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse, Returns ------- effective_irradiance : numeric - The SAPM effective irradiance. + The SAPM effective irradiance in W/m^2. """ return sapm_effective_irradiance( poa_direct, poa_diffuse, airmass_absolute, aoi, @@ -1649,7 +1640,7 @@ def _parse_raw_sam_df(csvdata): return df -def sapm(effective_irradiance, temp_cell, module): +def sapm(effective_irradiance, temp_cell, module, reference_irradiance=1000): ''' The Sandia PV Array Performance Model (SAPM) generates 5 points on a PV module's I-V curve (Voc, Isc, Ix, Ixx, Vmp/Imp) according to @@ -1658,7 +1649,7 @@ def sapm(effective_irradiance, temp_cell, module): Parameters ---------- effective_irradiance : numeric - Effective irradiance (suns). + Effective irradiance (W/m^2). temp_cell : numeric The cell temperature (degrees C). @@ -1667,6 +1658,9 @@ def sapm(effective_irradiance, temp_cell, module): A dict, Series, or DataFrame defining the SAPM performance parameters. See the notes section for more details. + reference_irradiance : float + Default 1000 W/m^2. + Returns ------- A DataFrame with the columns: @@ -1739,7 +1733,7 @@ def sapm(effective_irradiance, temp_cell, module): kb = 1.38066e-23 # Boltzmann's constant in units of J/K # avoid problem with integer input - Ee = np.array(effective_irradiance, dtype='float64') + Ee = np.array(effective_irradiance, dtype='float64') / reference_irradiance # set up masking for 0, positive, and nan inputs Ee_gt_0 = np.full_like(Ee, False, dtype='bool') @@ -1986,7 +1980,7 @@ def sapm_aoi_loss(aoi, module, upper=None): def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi, - module, reference_irradiance=1000): + module): """ Calculates the SAPM effective irradiance using the SAPM spectral loss and SAPM angle of incidence loss functions. @@ -2010,21 +2004,16 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi, parameters. See the :py:func:`sapm` notes section for more details. - reference_irradiance : numeric, default 1000 - Reference irradiance by which to divide the input irradiance. - Returns ------- effective_irradiance : numeric - The SAPM effective irradiance. + The SAPM effective irradiance in W/m^2. """ F1 = sapm_spectral_loss(airmass_absolute, module) F2 = sapm_aoi_loss(aoi, module) - E0 = reference_irradiance - - Ee = F1 * (poa_direct*F2 + module['FD']*poa_diffuse) / E0 + Ee = F1 * (poa_direct*F2 + module['FD']*poa_diffuse) return Ee From 00dcf1a6c6f0c0e71ef058255f279f6e1155f0a1 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 11:40:29 -0600 Subject: [PATCH 02/11] update PVSystem.sapm_effective_irradiance --- pvlib/pvsystem.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index b0972cc0e3..1f8371e033 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -469,8 +469,7 @@ def sapm_aoi_loss(self, aoi): return sapm_aoi_loss(aoi, self.module_parameters) def sapm_effective_irradiance(self, poa_direct, poa_diffuse, - airmass_absolute, aoi, - reference_irradiance=1000): + airmass_absolute, aoi): """ Use the :py:func:`sapm_effective_irradiance` function, the input parameters, and ``self.module_parameters`` to calculate @@ -490,9 +489,6 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse, aoi : numeric Angle of incidence in degrees. - reference_irradiance : numeric, default 1000 - Reference irradiance by which to divide the input irradiance. - Returns ------- effective_irradiance : numeric @@ -500,7 +496,7 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse, """ return sapm_effective_irradiance( poa_direct, poa_diffuse, airmass_absolute, aoi, - self.module_parameters, reference_irradiance=reference_irradiance) + self.module_parameters) def first_solar_spectral_loss(self, pw, airmass_absolute): From 8f85b55e262eecb38feacf0ef969036e5c6488f1 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 11:40:42 -0600 Subject: [PATCH 03/11] update whatsnew --- docs/sphinx/source/whatsnew/v0.6.1.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.6.1.rst b/docs/sphinx/source/whatsnew/v0.6.1.rst index c462a2c776..e3a697d787 100644 --- a/docs/sphinx/source/whatsnew/v0.6.1.rst +++ b/docs/sphinx/source/whatsnew/v0.6.1.rst @@ -24,6 +24,9 @@ API Changes * Changed function name from :py:func:`pvlib.solarposition.get_rise_set_transit` (deprecated) to :py:func:`pvlib.solarposition.sun_rise_set_transit_spa. `sun_rise_set_transit_spa` requires time input to be localized to the specified latitude/longitude. (:issue:`316') +* Changed function :py:func:`pvlib.pvsystem.sapm` to expect input `effective_irradiance` + in units of W/m2 rather than suns. Changed output of function + :py:func:`sapm_effective_irradiance` to units of W/m2 rather than suns. Enhancements From fd51223b0628e150972df83b8d6d2b8885b91b23 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 11:50:21 -0600 Subject: [PATCH 04/11] update unit tests for sapm_effective_irradiance --- pvlib/test/test_pvsystem.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index c0e89c5095..12cb59560c 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -331,16 +331,16 @@ def test_PVSystem_sapm_aoi_loss(sapm_module_params, mocker): @pytest.mark.parametrize('test_input,expected', [ - ([1000, 100, 5, 45, 1000], 1.1400510967821877), + ([1000, 100, 5, 45, 1000], 1140.0510967821877), ([np.array([np.nan, 1000, 1000]), np.array([100, np.nan, 100]), np.array([1.1, 1.1, 1.1]), np.array([10, 10, 10]), 1000], - np.array([np.nan, np.nan, 1.081157])), + np.array([np.nan, np.nan, 1081.157])), ([pd.Series([1000]), pd.Series([100]), pd.Series([1.1]), pd.Series([10]), 1370], - pd.Series([0.789166])) + pd.Series([789.166])) ]) def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): @@ -368,14 +368,11 @@ def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker): poa_diffuse = 100 airmass_absolute = 1.5 aoi = 0 - reference_irradiance = 1000 out = system.sapm_effective_irradiance( - poa_direct, poa_diffuse, airmass_absolute, - aoi, reference_irradiance=reference_irradiance) + poa_direct, poa_diffuse, airmass_absolute, aoi) pvsystem.sapm_effective_irradiance.assert_called_once_with( - poa_direct, poa_diffuse, airmass_absolute, aoi, sapm_module_params, - reference_irradiance=reference_irradiance) + poa_direct, poa_diffuse, airmass_absolute, aoi, sapm_module_params) assert_allclose(out, 1, atol=0.1) From c0ef9668f7886197b548f9680c1c502432034648 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 11:53:54 -0600 Subject: [PATCH 05/11] update units tests for sapm --- pvlib/test/test_pvsystem.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 12cb59560c..65dad1009d 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -195,10 +195,13 @@ def pvsyst_module_params(): def test_sapm(sapm_module_params): times = pd.DatetimeIndex(start='2015-01-01', periods=5, freq='12H') - effective_irradiance = pd.Series([-1, 0.5, 1.1, np.nan, 1], index=times) + effective_irradiance = pd.Series([-1000, 500, 1100, np.nan, 1000], + index=times) temp_cell = pd.Series([10, 25, 50, 25, np.nan], index=times) + reference_irradiance = 1000 - out = pvsystem.sapm(effective_irradiance, temp_cell, sapm_module_params) + out = pvsystem.sapm(effective_irradiance, temp_cell, sapm_module_params, + reference_irradiance) expected = pd.DataFrame(np.array( [[ -5.0608322 , -4.65037767, nan, nan, @@ -238,7 +241,7 @@ def test_sapm(sapm_module_params): def test_PVSystem_sapm(sapm_module_params, mocker): mocker.spy(pvsystem, 'sapm') system = pvsystem.PVSystem(module_parameters=sapm_module_params) - effective_irradiance = 0.5 + effective_irradiance = 500 temp_cell = 25 out = system.sapm(effective_irradiance, temp_cell) pvsystem.sapm.assert_called_once_with(effective_irradiance, temp_cell, From 6412743ca542b545cafb6438ec03014166eb7287 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 13:13:31 -0600 Subject: [PATCH 06/11] remove kwarg reference_irradiance from sapm_effective_irradiance unit test --- pvlib/test/test_pvsystem.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 65dad1009d..b66336ec37 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -334,28 +334,21 @@ def test_PVSystem_sapm_aoi_loss(sapm_module_params, mocker): @pytest.mark.parametrize('test_input,expected', [ - ([1000, 100, 5, 45, 1000], 1140.0510967821877), + ([1000, 100, 5, 45], 1140.0510967821877), ([np.array([np.nan, 1000, 1000]), np.array([100, np.nan, 100]), np.array([1.1, 1.1, 1.1]), - np.array([10, 10, 10]), - 1000], + np.array([10, 10, 10])], np.array([np.nan, np.nan, 1081.157])), ([pd.Series([1000]), pd.Series([100]), pd.Series([1.1]), - pd.Series([10]), 1370], + pd.Series([10])], pd.Series([789.166])) ]) def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): - try: - kwargs = {'reference_irradiance': test_input[4]} - test_input = test_input[:-1] - except IndexError: - kwargs = {} - test_input.append(sapm_module_params) - out = pvsystem.sapm_effective_irradiance(*test_input, **kwargs) + out = pvsystem.sapm_effective_irradiance(test_input) if isinstance(test_input, pd.Series): assert_series_equal(out, expected, check_less_precise=4) From 6e7d1c7a351a091141e0db8305b688ccd9be46a3 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 13:33:53 -0600 Subject: [PATCH 07/11] correct tuple argument --- pvlib/test/test_pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index b66336ec37..b6a9703436 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -348,7 +348,7 @@ def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): test_input.append(sapm_module_params) - out = pvsystem.sapm_effective_irradiance(test_input) + out = pvsystem.sapm_effective_irradiance(*test_input) if isinstance(test_input, pd.Series): assert_series_equal(out, expected, check_less_precise=4) From ad8f5b125b247eed35d6e83c07eb426716e0afb7 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 19 Oct 2018 13:58:25 -0600 Subject: [PATCH 08/11] test fixes for test_sapm_effective_irradiance --- pvlib/pvsystem.py | 2 +- pvlib/test/test_pvsystem.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 1f8371e033..6ae92869be 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -2009,7 +2009,7 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi, F1 = sapm_spectral_loss(airmass_absolute, module) F2 = sapm_aoi_loss(aoi, module) - Ee = F1 * (poa_direct*F2 + module['FD']*poa_diffuse) + Ee = F1 * (poa_direct * F2 + module['FD'] * poa_diffuse) return Ee diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index b6a9703436..55887f366c 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -342,7 +342,7 @@ def test_PVSystem_sapm_aoi_loss(sapm_module_params, mocker): np.array([np.nan, np.nan, 1081.157])), ([pd.Series([1000]), pd.Series([100]), pd.Series([1.1]), pd.Series([10])], - pd.Series([789.166])) + pd.Series([1081.11573])) ]) def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): @@ -353,7 +353,7 @@ def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): if isinstance(test_input, pd.Series): assert_series_equal(out, expected, check_less_precise=4) else: - assert_allclose(out, expected, atol=1e-4) + assert_allclose(out, expected, atol=1e-2) def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker): @@ -369,7 +369,7 @@ def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker): poa_direct, poa_diffuse, airmass_absolute, aoi) pvsystem.sapm_effective_irradiance.assert_called_once_with( poa_direct, poa_diffuse, airmass_absolute, aoi, sapm_module_params) - assert_allclose(out, 1, atol=0.1) + assert_allclose(out, 1000, atol=0.1) def test_calcparams_desoto(cec_module_params): From 6506e2cf481f1f5612ea9217595825ebf70d59c1 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 24 Oct 2018 11:19:59 -0600 Subject: [PATCH 09/11] Revert "update whatsnew" This reverts commit 8f85b55e262eecb38feacf0ef969036e5c6488f1. --- docs/sphinx/source/whatsnew/v0.6.1.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.6.1.rst b/docs/sphinx/source/whatsnew/v0.6.1.rst index e3a697d787..c462a2c776 100644 --- a/docs/sphinx/source/whatsnew/v0.6.1.rst +++ b/docs/sphinx/source/whatsnew/v0.6.1.rst @@ -24,9 +24,6 @@ API Changes * Changed function name from :py:func:`pvlib.solarposition.get_rise_set_transit` (deprecated) to :py:func:`pvlib.solarposition.sun_rise_set_transit_spa. `sun_rise_set_transit_spa` requires time input to be localized to the specified latitude/longitude. (:issue:`316') -* Changed function :py:func:`pvlib.pvsystem.sapm` to expect input `effective_irradiance` - in units of W/m2 rather than suns. Changed output of function - :py:func:`sapm_effective_irradiance` to units of W/m2 rather than suns. Enhancements From 32bbc451aaa2d90eed815302fb589a8cf0bf131e Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 24 Oct 2018 12:41:51 -0600 Subject: [PATCH 10/11] adjust ModelChain.sapm --- pvlib/modelchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index b1e5f07b82..35e23a3559 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -414,7 +414,7 @@ def infer_dc_model(self): 'system.module_parameters') def sapm(self): - self.dc = self.system.sapm(self.effective_irradiance/1000., + self.dc = self.system.sapm(self.effective_irradiance, self.temps['temp_cell']) self.dc = self.system.scale_voltage_current_power(self.dc) From 425ba08f37bc3140f7bb1a7b2dc6bbeb19a7cd48 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 24 Oct 2018 13:27:51 -0600 Subject: [PATCH 11/11] more test fixes --- pvlib/test/test_pvsystem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 55887f366c..210d9e3bf8 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -219,7 +219,7 @@ def test_sapm(sapm_module_params): assert_frame_equal(out, expected, check_less_precise=4) - out = pvsystem.sapm(1, 25, sapm_module_params) + out = pvsystem.sapm(1000, 25, sapm_module_params) expected = OrderedDict() expected['i_sc'] = 5.09115 @@ -353,7 +353,7 @@ def test_sapm_effective_irradiance(sapm_module_params, test_input, expected): if isinstance(test_input, pd.Series): assert_series_equal(out, expected, check_less_precise=4) else: - assert_allclose(out, expected, atol=1e-2) + assert_allclose(out, expected, atol=1) def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker): @@ -369,7 +369,7 @@ def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker): poa_direct, poa_diffuse, airmass_absolute, aoi) pvsystem.sapm_effective_irradiance.assert_called_once_with( poa_direct, poa_diffuse, airmass_absolute, aoi, sapm_module_params) - assert_allclose(out, 1000, atol=0.1) + assert_allclose(out, 1000, atol=1) def test_calcparams_desoto(cec_module_params):