pvlib 0.11.2__py3-none-any.whl → 0.12.1a1__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 (147) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/atmosphere.py +40 -40
  3. pvlib/bifacial/infinite_sheds.py +4 -3
  4. pvlib/bifacial/utils.py +2 -1
  5. pvlib/iotools/__init__.py +6 -0
  6. pvlib/iotools/psm3.py +1 -1
  7. pvlib/iotools/psm4.py +819 -0
  8. pvlib/iotools/pvgis.py +10 -2
  9. pvlib/iotools/tmy.py +3 -69
  10. pvlib/irradiance.py +38 -15
  11. pvlib/ivtools/sdm/__init__.py +20 -0
  12. pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
  13. pvlib/ivtools/sdm/cec.py +93 -0
  14. pvlib/ivtools/sdm/desoto.py +401 -0
  15. pvlib/ivtools/sdm/pvsyst.py +630 -0
  16. pvlib/location.py +73 -33
  17. pvlib/modelchain.py +19 -36
  18. pvlib/pvsystem.py +114 -65
  19. pvlib/snow.py +64 -28
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/tools.py +6 -5
  24. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/METADATA +6 -5
  25. pvlib-0.12.1a1.dist-info/RECORD +80 -0
  26. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/WHEEL +1 -1
  27. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  28. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  29. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  30. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  31. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  32. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  33. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  34. pvlib/data/CRN_with_problems.txt +0 -3
  35. pvlib/data/ET-M772BH550GL.PAN +0 -75
  36. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  37. pvlib/data/PVsyst_demo.csv +0 -10757
  38. pvlib/data/PVsyst_demo_model.csv +0 -3588
  39. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  40. pvlib/data/abq19056.dat +0 -6
  41. pvlib/data/bishop88_numerical_precision.csv +0 -101
  42. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  43. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  44. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  45. pvlib/data/cams_mcclear_monthly.csv +0 -42
  46. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  47. pvlib/data/cams_radiation_monthly.csv +0 -47
  48. pvlib/data/detect_clearsky_data.csv +0 -35
  49. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  50. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  51. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  52. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  53. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  54. pvlib/data/ivtools_numdiff.csv +0 -52
  55. pvlib/data/midc_20181014.txt +0 -1441
  56. pvlib/data/midc_raw_20181018.txt +0 -1441
  57. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  58. pvlib/data/msn19056.dat +0 -6
  59. pvlib/data/precise_iv_curves1.json +0 -10251
  60. pvlib/data/precise_iv_curves2.json +0 -10251
  61. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  62. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  63. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  64. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  65. pvlib/data/pvgis_tmy_meta.json +0 -32
  66. pvlib/data/pvgis_tmy_test.csv +0 -8761
  67. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  68. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  69. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  70. pvlib/data/spectrl2_example_spectra.csv +0 -123
  71. pvlib/data/surfrad-slv16001.dat +0 -1442
  72. pvlib/data/test_psm3_2017.csv +0 -17521
  73. pvlib/data/test_psm3_2019_5min.csv +0 -289
  74. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  75. pvlib/data/test_read_psm3.csv +0 -17523
  76. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  77. pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
  78. pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
  79. pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
  80. pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
  81. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  82. pvlib/ivtools/sdm.py +0 -1379
  83. pvlib/spa_c_files/README.md +0 -81
  84. pvlib/spa_c_files/cspa_py.pxd +0 -43
  85. pvlib/spa_c_files/spa_py.pyx +0 -30
  86. pvlib/tests/__init__.py +0 -0
  87. pvlib/tests/bifacial/__init__.py +0 -0
  88. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  89. pvlib/tests/bifacial/test_losses_models.py +0 -54
  90. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  91. pvlib/tests/bifacial/test_utils.py +0 -192
  92. pvlib/tests/conftest.py +0 -476
  93. pvlib/tests/iotools/__init__.py +0 -0
  94. pvlib/tests/iotools/test_acis.py +0 -213
  95. pvlib/tests/iotools/test_bsrn.py +0 -131
  96. pvlib/tests/iotools/test_crn.py +0 -95
  97. pvlib/tests/iotools/test_epw.py +0 -23
  98. pvlib/tests/iotools/test_midc.py +0 -89
  99. pvlib/tests/iotools/test_panond.py +0 -32
  100. pvlib/tests/iotools/test_psm3.py +0 -198
  101. pvlib/tests/iotools/test_pvgis.py +0 -644
  102. pvlib/tests/iotools/test_sodapro.py +0 -298
  103. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  104. pvlib/tests/iotools/test_solargis.py +0 -68
  105. pvlib/tests/iotools/test_solcast.py +0 -324
  106. pvlib/tests/iotools/test_solrad.py +0 -152
  107. pvlib/tests/iotools/test_srml.py +0 -124
  108. pvlib/tests/iotools/test_surfrad.py +0 -75
  109. pvlib/tests/iotools/test_tmy.py +0 -133
  110. pvlib/tests/ivtools/__init__.py +0 -0
  111. pvlib/tests/ivtools/test_sde.py +0 -230
  112. pvlib/tests/ivtools/test_sdm.py +0 -429
  113. pvlib/tests/ivtools/test_utils.py +0 -173
  114. pvlib/tests/spectrum/__init__.py +0 -0
  115. pvlib/tests/spectrum/conftest.py +0 -40
  116. pvlib/tests/spectrum/test_irradiance.py +0 -138
  117. pvlib/tests/spectrum/test_mismatch.py +0 -304
  118. pvlib/tests/spectrum/test_response.py +0 -124
  119. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  120. pvlib/tests/test__deprecation.py +0 -97
  121. pvlib/tests/test_albedo.py +0 -84
  122. pvlib/tests/test_atmosphere.py +0 -351
  123. pvlib/tests/test_clearsky.py +0 -884
  124. pvlib/tests/test_conftest.py +0 -37
  125. pvlib/tests/test_iam.py +0 -555
  126. pvlib/tests/test_inverter.py +0 -213
  127. pvlib/tests/test_irradiance.py +0 -1487
  128. pvlib/tests/test_location.py +0 -356
  129. pvlib/tests/test_modelchain.py +0 -2020
  130. pvlib/tests/test_numerical_precision.py +0 -124
  131. pvlib/tests/test_pvarray.py +0 -71
  132. pvlib/tests/test_pvsystem.py +0 -2511
  133. pvlib/tests/test_scaling.py +0 -207
  134. pvlib/tests/test_shading.py +0 -391
  135. pvlib/tests/test_singlediode.py +0 -608
  136. pvlib/tests/test_snow.py +0 -212
  137. pvlib/tests/test_soiling.py +0 -230
  138. pvlib/tests/test_solarposition.py +0 -966
  139. pvlib/tests/test_spa.py +0 -454
  140. pvlib/tests/test_temperature.py +0 -470
  141. pvlib/tests/test_tools.py +0 -146
  142. pvlib/tests/test_tracking.py +0 -474
  143. pvlib/tests/test_transformer.py +0 -60
  144. pvlib-0.11.2.dist-info/RECORD +0 -191
  145. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/AUTHORS.md +0 -0
  146. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/LICENSE +0 -0
  147. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/top_level.txt +0 -0
@@ -1,138 +0,0 @@
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,304 +0,0 @@
1
- import pytest
2
- from numpy.testing import assert_allclose, assert_approx_equal
3
- import pandas as pd
4
- import numpy as np
5
- from pvlib import spectrum
6
-
7
- from ..conftest import assert_series_equal
8
-
9
-
10
- def test_calc_spectral_mismatch_field(spectrl2_data):
11
- # test that the mismatch is calculated correctly with
12
- # - default and custom reference spectrum
13
- # - single or multiple sun spectra
14
-
15
- # sample data
16
- _, e_sun = spectrl2_data
17
- e_sun = e_sun.set_index('wavelength')
18
- e_sun = e_sun.transpose()
19
-
20
- e_ref = spectrum.get_reference_spectra(standard='ASTM G173-03')["global"]
21
- sr = spectrum.get_example_spectral_response()
22
-
23
- # test with single sun spectrum, same as ref spectrum
24
- mm = spectrum.calc_spectral_mismatch_field(sr, e_sun=e_ref)
25
- assert_approx_equal(mm, 1.0, significant=6)
26
-
27
- # test with single sun spectrum
28
- mm = spectrum.calc_spectral_mismatch_field(sr, e_sun=e_sun.loc['specglo'])
29
- assert_approx_equal(mm, 0.992397, significant=6)
30
-
31
- # test with single sun spectrum, also used as reference spectrum
32
- mm = spectrum.calc_spectral_mismatch_field(sr,
33
- e_sun=e_sun.loc['specglo'],
34
- e_ref=e_sun.loc['specglo'])
35
- assert_approx_equal(mm, 1.0, significant=6)
36
-
37
- # test with multiple sun spectra
38
- expected = [0.972982, 0.995581, 0.899782, 0.992397]
39
-
40
- mm = spectrum.calc_spectral_mismatch_field(sr, e_sun=e_sun)
41
- assert mm.index is e_sun.index
42
- assert_allclose(mm, expected, rtol=1e-6)
43
-
44
-
45
- @pytest.mark.parametrize("module_type,expect", [
46
- ('cdte', np.array(
47
- [[0.99051020, 0.97640320, 0.93975028],
48
- [1.02928735, 1.01881074, 0.98578821],
49
- [1.04750335, 1.03814456, 1.00623986]])),
50
- ('monosi', np.array(
51
- [[0.97769770, 1.02043409, 1.03574032],
52
- [0.98630905, 1.03055092, 1.04736262],
53
- [0.98828494, 1.03299036, 1.05026561]])),
54
- ('polysi', np.array(
55
- [[0.97704080, 1.01705849, 1.02613202],
56
- [0.98992828, 1.03173953, 1.04260662],
57
- [0.99352435, 1.03588785, 1.04730718]])),
58
- ('cigs', np.array(
59
- [[0.97459190, 1.02821696, 1.05067895],
60
- [0.97529378, 1.02967497, 1.05289307],
61
- [0.97269159, 1.02730558, 1.05075651]])),
62
- ('asi', np.array(
63
- [[1.05552750, 0.87707583, 0.72243772],
64
- [1.11225204, 0.93665901, 0.78487953],
65
- [1.14555295, 0.97084011, 0.81994083]]))
66
- ])
67
- def test_spectral_factor_firstsolar(module_type, expect):
68
- ams = np.array([1, 3, 5])
69
- pws = np.array([1, 3, 5])
70
- ams, pws = np.meshgrid(ams, pws)
71
- out = spectrum.spectral_factor_firstsolar(pws, ams, module_type)
72
- assert_allclose(out, expect, atol=0.001)
73
-
74
-
75
- def test_spectral_factor_firstsolar_supplied():
76
- # use the cdte coeffs
77
- coeffs = (0.87102, -0.040543, -0.00929202, 0.10052, 0.073062, -0.0034187)
78
- out = spectrum.spectral_factor_firstsolar(1, 1, coefficients=coeffs)
79
- expected = 0.99134828
80
- assert_allclose(out, expected, atol=1e-3)
81
-
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
-
99
- def test_spectral_factor_firstsolar_ambiguous():
100
- with pytest.raises(TypeError):
101
- spectrum.spectral_factor_firstsolar(1, 1)
102
-
103
-
104
- def test_spectral_factor_firstsolar_ambiguous_both():
105
- # use the cdte coeffs
106
- coeffs = (0.87102, -0.040543, -0.00929202, 0.10052, 0.073062, -0.0034187)
107
- with pytest.raises(TypeError):
108
- spectrum.spectral_factor_firstsolar(1, 1, 'cdte', coefficients=coeffs)
109
-
110
-
111
- def test_spectral_factor_firstsolar_low_airmass():
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'):
116
- _ = spectrum.spectral_factor_firstsolar(1, 0.1, 'monosi')
117
-
118
-
119
- def test_spectral_factor_firstsolar_range():
120
- out = spectrum.spectral_factor_firstsolar(np.array([.1, 3, 10]),
121
- np.array([1, 3, 5]),
122
- module_type='monosi')
123
- expected = np.array([0.96080878, 1.03055092, np.nan])
124
- assert_allclose(out, expected, atol=1e-3)
125
- with pytest.warns(UserWarning, match='High precipitable water values '
126
- 'replaced'):
127
- out = spectrum.spectral_factor_firstsolar(6, 1.5,
128
- max_precipitable_water=5,
129
- module_type='monosi')
130
- with pytest.warns(UserWarning, match='Low precipitable water values '
131
- 'replaced'):
132
- out = spectrum.spectral_factor_firstsolar(np.array([0, 3, 8]),
133
- np.array([1, 3, 5]),
134
- module_type='monosi')
135
- expected = np.array([0.96080878, 1.03055092, 1.04932727])
136
- assert_allclose(out, expected, atol=1e-3)
137
- with pytest.warns(UserWarning, match='Low precipitable water values '
138
- 'replaced'):
139
- out = spectrum.spectral_factor_firstsolar(0.2, 1.5,
140
- min_precipitable_water=1,
141
- module_type='monosi')
142
-
143
-
144
- @pytest.mark.parametrize('airmass,expected', [
145
- (1.5, 1.00028714375),
146
- (np.array([[10, np.nan]]), np.array([[0.999535, 0]])),
147
- (pd.Series([5]), pd.Series([1.0387675]))
148
- ])
149
- def test_spectral_factor_sapm(sapm_module_params, airmass, expected):
150
-
151
- out = spectrum.spectral_factor_sapm(airmass, sapm_module_params)
152
-
153
- if isinstance(airmass, pd.Series):
154
- assert_series_equal(out, expected, check_less_precise=4)
155
- else:
156
- assert_allclose(out, expected, atol=1e-4)
157
-
158
-
159
- @pytest.mark.parametrize("module_type,expected", [
160
- ('asi', np.array([0.9108, 0.9897, 0.9707, 1.0265, 1.0798, 0.9537])),
161
- ('perovskite', np.array([0.9422, 0.9932, 0.9868, 1.0183, 1.0604, 0.9737])),
162
- ('cdte', np.array([0.9824, 1.0000, 1.0065, 1.0117, 1.042, 0.9979])),
163
- ('multisi', np.array([0.9907, 0.9979, 1.0203, 1.0081, 1.0058, 1.019])),
164
- ('monosi', np.array([0.9935, 0.9987, 1.0264, 1.0074, 0.9999, 1.0263])),
165
- ('cigs', np.array([1.0014, 1.0011, 1.0270, 1.0082, 1.0029, 1.026])),
166
- ])
167
- def test_spectral_factor_caballero(module_type, expected):
168
- ams = np.array([3.0, 1.5, 3.0, 1.5, 1.5, 3.0])
169
- aods = np.array([1.0, 1.0, 0.02, 0.02, 0.08, 0.08])
170
- pws = np.array([1.42, 1.42, 1.42, 1.42, 4.0, 1.0])
171
- out = spectrum.spectral_factor_caballero(pws, ams, aods,
172
- module_type=module_type)
173
- assert np.allclose(expected, out, atol=1e-3)
174
-
175
-
176
- def test_spectral_factor_caballero_supplied():
177
- # use the cdte coeffs
178
- coeffs = (
179
- 1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
180
- -0.0182, 0, 0.0095, 0.0068, 0, 1)
181
- out = spectrum.spectral_factor_caballero(1, 1, 1, coefficients=coeffs)
182
- expected = 1.0021964
183
- assert_allclose(out, expected, atol=1e-3)
184
-
185
-
186
- def test_spectral_factor_caballero_supplied_redundant():
187
- # Error when specifying both module_type and coefficients
188
- coeffs = (
189
- 1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
190
- -0.0182, 0, 0.0095, 0.0068, 0, 1)
191
- with pytest.raises(ValueError):
192
- spectrum.spectral_factor_caballero(1, 1, 1, module_type='cdte',
193
- coefficients=coeffs)
194
-
195
-
196
- def test_spectral_factor_caballero_supplied_ambiguous():
197
- # Error when specifying neither module_type nor coefficients
198
- with pytest.raises(ValueError):
199
- spectrum.spectral_factor_caballero(1, 1, 1, module_type=None,
200
- coefficients=None)
201
-
202
-
203
- @pytest.mark.parametrize("module_type,expected", [
204
- ('asi', np.array([1.15534029, 1.1123772, 1.08286684, 1.01915462])),
205
- ('fs-2', np.array([1.0694323, 1.04948777, 1.03556288, 0.9881471])),
206
- ('fs-4', np.array([1.05234725, 1.037771, 1.0275516, 0.98820533])),
207
- ('multisi', np.array([1.03310403, 1.02391703, 1.01744833, 0.97947605])),
208
- ('monosi', np.array([1.03225083, 1.02335353, 1.01708734, 0.97950110])),
209
- ('cigs', np.array([1.01475834, 1.01143927, 1.00909094, 0.97852966])),
210
- ])
211
- def test_spectral_factor_pvspec(module_type, expected):
212
- ams = np.array([1.0, 1.5, 2.0, 1.5])
213
- kcs = np.array([0.4, 0.6, 0.8, 1.4])
214
- out = spectrum.spectral_factor_pvspec(ams, kcs,
215
- module_type=module_type)
216
- assert np.allclose(expected, out, atol=1e-8)
217
-
218
-
219
- @pytest.mark.parametrize("module_type,expected", [
220
- ('asi', pd.Series([1.15534029, 1.1123772, 1.08286684, 1.01915462])),
221
- ('fs-2', pd.Series([1.0694323, 1.04948777, 1.03556288, 0.9881471])),
222
- ('fs-4', pd.Series([1.05234725, 1.037771, 1.0275516, 0.98820533])),
223
- ('multisi', pd.Series([1.03310403, 1.02391703, 1.01744833, 0.97947605])),
224
- ('monosi', pd.Series([1.03225083, 1.02335353, 1.01708734, 0.97950110])),
225
- ('cigs', pd.Series([1.01475834, 1.01143927, 1.00909094, 0.97852966])),
226
- ])
227
- def test_spectral_factor_pvspec_series(module_type, expected):
228
- ams = pd.Series([1.0, 1.5, 2.0, 1.5])
229
- kcs = pd.Series([0.4, 0.6, 0.8, 1.4])
230
- out = spectrum.spectral_factor_pvspec(ams, kcs,
231
- module_type=module_type)
232
- assert isinstance(out, pd.Series)
233
- assert np.allclose(expected, out, atol=1e-8)
234
-
235
-
236
- def test_spectral_factor_pvspec_supplied():
237
- # use the multisi coeffs
238
- coeffs = (0.9847, -0.05237, 0.03034)
239
- out = spectrum.spectral_factor_pvspec(1.5, 0.8, coefficients=coeffs)
240
- expected = 1.00860641
241
- assert_allclose(out, expected, atol=1e-8)
242
-
243
-
244
- def test_spectral_factor_pvspec_supplied_redundant():
245
- # Error when specifying both module_type and coefficients
246
- coeffs = (0.9847, -0.05237, 0.03034)
247
- with pytest.raises(ValueError, match='supply only one of'):
248
- spectrum.spectral_factor_pvspec(1.5, 0.8, module_type='multisi',
249
- coefficients=coeffs)
250
-
251
-
252
- def test_spectral_factor_pvspec_supplied_ambiguous():
253
- # Error when specifying neither module_type nor coefficients
254
- with pytest.raises(ValueError, match='No valid input provided'):
255
- spectrum.spectral_factor_pvspec(1.5, 0.8, module_type=None,
256
- coefficients=None)
257
-
258
-
259
- @pytest.mark.parametrize("module_type,expected", [
260
- ('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
261
- ('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
262
- ])
263
- def test_spectral_factor_jrc(module_type, expected):
264
- ams = np.array([1.0, 1.5, 2.0, 1.5])
265
- kcs = np.array([0.4, 0.6, 0.8, 1.4])
266
- out = spectrum.spectral_factor_jrc(ams, kcs,
267
- module_type=module_type)
268
- assert np.allclose(expected, out, atol=1e-4)
269
-
270
-
271
- @pytest.mark.parametrize("module_type,expected", [
272
- ('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
273
- ('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
274
- ])
275
- def test_spectral_factor_jrc_series(module_type, expected):
276
- ams = pd.Series([1.0, 1.5, 2.0, 1.5])
277
- kcs = pd.Series([0.4, 0.6, 0.8, 1.4])
278
- out = spectrum.spectral_factor_jrc(ams, kcs,
279
- module_type=module_type)
280
- assert isinstance(out, pd.Series)
281
- assert np.allclose(expected, out, atol=1e-4)
282
-
283
-
284
- def test_spectral_factor_jrc_supplied():
285
- # use the multisi coeffs
286
- coeffs = (0.494, 0.146, 0.00103)
287
- out = spectrum.spectral_factor_jrc(1.0, 0.8, coefficients=coeffs)
288
- expected = 1.01052106
289
- assert_allclose(out, expected, atol=1e-4)
290
-
291
-
292
- def test_spectral_factor_jrc_supplied_redundant():
293
- # Error when specifying both module_type and coefficients
294
- coeffs = (0.494, 0.146, 0.00103)
295
- with pytest.raises(ValueError, match='supply only one of'):
296
- spectrum.spectral_factor_jrc(1.0, 0.8, module_type='multisi',
297
- coefficients=coeffs)
298
-
299
-
300
- def test_spectral_factor_jrc_supplied_ambiguous():
301
- # Error when specifying neither module_type nor coefficients
302
- with pytest.raises(ValueError, match='No valid input provided'):
303
- spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None,
304
- coefficients=None)
@@ -1,124 +0,0 @@
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"])
@@ -1,72 +0,0 @@
1
- import pytest
2
- import pandas as pd
3
- import numpy as np
4
- from pvlib import spectrum
5
- from numpy.testing import assert_allclose
6
-
7
-
8
- def test_spectrl2(spectrl2_data):
9
- # compare against output from solar_utils wrapper around NREL spectrl2_2.c
10
- kwargs, expected = spectrl2_data
11
- actual = spectrum.spectrl2(**kwargs)
12
- assert_allclose(expected['wavelength'].values, actual['wavelength'])
13
- assert_allclose(expected['specdif'].values, actual['dhi'].ravel(),
14
- atol=7e-5)
15
- assert_allclose(expected['specdir'].values, actual['dni'].ravel(),
16
- atol=1.5e-4)
17
- assert_allclose(expected['specetr'], actual['dni_extra'].ravel(),
18
- atol=2e-4)
19
- assert_allclose(expected['specglo'], actual['poa_global'].ravel(),
20
- atol=1e-4)
21
-
22
-
23
- def test_spectrl2_array(spectrl2_data):
24
- # test that supplying arrays instead of scalars works
25
- kwargs, expected = spectrl2_data
26
- kwargs = {k: np.array([v, v, v]) for k, v in kwargs.items()}
27
- actual = spectrum.spectrl2(**kwargs)
28
-
29
- assert actual['wavelength'].shape == (122,)
30
-
31
- keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse',
32
- 'poa_direct', 'poa_global']
33
- for key in keys:
34
- assert actual[key].shape == (122, 3)
35
-
36
-
37
- def test_spectrl2_series(spectrl2_data):
38
- # test that supplying Series instead of scalars works
39
- kwargs, expected = spectrl2_data
40
- kwargs.pop('dayofyear')
41
- index = pd.to_datetime(['2020-03-15 10:45:59']*3)
42
- kwargs = {k: pd.Series([v, v, v], index=index) for k, v in kwargs.items()}
43
- actual = spectrum.spectrl2(**kwargs)
44
-
45
- assert actual['wavelength'].shape == (122,)
46
-
47
- keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse',
48
- 'poa_direct', 'poa_global']
49
- for key in keys:
50
- assert actual[key].shape == (122, 3)
51
-
52
-
53
- def test_dayofyear_missing(spectrl2_data):
54
- # test that not specifying dayofyear with non-pandas inputs raises error
55
- kwargs, expected = spectrl2_data
56
- kwargs.pop('dayofyear')
57
- with pytest.raises(ValueError, match='dayofyear must be specified'):
58
- _ = spectrum.spectrl2(**kwargs)
59
-
60
-
61
- def test_aoi_gt_90(spectrl2_data):
62
- # test that returned irradiance values are non-negative when aoi > 90
63
- # see GH #1348
64
- kwargs, _ = spectrl2_data
65
- kwargs['apparent_zenith'] = 70
66
- kwargs['aoi'] = 130
67
- kwargs['surface_tilt'] = 60
68
-
69
- spectra = spectrum.spectrl2(**kwargs)
70
- for key in ['poa_direct', 'poa_global']:
71
- message = f'{key} contains negative values for aoi>90'
72
- assert np.all(spectra[key] >= 0), message