From 3363ace052d9137480ab715a540e997e07dfa088 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Wed, 25 Jun 2025 08:07:02 +0200 Subject: [PATCH 01/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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), From c958abffaaf3c829155e63706b2d0929385912b4 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Fri, 14 Nov 2025 08:42:05 +0100 Subject: [PATCH 24/36] Update mismatch.py --- pvlib/spectrum/mismatch.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 3e6e255ab8..c5002c3202 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -767,10 +767,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, '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 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 = { From bd1ff4fd159728dc4d690adaaf8c70a2a652058b Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:06:49 -0500 Subject: [PATCH 25/36] Apply suggestions from code review --- pvlib/spectrum/mismatch.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index c5002c3202..5f81afd155 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -739,12 +739,11 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, * ``'monosi'`` - anonymous monocrystalline silicon module. * ``'cigs'`` - anonymous copper indium gallium selenide module. * ``'asi'`` - anonymous amorphous silicon module. - 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 sets via the ``module_type`` parameter. + albedo : float, optional + Ground albedo (default value 0.2). See :term:`albedo`. [unitless] Returns ------- @@ -765,15 +764,15 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, 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) - f_aoi_rel= pvlib.atmosphere.get_relative_airmass(aoi, model='kastenyoung1989') + f_aoi_rel = pvlib.atmosphere.get_relative_airmass(aoi, + model='kastenyoung1989') 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), - 'cigs': (0.0017, 2.33, 1.30, 0.11, 0.00098, -0.0177), + 'monosi': (0.0027, 10.34, 9.48, 0.31, 0.00077, 0.006), + 'cigs': (0.0017, 2.33, 1.30, 0.11, 0.00098, -0.018), 'asi': (0.0024, 7.32, 7.09, -0.72, -0.0013, 0.089), } c = { From f0a4f34ce8f100da467e03452fab5495260aecd9 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:21:20 -0500 Subject: [PATCH 26/36] replace `altitude` parameter with `pressure` --- pvlib/spectrum/mismatch.py | 7 +++---- tests/spectrum/test_mismatch.py | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 5f81afd155..d9f86f693e 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -713,7 +713,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, - altitude, module_type=None, coefficients=None, + pressure, module_type=None, coefficients=None, albedo=0.2): """ Estimate the spectral mismatch for BIPV application in vertical facades. @@ -730,8 +730,8 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, aoi : numeric Angle of incidence on the vertical surface. See :term:`aoi`. [degrees] - altitude: numeric - altitude over sea level. [m] + pressure : numeric + Atmospheric pressure. See :term`pressure`. [Pa] module_type : str, optional One of the following PV technology strings from [1]_: @@ -764,7 +764,6 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, if module_type is not None and coefficients is not None: raise ValueError('Only one of `module_type` and `coefficients` should ' 'be provided') - pressure = pvlib.atmosphere.alt2pres(altitude) f_aoi_rel = pvlib.atmosphere.get_relative_airmass(aoi, model='kastenyoung1989') f_aoi = pvlib.atmosphere.get_absolute_airmass(f_aoi_rel, pressure) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 1871b1066f..8bb4b68a6d 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -306,21 +306,21 @@ 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])), + [0.992801, 1.00004 , 1.011576, 0.995003, 0.950156, 0.975665])), ('monosi', np.array( - [1.00174, 0.971769, 0.986224, 1.01661, 1.02026, 1.0106])), + [1.000152, 0.969588, 0.984636, 1.015405, 1.024238, 1.005061])), ('cigs', np.array( - [1.00769, 0.959666, 0.974438, 1.02861, 1.05203, 1.03117])), + [1.004621, 0.956719, 0.971668, 1.0254, 1.060066, 1.020196])), ('asi', np.array( - [0.982133, 1.04674, 1.04859, 0.951109, 0.865328, 0.919515])), + [0.986968, 1.049725, 1.051978, 0.957968, 0.842258, 0.941927])), ]) 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]) + pressure = np.array([101300, 101400, 100500, 101325, 80000, 120000]) 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) + pws, ams, aods, aois, pressure, module_type=module_type, albedo=alb) + np.testing.assert_allclose(out, expected, atol=1e-6) From ee7f13ff9259dd68079dbb0c5d6156e88adcbc51 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:22:21 -0500 Subject: [PATCH 27/36] `albedo : numeric` --- 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 d9f86f693e..d708a60f68 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -742,7 +742,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, coefficients : array-like, optional user-defined coefficients, if not using one of the coefficient sets via the ``module_type`` parameter. - albedo : float, optional + albedo : numeric, optional Ground albedo (default value 0.2). See :term:`albedo`. [unitless] Returns From 82598ec8fe0cc2417741684e4a807a9c63877405 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:43:39 -0500 Subject: [PATCH 28/36] make albedo coefficients user-specified as well --- pvlib/spectrum/mismatch.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index d708a60f68..e6b28391ac 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -740,8 +740,11 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, * ``'cigs'`` - anonymous copper indium gallium selenide module. * ``'asi'`` - anonymous amorphous silicon module. coefficients : array-like, optional - user-defined coefficients, if not using one of the coefficient - sets via the ``module_type`` parameter. + User-defined coefficients, if not using one of the coefficient + sets via the ``module_type`` parameter. Must have nine elements. + The first six elements correspond to the [p1, p2, p3, p4, b, c] + parameters of the SMM model. The last three elements corresponds + to the [c1, c2, c3] parameters of the albedo correction factor. albedo : numeric, optional Ground albedo (default value 0.2). See :term:`albedo`. [unitless] @@ -784,8 +787,8 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, coeff = _coefficients[module_type] c_albedo = c[module_type] else: - coeff = coefficients - c_albedo = (0.0, 0.0, 1.0) # 0.2 albedo assumed + coeff = coefficients[:6] + c_albedo = coefficients[6:] smm = coeff[0] * Ram + coeff[1] / (coeff[2] + Ram**coeff[3]) \ + coeff[4] / aod500 + coeff[5]*np.sqrt(precipitable_water) # Ground albedo correction From 8b2b7ca15a78fa9270ffe4dfceb7dbb56d5ffaa4 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:45:47 -0500 Subject: [PATCH 29/36] complete tests --- tests/spectrum/test_mismatch.py | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/spectrum/test_mismatch.py b/tests/spectrum/test_mismatch.py index 8bb4b68a6d..2103620b2d 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -324,3 +324,66 @@ def test_spectral_factor_polo(module_type, expected): out = spectrum.spectral_factor_polo( pws, ams, aods, aois, pressure, module_type=module_type, albedo=alb) np.testing.assert_allclose(out, expected, atol=1e-6) + + +@pytest.fixture +def polo_inputs(): + return {'precipitable_water': 0.96, + 'airmass_absolute': 1.34, + 'aod500': 0.085, + 'aoi': 76, + 'pressure': 101400, + 'albedo': 0.2} + + +def test_spectral_factor_polo_coefficients(polo_inputs): + # test that supplying custom coefficients works as expected + coefficients = ( + (0.0027, 10.34, 9.48, 0.31, 0.00077, 0.006) # base Si coeffs + + (0, -0.003, 1.0) # Si albedo correction coeffs + ) + out = spectrum.spectral_factor_polo(**polo_inputs, + coefficients=coefficients) + np.testing.assert_allclose(out, 0.969588, atol=1e-6) + + +def test_spectral_factor_polo_errors(polo_inputs): + with pytest.raises(ValueError, match='Must provide either'): + spectrum.spectral_factor_polo(**polo_inputs) + with pytest.raises(ValueError, match='Only one of'): + spectrum.spectral_factor_polo(**polo_inputs, module_type='CdTe', + coefficients=(1, 1, 1, 1, 1, 1)) + + +def test_spectral_factor_polo_types(polo_inputs): + # float: + out = spectrum.spectral_factor_polo(**polo_inputs, module_type='monosi') + assert isinstance(out, float) + np.testing.assert_allclose(out, 0.969588, atol=1e-6) + + # array: + arrays = {k: np.array([v, v]) for k, v in polo_inputs.items()} + out = spectrum.spectral_factor_polo(**arrays, module_type='monosi') + assert isinstance(out, np.ndarray) + np.testing.assert_allclose(out, [0.969588]*2, atol=1e-6) + + # series: + series = {k: pd.Series(v) for k, v in arrays.items()} + out = spectrum.spectral_factor_polo(**series, module_type='monosi') + assert isinstance(out, pd.Series) + pd.testing.assert_series_equal(out, pd.Series([0.969588]*2), atol=1e-6) + + +def test_spectral_factor_polo_NaN(polo_inputs): + # nan in -> nan out + for key in polo_inputs: + inputs = polo_inputs.copy() + inputs[key] = np.nan + out = spectrum.spectral_factor_polo(**inputs, module_type='monosi') + assert np.isnan(out) + + +def test_spectral_factor_polo_aoi_gt_90(polo_inputs): + polo_inputs['aoi'] = 95 + out = spectrum.spectral_factor_polo(**polo_inputs, module_type='monosi') + assert np.isnan(out) From 31f26b570456880ec83b888d2a0c4b8cf690b069 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:48:10 -0500 Subject: [PATCH 30/36] docstring cleanup --- pvlib/spectrum/mismatch.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index e6b28391ac..15cca6c3a9 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -718,15 +718,19 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, """ Estimate the spectral mismatch for BIPV application in vertical facades. + The model's authors note that this model could also be applied to + vertical bifacial ground-mount systems [1]_, although it has not been + validated in that context. + Parameters ---------- precipitable_water : numeric - atmospheric precipitable water. [cm] + Atmospheric precipitable water. [cm] airmass_absolute : numeric - absolute (pressure-adjusted) airmass. See :term:`airmass_absolute`. + Absolute (pressure-adjusted) airmass. See :term:`airmass_absolute`. [unitless] aod500 : numeric - atmospheric aerosol optical depth at 500 nm. [unitless] + Atmospheric aerosol optical depth at 500 nm. [unitless] aoi : numeric Angle of incidence on the vertical surface. See :term:`aoi`. [degrees] @@ -745,8 +749,8 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, The first six elements correspond to the [p1, p2, p3, p4, b, c] parameters of the SMM model. The last three elements corresponds to the [c1, c2, c3] parameters of the albedo correction factor. - albedo : numeric, optional - Ground albedo (default value 0.2). See :term:`albedo`. [unitless] + albedo : numeric, default 0.2 + Ground albedo. See :term:`albedo`. [unitless] Returns ------- From 5ec4bee1775c6dcd403912f4d0fcaa1de8b8f81a Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 10:54:39 -0500 Subject: [PATCH 31/36] whatsnew note and contributors --- docs/sphinx/source/whatsnew/v0.13.2.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.13.2.rst b/docs/sphinx/source/whatsnew/v0.13.2.rst index 7d0f0e0747..663c48cae3 100644 --- a/docs/sphinx/source/whatsnew/v0.13.2.rst +++ b/docs/sphinx/source/whatsnew/v0.13.2.rst @@ -43,6 +43,8 @@ Enhancements installed. (:issue:`2497`, :pull:`2571`) * Add :py:func:`~pvlib.iotools.get_era5`, a function for accessing ERA5 reanalysis data. (:pull:`2573`) +* Add :py:func:`~pvlib.spectrum.spectral_factor_polo`, a function for estimating + spectral mismatch factors for vertical PV façades. (:issue:`2406`, :pull:`2491`) Documentation ~~~~~~~~~~~~~ @@ -75,3 +77,9 @@ Contributors * Will Hobbs (:ghuser:`williamhobbs`) * Cliff Hansen (:ghuser:`cwhanse`) * Joseph Radford (:ghuser:`josephradford`) +* Jesús Polo (:ghuser:`jesuspolo`) +* Adam R. Jensen (:ghuser:`adamrjensen`) +* Echedey Luis (:ghuser:`echedey-ls`) +* Anton Driesse (:ghuser:`adriesse`) +* Rajiv Daxini (:ghuser:`RDaxini`) +* Kevin Anderson (:ghuser:`kandersolar`) From d0efc3714b78be13a289692e853a58f7319734c8 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 11:02:55 -0500 Subject: [PATCH 32/36] add to user guide SMM model comparison table --- .../user_guide/modeling_topics/spectrum.rst | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst b/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst index bd6440a47c..5d720d92da 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst @@ -61,11 +61,21 @@ Reference [2]_. | +-----------------------------+ | ✓ | ✓ | | | + [4]_ | | | clearsky_index | | | | | | | | +-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ +| :py:func:`Polo ` | :term:`precipitable_water`, | | | | | | | | +| +-----------------------------+ ✓ | | ✓ | ✓ | ✓ | + [5]_ | +| | :term:`airmass_absolute`, | | | | | | | | +| +-----------------------------+ | | | | | | | +| | aod500 | | | | | | | | +| +-----------------------------+ | | | | | | | +| | :term:`aoi` | | | | | | | | +| +-----------------------------+ | | | | | | | +| | :term:`pressure` | | | | | | | | ++-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ | :py:func:`PVSPEC ` | :term:`airmass_absolute`, | | | | | | | | -| +-----------------------------+ ✓ | ✓ | ✓ | ✓ | ✓ | | [5]_ | +| +-----------------------------+ ✓ | ✓ | ✓ | ✓ | ✓ | | [6]_ | | | clearsky_index | | | | | | | | +-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ -| :py:func:`SAPM ` | :term:`airmass_absolute` | | | | | | | [6]_ | +| :py:func:`SAPM ` | :term:`airmass_absolute` | | | | | | | [7]_ | +-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ @@ -88,16 +98,19 @@ References PVSPEC Model of Photovoltaic Spectral Mismatch Factor," in Proc. 2020 IEEE 47th Photovoltaic Specialists Conference (PVSC), Calgary, AB, Canada, 2020, pp. 1–6. :doi:`10.1109/PVSC45281.2020.9300932` -.. [5] D. L. King, W. E. Boyson, and J. A. Kratochvil, Photovoltaic Array +.. [5] 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` +.. [6] D. L. King, W. E. Boyson, and J. A. Kratochvil, Photovoltaic Array Performance Model, Sandia National Laboratories, Albuquerque, NM, USA, Tech. Rep. SAND2004-3535, Aug. 2004. :doi:`10.2172/919131` -.. [6] M. Lee and A. Panchula, "Spectral Correction for Photovoltaic Module +.. [7] M. Lee and A. Panchula, "Spectral Correction for Photovoltaic Module Performance Based on Air Mass and Precipitable Water," 2016 IEEE 43rd Photovoltaic Specialists Conference (PVSC), Portland, OR, USA, 2016, pp. 3696-3699. :doi:`10.1109/PVSC.2016.7749836` -.. [7] H. Thomas, S. Tony, and D. Ewan, “A Simple Model for Estimating the - Influence of Spectrum Variations on PV Performance,” pp. 3385–3389, Nov. +.. [8] T. Huld, T. Sample, and E. Dunlop, "A Simple Model for Estimating the + Influence of Spectrum Variations on PV Performance," pp. 3385–3389, Nov. 2009, :doi:`10.4229/24THEUPVSEC2009-4AV.3.27` -.. [8] IEC 60904-7:2019, Photovoltaic devices — Part 7: Computation of the +.. [9] IEC 60904-7:2019, Photovoltaic devices — Part 7: Computation of the spectral mismatch correction for measurements of photovoltaic devices, International Electrotechnical Commission, Geneva, Switzerland, 2019. \ No newline at end of file From 297f160b00b405cd06c4a811ff693d5b00eb6393 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 11:38:25 -0500 Subject: [PATCH 33/36] lint --- 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 91f52e415b..bc7b6c8a2c 100644 --- a/tests/spectrum/test_mismatch.py +++ b/tests/spectrum/test_mismatch.py @@ -292,7 +292,7 @@ def test_spectral_factor_jrc_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ ('cdte', np.array( - [0.992801, 1.00004 , 1.011576, 0.995003, 0.950156, 0.975665])), + [0.992801, 1.00004, 1.011576, 0.995003, 0.950156, 0.975665])), ('monosi', np.array( [1.000152, 0.969588, 0.984636, 1.015405, 1.024238, 1.005061])), ('cigs', np.array( From c9b9816d72fc0ef87dd78f82540f40d9718939a9 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 19 Nov 2025 11:45:06 -0500 Subject: [PATCH 34/36] minor doc fixes --- docs/sphinx/source/user_guide/modeling_topics/spectrum.rst | 6 +++--- pvlib/spectrum/mismatch.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst b/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst index 5d720d92da..0747c0b295 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/spectrum.rst @@ -61,13 +61,13 @@ Reference [2]_. | +-----------------------------+ | ✓ | ✓ | | | + [4]_ | | | clearsky_index | | | | | | | | +-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ -| :py:func:`Polo ` | :term:`precipitable_water`, | | | | | | | | +| :py:func:`Polo ` | :term:`precipitable_water`, | | | | | | | | | +-----------------------------+ ✓ | | ✓ | ✓ | ✓ | + [5]_ | | | :term:`airmass_absolute`, | | | | | | | | | +-----------------------------+ | | | | | | | -| | aod500 | | | | | | | | +| | aod500, | | | | | | | | | +-----------------------------+ | | | | | | | -| | :term:`aoi` | | | | | | | | +| | :term:`aoi`, | | | | | | | | | +-----------------------------+ | | | | | | | | | :term:`pressure` | | | | | | | | +-----------------------------------------------------+-----------------------------+---------+---------+------+------+------+------------+-----------+ diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 3a06ac1fdc..d95840869f 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -723,7 +723,7 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, Angle of incidence on the vertical surface. See :term:`aoi`. [degrees] pressure : numeric - Atmospheric pressure. See :term`pressure`. [Pa] + Atmospheric pressure. See :term:`pressure`. [Pa] module_type : str, optional One of the following PV technology strings from [1]_: From 3df13ae44edb4368a79b0b490ad584733f7a2ad1 Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Fri, 21 Nov 2025 11:19:50 +0100 Subject: [PATCH 35/36] 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 d95840869f..d8a069ed5e 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -786,4 +786,8 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, # Ground albedo correction g = c_albedo[0] * (albedo/0.2)**2 \ + c_albedo[1] * (albedo/0.2) + c_albedo[2] + # if aoi > 90 no ilumination, no spectral correction + if aoi > 90: + g=1 + smm=1 return g*smm From 3015b3ada8b4e2a6f74095f54cd4a1932a42dfed Mon Sep 17 00:00:00 2001 From: Jesus Polo Date: Mon, 24 Nov 2025 07:59:01 +0100 Subject: [PATCH 36/36] Update mismatch.py --- pvlib/spectrum/mismatch.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index d8a069ed5e..c754040213 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -759,6 +759,9 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, if module_type is not None and coefficients is not None: raise ValueError('Only one of `module_type` and `coefficients` should ' 'be provided') + # prevent nan for aoi greater than 90 + if aoi > 90: + aoi = 90 f_aoi_rel = pvlib.atmosphere.get_relative_airmass(aoi, model='kastenyoung1989') f_aoi = pvlib.atmosphere.get_absolute_airmass(f_aoi_rel, pressure) @@ -786,8 +789,4 @@ def spectral_factor_polo(precipitable_water, airmass_absolute, aod500, aoi, # Ground albedo correction g = c_albedo[0] * (albedo/0.2)**2 \ + c_albedo[1] * (albedo/0.2) + c_albedo[2] - # if aoi > 90 no ilumination, no spectral correction - if aoi > 90: - g=1 - smm=1 return g*smm