pvlib 0.11.0__py3-none-any.whl → 0.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. pvlib/atmosphere.py +157 -1
  2. pvlib/bifacial/__init__.py +4 -4
  3. pvlib/bifacial/loss_models.py +163 -0
  4. pvlib/clearsky.py +18 -29
  5. pvlib/data/pvgis_tmy_meta.json +32 -93
  6. pvlib/data/pvgis_tmy_test.dat +8761 -8761
  7. pvlib/data/tmy_45.000_8.000_2005_2020.csv +8789 -0
  8. pvlib/data/tmy_45.000_8.000_2005_2020.epw +8768 -0
  9. pvlib/data/tmy_45.000_8.000_2005_2020.json +1 -0
  10. pvlib/data/tmy_45.000_8.000_2005_2020.txt +8761 -0
  11. pvlib/data/tmy_45.000_8.000_userhorizon.json +1 -1
  12. pvlib/data/variables_style_rules.csv +2 -1
  13. pvlib/iotools/pvgis.py +39 -3
  14. pvlib/irradiance.py +141 -120
  15. pvlib/location.py +5 -5
  16. pvlib/modelchain.py +1 -1
  17. pvlib/pvsystem.py +2 -2
  18. pvlib/shading.py +8 -8
  19. pvlib/singlediode.py +1 -1
  20. pvlib/solarposition.py +55 -50
  21. pvlib/spa.py +24 -22
  22. pvlib/spectrum/__init__.py +9 -4
  23. pvlib/spectrum/irradiance.py +272 -0
  24. pvlib/spectrum/mismatch.py +118 -508
  25. pvlib/spectrum/response.py +280 -0
  26. pvlib/spectrum/spectrl2.py +16 -16
  27. pvlib/tests/bifacial/test_losses_models.py +54 -0
  28. pvlib/tests/iotools/test_pvgis.py +57 -11
  29. pvlib/tests/spectrum/__init__.py +0 -0
  30. pvlib/tests/spectrum/conftest.py +40 -0
  31. pvlib/tests/spectrum/test_irradiance.py +138 -0
  32. pvlib/tests/{test_spectrum.py → spectrum/test_mismatch.py} +32 -306
  33. pvlib/tests/spectrum/test_response.py +124 -0
  34. pvlib/tests/spectrum/test_spectrl2.py +72 -0
  35. pvlib/tests/test_atmosphere.py +71 -0
  36. pvlib/tests/test_clearsky.py +37 -25
  37. pvlib/tests/test_irradiance.py +6 -6
  38. pvlib/tests/test_solarposition.py +84 -36
  39. pvlib/tests/test_spa.py +1 -1
  40. pvlib/tools.py +26 -2
  41. pvlib/tracking.py +53 -47
  42. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/METADATA +31 -29
  43. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/RECORD +47 -38
  44. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/WHEEL +1 -1
  45. pvlib/data/tmy_45.000_8.000_2005_2016.csv +0 -8789
  46. pvlib/data/tmy_45.000_8.000_2005_2016.epw +0 -8768
  47. pvlib/data/tmy_45.000_8.000_2005_2016.json +0 -1
  48. pvlib/data/tmy_45.000_8.000_2005_2016.txt +0 -8761
  49. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/AUTHORS.md +0 -0
  50. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/LICENSE +0 -0
  51. {pvlib-0.11.0.dist-info → pvlib-0.11.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,138 @@
1
+ import pytest
2
+ from numpy.testing import assert_allclose, assert_approx_equal, assert_equal
3
+ import pandas as pd
4
+ import numpy as np
5
+ from pvlib import spectrum
6
+ from pvlib._deprecation import pvlibDeprecationWarning
7
+
8
+ from ..conftest import assert_series_equal, fail_on_pvlib_version
9
+
10
+
11
+ @fail_on_pvlib_version('0.12')
12
+ def test_get_am15g():
13
+ # test that the reference spectrum is read and interpolated correctly
14
+ with pytest.warns(pvlibDeprecationWarning,
15
+ match="get_reference_spectra instead"):
16
+ e = spectrum.get_am15g()
17
+ assert_equal(len(e), 2002)
18
+ assert_equal(np.sum(e.index), 2761442)
19
+ assert_approx_equal(np.sum(e), 1002.88, significant=6)
20
+
21
+ wavelength = [270, 850, 950, 1200, 1201.25, 4001]
22
+ expected = [0.0, 0.893720, 0.147260, 0.448250, 0.4371025, 0.0]
23
+
24
+ with pytest.warns(pvlibDeprecationWarning,
25
+ match="get_reference_spectra instead"):
26
+ e = spectrum.get_am15g(wavelength)
27
+ assert_equal(len(e), len(wavelength))
28
+ assert_allclose(e, expected, rtol=1e-6)
29
+
30
+
31
+ @pytest.mark.parametrize(
32
+ "reference_identifier,expected_sums",
33
+ [
34
+ (
35
+ "ASTM G173-03", # reference_identifier
36
+ { # expected_sums
37
+ "extraterrestrial": 1356.15,
38
+ "global": 1002.88,
39
+ "direct": 887.65,
40
+ },
41
+ ),
42
+ ],
43
+ )
44
+ def test_get_reference_spectra(reference_identifier, expected_sums):
45
+ # test reading of a standard spectrum
46
+ standard = spectrum.get_reference_spectra(standard=reference_identifier)
47
+ assert set(standard.columns) == expected_sums.keys()
48
+ assert standard.index.name == "wavelength"
49
+ assert standard.index.is_monotonic_increasing is True
50
+ expected_sums = pd.Series(expected_sums) # convert prior to comparison
51
+ assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-2)
52
+
53
+
54
+ def test_get_reference_spectra_custom_wavelengths():
55
+ # test that the spectrum is interpolated correctly when custom wavelengths
56
+ # are specified
57
+ # only checked for ASTM G173-03 reference spectrum
58
+ wavelength = [270, 850, 951.634, 1200, 4001]
59
+ expected_sums = pd.Series(
60
+ {"extraterrestrial": 2.23266, "global": 1.68952, "direct": 1.58480}
61
+ ) # for given ``wavelength``
62
+ standard = spectrum.get_reference_spectra(
63
+ wavelength, standard="ASTM G173-03"
64
+ )
65
+ assert_equal(len(standard), len(wavelength))
66
+ # check no NaN values were returned
67
+ assert not standard.isna().any().any() # double any to return one value
68
+ assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-4)
69
+
70
+
71
+ def test_get_reference_spectra_invalid_reference():
72
+ # test that an invalid reference identifier raises a ValueError
73
+ with pytest.raises(ValueError, match="Invalid standard identifier"):
74
+ spectrum.get_reference_spectra(standard="invalid")
75
+
76
+
77
+ def test_average_photon_energy_series():
78
+ # test that the APE is calculated correctly with single spectrum
79
+ # series input
80
+
81
+ spectra = spectrum.get_reference_spectra()
82
+ spectra = spectra['global']
83
+ ape = spectrum.average_photon_energy(spectra)
84
+ expected = 1.45017
85
+ assert_allclose(ape, expected, rtol=1e-4)
86
+
87
+
88
+ def test_average_photon_energy_dataframe():
89
+ # test that the APE is calculated correctly with multiple spectra
90
+ # dataframe input and that the output is a series
91
+
92
+ spectra = spectrum.get_reference_spectra().T
93
+ ape = spectrum.average_photon_energy(spectra)
94
+ expected = pd.Series([1.36848, 1.45017, 1.40885])
95
+ expected.index = spectra.index
96
+ assert_series_equal(ape, expected, rtol=1e-4)
97
+
98
+
99
+ def test_average_photon_energy_invalid_type():
100
+ # test that spectrum argument is either a pandas Series or dataframe
101
+ spectra = 5
102
+ with pytest.raises(TypeError, match='must be either a pandas Series or'
103
+ ' DataFrame'):
104
+ spectrum.average_photon_energy(spectra)
105
+
106
+
107
+ def test_average_photon_energy_neg_irr_series():
108
+ # test for handling of negative spectral irradiance values with a
109
+ # pandas Series input
110
+
111
+ spectra = spectrum.get_reference_spectra()['global']*-1
112
+ with pytest.raises(ValueError, match='must be positive'):
113
+ spectrum.average_photon_energy(spectra)
114
+
115
+
116
+ def test_average_photon_energy_neg_irr_dataframe():
117
+ # test for handling of negative spectral irradiance values with a
118
+ # pandas DataFrame input
119
+
120
+ spectra = spectrum.get_reference_spectra().T*-1
121
+
122
+ with pytest.raises(ValueError, match='must be positive'):
123
+ spectrum.average_photon_energy(spectra)
124
+
125
+
126
+ def test_average_photon_energy_zero_irr():
127
+ # test for handling of zero spectral irradiance values with
128
+ # pandas DataFrame and pandas Series input
129
+
130
+ spectra_df_zero = spectrum.get_reference_spectra().T
131
+ spectra_df_zero.iloc[1] = 0
132
+ spectra_series_zero = spectrum.get_reference_spectra()['global']*0
133
+ out_1 = spectrum.average_photon_energy(spectra_df_zero)
134
+ out_2 = spectrum.average_photon_energy(spectra_series_zero)
135
+ expected_1 = np.array([1.36848, np.nan, 1.40885])
136
+ expected_2 = np.nan
137
+ assert_allclose(out_1, expected_1, atol=1e-3)
138
+ assert_allclose(out_2, expected_2, atol=1e-3)
@@ -1,194 +1,10 @@
1
1
  import pytest
2
- from numpy.testing import assert_allclose, assert_approx_equal, assert_equal
2
+ from numpy.testing import assert_allclose, assert_approx_equal
3
3
  import pandas as pd
4
4
  import numpy as np
5
5
  from pvlib import spectrum
6
- from pvlib._deprecation import pvlibDeprecationWarning
7
-
8
- from .conftest import DATA_DIR, assert_series_equal, fail_on_pvlib_version
9
-
10
- SPECTRL2_TEST_DATA = DATA_DIR / 'spectrl2_example_spectra.csv'
11
-
12
-
13
- @pytest.fixture
14
- def spectrl2_data():
15
- # reference spectra generated with solar_utils==0.3
16
- """
17
- expected = solar_utils.spectrl2(
18
- units=1,
19
- location=[40, -80, -5],
20
- datetime=[2020, 3, 15, 10, 45, 59],
21
- weather=[1013, 15],
22
- orientation=[0, 180],
23
- atmospheric_conditions=[1.14, 0.65, 0.344, 0.1, 1.42],
24
- albedo=[0.3, 0.7, 0.8, 1.3, 2.5, 4.0] + [0.2]*6,
25
- )
26
- """
27
- kwargs = {
28
- 'surface_tilt': 0,
29
- 'relative_airmass': 1.4899535986910446,
30
- 'apparent_zenith': 47.912086486816406,
31
- 'aoi': 47.91208648681641,
32
- 'ground_albedo': 0.2,
33
- 'surface_pressure': 101300,
34
- 'ozone': 0.344,
35
- 'precipitable_water': 1.42,
36
- 'aerosol_turbidity_500nm': 0.1,
37
- 'dayofyear': 75
38
- }
39
- df = pd.read_csv(SPECTRL2_TEST_DATA, index_col=0)
40
- # convert um to nm
41
- df['wavelength'] = np.round(df['wavelength'] * 1000, 1)
42
- df[['specdif', 'specdir', 'specetr', 'specglo']] /= 1000
43
- return kwargs, df
44
-
45
-
46
- def test_spectrl2(spectrl2_data):
47
- # compare against output from solar_utils wrapper around NREL spectrl2_2.c
48
- kwargs, expected = spectrl2_data
49
- actual = spectrum.spectrl2(**kwargs)
50
- assert_allclose(expected['wavelength'].values, actual['wavelength'])
51
- assert_allclose(expected['specdif'].values, actual['dhi'].ravel(),
52
- atol=7e-5)
53
- assert_allclose(expected['specdir'].values, actual['dni'].ravel(),
54
- atol=1.5e-4)
55
- assert_allclose(expected['specetr'], actual['dni_extra'].ravel(),
56
- atol=2e-4)
57
- assert_allclose(expected['specglo'], actual['poa_global'].ravel(),
58
- atol=1e-4)
59
-
60
-
61
- def test_spectrl2_array(spectrl2_data):
62
- # test that supplying arrays instead of scalars works
63
- kwargs, expected = spectrl2_data
64
- kwargs = {k: np.array([v, v, v]) for k, v in kwargs.items()}
65
- actual = spectrum.spectrl2(**kwargs)
66
-
67
- assert actual['wavelength'].shape == (122,)
68
-
69
- keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse',
70
- 'poa_direct', 'poa_global']
71
- for key in keys:
72
- assert actual[key].shape == (122, 3)
73
-
74
-
75
- def test_spectrl2_series(spectrl2_data):
76
- # test that supplying Series instead of scalars works
77
- kwargs, expected = spectrl2_data
78
- kwargs.pop('dayofyear')
79
- index = pd.to_datetime(['2020-03-15 10:45:59']*3)
80
- kwargs = {k: pd.Series([v, v, v], index=index) for k, v in kwargs.items()}
81
- actual = spectrum.spectrl2(**kwargs)
82
-
83
- assert actual['wavelength'].shape == (122,)
84
-
85
- keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse',
86
- 'poa_direct', 'poa_global']
87
- for key in keys:
88
- assert actual[key].shape == (122, 3)
89
-
90
-
91
- def test_dayofyear_missing(spectrl2_data):
92
- # test that not specifying dayofyear with non-pandas inputs raises error
93
- kwargs, expected = spectrl2_data
94
- kwargs.pop('dayofyear')
95
- with pytest.raises(ValueError, match='dayofyear must be specified'):
96
- _ = spectrum.spectrl2(**kwargs)
97
-
98
-
99
- def test_aoi_gt_90(spectrl2_data):
100
- # test that returned irradiance values are non-negative when aoi > 90
101
- # see GH #1348
102
- kwargs, _ = spectrl2_data
103
- kwargs['apparent_zenith'] = 70
104
- kwargs['aoi'] = 130
105
- kwargs['surface_tilt'] = 60
106
-
107
- spectra = spectrum.spectrl2(**kwargs)
108
- for key in ['poa_direct', 'poa_global']:
109
- message = f'{key} contains negative values for aoi>90'
110
- assert np.all(spectra[key] >= 0), message
111
-
112
-
113
- def test_get_example_spectral_response():
114
- # test that the sample sr is read and interpolated correctly
115
- sr = spectrum.get_example_spectral_response()
116
- assert_equal(len(sr), 185)
117
- assert_equal(np.sum(sr.index), 136900)
118
- assert_approx_equal(np.sum(sr), 107.6116)
119
-
120
- wavelength = [270, 850, 950, 1200, 4001]
121
- expected = [0.0, 0.92778, 1.0, 0.0, 0.0]
122
-
123
- sr = spectrum.get_example_spectral_response(wavelength)
124
- assert_equal(len(sr), len(wavelength))
125
- assert_allclose(sr, expected, rtol=1e-5)
126
-
127
-
128
- @fail_on_pvlib_version('0.12')
129
- def test_get_am15g():
130
- # test that the reference spectrum is read and interpolated correctly
131
- with pytest.warns(pvlibDeprecationWarning,
132
- match="get_reference_spectra instead"):
133
- e = spectrum.get_am15g()
134
- assert_equal(len(e), 2002)
135
- assert_equal(np.sum(e.index), 2761442)
136
- assert_approx_equal(np.sum(e), 1002.88, significant=6)
137
-
138
- wavelength = [270, 850, 950, 1200, 1201.25, 4001]
139
- expected = [0.0, 0.893720, 0.147260, 0.448250, 0.4371025, 0.0]
140
-
141
- with pytest.warns(pvlibDeprecationWarning,
142
- match="get_reference_spectra instead"):
143
- e = spectrum.get_am15g(wavelength)
144
- assert_equal(len(e), len(wavelength))
145
- assert_allclose(e, expected, rtol=1e-6)
146
-
147
-
148
- @pytest.mark.parametrize(
149
- "reference_identifier,expected_sums",
150
- [
151
- (
152
- "ASTM G173-03", # reference_identifier
153
- { # expected_sums
154
- "extraterrestrial": 1356.15,
155
- "global": 1002.88,
156
- "direct": 887.65,
157
- },
158
- ),
159
- ],
160
- )
161
- def test_get_reference_spectra(reference_identifier, expected_sums):
162
- # test reading of a standard spectrum
163
- standard = spectrum.get_reference_spectra(standard=reference_identifier)
164
- assert set(standard.columns) == expected_sums.keys()
165
- assert standard.index.name == "wavelength"
166
- assert standard.index.is_monotonic_increasing is True
167
- expected_sums = pd.Series(expected_sums) # convert prior to comparison
168
- assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-2)
169
-
170
-
171
- def test_get_reference_spectra_custom_wavelengths():
172
- # test that the spectrum is interpolated correctly when custom wavelengths
173
- # are specified
174
- # only checked for ASTM G173-03 reference spectrum
175
- wavelength = [270, 850, 951.634, 1200, 4001]
176
- expected_sums = pd.Series(
177
- {"extraterrestrial": 2.23266, "global": 1.68952, "direct": 1.58480}
178
- ) # for given ``wavelength``
179
- standard = spectrum.get_reference_spectra(
180
- wavelength, standard="ASTM G173-03"
181
- )
182
- assert_equal(len(standard), len(wavelength))
183
- # check no NaN values were returned
184
- assert not standard.isna().any().any() # double any to return one value
185
- assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-4)
186
-
187
-
188
- def test_get_reference_spectra_invalid_reference():
189
- # test that an invalid reference identifier raises a ValueError
190
- with pytest.raises(ValueError, match="Invalid standard identifier"):
191
- spectrum.get_reference_spectra(standard="invalid")
6
+
7
+ from ..conftest import assert_series_equal
192
8
 
193
9
 
194
10
  def test_calc_spectral_mismatch_field(spectrl2_data):
@@ -264,6 +80,22 @@ def test_spectral_factor_firstsolar_supplied():
264
80
  assert_allclose(out, expected, atol=1e-3)
265
81
 
266
82
 
83
+ def test_spectral_factor_firstsolar_large_airmass_supplied_max():
84
+ # test airmass > user-defined maximum is treated same as airmass=maximum
85
+ m_eq11 = spectrum.spectral_factor_firstsolar(1, 11, 'monosi',
86
+ max_airmass_absolute=11)
87
+ m_gt11 = spectrum.spectral_factor_firstsolar(1, 15, 'monosi',
88
+ max_airmass_absolute=11)
89
+ assert_allclose(m_eq11, m_gt11)
90
+
91
+
92
+ def test_spectral_factor_firstsolar_large_airmass():
93
+ # test that airmass > 10 is treated same as airmass=10
94
+ m_eq10 = spectrum.spectral_factor_firstsolar(1, 10, 'monosi')
95
+ m_gt10 = spectrum.spectral_factor_firstsolar(1, 15, 'monosi')
96
+ assert_allclose(m_eq10, m_gt10)
97
+
98
+
267
99
  def test_spectral_factor_firstsolar_ambiguous():
268
100
  with pytest.raises(TypeError):
269
101
  spectrum.spectral_factor_firstsolar(1, 1)
@@ -276,36 +108,34 @@ def test_spectral_factor_firstsolar_ambiguous_both():
276
108
  spectrum.spectral_factor_firstsolar(1, 1, 'cdte', coefficients=coeffs)
277
109
 
278
110
 
279
- def test_spectral_factor_firstsolar_large_airmass():
280
- # test that airmass > 10 is treated same as airmass==10
281
- m_eq10 = spectrum.spectral_factor_firstsolar(1, 10, 'monosi')
282
- m_gt10 = spectrum.spectral_factor_firstsolar(1, 15, 'monosi')
283
- assert_allclose(m_eq10, m_gt10)
284
-
285
-
286
111
  def test_spectral_factor_firstsolar_low_airmass():
287
- with pytest.warns(UserWarning, match='Exceptionally low air mass'):
112
+ m_eq58 = spectrum.spectral_factor_firstsolar(1, 0.58, 'monosi')
113
+ m_lt58 = spectrum.spectral_factor_firstsolar(1, 0.1, 'monosi')
114
+ assert_allclose(m_eq58, m_lt58)
115
+ with pytest.warns(UserWarning, match='Low airmass values replaced'):
288
116
  _ = spectrum.spectral_factor_firstsolar(1, 0.1, 'monosi')
289
117
 
290
118
 
291
119
  def test_spectral_factor_firstsolar_range():
292
- with pytest.warns(UserWarning, match='Exceptionally high pw values'):
293
- out = spectrum.spectral_factor_firstsolar(np.array([.1, 3, 10]),
294
- np.array([1, 3, 5]),
295
- module_type='monosi')
120
+ out = spectrum.spectral_factor_firstsolar(np.array([.1, 3, 10]),
121
+ np.array([1, 3, 5]),
122
+ module_type='monosi')
296
123
  expected = np.array([0.96080878, 1.03055092, np.nan])
297
124
  assert_allclose(out, expected, atol=1e-3)
298
- with pytest.warns(UserWarning, match='Exceptionally high pw values'):
125
+ with pytest.warns(UserWarning, match='High precipitable water values '
126
+ 'replaced'):
299
127
  out = spectrum.spectral_factor_firstsolar(6, 1.5,
300
128
  max_precipitable_water=5,
301
129
  module_type='monosi')
302
- with pytest.warns(UserWarning, match='Exceptionally low pw values'):
130
+ with pytest.warns(UserWarning, match='Low precipitable water values '
131
+ 'replaced'):
303
132
  out = spectrum.spectral_factor_firstsolar(np.array([0, 3, 8]),
304
133
  np.array([1, 3, 5]),
305
134
  module_type='monosi')
306
135
  expected = np.array([0.96080878, 1.03055092, 1.04932727])
307
136
  assert_allclose(out, expected, atol=1e-3)
308
- with pytest.warns(UserWarning, match='Exceptionally low pw values'):
137
+ with pytest.warns(UserWarning, match='Low precipitable water values '
138
+ 'replaced'):
309
139
  out = spectrum.spectral_factor_firstsolar(0.2, 1.5,
310
140
  min_precipitable_water=1,
311
141
  module_type='monosi')
@@ -472,107 +302,3 @@ def test_spectral_factor_jrc_supplied_ambiguous():
472
302
  with pytest.raises(ValueError, match='No valid input provided'):
473
303
  spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None,
474
304
  coefficients=None)
475
-
476
-
477
- @pytest.fixture
478
- def sr_and_eqe_fixture():
479
- # Just some arbitrary data for testing the conversion functions
480
- df = pd.DataFrame(
481
- columns=("wavelength", "quantum_efficiency", "spectral_response"),
482
- data=[
483
- # nm, [0,1], A/W
484
- [300, 0.85, 0.205671370402405],
485
- [350, 0.86, 0.242772872514211],
486
- [400, 0.87, 0.280680929019753],
487
- [450, 0.88, 0.319395539919029],
488
- [500, 0.89, 0.358916705212040],
489
- [550, 0.90, 0.399244424898786],
490
- [600, 0.91, 0.440378698979267],
491
- [650, 0.92, 0.482319527453483],
492
- [700, 0.93, 0.525066910321434],
493
- [750, 0.94, 0.568620847583119],
494
- [800, 0.95, 0.612981339238540],
495
- [850, 0.90, 0.617014111207215],
496
- [900, 0.80, 0.580719163489143],
497
- [950, 0.70, 0.536358671833723],
498
- [1000, 0.6, 0.483932636240953],
499
- [1050, 0.4, 0.338752845368667],
500
- ],
501
- )
502
- df.set_index("wavelength", inplace=True)
503
- return df
504
-
505
-
506
- def test_sr_to_qe(sr_and_eqe_fixture):
507
- # vector type
508
- qe = spectrum.sr_to_qe(
509
- sr_and_eqe_fixture["spectral_response"].values,
510
- sr_and_eqe_fixture.index.values, # wavelength, nm
511
- )
512
- assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"])
513
- # pandas series type
514
- # note: output Series' name should match the input
515
- qe = spectrum.sr_to_qe(
516
- sr_and_eqe_fixture["spectral_response"]
517
- )
518
- pd.testing.assert_series_equal(
519
- qe, sr_and_eqe_fixture["quantum_efficiency"],
520
- check_names=False
521
- )
522
- assert qe.name == "spectral_response"
523
- # series normalization
524
- qe = spectrum.sr_to_qe(
525
- sr_and_eqe_fixture["spectral_response"] * 10, normalize=True
526
- )
527
- pd.testing.assert_series_equal(
528
- qe,
529
- sr_and_eqe_fixture["quantum_efficiency"]
530
- / max(sr_and_eqe_fixture["quantum_efficiency"]),
531
- check_names=False,
532
- )
533
- # error on lack of wavelength parameter if no pandas object is provided
534
- with pytest.raises(TypeError, match="must have an '.index' attribute"):
535
- _ = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"].values)
536
-
537
-
538
- def test_qe_to_sr(sr_and_eqe_fixture):
539
- # vector type
540
- sr = spectrum.qe_to_sr(
541
- sr_and_eqe_fixture["quantum_efficiency"].values,
542
- sr_and_eqe_fixture.index.values, # wavelength, nm
543
- )
544
- assert_allclose(sr, sr_and_eqe_fixture["spectral_response"])
545
- # pandas series type
546
- # note: output Series' name should match the input
547
- sr = spectrum.qe_to_sr(
548
- sr_and_eqe_fixture["quantum_efficiency"]
549
- )
550
- pd.testing.assert_series_equal(
551
- sr, sr_and_eqe_fixture["spectral_response"],
552
- check_names=False
553
- )
554
- assert sr.name == "quantum_efficiency"
555
- # series normalization
556
- sr = spectrum.qe_to_sr(
557
- sr_and_eqe_fixture["quantum_efficiency"] * 10, normalize=True
558
- )
559
- pd.testing.assert_series_equal(
560
- sr,
561
- sr_and_eqe_fixture["spectral_response"]
562
- / max(sr_and_eqe_fixture["spectral_response"]),
563
- check_names=False,
564
- )
565
- # error on lack of wavelength parameter if no pandas object is provided
566
- with pytest.raises(TypeError, match="must have an '.index' attribute"):
567
- _ = spectrum.qe_to_sr(
568
- sr_and_eqe_fixture["quantum_efficiency"].values
569
- )
570
-
571
-
572
- def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture):
573
- # test that the conversion functions are reciprocal
574
- qe = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"])
575
- sr = spectrum.qe_to_sr(qe)
576
- assert_allclose(sr, sr_and_eqe_fixture["spectral_response"])
577
- qe = spectrum.sr_to_qe(sr)
578
- assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"])
@@ -0,0 +1,124 @@
1
+ import pytest
2
+ import pandas as pd
3
+ from numpy.testing import assert_allclose, assert_approx_equal, assert_equal
4
+ import numpy as np
5
+ from pvlib import spectrum
6
+
7
+
8
+ def test_get_example_spectral_response():
9
+ # test that the sample sr is read and interpolated correctly
10
+ sr = spectrum.get_example_spectral_response()
11
+ assert_equal(len(sr), 185)
12
+ assert_equal(np.sum(sr.index), 136900)
13
+ assert_approx_equal(np.sum(sr), 107.6116)
14
+
15
+ wavelength = [270, 850, 950, 1200, 4001]
16
+ expected = [0.0, 0.92778, 1.0, 0.0, 0.0]
17
+
18
+ sr = spectrum.get_example_spectral_response(wavelength)
19
+ assert_equal(len(sr), len(wavelength))
20
+ assert_allclose(sr, expected, rtol=1e-5)
21
+
22
+
23
+ @pytest.fixture
24
+ def sr_and_eqe_fixture():
25
+ # Just some arbitrary data for testing the conversion functions
26
+ df = pd.DataFrame(
27
+ columns=("wavelength", "quantum_efficiency", "spectral_response"),
28
+ data=[
29
+ # nm, [0,1], A/W
30
+ [300, 0.85, 0.205671370402405],
31
+ [350, 0.86, 0.242772872514211],
32
+ [400, 0.87, 0.280680929019753],
33
+ [450, 0.88, 0.319395539919029],
34
+ [500, 0.89, 0.358916705212040],
35
+ [550, 0.90, 0.399244424898786],
36
+ [600, 0.91, 0.440378698979267],
37
+ [650, 0.92, 0.482319527453483],
38
+ [700, 0.93, 0.525066910321434],
39
+ [750, 0.94, 0.568620847583119],
40
+ [800, 0.95, 0.612981339238540],
41
+ [850, 0.90, 0.617014111207215],
42
+ [900, 0.80, 0.580719163489143],
43
+ [950, 0.70, 0.536358671833723],
44
+ [1000, 0.6, 0.483932636240953],
45
+ [1050, 0.4, 0.338752845368667],
46
+ ],
47
+ )
48
+ df.set_index("wavelength", inplace=True)
49
+ return df
50
+
51
+
52
+ def test_sr_to_qe(sr_and_eqe_fixture):
53
+ # vector type
54
+ qe = spectrum.sr_to_qe(
55
+ sr_and_eqe_fixture["spectral_response"].values,
56
+ sr_and_eqe_fixture.index.values, # wavelength, nm
57
+ )
58
+ assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"])
59
+ # pandas series type
60
+ # note: output Series' name should match the input
61
+ qe = spectrum.sr_to_qe(
62
+ sr_and_eqe_fixture["spectral_response"]
63
+ )
64
+ pd.testing.assert_series_equal(
65
+ qe, sr_and_eqe_fixture["quantum_efficiency"],
66
+ check_names=False
67
+ )
68
+ assert qe.name == "spectral_response"
69
+ # series normalization
70
+ qe = spectrum.sr_to_qe(
71
+ sr_and_eqe_fixture["spectral_response"] * 10, normalize=True
72
+ )
73
+ pd.testing.assert_series_equal(
74
+ qe,
75
+ sr_and_eqe_fixture["quantum_efficiency"]
76
+ / max(sr_and_eqe_fixture["quantum_efficiency"]),
77
+ check_names=False,
78
+ )
79
+ # error on lack of wavelength parameter if no pandas object is provided
80
+ with pytest.raises(TypeError, match="must have an '.index' attribute"):
81
+ _ = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"].values)
82
+
83
+
84
+ def test_qe_to_sr(sr_and_eqe_fixture):
85
+ # vector type
86
+ sr = spectrum.qe_to_sr(
87
+ sr_and_eqe_fixture["quantum_efficiency"].values,
88
+ sr_and_eqe_fixture.index.values, # wavelength, nm
89
+ )
90
+ assert_allclose(sr, sr_and_eqe_fixture["spectral_response"])
91
+ # pandas series type
92
+ # note: output Series' name should match the input
93
+ sr = spectrum.qe_to_sr(
94
+ sr_and_eqe_fixture["quantum_efficiency"]
95
+ )
96
+ pd.testing.assert_series_equal(
97
+ sr, sr_and_eqe_fixture["spectral_response"],
98
+ check_names=False
99
+ )
100
+ assert sr.name == "quantum_efficiency"
101
+ # series normalization
102
+ sr = spectrum.qe_to_sr(
103
+ sr_and_eqe_fixture["quantum_efficiency"] * 10, normalize=True
104
+ )
105
+ pd.testing.assert_series_equal(
106
+ sr,
107
+ sr_and_eqe_fixture["spectral_response"]
108
+ / max(sr_and_eqe_fixture["spectral_response"]),
109
+ check_names=False,
110
+ )
111
+ # error on lack of wavelength parameter if no pandas object is provided
112
+ with pytest.raises(TypeError, match="must have an '.index' attribute"):
113
+ _ = spectrum.qe_to_sr(
114
+ sr_and_eqe_fixture["quantum_efficiency"].values
115
+ )
116
+
117
+
118
+ def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture):
119
+ # test that the conversion functions are reciprocal
120
+ qe = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"])
121
+ sr = spectrum.qe_to_sr(qe)
122
+ assert_allclose(sr, sr_and_eqe_fixture["spectral_response"])
123
+ qe = spectrum.sr_to_qe(sr)
124
+ assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"])