From 4cf996105a66d157251466273cc2834f0c4a5fef Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:33:07 +0100 Subject: [PATCH 01/35] create --- pvlib/spectrum/__init__.py | 3 ++- pvlib/spectrum/mismatch.py | 18 ++++++++++++++++++ pvlib/tests/test_spectrum.py | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pvlib/spectrum/__init__.py b/pvlib/spectrum/__init__.py index b95f221066..6a0a378267 100644 --- a/pvlib/spectrum/__init__.py +++ b/pvlib/spectrum/__init__.py @@ -10,5 +10,6 @@ spectral_factor_pvspec, spectral_factor_jrc, sr_to_qe, - qe_to_sr + qe_to_sr, + average_photon_energy ) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index d2fc4dcf1d..6ad8470b4e 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -10,6 +10,7 @@ import scipy.constants from scipy.integrate import trapezoid from scipy.interpolate import interp1d +from scipy import constants from pathlib import Path from warnings import warn @@ -1100,3 +1101,20 @@ def qe_to_sr(qe, wavelength=None, normalize=False): spectral_responsivity = normalize_max2one(spectral_responsivity) return spectral_responsivity + + +def average_photon_energy(spectral_irr): + si = spectral_irr + hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) + hclambda.index = si.T.index # set wavelength as the index + pfd = si.div(hclambda) # calculate the photon flux density + + def integrate(e): # define a helper function + return trapezoid(e, x=e.T.index, axis=-1) + + int_si = integrate(si) # integrate spectral irradiance wrt wavelength + int_pfd = integrate(pfd) # integrate photon flux density wrt wavelength + + ape = (1/constants.elementary_charge)*int_si/int_pfd + + return ape diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 969fb819b8..04de39f4e9 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -576,3 +576,18 @@ def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture): assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) qe = spectrum.sr_to_qe(sr) assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) + + +def test_average_photon_energy_series(): + # test that the APE is calculated correctly with single spectrum + # series input + + si = spectrum.get_reference_spectra() + si = si['global'] + + ape = spectrum.average_photon_energy(si) + + expected = 1.45029 + + assert_allclose(ape, expected, rtol=1e-4) + From a9d8dd970445fc60a6cbfc8fd91d36c5abbcdd49 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:39:17 +0100 Subject: [PATCH 02/35] Update spectrum.rst --- .../source/reference/effects_on_pv_system_output/spectrum.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst index 15fd1d09b8..23b5f5bb6d 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst @@ -18,3 +18,4 @@ Spectrum spectrum.spectral_factor_jrc spectrum.sr_to_qe spectrum.qe_to_sr + spectrum.average_photon_energy From 513d7080428a864c07c0e860a466d4a6f73d4dac Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:44:26 +0100 Subject: [PATCH 03/35] Update test_spectrum.py --- pvlib/tests/test_spectrum.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 04de39f4e9..3555621eff 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -590,4 +590,3 @@ def test_average_photon_energy_series(): expected = 1.45029 assert_allclose(ape, expected, rtol=1e-4) - From f376d598d8736cb8b79e9c3df395c5afc6b0316a Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:47:34 +0100 Subject: [PATCH 04/35] Update mismatch.py update docstring --- pvlib/spectrum/mismatch.py | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 6ad8470b4e..4ff4da5091 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1104,6 +1104,54 @@ def qe_to_sr(qe, wavelength=None, normalize=False): def average_photon_energy(spectral_irr): + r""" + Calculate the average photon energy of a spectral irradiance distribution. + + Parameters + ---------- + spectral_irr : numeric + Spectral irradiance [W/m^2)/nm]. + + Returns + ------- + ape : numeric + Average photon energy [eV]. + + Notes + ----- + The average photon energy is an index used to characterise the solar + spectrum. It is calculated based on the principle that a photon's + wavelength is inversely proportional to its energy: + + .. math:: + + E_\gamma = \frac{hc}{\lambda}, + + where \(\lambda\) is the energy of a photon with wavelength \(\lambda\), + \(h\) is Planck's constant, and \(c\) is the speed of light. If one + considers the average energy of all photons within a single spectral + distribution, an indication of the general shape of the spectrum may be + obtained. A higher average photon energy (shorter wavelength) indicates a + blue-shifted spectrum, while a lower average photon energy + (longer wavelength) would indicate a red-shifted spectrum. This value + of the average photon energy can be calculated by dividing the total number + of photons in the spectrum by the total energy in the spectrum as follows: + + ..math:: + \varphi[eV] = \frac{1}{q}\cdot\frac{ + \int_a^b \Phi(\lambda)\,d\lambda} + {\int_a^b E(\lambda)\,d\lambda}. + + \(\Phi(\lambda)\) is the photon flux density as a function of wavelength, + and \(q\) is the elementary charge used here such that the average photon + energy, \(\varphi\), is express in electronvolts (eV). The APE value is + dependent on the integration limits (\a\) and (\b\) + + + References + ---------- + .. [1] + """ si = spectral_irr hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) hclambda.index = si.T.index # set wavelength as the index From 5eb7c1328568d929ee2b7cf39e86fb362d716494 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:48:10 +0100 Subject: [PATCH 05/35] Update mismatch.py --- pvlib/spectrum/mismatch.py | 52 ++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 4ff4da5091..39cce0b665 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1105,53 +1105,67 @@ def qe_to_sr(qe, wavelength=None, normalize=False): def average_photon_energy(spectral_irr): r""" - Calculate the average photon energy of a spectral irradiance distribution. + Calculate the average photon energy of one or more spectral irradiance + distributions. Parameters ---------- - spectral_irr : numeric + spectral_irr : numeric, :py:class:`pandas.Series` or + :py:class:`pandas.DataFrame` Spectral irradiance [W/m^2)/nm]. + A single spectrum must be a :py:class:`pandas.Series` with wavelength as + the index, while multiple spectra must be a :py:class:`pandas.DataFrame` + with column headers as wavelength. Returns ------- - ape : numeric + ape : numeric or array Average photon energy [eV]. Notes ----- - The average photon energy is an index used to characterise the solar - spectrum. It is calculated based on the principle that a photon's - wavelength is inversely proportional to its energy: + The average photon energy (APE) is an index used to characterise the solar + spectrum. It has been used widely in the Physics literature since the + 1900s, but its application for solar spectral irradiance characterisation + in the context of PV performance modelling was proposed in [1]_. The APE + is calculated based on the principle that a photon's wavelength is + inversely proportional to its energy: .. math:: E_\gamma = \frac{hc}{\lambda}, where \(\lambda\) is the energy of a photon with wavelength \(\lambda\), - \(h\) is Planck's constant, and \(c\) is the speed of light. If one - considers the average energy of all photons within a single spectral - distribution, an indication of the general shape of the spectrum may be - obtained. A higher average photon energy (shorter wavelength) indicates a + \(h\) is Planck's constant, and \(c\) is the speed of light. Therefore, + the average energy of all photons within a single spectral + distribution provides an indication of the general shape of the spectrum. + A higher average photon energy (shorter wavelength) indicates a blue-shifted spectrum, while a lower average photon energy (longer wavelength) would indicate a red-shifted spectrum. This value of the average photon energy can be calculated by dividing the total number - of photons in the spectrum by the total energy in the spectrum as follows: + of photons in the spectrum by the total energy in the spectrum as + follows [1]_: ..math:: \varphi[eV] = \frac{1}{q}\cdot\frac{ - \int_a^b \Phi(\lambda)\,d\lambda} - {\int_a^b E(\lambda)\,d\lambda}. - - \(\Phi(\lambda)\) is the photon flux density as a function of wavelength, - and \(q\) is the elementary charge used here such that the average photon - energy, \(\varphi\), is express in electronvolts (eV). The APE value is - dependent on the integration limits (\a\) and (\b\) + \int_a^b \Phi_\lambda \, d\lambda} + {\int_a^b E_\lambda \, d\lambda}. + \(\Phi_\lambda\) is the photon flux density as a function of wavelength, + and \(q\) is the elementary charge used here so that the average photon + energy, \(\varphi\), is expressed in electronvolts (eV). The integration + limits, (\a\) and (\b\), define the wavelength range within which the + APE is calculated. By default, this function will calculate the value for + APE based on full wavelength range of the input spectral irradiance. References ---------- - .. [1] + .. [1] Jardine, C., et al., 2002, January. Influence of spectral effects on + the performance of multijunction amorphous silicon cells. In Proc. + Photovoltaic in Europe Conference (pp. 1756-1759). + """ + si = spectral_irr hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) hclambda.index = si.T.index # set wavelength as the index From 3420a921034c19e0fdfc3dfd3680b737e0ba8179 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 1 Aug 2024 22:06:45 +0100 Subject: [PATCH 06/35] Update mismatch.py fix docs typesetting --- pvlib/spectrum/mismatch.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 39cce0b665..fc79d17784 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1112,15 +1112,16 @@ def average_photon_energy(spectral_irr): ---------- spectral_irr : numeric, :py:class:`pandas.Series` or :py:class:`pandas.DataFrame` + Spectral irradiance [W/m^2)/nm]. - A single spectrum must be a :py:class:`pandas.Series` with wavelength as - the index, while multiple spectra must be a :py:class:`pandas.DataFrame` - with column headers as wavelength. + A single spectrum must be a :py:class:`pandas.Series` with wavelength + as the index, while multiple spectra must be a + :py:class:`pandas.DataFrame` with column headers as wavelength. Returns ------- ape : numeric or array - Average photon energy [eV]. + Average Photon Energy [eV]. Notes ----- @@ -1135,12 +1136,12 @@ def average_photon_energy(spectral_irr): E_\gamma = \frac{hc}{\lambda}, - where \(\lambda\) is the energy of a photon with wavelength \(\lambda\), - \(h\) is Planck's constant, and \(c\) is the speed of light. Therefore, - the average energy of all photons within a single spectral - distribution provides an indication of the general shape of the spectrum. - A higher average photon energy (shorter wavelength) indicates a - blue-shifted spectrum, while a lower average photon energy + where :math:`E_\gamma` is the energy of a photon with wavelength + :math:`\lambda`, :math:`h` is the Planck constant, and :math:`c` is the + speed of light. Therefore, the average energy of all photons within a + single spectral distribution provides an indication of the general shape of + the spectrum. A higher average photon energy (shorter wavelength) indicates + a blue-shifted spectrum, while a lower average photon energy (longer wavelength) would indicate a red-shifted spectrum. This value of the average photon energy can be calculated by dividing the total number of photons in the spectrum by the total energy in the spectrum as @@ -1151,12 +1152,13 @@ def average_photon_energy(spectral_irr): \int_a^b \Phi_\lambda \, d\lambda} {\int_a^b E_\lambda \, d\lambda}. - \(\Phi_\lambda\) is the photon flux density as a function of wavelength, - and \(q\) is the elementary charge used here so that the average photon - energy, \(\varphi\), is expressed in electronvolts (eV). The integration - limits, (\a\) and (\b\), define the wavelength range within which the - APE is calculated. By default, this function will calculate the value for - APE based on full wavelength range of the input spectral irradiance. + :math:`\Phi_\lambda` is the photon flux density as a function of + wavelength, :math:`q` is the elementary charge used here so that the + average photon energy, :math:`\varphi`, is expressed in electronvolts (eV). + The integration limits, :math:`a` and :math:`b`, define the wavelength + range within which the APE is calculated. By default, this function + calculates the value for APE based on full wavelength range of the + ``spectral_irr`` parameter. References ---------- From c2049ee2092485e62aee95921eaeb00cea1fea17 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:12:35 +0100 Subject: [PATCH 07/35] Update mismatch.py --- pvlib/spectrum/mismatch.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index fc79d17784..41c26a6f4f 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1110,13 +1110,12 @@ def average_photon_energy(spectral_irr): Parameters ---------- - spectral_irr : numeric, :py:class:`pandas.Series` or - :py:class:`pandas.DataFrame` + spectral_irr : pandas.Series or pandas.DataFrame - Spectral irradiance [W/m^2)/nm]. + Spectral irradiance [math:`Wm^{-2}nm^{-1}`]. A single spectrum must be a :py:class:`pandas.Series` with wavelength - as the index, while multiple spectra must be a - :py:class:`pandas.DataFrame` with column headers as wavelength. + [nm] as the index, while multiple spectra must be a + :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. Returns ------- @@ -1139,17 +1138,17 @@ def average_photon_energy(spectral_irr): where :math:`E_\gamma` is the energy of a photon with wavelength :math:`\lambda`, :math:`h` is the Planck constant, and :math:`c` is the speed of light. Therefore, the average energy of all photons within a - single spectral distribution provides an indication of the general shape of - the spectrum. A higher average photon energy (shorter wavelength) indicates - a blue-shifted spectrum, while a lower average photon energy - (longer wavelength) would indicate a red-shifted spectrum. This value - of the average photon energy can be calculated by dividing the total number - of photons in the spectrum by the total energy in the spectrum as - follows [1]_: + single spectral irradiance distribution provides an indication of the + general shape of the spectrum. A higher average photon energy + (shorter wavelength) indicates a blue-shifted spectrum, while a lower + average photon energy (longer wavelength) would indicate a red-shifted + spectrum. This value of the average photon energy can be calculated by + dividing the total number of photons in the spectrum by the total energy in + the spectrum as follows [1]_: ..math:: - \varphi[eV] = \frac{1}{q}\cdot\frac{ - \int_a^b \Phi_\lambda \, d\lambda} + + \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \,d\lambda} {\int_a^b E_\lambda \, d\lambda}. :math:`\Phi_\lambda` is the photon flux density as a function of From afb06f43e5b26a801f1497eaf7a80f856467ffaf Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:55:36 +0100 Subject: [PATCH 08/35] docs, tests --- pvlib/spectrum/mismatch.py | 8 ++++---- pvlib/tests/test_spectrum.py | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 41c26a6f4f..be485ad166 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1112,7 +1112,7 @@ def average_photon_energy(spectral_irr): ---------- spectral_irr : pandas.Series or pandas.DataFrame - Spectral irradiance [math:`Wm^{-2}nm^{-1}`]. + Spectral irradiance [:math:`Wm^{-2}nm^{-1}`]. A single spectrum must be a :py:class:`pandas.Series` with wavelength [nm] as the index, while multiple spectra must be a :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. @@ -1146,10 +1146,10 @@ def average_photon_energy(spectral_irr): dividing the total number of photons in the spectrum by the total energy in the spectrum as follows [1]_: - ..math:: + ..math:: - \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \,d\lambda} - {\int_a^b E_\lambda \, d\lambda}. + \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \,d\lambda} + {\int_a^b E_\lambda \, d\lambda}. :math:`\Phi_\lambda` is the photon flux density as a function of wavelength, :math:`q` is the elementary charge used here so that the diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 3555621eff..5b1c95c32b 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -587,6 +587,21 @@ def test_average_photon_energy_series(): ape = spectrum.average_photon_energy(si) - expected = 1.45029 + expected = 1.45017 + + assert_allclose(ape, expected, rtol=1e-4) + + +def test_average_photon_energy_dataframe(): + # test that the APE is calculated correctly with multiple spectra + # dataframe input + + si = spectrum.get_reference_spectra().T + # Generate three spectra and orientate the dataframe according to the + # function requirements + + ape = spectrum.average_photon_energy(si) + + expected = [1.36848, 1.45017, 1.40885] assert_allclose(ape, expected, rtol=1e-4) From 928c38cc8b2db1abc606dd2f597ef80062742e60 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:43:38 +0100 Subject: [PATCH 09/35] docs, data checks, tests add checks in function for negative irradiance and invalid data type add tests for these checks update docs maths typesetting --- pvlib/spectrum/mismatch.py | 19 ++++++++++++++++--- pvlib/tests/test_spectrum.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index be485ad166..1651b7ab03 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1112,7 +1112,9 @@ def average_photon_energy(spectral_irr): ---------- spectral_irr : pandas.Series or pandas.DataFrame - Spectral irradiance [:math:`Wm^{-2}nm^{-1}`]. + Spectral irradiance, must be positive. + :raw-latex:`\mathrm{Wm^{-2}nm^{-1}}`. + A single spectrum must be a :py:class:`pandas.Series` with wavelength [nm] as the index, while multiple spectra must be a :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. @@ -1146,9 +1148,9 @@ def average_photon_energy(spectral_irr): dividing the total number of photons in the spectrum by the total energy in the spectrum as follows [1]_: - ..math:: + .. math:: - \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \,d\lambda} + \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \, d\lambda} {\int_a^b E_\lambda \, d\lambda}. :math:`\Phi_\lambda` is the photon flux density as a function of @@ -1168,6 +1170,16 @@ def average_photon_energy(spectral_irr): """ si = spectral_irr + + if not isinstance(si, (pd.Series, pd.DataFrame)): + raise TypeError('`spectral_irr` must be either a' + ' pandas Series or DataFrame') + # check si type + + if (si < 0).any().any(): + raise ValueError('Spectral irradiance data must be positive') + # check if si contains any negative irradiance values + hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) hclambda.index = si.T.index # set wavelength as the index pfd = si.div(hclambda) # calculate the photon flux density @@ -1179,5 +1191,6 @@ def integrate(e): # define a helper function int_pfd = integrate(pfd) # integrate photon flux density wrt wavelength ape = (1/constants.elementary_charge)*int_si/int_pfd + # calculate the average photon energy (ape) in electronvolts (eV) return ape diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 5b1c95c32b..43dc8ef861 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -605,3 +605,31 @@ def test_average_photon_energy_dataframe(): expected = [1.36848, 1.45017, 1.40885] assert_allclose(ape, expected, rtol=1e-4) + + +def test_average_photon_energy_invalid_type(): + # test that spectral_irr argument is either a pandas Series or dataframe + spectral_irr = 5 + with pytest.raises(TypeError, match='must be either a pandas Series or' + ' DataFrame'): + spectrum.average_photon_energy(spectral_irr) + + +def test_average_photon_energy_neg_irr_series(): + # test for handling of negative spectral irradiance values with a + # pandas Series input + + spectral_irr = spectrum.get_reference_spectra()['global']*-1 + + with pytest.raises(ValueError, match='must be positive'): + spectrum.average_photon_energy(spectral_irr) + + +def test_average_photon_energy_neg_irr_dataframe(): + # test for handling of negative spectral irradiance values with a + # pandas Series input + + spectral_irr = spectrum.get_reference_spectra().T*-1 + + with pytest.raises(ValueError, match='must be positive'): + spectrum.average_photon_energy(spectral_irr) From d63298a87586d17d14e136d3faac17c2a7d29b9e Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:10:48 +0100 Subject: [PATCH 10/35] Update mismatch.py still trying to typeset the units without using / / between multiple length units --- pvlib/spectrum/mismatch.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 1651b7ab03..cc5ef86e25 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1112,8 +1112,7 @@ def average_photon_energy(spectral_irr): ---------- spectral_irr : pandas.Series or pandas.DataFrame - Spectral irradiance, must be positive. - :raw-latex:`\mathrm{Wm^{-2}nm^{-1}}`. + Spectral irradiance, must be positive. :math:`\mathrm{Wm^{-2}nm^{-1}}` A single spectrum must be a :py:class:`pandas.Series` with wavelength [nm] as the index, while multiple spectra must be a From 3e46831dfe2a2a46482f9151a513e67ebb00b5c3 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:40:21 +0100 Subject: [PATCH 11/35] Update mismatch.py trying unicode superscript --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index cc5ef86e25..8fecb126aa 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1112,7 +1112,7 @@ def average_photon_energy(spectral_irr): ---------- spectral_irr : pandas.Series or pandas.DataFrame - Spectral irradiance, must be positive. :math:`\mathrm{Wm^{-2}nm^{-1}}` + Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] A single spectrum must be a :py:class:`pandas.Series` with wavelength [nm] as the index, while multiple spectra must be a From 2f4b17e478ca002085556f685262ed4a0745ae46 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:10:47 +0100 Subject: [PATCH 12/35] Apply suggestions from code review Co-authored-by: Kevin Anderson --- pvlib/spectrum/__init__.py | 2 +- pvlib/tests/test_spectrum.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/spectrum/__init__.py b/pvlib/spectrum/__init__.py index 6a0a378267..8d29420bf4 100644 --- a/pvlib/spectrum/__init__.py +++ b/pvlib/spectrum/__init__.py @@ -11,5 +11,5 @@ spectral_factor_jrc, sr_to_qe, qe_to_sr, - average_photon_energy + average_photon_energy, ) diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 43dc8ef861..47bf6b2964 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -627,7 +627,7 @@ def test_average_photon_energy_neg_irr_series(): def test_average_photon_energy_neg_irr_dataframe(): # test for handling of negative spectral irradiance values with a - # pandas Series input + # pandas DataFrame input spectral_irr = spectrum.get_reference_spectra().T*-1 From 5a6641453b502848155bf7e71efbd41bbb4d3959 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:48:53 +0100 Subject: [PATCH 13/35] remove comments, inverse fraction --- pvlib/spectrum/mismatch.py | 16 +++++++--------- pvlib/tests/test_spectrum.py | 5 ----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 8fecb126aa..96677a26c7 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1149,8 +1149,8 @@ def average_photon_energy(spectral_irr): .. math:: - \varphi = \frac{1}{q} \cdot \frac{\int_a^b \Phi_\lambda \, d\lambda} - {\int_a^b E_\lambda \, d\lambda}. + \varphi = \frac{1}{q} \cdot \frac{\int_a^b E_\lambda \, d\lambda} + {\int_a^b \Phi_\lambda \, d\lambda}. :math:`\Phi_\lambda` is the photon flux density as a function of wavelength, :math:`q` is the elementary charge used here so that the @@ -1177,19 +1177,17 @@ def average_photon_energy(spectral_irr): if (si < 0).any().any(): raise ValueError('Spectral irradiance data must be positive') - # check if si contains any negative irradiance values hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) - hclambda.index = si.T.index # set wavelength as the index - pfd = si.div(hclambda) # calculate the photon flux density + hclambda.index = si.T.index + pfd = si.div(hclambda) - def integrate(e): # define a helper function + def integrate(e): return trapezoid(e, x=e.T.index, axis=-1) - int_si = integrate(si) # integrate spectral irradiance wrt wavelength - int_pfd = integrate(pfd) # integrate photon flux density wrt wavelength + int_si = integrate(si) + int_pfd = integrate(pfd) ape = (1/constants.elementary_charge)*int_si/int_pfd - # calculate the average photon energy (ape) in electronvolts (eV) return ape diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 47bf6b2964..367aa3c905 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -597,13 +597,8 @@ def test_average_photon_energy_dataframe(): # dataframe input si = spectrum.get_reference_spectra().T - # Generate three spectra and orientate the dataframe according to the - # function requirements - ape = spectrum.average_photon_energy(si) - expected = [1.36848, 1.45017, 1.40885] - assert_allclose(ape, expected, rtol=1e-4) From ec5bc6c219e16eb202e04d80d769ca6f0938b61f Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:23:34 +0100 Subject: [PATCH 14/35] remove comment --- pvlib/spectrum/mismatch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 96677a26c7..fc6084f835 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -1173,7 +1173,6 @@ def average_photon_energy(spectral_irr): if not isinstance(si, (pd.Series, pd.DataFrame)): raise TypeError('`spectral_irr` must be either a' ' pandas Series or DataFrame') - # check si type if (si < 0).any().any(): raise ValueError('Spectral irradiance data must be positive') From 6cb968989ad641b23230a4c1ce984a058a144bed Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:33:15 +0100 Subject: [PATCH 15/35] Update irradiance.py --- pvlib/spectrum/irradiance.py | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 45846a0046..24a38fd204 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -9,6 +9,8 @@ import pandas as pd from pathlib import Path from functools import partial +from scipy import constants +from scipy.integrate import trapezoid @deprecated( @@ -176,3 +178,92 @@ def get_reference_spectra(wavelengths=None, standard="ASTM G173-03"): ) return standard + + +def average_photon_energy(spectral_irr): + r""" + Calculate the average photon energy of one or more spectral irradiance + distributions. + + Parameters + ---------- + spectral_irr : pandas.Series or pandas.DataFrame + + Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] + + A single spectrum must be a :py:class:`pandas.Series` with wavelength + [nm] as the index, while multiple spectra must be a + :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. + + Returns + ------- + ape : numeric or array + Average Photon Energy [eV]. + + Notes + ----- + The average photon energy (APE) is an index used to characterise the solar + spectrum. It has been used widely in the Physics literature since the + 1900s, but its application for solar spectral irradiance characterisation + in the context of PV performance modelling was proposed in [1]_. The APE + is calculated based on the principle that a photon's wavelength is + inversely proportional to its energy: + + .. math:: + + E_\gamma = \frac{hc}{\lambda}, + + where :math:`E_\gamma` is the energy of a photon with wavelength + :math:`\lambda`, :math:`h` is the Planck constant, and :math:`c` is the + speed of light. Therefore, the average energy of all photons within a + single spectral irradiance distribution provides an indication of the + general shape of the spectrum. A higher average photon energy + (shorter wavelength) indicates a blue-shifted spectrum, while a lower + average photon energy (longer wavelength) would indicate a red-shifted + spectrum. This value of the average photon energy can be calculated by + dividing the total number of photons in the spectrum by the total energy in + the spectrum as follows [1]_: + + .. math:: + + \varphi = \frac{1}{q} \cdot \frac{\int_a^b E_\lambda \, d\lambda} + {\int_a^b \Phi_\lambda \, d\lambda}. + + :math:`\Phi_\lambda` is the photon flux density as a function of + wavelength, :math:`q` is the elementary charge used here so that the + average photon energy, :math:`\varphi`, is expressed in electronvolts (eV). + The integration limits, :math:`a` and :math:`b`, define the wavelength + range within which the APE is calculated. By default, this function + calculates the value for APE based on full wavelength range of the + ``spectral_irr`` parameter. + + References + ---------- + .. [1] Jardine, C., et al., 2002, January. Influence of spectral effects on + the performance of multijunction amorphous silicon cells. In Proc. + Photovoltaic in Europe Conference (pp. 1756-1759). + + """ + + si = spectral_irr + + if not isinstance(si, (pd.Series, pd.DataFrame)): + raise TypeError('`spectral_irr` must be either a' + ' pandas Series or DataFrame') + + if (si < 0).any().any(): + raise ValueError('Spectral irradiance data must be positive') + + hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) + hclambda.index = si.T.index + pfd = si.div(hclambda) + + def integrate(e): + return trapezoid(e, x=e.T.index, axis=-1) + + int_si = integrate(si) + int_pfd = integrate(pfd) + + ape = (1/constants.elementary_charge)*int_si/int_pfd + + return ape From 1720d7dca642f87107622fc6edd1f84ee34f52c0 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:52:22 +0100 Subject: [PATCH 16/35] Update test_irradiance.py --- pvlib/tests/spectrum/test_irradiance.py | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index dd6740a02f..4a68ea9321 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -72,3 +72,55 @@ def test_get_reference_spectra_invalid_reference(): # test that an invalid reference identifier raises a ValueError with pytest.raises(ValueError, match="Invalid standard identifier"): spectrum.get_reference_spectra(standard="invalid") + + +def test_average_photon_energy_series(): + # test that the APE is calculated correctly with single spectrum + # series input + + si = spectrum.get_reference_spectra() + si = si['global'] + + ape = spectrum.average_photon_energy(si) + + expected = 1.45017 + + assert_allclose(ape, expected, rtol=1e-4) + + +def test_average_photon_energy_dataframe(): + # test that the APE is calculated correctly with multiple spectra + # dataframe input + + si = spectrum.get_reference_spectra().T + ape = spectrum.average_photon_energy(si) + expected = [1.36848, 1.45017, 1.40885] + assert_allclose(ape, expected, rtol=1e-4) + + +def test_average_photon_energy_invalid_type(): + # test that spectral_irr argument is either a pandas Series or dataframe + spectral_irr = 5 + with pytest.raises(TypeError, match='must be either a pandas Series or' + ' DataFrame'): + spectrum.average_photon_energy(spectral_irr) + + +def test_average_photon_energy_neg_irr_series(): + # test for handling of negative spectral irradiance values with a + # pandas Series input + + spectral_irr = spectrum.get_reference_spectra()['global']*-1 + + with pytest.raises(ValueError, match='must be positive'): + spectrum.average_photon_energy(spectral_irr) + + +def test_average_photon_energy_neg_irr_dataframe(): + # test for handling of negative spectral irradiance values with a + # pandas DataFrame input + + spectral_irr = spectrum.get_reference_spectra().T*-1 + + with pytest.raises(ValueError, match='must be positive'): + spectrum.average_photon_energy(spectral_irr) \ No newline at end of file From a869f83bff4430b1c2785859f91ced1b653fa70c Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:53:49 +0100 Subject: [PATCH 17/35] Update test_irradiance.py --- pvlib/tests/spectrum/test_irradiance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index 4a68ea9321..d417d18f2e 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -123,4 +123,4 @@ def test_average_photon_energy_neg_irr_dataframe(): spectral_irr = spectrum.get_reference_spectra().T*-1 with pytest.raises(ValueError, match='must be positive'): - spectrum.average_photon_energy(spectral_irr) \ No newline at end of file + spectrum.average_photon_energy(spectral_irr) From af63875213d6446c4581b89e25917b9d4302976c Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:27:33 +0100 Subject: [PATCH 18/35] Update irradiance.py update returns statement, change symbols, suppress runtimewarning for division by zero Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/spectrum/irradiance.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 24a38fd204..992886ae74 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -199,6 +199,8 @@ def average_photon_energy(spectral_irr): ------- ape : numeric or array Average Photon Energy [eV]. + Note: returns ``np.nan`` in the case of 0 Wm⁻²nm⁻¹ spectral irradiance + input. Notes ----- @@ -226,16 +228,15 @@ def average_photon_energy(spectral_irr): .. math:: - \varphi = \frac{1}{q} \cdot \frac{\int_a^b E_\lambda \, d\lambda} - {\int_a^b \Phi_\lambda \, d\lambda}. + \overline{E_\lambda} = \frac{1}{q} \cdot \frac{\int G(\lambda) \, + d\lambda} + {\int \Phi(\lambda) \, d\lambda}. - :math:`\Phi_\lambda` is the photon flux density as a function of + :math:`\Phi(\lambda)` is the photon flux density as a function of wavelength, :math:`q` is the elementary charge used here so that the - average photon energy, :math:`\varphi`, is expressed in electronvolts (eV). - The integration limits, :math:`a` and :math:`b`, define the wavelength - range within which the APE is calculated. By default, this function - calculates the value for APE based on full wavelength range of the - ``spectral_irr`` parameter. + average photon energy, :math:`\overline{E(\lambda)}`, is expressed in + electronvolts (eV). By default, this function calculates the value for APE + based on full wavelength range of the ``spectral_irr`` parameter. References ---------- @@ -264,6 +265,7 @@ def integrate(e): int_si = integrate(si) int_pfd = integrate(pfd) - ape = (1/constants.elementary_charge)*int_si/int_pfd + with np.errstate(invalid='ignore'): + ape = (1/constants.elementary_charge)*int_si/int_pfd return ape From 43ae7d30266312e2531e3390d812abdf014dfed0 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:38:16 +0100 Subject: [PATCH 19/35] mixed up my lambdas and gammas:( --- pvlib/spectrum/irradiance.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 992886ae74..d16e1acb27 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -228,13 +228,14 @@ def average_photon_energy(spectral_irr): .. math:: - \overline{E_\lambda} = \frac{1}{q} \cdot \frac{\int G(\lambda) \, + \overline{E_\gamma} = \frac{1}{q} \cdot \frac{\int G(\lambda) \, d\lambda} {\int \Phi(\lambda) \, d\lambda}. :math:`\Phi(\lambda)` is the photon flux density as a function of - wavelength, :math:`q` is the elementary charge used here so that the - average photon energy, :math:`\overline{E(\lambda)}`, is expressed in + wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the + elementary charge used here so that the average photon energy, + :math:`\overline{E_\gamma}`, is expressed in electronvolts (eV). By default, this function calculates the value for APE based on full wavelength range of the ``spectral_irr`` parameter. From c2c373da83bbb139d388a398c4a6cfd477efdc07 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:59:23 +0100 Subject: [PATCH 20/35] change variable name spectral_irr -> spectrum --- pvlib/spectrum/irradiance.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index d16e1acb27..ec2f8a568d 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -180,7 +180,7 @@ def get_reference_spectra(wavelengths=None, standard="ASTM G173-03"): return standard -def average_photon_energy(spectral_irr): +def average_photon_energy(spectrum): r""" Calculate the average photon energy of one or more spectral irradiance distributions. @@ -247,26 +247,24 @@ def average_photon_energy(spectral_irr): """ - si = spectral_irr - - if not isinstance(si, (pd.Series, pd.DataFrame)): + if not isinstance(spectrum, (pd.Series, pd.DataFrame)): raise TypeError('`spectral_irr` must be either a' ' pandas Series or DataFrame') - if (si < 0).any().any(): + if (spectrum < 0).any().any(): raise ValueError('Spectral irradiance data must be positive') - hclambda = pd.Series((constants.h*constants.c)/(si.T.index*1e-9)) - hclambda.index = si.T.index - pfd = si.div(hclambda) + hclambda = pd.Series((constants.h*constants.c)/(spectrum.T.index*1e-9)) + hclambda.index = spectrum.T.index + pfd = spectrum.div(hclambda) def integrate(e): return trapezoid(e, x=e.T.index, axis=-1) - int_si = integrate(si) + int_spectrum = integrate(spectrum) int_pfd = integrate(pfd) with np.errstate(invalid='ignore'): - ape = (1/constants.elementary_charge)*int_si/int_pfd + ape = (1/constants.elementary_charge)*int_spectrum/int_pfd return ape From 698d9d795f50acf8aacddd18915aa6567d5de73a Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 9 Aug 2024 11:34:44 +0100 Subject: [PATCH 21/35] update variable name in docstring + error messages --- pvlib/spectrum/irradiance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index ec2f8a568d..cdcdb8d122 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -187,7 +187,7 @@ def average_photon_energy(spectrum): Parameters ---------- - spectral_irr : pandas.Series or pandas.DataFrame + spectrum : pandas.Series or pandas.DataFrame Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] @@ -237,7 +237,7 @@ def average_photon_energy(spectrum): elementary charge used here so that the average photon energy, :math:`\overline{E_\gamma}`, is expressed in electronvolts (eV). By default, this function calculates the value for APE - based on full wavelength range of the ``spectral_irr`` parameter. + based on full wavelength range of the ``spectrum`` parameter. References ---------- @@ -248,7 +248,7 @@ def average_photon_energy(spectrum): """ if not isinstance(spectrum, (pd.Series, pd.DataFrame)): - raise TypeError('`spectral_irr` must be either a' + raise TypeError('`spectrum` must be either a' ' pandas Series or DataFrame') if (spectrum < 0).any().any(): From e9919f52578cab314ac49977bb45e550ffdefe35 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:32:04 +0100 Subject: [PATCH 22/35] Update irradiance.py --- pvlib/spectrum/irradiance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index cdcdb8d122..7f234df350 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -236,8 +236,8 @@ def average_photon_energy(spectrum): wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the elementary charge used here so that the average photon energy, :math:`\overline{E_\gamma}`, is expressed in - electronvolts (eV). By default, this function calculates the value for APE - based on full wavelength range of the ``spectrum`` parameter. + electronvolts (eV). By default, this function calculates the value for the + APE based on the full wavelength range of the ``spectrum`` parameter. References ---------- From 458bf16ed2d4053c0471005f975f955bbe81a9fc Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:07:15 +0100 Subject: [PATCH 23/35] Update test_irradiance.py add test for return np.nan in case of zero si input --- pvlib/tests/spectrum/test_irradiance.py | 32 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index d417d18f2e..1cea68bd83 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -99,28 +99,46 @@ def test_average_photon_energy_dataframe(): def test_average_photon_energy_invalid_type(): - # test that spectral_irr argument is either a pandas Series or dataframe - spectral_irr = 5 + # test that spectrum argument is either a pandas Series or dataframe + si = 5 with pytest.raises(TypeError, match='must be either a pandas Series or' ' DataFrame'): - spectrum.average_photon_energy(spectral_irr) + spectrum.average_photon_energy(si) def test_average_photon_energy_neg_irr_series(): # test for handling of negative spectral irradiance values with a # pandas Series input - spectral_irr = spectrum.get_reference_spectra()['global']*-1 + si = spectrum.get_reference_spectra()['global']*-1 with pytest.raises(ValueError, match='must be positive'): - spectrum.average_photon_energy(spectral_irr) + spectrum.average_photon_energy(si) def test_average_photon_energy_neg_irr_dataframe(): # test for handling of negative spectral irradiance values with a # pandas DataFrame input - spectral_irr = spectrum.get_reference_spectra().T*-1 + si = spectrum.get_reference_spectra().T*-1 with pytest.raises(ValueError, match='must be positive'): - spectrum.average_photon_energy(spectral_irr) + spectrum.average_photon_energy(si) + + +def test_average_photon_energy_zero_irr(): + # test for handling of zero spectral irradiance values with + # pandas DataFrame and pandas Series input + + si_df_zero = spectrum.get_reference_spectra().T + si_df_zero.iloc[1] = 0 + si_series_zero = spectrum.get_reference_spectra()['global']*0 + + out_1 = spectrum.average_photon_energy(si_df_zero) + out_2 = spectrum.average_photon_energy(si_series_zero) + + expected_1 = np.array([1.36848, np.nan, 1.40885]) + expected_2 = np.nan + + assert_allclose(out_1, expected_1, atol=1e-3) + assert_allclose(out_2, expected_2, atol=1e-3) From ecba3eb5b0543f41d80632d355634b2576dd402f Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:09:37 +0100 Subject: [PATCH 24/35] Apply suggestions from code review Co-authored-by: Cliff Hansen --- pvlib/spectrum/irradiance.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 7f234df350..673c151345 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -192,7 +192,7 @@ def average_photon_energy(spectrum): Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] A single spectrum must be a :py:class:`pandas.Series` with wavelength - [nm] as the index, while multiple spectra must be a + [nm] as the index, while multiple spectra must be rows in a :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. Returns @@ -208,8 +208,8 @@ def average_photon_energy(spectrum): spectrum. It has been used widely in the Physics literature since the 1900s, but its application for solar spectral irradiance characterisation in the context of PV performance modelling was proposed in [1]_. The APE - is calculated based on the principle that a photon's wavelength is - inversely proportional to its energy: + is calculated based on the principle that a photon's energy is + inversely proportional to its wavelength: .. math:: @@ -236,8 +236,7 @@ def average_photon_energy(spectrum): wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the elementary charge used here so that the average photon energy, :math:`\overline{E_\gamma}`, is expressed in - electronvolts (eV). By default, this function calculates the value for the - APE based on the full wavelength range of the ``spectrum`` parameter. + electronvolts (eV). The integrals are computed over the full wavelength range of the ``spectrum`` parameter. References ---------- From 0b953071db6e15cd0a9560b2b7691dfdbf9bc961 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:11:40 +0100 Subject: [PATCH 25/35] Update irradiance.py --- pvlib/spectrum/irradiance.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 673c151345..ad26a898a8 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -205,7 +205,7 @@ def average_photon_energy(spectrum): Notes ----- The average photon energy (APE) is an index used to characterise the solar - spectrum. It has been used widely in the Physics literature since the + spectrum. It has been used widely in the physics literature since the 1900s, but its application for solar spectral irradiance characterisation in the context of PV performance modelling was proposed in [1]_. The APE is calculated based on the principle that a photon's energy is @@ -235,8 +235,9 @@ def average_photon_energy(spectrum): :math:`\Phi(\lambda)` is the photon flux density as a function of wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the elementary charge used here so that the average photon energy, - :math:`\overline{E_\gamma}`, is expressed in - electronvolts (eV). The integrals are computed over the full wavelength range of the ``spectrum`` parameter. + :math:`\overline{E_\gamma}`, is expressed in electronvolts (eV). The + integrals are computed over the full wavelength range of the ``spectrum`` + parameter. References ---------- From 39fe12cf9532f526694b92385db108d9cf40e08b Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Tue, 13 Aug 2024 23:00:33 +0100 Subject: [PATCH 26/35] Update v0.11.1.rst --- docs/sphinx/source/whatsnew/v0.11.1.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.11.1.rst b/docs/sphinx/source/whatsnew/v0.11.1.rst index 2839a0ff25..206cd2de76 100644 --- a/docs/sphinx/source/whatsnew/v0.11.1.rst +++ b/docs/sphinx/source/whatsnew/v0.11.1.rst @@ -10,6 +10,9 @@ Deprecations Enhancements ~~~~~~~~~~~~ +* Add new function to calculate the average photon energy, + :py:func:`pvlib.spectrum.average_photon_energy`. + (:issue:`2135`, :'pull:`2140') * Add new losses function that accounts for non-uniform irradiance on bifacial modules, :py:func:`pvlib.bifacial.power_mismatch_deline`. (:issue:`2045`, :pull:`2046`) From 112747e21678bb1559681abae69fb6ca39fed205 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:56:38 +0100 Subject: [PATCH 27/35] Update irradiance.py apple suggestions from code review Co-Authored-By: Adam R. Jensen <39184289+adamrjensen@users.noreply.github.com> --- pvlib/spectrum/irradiance.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index ad26a898a8..41a2da1491 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -199,7 +199,7 @@ def average_photon_energy(spectrum): ------- ape : numeric or array Average Photon Energy [eV]. - Note: returns ``np.nan`` in the case of 0 Wm⁻²nm⁻¹ spectral irradiance + Note: returns ``np.nan`` in the case of all-zero spectral irradiance input. Notes @@ -207,8 +207,8 @@ def average_photon_energy(spectrum): The average photon energy (APE) is an index used to characterise the solar spectrum. It has been used widely in the physics literature since the 1900s, but its application for solar spectral irradiance characterisation - in the context of PV performance modelling was proposed in [1]_. The APE - is calculated based on the principle that a photon's energy is + in the context of PV performance modelling was proposed in 2002 [1]_. The + APE is calculated based on the principle that a photon's energy is inversely proportional to its wavelength: .. math:: @@ -244,7 +244,6 @@ def average_photon_energy(spectrum): .. [1] Jardine, C., et al., 2002, January. Influence of spectral effects on the performance of multijunction amorphous silicon cells. In Proc. Photovoltaic in Europe Conference (pp. 1756-1759). - """ if not isinstance(spectrum, (pd.Series, pd.DataFrame)): From ddc70c5c6479221485485ea1bc2ee9a82ad66ad4 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:59:20 +0100 Subject: [PATCH 28/35] Update irradiance.py "spectrum" variable --> "spectra" (see #2150) --- pvlib/spectrum/irradiance.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 41a2da1491..2fa021aa27 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -180,14 +180,14 @@ def get_reference_spectra(wavelengths=None, standard="ASTM G173-03"): return standard -def average_photon_energy(spectrum): +def average_photon_energy(spectra): r""" Calculate the average photon energy of one or more spectral irradiance distributions. Parameters ---------- - spectrum : pandas.Series or pandas.DataFrame + spectra : pandas.Series or pandas.DataFrame Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] @@ -236,7 +236,7 @@ def average_photon_energy(spectrum): wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the elementary charge used here so that the average photon energy, :math:`\overline{E_\gamma}`, is expressed in electronvolts (eV). The - integrals are computed over the full wavelength range of the ``spectrum`` + integrals are computed over the full wavelength range of the ``spectra`` parameter. References @@ -246,24 +246,24 @@ def average_photon_energy(spectrum): Photovoltaic in Europe Conference (pp. 1756-1759). """ - if not isinstance(spectrum, (pd.Series, pd.DataFrame)): - raise TypeError('`spectrum` must be either a' + if not isinstance(spectra, (pd.Series, pd.DataFrame)): + raise TypeError('`spectra` must be either a' ' pandas Series or DataFrame') - if (spectrum < 0).any().any(): + if (spectra < 0).any().any(): raise ValueError('Spectral irradiance data must be positive') - hclambda = pd.Series((constants.h*constants.c)/(spectrum.T.index*1e-9)) - hclambda.index = spectrum.T.index - pfd = spectrum.div(hclambda) + hclambda = pd.Series((constants.h*constants.c)/(spectra.T.index*1e-9)) + hclambda.index = spectra.T.index + pfd = spectra.div(hclambda) def integrate(e): return trapezoid(e, x=e.T.index, axis=-1) - int_spectrum = integrate(spectrum) + int_spectra = integrate(spectra) int_pfd = integrate(pfd) with np.errstate(invalid='ignore'): - ape = (1/constants.elementary_charge)*int_spectrum/int_pfd + ape = (1/constants.elementary_charge)*int_spectra/int_pfd return ape From a8e72d8ea08ae0e7d9be7ebc344e6282e8ba0c2f Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:01:55 +0100 Subject: [PATCH 29/35] Update test_irradiance.py "spectrum" variable --> "spectra" (see #2150) --- pvlib/tests/spectrum/test_irradiance.py | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index 1cea68bd83..fdfe6ebb2f 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -78,10 +78,10 @@ def test_average_photon_energy_series(): # test that the APE is calculated correctly with single spectrum # series input - si = spectrum.get_reference_spectra() - si = si['global'] + spectra = spectrum.get_reference_spectra() + spectra = spectra['global'] - ape = spectrum.average_photon_energy(si) + ape = spectrum.average_photon_energy(spectra) expected = 1.45017 @@ -92,50 +92,50 @@ def test_average_photon_energy_dataframe(): # test that the APE is calculated correctly with multiple spectra # dataframe input - si = spectrum.get_reference_spectra().T - ape = spectrum.average_photon_energy(si) + spectra = spectrum.get_reference_spectra().T + ape = spectrum.average_photon_energy(spectra) expected = [1.36848, 1.45017, 1.40885] assert_allclose(ape, expected, rtol=1e-4) def test_average_photon_energy_invalid_type(): # test that spectrum argument is either a pandas Series or dataframe - si = 5 + spectra = 5 with pytest.raises(TypeError, match='must be either a pandas Series or' ' DataFrame'): - spectrum.average_photon_energy(si) + spectrum.average_photon_energy(spectra) def test_average_photon_energy_neg_irr_series(): # test for handling of negative spectral irradiance values with a # pandas Series input - si = spectrum.get_reference_spectra()['global']*-1 + spectra = spectrum.get_reference_spectra()['global']*-1 with pytest.raises(ValueError, match='must be positive'): - spectrum.average_photon_energy(si) + spectrum.average_photon_energy(spectra) def test_average_photon_energy_neg_irr_dataframe(): # test for handling of negative spectral irradiance values with a # pandas DataFrame input - si = spectrum.get_reference_spectra().T*-1 + spectra = spectrum.get_reference_spectra().T*-1 with pytest.raises(ValueError, match='must be positive'): - spectrum.average_photon_energy(si) + spectrum.average_photon_energy(spectra) def test_average_photon_energy_zero_irr(): # test for handling of zero spectral irradiance values with # pandas DataFrame and pandas Series input - si_df_zero = spectrum.get_reference_spectra().T - si_df_zero.iloc[1] = 0 - si_series_zero = spectrum.get_reference_spectra()['global']*0 + spectra_df_zero = spectrum.get_reference_spectra().T + spectra_df_zero.iloc[1] = 0 + spectra_series_zero = spectrum.get_reference_spectra()['global']*0 - out_1 = spectrum.average_photon_energy(si_df_zero) - out_2 = spectrum.average_photon_energy(si_series_zero) + out_1 = spectrum.average_photon_energy(spectra_df_zero) + out_2 = spectrum.average_photon_energy(spectra_series_zero) expected_1 = np.array([1.36848, np.nan, 1.40885]) expected_2 = np.nan From 80bf69036c00def12f710a30f1c38a6a46c1a9ce Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:58:48 +0100 Subject: [PATCH 30/35] Update test_mismatch.py remove unintentional change --- pvlib/tests/spectrum/test_mismatch.py | 104 -------------------------- 1 file changed, 104 deletions(-) diff --git a/pvlib/tests/spectrum/test_mismatch.py b/pvlib/tests/spectrum/test_mismatch.py index cb851b44c9..5397a81f46 100644 --- a/pvlib/tests/spectrum/test_mismatch.py +++ b/pvlib/tests/spectrum/test_mismatch.py @@ -302,107 +302,3 @@ def test_spectral_factor_jrc_supplied_ambiguous(): with pytest.raises(ValueError, match='No valid input provided'): spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None, coefficients=None) - - -@pytest.fixture -def sr_and_eqe_fixture(): - # Just some arbitrary data for testing the conversion functions - df = pd.DataFrame( - columns=("wavelength", "quantum_efficiency", "spectral_response"), - data=[ - # nm, [0,1], A/W - [300, 0.85, 0.205671370402405], - [350, 0.86, 0.242772872514211], - [400, 0.87, 0.280680929019753], - [450, 0.88, 0.319395539919029], - [500, 0.89, 0.358916705212040], - [550, 0.90, 0.399244424898786], - [600, 0.91, 0.440378698979267], - [650, 0.92, 0.482319527453483], - [700, 0.93, 0.525066910321434], - [750, 0.94, 0.568620847583119], - [800, 0.95, 0.612981339238540], - [850, 0.90, 0.617014111207215], - [900, 0.80, 0.580719163489143], - [950, 0.70, 0.536358671833723], - [1000, 0.6, 0.483932636240953], - [1050, 0.4, 0.338752845368667], - ], - ) - df.set_index("wavelength", inplace=True) - return df - - -def test_sr_to_qe(sr_and_eqe_fixture): - # vector type - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"].values, - sr_and_eqe_fixture.index.values, # wavelength, nm - ) - assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) - # pandas series type - # note: output Series' name should match the input - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"] - ) - pd.testing.assert_series_equal( - qe, sr_and_eqe_fixture["quantum_efficiency"], - check_names=False - ) - assert qe.name == "spectral_response" - # series normalization - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"] * 10, normalize=True - ) - pd.testing.assert_series_equal( - qe, - sr_and_eqe_fixture["quantum_efficiency"] - / max(sr_and_eqe_fixture["quantum_efficiency"]), - check_names=False, - ) - # error on lack of wavelength parameter if no pandas object is provided - with pytest.raises(TypeError, match="must have an '.index' attribute"): - _ = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"].values) - - -def test_qe_to_sr(sr_and_eqe_fixture): - # vector type - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"].values, - sr_and_eqe_fixture.index.values, # wavelength, nm - ) - assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) - # pandas series type - # note: output Series' name should match the input - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"] - ) - pd.testing.assert_series_equal( - sr, sr_and_eqe_fixture["spectral_response"], - check_names=False - ) - assert sr.name == "quantum_efficiency" - # series normalization - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"] * 10, normalize=True - ) - pd.testing.assert_series_equal( - sr, - sr_and_eqe_fixture["spectral_response"] - / max(sr_and_eqe_fixture["spectral_response"]), - check_names=False, - ) - # error on lack of wavelength parameter if no pandas object is provided - with pytest.raises(TypeError, match="must have an '.index' attribute"): - _ = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"].values - ) - - -def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture): - # test that the conversion functions are reciprocal - qe = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"]) - sr = spectrum.qe_to_sr(qe) - assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) - qe = spectrum.sr_to_qe(sr) - assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) From 1bafc90074d76530cb473d008bc7f84088354976 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:59:47 +0100 Subject: [PATCH 31/35] Update v0.11.1.rst apply suggestion from code review Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- docs/sphinx/source/whatsnew/v0.11.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.11.1.rst b/docs/sphinx/source/whatsnew/v0.11.1.rst index 206cd2de76..093e3b4895 100644 --- a/docs/sphinx/source/whatsnew/v0.11.1.rst +++ b/docs/sphinx/source/whatsnew/v0.11.1.rst @@ -12,7 +12,7 @@ Enhancements ~~~~~~~~~~~~ * Add new function to calculate the average photon energy, :py:func:`pvlib.spectrum.average_photon_energy`. - (:issue:`2135`, :'pull:`2140') + (:issue:`2135`, :`pull:`2140') * Add new losses function that accounts for non-uniform irradiance on bifacial modules, :py:func:`pvlib.bifacial.power_mismatch_deline`. (:issue:`2045`, :pull:`2046`) From 6a212287744ed885fa098e7cb2de33430a12a1e7 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:02:20 +0100 Subject: [PATCH 32/35] Update irradiance.py sentence correction Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/spectrum/irradiance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index 2fa021aa27..a2d2204383 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -223,8 +223,8 @@ def average_photon_energy(spectra): (shorter wavelength) indicates a blue-shifted spectrum, while a lower average photon energy (longer wavelength) would indicate a red-shifted spectrum. This value of the average photon energy can be calculated by - dividing the total number of photons in the spectrum by the total energy in - the spectrum as follows [1]_: + dividing the total energy in the spectrum by the total number of photons + in the spectrum as follows [1]_: .. math:: From c224e05f30a2c0ca20c37422275eccbe7befb771 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:13:42 +0100 Subject: [PATCH 33/35] update output datatype and associated tests return series in case of dataframe input, add test to verify. Remove unnecessary spaces from tests --- pvlib/spectrum/irradiance.py | 5 ++++- pvlib/tests/spectrum/test_irradiance.py | 10 ++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/pvlib/spectrum/irradiance.py b/pvlib/spectrum/irradiance.py index a2d2204383..cb3e5e1ddb 100644 --- a/pvlib/spectrum/irradiance.py +++ b/pvlib/spectrum/irradiance.py @@ -197,7 +197,7 @@ def average_photon_energy(spectra): Returns ------- - ape : numeric or array + ape : numeric or pandas.Series Average Photon Energy [eV]. Note: returns ``np.nan`` in the case of all-zero spectral irradiance input. @@ -266,4 +266,7 @@ def integrate(e): with np.errstate(invalid='ignore'): ape = (1/constants.elementary_charge)*int_spectra/int_pfd + if isinstance(spectra, pd.DataFrame): + ape = pd.Series(ape, index=spectra.index) + return ape diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index fdfe6ebb2f..fb416522c5 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -80,21 +80,19 @@ def test_average_photon_energy_series(): spectra = spectrum.get_reference_spectra() spectra = spectra['global'] - ape = spectrum.average_photon_energy(spectra) - expected = 1.45017 - assert_allclose(ape, expected, rtol=1e-4) def test_average_photon_energy_dataframe(): # test that the APE is calculated correctly with multiple spectra - # dataframe input + # dataframe input and that the output is a series spectra = spectrum.get_reference_spectra().T ape = spectrum.average_photon_energy(spectra) expected = [1.36848, 1.45017, 1.40885] + assert isinstance(ape, pd.Series) assert_allclose(ape, expected, rtol=1e-4) @@ -111,7 +109,6 @@ def test_average_photon_energy_neg_irr_series(): # pandas Series input spectra = spectrum.get_reference_spectra()['global']*-1 - with pytest.raises(ValueError, match='must be positive'): spectrum.average_photon_energy(spectra) @@ -133,12 +130,9 @@ def test_average_photon_energy_zero_irr(): spectra_df_zero = spectrum.get_reference_spectra().T spectra_df_zero.iloc[1] = 0 spectra_series_zero = spectrum.get_reference_spectra()['global']*0 - out_1 = spectrum.average_photon_energy(spectra_df_zero) out_2 = spectrum.average_photon_energy(spectra_series_zero) - expected_1 = np.array([1.36848, np.nan, 1.40885]) expected_2 = np.nan - assert_allclose(out_1, expected_1, atol=1e-3) assert_allclose(out_2, expected_2, atol=1e-3) From ace5a651496917145fc5010dc711e9a01c6e0e08 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:29:32 +0100 Subject: [PATCH 34/35] Update test_irradiance.py update test for datatype according to suggestion from code review --- pvlib/tests/spectrum/test_irradiance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py index fb416522c5..63b0bc95d2 100644 --- a/pvlib/tests/spectrum/test_irradiance.py +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -91,9 +91,9 @@ def test_average_photon_energy_dataframe(): spectra = spectrum.get_reference_spectra().T ape = spectrum.average_photon_energy(spectra) - expected = [1.36848, 1.45017, 1.40885] - assert isinstance(ape, pd.Series) - assert_allclose(ape, expected, rtol=1e-4) + expected = pd.Series([1.36848, 1.45017, 1.40885]) + expected.index = spectra.index + assert_series_equal(ape, expected, rtol=1e-4) def test_average_photon_energy_invalid_type(): From 072eeeb412ab928c783e373788fd9d16e318ace1 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:44:57 +0100 Subject: [PATCH 35/35] Update docs/sphinx/source/whatsnew/v0.11.1.rst Co-authored-by: Kevin Anderson --- docs/sphinx/source/whatsnew/v0.11.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.11.1.rst b/docs/sphinx/source/whatsnew/v0.11.1.rst index 093e3b4895..beaca6c466 100644 --- a/docs/sphinx/source/whatsnew/v0.11.1.rst +++ b/docs/sphinx/source/whatsnew/v0.11.1.rst @@ -12,7 +12,7 @@ Enhancements ~~~~~~~~~~~~ * Add new function to calculate the average photon energy, :py:func:`pvlib.spectrum.average_photon_energy`. - (:issue:`2135`, :`pull:`2140') + (:issue:`2135`, :pull:`2140`) * Add new losses function that accounts for non-uniform irradiance on bifacial modules, :py:func:`pvlib.bifacial.power_mismatch_deline`. (:issue:`2045`, :pull:`2046`)