From 3363ace052d9137480ab715a540e997e07dfa088 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 08:07:02 +0200 Subject: [PATCH 01/23] Add polo-smm Add the polo spectral model for BIPV facades --- pvlib/spectrum/mismatch.py | 99 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 980f0d0165..0fbcd80234 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -710,3 +710,102 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, + coeff[2] * (airmass - 1.5) ) return mismatch + +def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, altitude, + module_type=None, coefficients=None, albedo=0.2): + """ + Estimation of spectral mismatch for BIPV application in vertical facades. + + + + Parameters + ---------- + precipitable_water : numeric + atmospheric precipitable water. [cm] + + airmass_absolute : numeric + absolute (pressure-adjusted) airmass. [unitless] + + aod500 : numeric + atmospheric aerosol optical depth at 500 nm. [unitless] + + aoi : numeric + angle of incidence. [degrees] + + altitude: numeric + altitude over sea level. [m] + + module_type : str, optional + One of the following PV technology strings from [1]_: + + * ``'cdte'`` - anonymous CdTe module. + * ``'monosi'`` - anonymous sc-si module. + * ``'cigs'`` - anonymous copper indium gallium selenide module. + * ``'asi'`` - anonymous amorphous silicon module. + albedo + Ground albedo (default value if 0.2). [unitless] + + coefficients : array-like, optional + user-defined coefficients, if not using one of the default coefficient + sets via the ``module_type`` parameter. + + Returns + ------- + modifier: numeric + spectral mismatch factor (unitless) which is multiplied + with broadband irradiance reaching a module's cells to estimate + effective irradiance, i.e., the irradiance that is converted to + electrical current. + + References + ---------- + [1]. Polo, J., Sanz-saiz, C., Development of spectral mismatch models + for BIPV applications in building façades Abbreviations : Renew. Energy 245, 122820, 2025. + https://doi.org/10.1016/j.renene.2025.122820 + + """ + if module_type is None and coefficients is None: + raise ValueError('Must provide either `module_type` or `coefficients`') + if module_type is not None and coefficients is not None: + raise ValueError('Only one of `module_type` and `coefficients` should ' + 'be provided') + + am_aoi=pvlib.atmosphere.get_relative_airmass(aoi) + pressure=pvlib.atmosphere.alt2pres(altitude) + am90=pvlib.atmosphere.get_absolute_airmass(am_aoi,pressure) + Ram=am90/airmass_absolute + + _coefficients={} + _coefficients['cdte']=( + -0.0009,46.80,49.20,-0.87, 0.00041,0.053 ) + _coefficients['monosi']=( + 0.0027,10.34,9.48,0.307,0.00077,0.006 ) + _coefficients['cigs']=( + 0.0017,2.33,1.30,0.11,0.00098,-0.0177 ) + _coefficients['asi']=( + 0.0024,7.32,7.09,-0.72,-0.0013,0.089 ) + + c={} + c['asi']=(0.0056,-0.020,1.014) + c['cigs']=(-0.0009,-0.0003,1) + c['cdte']=(0.0021,-0.01,1.01) + c['monosi']=(0,-0.003,1.0) + + + if module_type is not None: + coeff = _coefficients[module_type] + c_albedo=c[module_type] + else: + coeff = coefficients + c_albedo=(0.0,0.0,1.0) # 0.2 albedo assumed + albedo=0.2 + + + smm=coeff[0]*Ram+coeff[1]/(coeff[2]+Ram**coeff[3])+coeff[4]/aod500+coeff[5]*np.sqrt(precipitable_water) + # Ground albedo correction + + g=c_albedo[0]*(albedo/0.2)**2+c_albedo[1]*(albedo/0.2)+c_albedo[2] + + + return g*smm + \ No newline at end of file From ceba758c14c346f7e1703e7cadf2aa06c331b25d Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 10:39:48 +0200 Subject: [PATCH 02/23] Apply suggestions from code review Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 66 +++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 0fbcd80234..4b194db537 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -711,13 +711,12 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, ) return mismatch -def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, altitude, - module_type=None, coefficients=None, albedo=0.2): + +def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, + altitude, module_type=None, coefficients=None, + albedo=0.2): """ Estimation of spectral mismatch for BIPV application in vertical facades. - - - Parameters ---------- precipitable_water : numeric @@ -725,16 +724,12 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, alti airmass_absolute : numeric absolute (pressure-adjusted) airmass. [unitless] - aod500 : numeric atmospheric aerosol optical depth at 500 nm. [unitless] - aoi : numeric angle of incidence. [degrees] - altitude: numeric - altitude over sea level. [m] - + altitude over sea level. [m] module_type : str, optional One of the following PV technology strings from [1]_: @@ -743,11 +738,11 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, alti * ``'cigs'`` - anonymous copper indium gallium selenide module. * ``'asi'`` - anonymous amorphous silicon module. albedo - Ground albedo (default value if 0.2). [unitless] + Ground albedo (default value if 0.2). [unitless] coefficients : array-like, optional user-defined coefficients, if not using one of the default coefficient - sets via the ``module_type`` parameter. + set via the ``module_type`` parameter. Returns ------- @@ -761,7 +756,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, alti ---------- [1]. Polo, J., Sanz-saiz, C., Development of spectral mismatch models for BIPV applications in building façades Abbreviations : Renew. Energy 245, 122820, 2025. - https://doi.org/10.1016/j.renene.2025.122820 + :doi:`10.1016/j.renene.2025.122820` """ if module_type is None and coefficients is None: @@ -776,36 +771,33 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, alti Ram=am90/airmass_absolute _coefficients={} - _coefficients['cdte']=( - -0.0009,46.80,49.20,-0.87, 0.00041,0.053 ) - _coefficients['monosi']=( - 0.0027,10.34,9.48,0.307,0.00077,0.006 ) - _coefficients['cigs']=( - 0.0017,2.33,1.30,0.11,0.00098,-0.0177 ) - _coefficients['asi']=( - 0.0024,7.32,7.09,-0.72,-0.0013,0.089 ) - - c={} - c['asi']=(0.0056,-0.020,1.014) - c['cigs']=(-0.0009,-0.0003,1) - c['cdte']=(0.0021,-0.01,1.01) - c['monosi']=(0,-0.003,1.0) + _coefficients = { + 'cdte': (-0.0009, 46.80, 49.20, -0.87, 0.00041, 0.053), + 'monosi': (0.0027, 10.34, 9.48, 0.307, 0.00077, 0.006), + 'cigs': (0.0017, 2.33, 1.30, 0.11, 0.00098, -0.0177), + 'asi': (0.0024, 7.32, 7.09, -0.72, -0.0013, 0.089), + } + c = { + 'asi': (0.0056, -0.020, 1.014), + 'cigs': (-0.0009, -0.0003, 1), + 'cdte': (0.0021, -0.01, 1.01), + 'monosi': (0, -0.003, 1.0), + } if module_type is not None: coeff = _coefficients[module_type] - c_albedo=c[module_type] + c_albedo = c[module_type] else: coeff = coefficients - c_albedo=(0.0,0.0,1.0) # 0.2 albedo assumed - albedo=0.2 - + c_albedo = (0.0, 0.0, 1.0) # 0.2 albedo assumed + albedo = 0.2 - smm=coeff[0]*Ram+coeff[1]/(coeff[2]+Ram**coeff[3])+coeff[4]/aod500+coeff[5]*np.sqrt(precipitable_water) + smm = coeff[0] * Ram + coeff[1] / (coeff[2] + Ram**coeff[3]) \ + + coeff[4] / aod500 + coeff[5]*np.sqrt(precipitable_water) + # Ground albedo correction - - g=c_albedo[0]*(albedo/0.2)**2+c_albedo[1]*(albedo/0.2)+c_albedo[2] - - + g = c_albedo[0] * (albedo/0.2)**2 \ + + c_albedo[1] * (albedo/0.2) + c_albedo[2] + return g*smm - \ No newline at end of file From 36c9b43dbf805ba82f26680cd81dbadfd0d75447 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 11:53:33 +0200 Subject: [PATCH 03/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 4b194db537..f10dc5d8dc 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -755,8 +755,8 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, References ---------- [1]. Polo, J., Sanz-saiz, C., Development of spectral mismatch models - for BIPV applications in building façades Abbreviations : Renew. Energy 245, 122820, 2025. - :doi:`10.1016/j.renene.2025.122820` + for BIPV applications in building façades Abbreviations : Renew. Energy 245 + ,122820, 2025.:doi:`10.1016/j.renene.2025.122820` """ if module_type is None and coefficients is None: @@ -765,12 +765,12 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, raise ValueError('Only one of `module_type` and `coefficients` should ' 'be provided') - am_aoi=pvlib.atmosphere.get_relative_airmass(aoi) - pressure=pvlib.atmosphere.alt2pres(altitude) - am90=pvlib.atmosphere.get_absolute_airmass(am_aoi,pressure) - Ram=am90/airmass_absolute + am_aoi = pvlib.atmosphere.get_relative_airmass(aoi) + pressure = pvlib.atmosphere.alt2pres(altitude) + am90 = pvlib.atmosphere.get_absolute_airmass(am_aoi,pressure) + Ram = am90/airmass_absolute - _coefficients={} + _coefficients = {} _coefficients = { 'cdte': (-0.0009, 46.80, 49.20, -0.87, 0.00041, 0.053), 'monosi': (0.0027, 10.34, 9.48, 0.307, 0.00077, 0.006), From eaa90b4281c240991b260198b193af464c6f5309 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 12:09:19 +0200 Subject: [PATCH 04/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index f10dc5d8dc..375b9f340b 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -757,19 +757,16 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, [1]. Polo, J., Sanz-saiz, C., Development of spectral mismatch models for BIPV applications in building façades Abbreviations : Renew. Energy 245 ,122820, 2025.:doi:`10.1016/j.renene.2025.122820` - """ if module_type is None and coefficients is None: raise ValueError('Must provide either `module_type` or `coefficients`') if module_type is not None and coefficients is not None: raise ValueError('Only one of `module_type` and `coefficients` should ' 'be provided') - am_aoi = pvlib.atmosphere.get_relative_airmass(aoi) pressure = pvlib.atmosphere.alt2pres(altitude) - am90 = pvlib.atmosphere.get_absolute_airmass(am_aoi,pressure) + am90 = pvlib.atmosphere.get_absolute_airmass(am_aoi, pressure) Ram = am90/airmass_absolute - _coefficients = {} _coefficients = { 'cdte': (-0.0009, 46.80, 49.20, -0.87, 0.00041, 0.053), @@ -777,27 +774,22 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, 'cigs': (0.0017, 2.33, 1.30, 0.11, 0.00098, -0.0177), 'asi': (0.0024, 7.32, 7.09, -0.72, -0.0013, 0.089), } - c = { 'asi': (0.0056, -0.020, 1.014), 'cigs': (-0.0009, -0.0003, 1), 'cdte': (0.0021, -0.01, 1.01), 'monosi': (0, -0.003, 1.0), } - - if module_type is not None: + if module_type is not None: coeff = _coefficients[module_type] c_albedo = c[module_type] else: coeff = coefficients c_albedo = (0.0, 0.0, 1.0) # 0.2 albedo assumed albedo = 0.2 - smm = coeff[0] * Ram + coeff[1] / (coeff[2] + Ram**coeff[3]) \ + coeff[4] / aod500 + coeff[5]*np.sqrt(precipitable_water) - # Ground albedo correction g = c_albedo[0] * (albedo/0.2)**2 \ + c_albedo[1] * (albedo/0.2) + c_albedo[2] - return g*smm From 794ed9898ecef4ff735c6260c6d81608e701ed74 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 12:17:39 +0200 Subject: [PATCH 05/23] Update mismatch.py --- 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 375b9f340b..df1349d21a 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -780,7 +780,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, 'cdte': (0.0021, -0.01, 1.01), 'monosi': (0, -0.003, 1.0), } - if module_type is not None: + if module_type is not None: coeff = _coefficients[module_type] c_albedo = c[module_type] else: From 7926a3d821763b6a32d9d8fab7b6cbffa131df23 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 12:51:55 +0200 Subject: [PATCH 06/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index df1349d21a..da00e28fdc 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -754,9 +754,9 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, References ---------- - [1]. Polo, J., Sanz-saiz, C., Development of spectral mismatch models - for BIPV applications in building façades Abbreviations : Renew. Energy 245 - ,122820, 2025.:doi:`10.1016/j.renene.2025.122820` + [1] J. Polo and C. Sanz-Saiz, 'Development of spectral mismatch models + for BIPV applications in building façades', Renewable Energy, vol. 245, + p. 122820, Jun. 2025,:doi:`10.1016/j.renene.2025.122820` """ if module_type is None and coefficients is None: raise ValueError('Must provide either `module_type` or `coefficients`') From 988557c061187d06d55cc32d5e15cd6b6f5ae093 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Fri, 11 Jul 2025 13:36:14 +0200 Subject: [PATCH 07/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index da00e28fdc..2f87565079 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -716,33 +716,33 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, altitude, module_type=None, coefficients=None, albedo=0.2): """ - Estimation of spectral mismatch for BIPV application in vertical facades. + Estimate the spectral mismatch for BIPV application in vertical facades. Parameters ---------- precipitable_water : numeric atmospheric precipitable water. [cm] airmass_absolute : numeric - absolute (pressure-adjusted) airmass. [unitless] + Absolute airmass. [unitless] aod500 : numeric atmospheric aerosol optical depth at 500 nm. [unitless] aoi : numeric - angle of incidence. [degrees] + Angle of incidence on the vertical surface. [degrees] altitude: numeric altitude over sea level. [m] module_type : str, optional One of the following PV technology strings from [1]_: * ``'cdte'`` - anonymous CdTe module. - * ``'monosi'`` - anonymous sc-si module. + * ``'monosi'`` - anonymous monocrystalline Si module. * ``'cigs'`` - anonymous copper indium gallium selenide module. * ``'asi'`` - anonymous amorphous silicon module. albedo - Ground albedo (default value if 0.2). [unitless] + Ground albedo (default value 0.2). [unitless] coefficients : array-like, optional - user-defined coefficients, if not using one of the default coefficient - set via the ``module_type`` parameter. + user-defined coefficients, if not using one of the coefficient + sets via the ``module_type`` parameter. Returns ------- From 45e768f884b4d7c7fe81c74c5f8896de92d274f5 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 28 Jul 2025 08:31:35 +0200 Subject: [PATCH 08/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 2f87565079..21b5301295 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -786,7 +786,6 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, else: coeff = coefficients c_albedo = (0.0, 0.0, 1.0) # 0.2 albedo assumed - albedo = 0.2 smm = coeff[0] * Ram + coeff[1] / (coeff[2] + Ram**coeff[3]) \ + coeff[4] / aod500 + coeff[5]*np.sqrt(precipitable_water) # Ground albedo correction From 38e569425c8ed62a548eef6458b9d786ec27d498 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 28 Jul 2025 14:25:24 +0200 Subject: [PATCH 09/23] Update pvlib/spectrum/mismatch.py Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 21b5301295..76022f7217 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -717,6 +717,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, albedo=0.2): """ Estimate the spectral mismatch for BIPV application in vertical facades. + Parameters ---------- precipitable_water : numeric From c24e013d6578b8a294971dda0d5a9273e4f15f73 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 28 Jul 2025 14:25:58 +0200 Subject: [PATCH 10/23] Update pvlib/spectrum/mismatch.py Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 76022f7217..935f729474 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -722,7 +722,6 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, ---------- precipitable_water : numeric atmospheric precipitable water. [cm] - airmass_absolute : numeric Absolute airmass. [unitless] aod500 : numeric From 0a00f1bccfcb927cb10c6e5e3bb2a09083fca24a Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Sat, 25 Oct 2025 18:13:47 +0200 Subject: [PATCH 11/23] Changes from code review --- .../effects_on_pv_system_output/spectrum.rst | 5 +++-- pvlib/spectrum/mismatch.py | 21 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) 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 982bc91742..b453a300ee 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 @@ -12,9 +12,10 @@ Spectrum spectrum.calc_spectral_mismatch_field spectrum.spectral_factor_caballero spectrum.spectral_factor_firstsolar - spectrum.spectral_factor_sapm - spectrum.spectral_factor_pvspec spectrum.spectral_factor_jrc + spectrum.spectral_factor_polo + spectrum.spectral_factor_pvspec + spectrum.spectral_factor_sapm spectrum.sr_to_qe spectrum.qe_to_sr spectrum.average_photon_energy diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 935f729474..e835a22e2b 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -723,22 +723,24 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, precipitable_water : numeric atmospheric precipitable water. [cm] airmass_absolute : numeric - Absolute airmass. [unitless] + absolute (pressure-adjusted) airmass. See :term:`airmass_absolute`. + [unitless] aod500 : numeric atmospheric aerosol optical depth at 500 nm. [unitless] aoi : numeric - Angle of incidence on the vertical surface. [degrees] + Angle of incidence on the vertical surface. See :term:`aoi`. + [degrees] altitude: numeric altitude over sea level. [m] module_type : str, optional One of the following PV technology strings from [1]_: * ``'cdte'`` - anonymous CdTe module. - * ``'monosi'`` - anonymous monocrystalline Si module. + * ``'monosi'`` - anonymous monocrystalline silicon module. * ``'cigs'`` - anonymous copper indium gallium selenide module. * ``'asi'`` - anonymous amorphous silicon module. - albedo - Ground albedo (default value 0.2). [unitless] + albedo : float, optional + Ground albedo (default value 0.2). See :term:`albedo`. [unitless] coefficients : array-like, optional user-defined coefficients, if not using one of the coefficient @@ -754,9 +756,9 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, References ---------- - [1] J. Polo and C. Sanz-Saiz, 'Development of spectral mismatch models - for BIPV applications in building façades', Renewable Energy, vol. 245, - p. 122820, Jun. 2025,:doi:`10.1016/j.renene.2025.122820` + .. [1] J. Polo and C. Sanz-Saiz, 'Development of spectral mismatch models + for BIPV applications in building façades', Renewable Energy, vol. 245, + p. 122820, Jun. 2025, :doi:`10.1016/j.renene.2025.122820` """ if module_type is None and coefficients is None: raise ValueError('Must provide either `module_type` or `coefficients`') @@ -766,8 +768,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, am_aoi = pvlib.atmosphere.get_relative_airmass(aoi) pressure = pvlib.atmosphere.alt2pres(altitude) am90 = pvlib.atmosphere.get_absolute_airmass(am_aoi, pressure) - Ram = am90/airmass_absolute - _coefficients = {} + Ram = am90 / airmass_absolute _coefficients = { 'cdte': (-0.0009, 46.80, 49.20, -0.87, 0.00041, 0.053), 'monosi': (0.0027, 10.34, 9.48, 0.307, 0.00077, 0.006), From 2a9d0dbbc36b56e41d94c30cbaa441a3daa50242 Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Sat, 25 Oct 2025 18:19:46 +0200 Subject: [PATCH 12/23] Add function to spectrum/__init__.py --- pvlib/spectrum/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pvlib/spectrum/__init__.py b/pvlib/spectrum/__init__.py index 59f9db9582..1e551c83fa 100644 --- a/pvlib/spectrum/__init__.py +++ b/pvlib/spectrum/__init__.py @@ -3,9 +3,10 @@ calc_spectral_mismatch_field, spectral_factor_caballero, spectral_factor_firstsolar, - spectral_factor_sapm, - spectral_factor_pvspec, spectral_factor_jrc, + spectral_factor_polo, + spectral_factor_pvspec, + spectral_factor_sapm, ) from pvlib.spectrum.irradiance import ( # noqa: F401 get_reference_spectra, From f296c7b1b782f65027d2c2449b8c8da649ac5538 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 27 Oct 2025 12:25:17 +0100 Subject: [PATCH 13/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 69ed476f59..a22d9d595d 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -302,3 +302,21 @@ 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.mark.parametrize("module_type,expected", [ + ('cdte', np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), + ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), +]) +def test_spectral_factor_polo(): + altitude=500 + + pws = np.array([0.96, 0.96, 1.85, 1.88, 0.66, 0.66]) + aods = np.array([0.085, 0.085, 0.16, 0.19, 0.088, 0.088]) + ams = np.array([1.34, 1.34, 2.2, 2.2, 2.6, 2.6]) + aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) + alb=np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) + + out=spectral_factor_polo(pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) + assert np.allclose(expected, out, atol=1e-8) + \ No newline at end of file From ce862d8a120c27cef41aaa9aba3eba1850723f15 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 27 Oct 2025 12:37:54 +0100 Subject: [PATCH 14/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index a22d9d595d..7e85cc777b 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -308,7 +308,7 @@ def test_spectral_factor_jrc_supplied_ambiguous(): ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) -def test_spectral_factor_polo(): +def test_spectral_factor_polo(module_type,expected): altitude=500 pws = np.array([0.96, 0.96, 1.85, 1.88, 0.66, 0.66]) From 11336ab34227fc624e190245e52214821513a044 Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:46:07 +0100 Subject: [PATCH 15/23] Fix module import in tests --- tests/spectrum/test_mismatch.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 7e85cc777b..84e025569d 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -317,6 +317,7 @@ def test_spectral_factor_polo(module_type,expected): aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) alb=np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) - out=spectral_factor_polo(pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) + out = spectrum.spectral_factor_polo( + pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) assert np.allclose(expected, out, atol=1e-8) \ No newline at end of file From e418218c756ed8f36948e5b28d32dea70d124f9c Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 27 Oct 2025 12:48:46 +0100 Subject: [PATCH 16/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 7e85cc777b..84e025569d 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -317,6 +317,7 @@ def test_spectral_factor_polo(module_type,expected): aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) alb=np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) - out=spectral_factor_polo(pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) + out = spectrum.spectral_factor_polo( + pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) assert np.allclose(expected, out, atol=1e-8) \ No newline at end of file From 450dd37c2b632cd5004a7750b4c3de402dcc9019 Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:56:08 +0100 Subject: [PATCH 17/23] Fix linter --- tests/spectrum/test_mismatch.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 84e025569d..acb1d3752a 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -302,22 +302,27 @@ 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.mark.parametrize("module_type,expected", [ - ('cdte', np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), - ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), - ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), - ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), + ('cdte', + np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), + ('monosi', + np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + ('cigs', + np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + ('asi', + np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) -def test_spectral_factor_polo(module_type,expected): - altitude=500 +def test_spectral_factor_polo(module_type, expected): + altitude = 500 pws = np.array([0.96, 0.96, 1.85, 1.88, 0.66, 0.66]) aods = np.array([0.085, 0.085, 0.16, 0.19, 0.088, 0.088]) ams = np.array([1.34, 1.34, 2.2, 2.2, 2.6, 2.6]) aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) - alb=np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) + alb = np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) out = spectrum.spectral_factor_polo( - pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) + pws, ams, aods, aois, altitude, module_type=module_type, albedo=alb) assert np.allclose(expected, out, atol=1e-8) - \ No newline at end of file From 1eb3293197a61fcce506d6db08cd3657321f85c5 Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:00:44 +0100 Subject: [PATCH 18/23] Remove tab character --- tests/spectrum/test_mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index acb1d3752a..3c0d26c27c 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -310,7 +310,7 @@ def test_spectral_factor_jrc_supplied_ambiguous(): ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), ('cigs', - np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) From 4892e8d8b8aacf612e4f8d1cd3301b46e2b14000 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 27 Oct 2025 13:47:01 +0100 Subject: [PATCH 19/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 84e025569d..9ae06dc86f 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -308,15 +308,13 @@ def test_spectral_factor_jrc_supplied_ambiguous(): ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) -def test_spectral_factor_polo(module_type,expected): - altitude=500 - +def test_spectral_factor_polo(module_type, expected): + altitude = 500 pws = np.array([0.96, 0.96, 1.85, 1.88, 0.66, 0.66]) aods = np.array([0.085, 0.085, 0.16, 0.19, 0.088, 0.088]) ams = np.array([1.34, 1.34, 2.2, 2.2, 2.6, 2.6]) aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) - alb=np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) - + alb = np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) out = spectrum.spectral_factor_polo( pws,ams,aods,aois,altitude,module_type=module_type,albedo=alb) assert np.allclose(expected, out, atol=1e-8) From 3e4dd567e9a65c9480854743f0cd935757cf7dfe Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 27 Oct 2025 13:59:54 +0100 Subject: [PATCH 20/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 705a7b4fc0..f665c45313 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -305,30 +305,18 @@ def test_spectral_factor_jrc_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ - ('cdte', - np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), - ('monosi', - np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), - ('cigs', - np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), - ('asi', - np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), + ('cdte', np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), + ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) def test_spectral_factor_polo(module_type, expected): altitude = 500 -<<<<<<< HEAD -======= - ->>>>>>> 1eb3293197a61fcce506d6db08cd3657321f85c5 pws = np.array([0.96, 0.96, 1.85, 1.88, 0.66, 0.66]) aods = np.array([0.085, 0.085, 0.16, 0.19, 0.088, 0.088]) ams = np.array([1.34, 1.34, 2.2, 2.2, 2.6, 2.6]) aois = np.array([46.0, 76.0, 74.0, 28.0, 24.0, 55.0]) alb = np.array([0.15, 0.2, 0.3, 0.18, 0.32, 0.26]) -<<<<<<< HEAD -======= - ->>>>>>> 1eb3293197a61fcce506d6db08cd3657321f85c5 out = spectrum.spectral_factor_polo( pws, ams, aods, aois, altitude, module_type=module_type, albedo=alb) assert np.allclose(expected, out, atol=1e-8) From b9d21aca9a202a439378652005ebb8d88d1edc27 Mon Sep 17 00:00:00 2001 From: "Adam R. Jensen" <39184289+AdamRJensen@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:47:01 +0100 Subject: [PATCH 21/23] fix line legth linter error --- tests/spectrum/test_mismatch.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index f665c45313..1871b1066f 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -305,10 +305,14 @@ def test_spectral_factor_jrc_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ - ('cdte', np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), - ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), - ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), - ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), + ('cdte', np.array( + [0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), + ('monosi', np.array( + [1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + ('cigs', np.array( + [1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + ('asi', np.array( + [0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) def test_spectral_factor_polo(module_type, expected): altitude = 500 From 49c8c91a0631990ac42f969c15aafcaacf58989c Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Tue, 28 Oct 2025 16:30:20 +0100 Subject: [PATCH 22/23] Update test_mismatch.py --- tests/spectrum/test_mismatch.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index f665c45313..1871b1066f 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -305,10 +305,14 @@ def test_spectral_factor_jrc_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ - ('cdte', np.array([0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), - ('monosi', np.array([1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), - ('cigs', np.array([1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), - ('asi', np.array([0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), + ('cdte', np.array( + [0.991926, 0.999809, 1.01108, 0.993319, 0.956621, 0.970872])), + ('monosi', np.array( + [1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + ('cigs', np.array( + [1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + ('asi', np.array( + [0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), ]) def test_spectral_factor_polo(module_type, expected): altitude = 500 From 31fe508376c00c86657064a1af584be2ac7a346a Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 29 Oct 2025 14:14:06 +0100 Subject: [PATCH 23/23] Update mismatch.py --- pvlib/spectrum/mismatch.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index e835a22e2b..3e6e255ab8 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -769,6 +769,10 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, pressure = pvlib.atmosphere.alt2pres(altitude) am90 = pvlib.atmosphere.get_absolute_airmass(am_aoi, pressure) Ram = am90 / airmass_absolute + f_aoi_rel= pvlib.atmosphere.get_relative_airmass(aoi, model='kastenyoung1989') + pressure = pvlib.atmosphere.alt2pres(altitude) + f_aoi = pvlib.atmosphere.get_absolute_airmass(f_aoi_rel, pressure) + Ram = f_aoi / airmass_absolute _coefficients = { 'cdte': (-0.0009, 46.80, 49.20, -0.87, 0.00041, 0.053), 'monosi': (0.0027, 10.34, 9.48, 0.307, 0.00077, 0.006),