Skip to content

Commit 3bbf743

Browse files
authored
Merge pull request #2 from kanderso-nrel/pr1296
Edits to the spectral correction function for pvlib PR 1296
2 parents 8124675 + 7e0d7df commit 3bbf743

File tree

2 files changed

+41
-74
lines changed

2 files changed

+41
-74
lines changed

pvlib/atmosphere.py

Lines changed: 8 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -687,8 +687,7 @@ def angstrom_alpha(aod1, lambda1, aod2, lambda2):
687687

688688
def AM_AOD_PW_spectral_correction(airmass_absolute, aod500, pw,
689689
module_type=None, coefficients=None,
690-
min_aod500=0.05, max_aod500=0.6,
691-
min_pw=0.25, max_pw=4):
690+
aod500_ref=0.84, pw_ref=1.42):
692691
r"""
693692
Spectral mismatch modifier based on absolute (pressure-adjusted)
694693
airmass (AM), aerosol optical depth (AOD) at 500 nm and
@@ -747,30 +746,17 @@ def AM_AOD_PW_spectral_correction(airmass_absolute, aod500, pw,
747746
* 'asi' - anonymous amorphous silicon module.
748747
* 'perovskite' - anonymous pervoskite module.
749748
750-
coefficients : None or array-like, default None
749+
coefficients : None or array-like, optional
751750
the coefficients employed have been obtained with experimental
752751
data in the city of Jaén, Spain. It is pending to verify if such
753752
coefficients vary in places with extreme climates where AOD and
754753
pw values are frequently high.
755754
756-
min_aod500 : float, default 0.05
757-
minimum atmospheric aerosol optical depth at 500 nm. Any aod500 value
758-
lower than min_aod500 is set to min_aod500 to avoid model
759-
divergence. [unitless]
760-
761-
max_aod500 : float, default 0.6
762-
maximum atmospheric aerosol optical depth at 500 nm. Any aod500 value
763-
higher than max_aod500 is set to NaN to avoid model
764-
divergence. [unitless]
765-
766-
min_pw : float, default 0.25
767-
minimum atmospheric precipitable water. Any pw value lower than min_pw
768-
is set to min_pw to avoid model divergence. [cm]
769-
770-
max_pw : float, default 4
771-
maximum atmospheric precipitable water. Any pw value higher than max_pw
772-
is set to NaN to avoid model divergence. [cm]
755+
aod500_ref : numeric, default 0.84
756+
TODO: description
773757
758+
pw_ref : numeric, default 1.42
759+
TODO: description
774760
775761
Returns
776762
-------
@@ -801,55 +787,6 @@ def AM_AOD_PW_spectral_correction(airmass_absolute, aod500, pw,
801787
802788
"""
803789

804-
# --- Screen Input Data ---
805-
806-
# *** ama ***
807-
# Replace Extremely High ama with ama 10 to prevent model divergence
808-
# ama > 10 will only occur very close to sunset
809-
if np.max(airmass_absolute) > 10:
810-
airmass_absolute = np.minimum(airmass_absolute, 10)
811-
812-
# Warn user about ama data that is exceptionally low
813-
814-
if np.min(airmass_absolute) < 0.58:
815-
warn('Exceptionally low air mass: ' +
816-
'model not intended for extra-terrestrial use')
817-
# pvl_absoluteairmass(1,pvl_alt2pres(4340)) = 0.58 Elevation of
818-
# Mina Pirquita, Argentian = 4340 m. Highest elevation city with
819-
# population over 50,000.
820-
821-
# *** aod500 ***
822-
# Replace aod500 Values below 0.05 with 0.05 to prevent model from
823-
# diverging"
824-
aod500 = np.atleast_1d(aod500)
825-
aod500 = aod500.astype('float64')
826-
if np.min(aod500) < min_aod500:
827-
aod500 = np.maximum(aod500, min_aod500)
828-
warn(f'Exceptionally low aod values replaced with {min_aod500} to'
829-
'prevent model divergence')
830-
831-
# Warn user about aod500 data that is exceptionally high
832-
if np.max(aod500) > max_aod500:
833-
aod500[aod500 > max_aod500] = np.nan
834-
warn('Exceptionally high aod values replaced by np.nan: '
835-
'check input data.')
836-
837-
# *** pw ***
838-
# Replace pw Values below 0.25 cm with 0.25 cm to prevent model from
839-
# diverging"
840-
pw = np.atleast_1d(pw)
841-
pw = pw.astype('float64')
842-
if np.min(pw) < min_pw:
843-
pw = np.maximum(pw, min_pw)
844-
warn(f'Exceptionally low pw values replaced with {min_pw} cm to '
845-
'prevent model divergence')
846-
847-
# Warn user about pw data that is exceptionally high
848-
if np.max(pw) > max_pw:
849-
pw[pw > max_pw] = np.nan
850-
warn('Exceptionally high pw values replaced by np.nan: '
851-
'check input data.')
852-
853790
# Experimental coefficients
854791

855792
_coefficients = {}
@@ -866,7 +803,7 @@ def AM_AOD_PW_spectral_correction(airmass_absolute, aod500, pw,
866803
0.9801, 0.0283, -0.0092, 0.0019, -0.0001, 0.0117,
867804
-0.0126, 0, -0.0011, -0.0019, 1, 0)
868805
_coefficients['asi'] = (
869-
1.1060, -0.0848, 0.0302, -0.0076, 0.0006, -0.12838,
806+
1.1060, -0.0848, 0.0302, -0.0076, 0.0006, -0.1283,
870807
0.0986, -0.0254, 0.0156, 0.0146, 1, 0)
871808
_coefficients['perovskite'] = (
872809
1.0637, -0.0491, 0.0180, -0.0047, 0.0004, -0.0773,
@@ -886,16 +823,13 @@ def AM_AOD_PW_spectral_correction(airmass_absolute, aod500, pw,
886823
# Evaluate Spectral Shift
887824
coeff = coefficients
888825
ama = airmass_absolute
889-
aod500_ref = 0.84
890-
pw_ref = 1.42
891-
892826
modifier = (
893827
coeff[0] + (ama) * coeff[1] + (ama * ama) * coeff[2]
894828
+ (ama * ama * ama) * coeff[3] + (ama * ama * ama * ama) * coeff[4]
895829
+ (aod500 - aod500_ref) * coeff[5]
896830
+ ((aod500 - aod500_ref) * (ama) * coeff[6]) * coeff[10]
897831
+ ((aod500 - aod500_ref) * (np.log(ama)) * coeff[6]) * coeff[11]
898-
+ (aod500 - aod500_ref) + (ama * ama) * coeff[7]
832+
+ (aod500 - aod500_ref) * (ama * ama) * coeff[7]
899833
+ (pw - pw_ref) * coeff[8] + (pw - pw_ref) * (np.log(ama)) * coeff[9])
900834

901835
return modifier

pvlib/tests/test_atmosphere.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,36 @@ def test_bird_hulstrom80_aod_bb():
187187
aod380, aod500 = 0.22072480948195175, 0.1614279181106312
188188
bird_hulstrom = atmosphere.bird_hulstrom80_aod_bb(aod380, aod500)
189189
assert np.isclose(0.11738229553812768, bird_hulstrom)
190+
191+
192+
@pytest.mark.parametrize("module_type,expected", [
193+
('asi', np.array([0.9124, 0.9908, 0.9723, 1.0276, 1.0808, 0.9554])),
194+
('perovskite', np.array([0.9434, 0.994, 0.988, 1.0191, 1.0612, 0.975])),
195+
('cdte', np.array([0.9832, 1.0005, 1.0073, 1.0122, 1.0431, 0.9987])),
196+
('multisi', np.array([0.9912, 0.9981, 1.0208, 1.0083, 1.006, 1.0196])),
197+
('monosi', np.array([0.9940, 0.9989, 1.0269, 1.0076, 1.0001, 1.0268])),
198+
('cigs', np.array([1.0018, 1.0012, 1.0274, 1.0083, 1.003, 1.0272])),
199+
])
200+
def test_AM_AOD_PW_spectral_correction(module_type, expected):
201+
ams = np.array([3.0, 1.5, 3.0, 1.5, 1.5, 3.0])
202+
aods = np.array([1.0, 1.0, 0.02, 0.02, 0.08, 0.08])
203+
pws = np.array([1.42, 1.42, 1.42, 1.42, 4.0, 1.0])
204+
out = atmosphere.AM_AOD_PW_spectral_correction(ams, aods, pws,
205+
module_type=module_type,
206+
aod500_ref=0.1, pw_ref=1.4)
207+
assert np.allclose(expected, out, atol=1e-3)
208+
209+
210+
def test_AM_AOD_PW_spectral_correction_supplied():
211+
# use the cdte coeffs
212+
coeffs = (
213+
1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
214+
-0.0182, 0, 0.0095, 0.0068, 0, 1)
215+
out = atmosphere.AM_AOD_PW_spectral_correction(1, 1, 1, coefficients=coeffs)
216+
expected = 1.005674
217+
assert_allclose(out, expected, atol=1e-3)
218+
219+
220+
def test_AM_AOD_PW_spectral_correction_supplied_ambiguous():
221+
with pytest.raises(TypeError):
222+
atmosphere.AM_AOD_PW_spectral_correction(1, 1, 1)

0 commit comments

Comments
 (0)