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,470 +0,0 @@
1
- import pandas as pd
2
- import numpy as np
3
-
4
- import pytest
5
- from .conftest import DATA_DIR, assert_series_equal
6
- from numpy.testing import assert_allclose
7
-
8
- from pvlib import temperature, tools
9
- from pvlib._deprecation import pvlibDeprecationWarning
10
-
11
- import re
12
-
13
-
14
- @pytest.fixture
15
- def sapm_default():
16
- return temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
17
- 'open_rack_glass_glass']
18
-
19
-
20
- def test_sapm_cell(sapm_default):
21
- default = temperature.sapm_cell(900, 20, 5, sapm_default['a'],
22
- sapm_default['b'], sapm_default['deltaT'])
23
- assert_allclose(default, 43.509, 1e-3)
24
-
25
-
26
- def test_sapm_module(sapm_default):
27
- default = temperature.sapm_module(900, 20, 5, sapm_default['a'],
28
- sapm_default['b'])
29
- assert_allclose(default, 40.809, 1e-3)
30
-
31
-
32
- def test_sapm_cell_from_module(sapm_default):
33
- default = temperature.sapm_cell_from_module(50, 900,
34
- sapm_default['deltaT'])
35
- assert_allclose(default, 50 + 900 / 1000 * sapm_default['deltaT'])
36
-
37
-
38
- def test_sapm_ndarray(sapm_default):
39
- temps = np.array([0, 10, 5])
40
- irrads = np.array([0, 500, 0])
41
- winds = np.array([10, 5, 0])
42
- cell_temps = temperature.sapm_cell(irrads, temps, winds, sapm_default['a'],
43
- sapm_default['b'],
44
- sapm_default['deltaT'])
45
- module_temps = temperature.sapm_module(irrads, temps, winds,
46
- sapm_default['a'],
47
- sapm_default['b'])
48
- expected_cell = np.array([0., 23.06066166, 5.])
49
- expected_module = np.array([0., 21.56066166, 5.])
50
- assert_allclose(expected_cell, cell_temps, 1e-3)
51
- assert_allclose(expected_module, module_temps, 1e-3)
52
-
53
-
54
- def test_sapm_series(sapm_default):
55
- times = pd.date_range(start='2015-01-01', end='2015-01-02', freq='12h')
56
- temps = pd.Series([0, 10, 5], index=times)
57
- irrads = pd.Series([0, 500, 0], index=times)
58
- winds = pd.Series([10, 5, 0], index=times)
59
- cell_temps = temperature.sapm_cell(irrads, temps, winds, sapm_default['a'],
60
- sapm_default['b'],
61
- sapm_default['deltaT'])
62
- module_temps = temperature.sapm_module(irrads, temps, winds,
63
- sapm_default['a'],
64
- sapm_default['b'])
65
- expected_cell = pd.Series([0., 23.06066166, 5.], index=times)
66
- expected_module = pd.Series([0., 21.56066166, 5.], index=times)
67
- assert_series_equal(expected_cell, cell_temps)
68
- assert_series_equal(expected_module, module_temps)
69
-
70
-
71
- def test_pvsyst_cell_default():
72
- result = temperature.pvsyst_cell(900, 20, 5)
73
- assert_allclose(result, 45.137, 0.001)
74
-
75
-
76
- def test_pvsyst_cell_kwargs():
77
- result = temperature.pvsyst_cell(900, 20, wind_speed=5.0, u_c=23.5,
78
- u_v=6.25, module_efficiency=0.1)
79
- assert_allclose(result, 33.315, 0.001)
80
-
81
-
82
- def test_pvsyst_cell_ndarray():
83
- temps = np.array([0, 10, 5])
84
- irrads = np.array([0, 500, 0])
85
- winds = np.array([10, 5, 0])
86
- result = temperature.pvsyst_cell(irrads, temps, wind_speed=winds)
87
- expected = np.array([0.0, 23.965517, 5.0])
88
- assert_allclose(expected, result)
89
-
90
-
91
- def test_pvsyst_cell_series():
92
- times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12h")
93
- temps = pd.Series([0, 10, 5], index=times)
94
- irrads = pd.Series([0, 500, 0], index=times)
95
- winds = pd.Series([10, 5, 0], index=times)
96
-
97
- result = temperature.pvsyst_cell(irrads, temps, wind_speed=winds)
98
- expected = pd.Series([0.0, 23.965517, 5.0], index=times)
99
- assert_series_equal(expected, result)
100
-
101
-
102
- def test_faiman_default():
103
- result = temperature.faiman(900, 20, 5)
104
- assert_allclose(result, 35.203, atol=0.001)
105
-
106
-
107
- def test_faiman_kwargs():
108
- result = temperature.faiman(900, 20, wind_speed=5.0, u0=22.0, u1=6.)
109
- assert_allclose(result, 37.308, atol=0.001)
110
-
111
-
112
- def test_faiman_list():
113
- temps = [0, 10, 5]
114
- irrads = [0, 500, 0]
115
- winds = [10, 5, 0]
116
- result = temperature.faiman(irrads, temps, wind_speed=winds)
117
- expected = np.array([0.0, 18.446, 5.0])
118
- assert_allclose(expected, result, atol=0.001)
119
-
120
-
121
- def test_faiman_ndarray():
122
- temps = np.array([0, 10, 5])
123
- irrads = np.array([0, 500, 0])
124
- winds = np.array([10, 5, 0])
125
- result = temperature.faiman(irrads, temps, wind_speed=winds)
126
- expected = np.array([0.0, 18.446, 5.0])
127
- assert_allclose(expected, result, atol=0.001)
128
-
129
-
130
- def test_faiman_rad_no_ir():
131
- expected = temperature.faiman(900, 20, 5)
132
- result = temperature.faiman_rad(900, 20, 5)
133
- assert_allclose(result, expected)
134
-
135
-
136
- def test_faiman_rad_ir():
137
- ir_down = np.array([0, 100, 200, 315.6574, 400])
138
- expected = [-11.111, -7.591, -4.071, -0.000, 2.969]
139
- result = temperature.faiman_rad(0, 0, 0, ir_down)
140
- assert_allclose(result, expected, atol=0.001)
141
-
142
- sky_view = np.array([1.0, 0.5, 0.0])
143
- expected = [-4.071, -2.036, 0.000]
144
- result = temperature.faiman_rad(0, 0, 0, ir_down=200,
145
- sky_view=sky_view)
146
- assert_allclose(result, expected, atol=0.001)
147
-
148
- emissivity = np.array([1.0, 0.88, 0.5, 0.0])
149
- expected = [-4.626, -4.071, -2.313, 0.000]
150
- result = temperature.faiman_rad(0, 0, 0, ir_down=200,
151
- emissivity=emissivity)
152
- assert_allclose(result, expected, atol=0.001)
153
-
154
-
155
- def test_ross():
156
- result = temperature.ross(np.array([1000., 600., 1000.]),
157
- np.array([20., 40., 60.]),
158
- np.array([40., 100., 20.]))
159
- expected = np.array([45., 100., 60.])
160
- assert_allclose(expected, result)
161
-
162
-
163
- def test_faiman_series():
164
- times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12h")
165
- temps = pd.Series([0, 10, 5], index=times)
166
- irrads = pd.Series([0, 500, 0], index=times)
167
- winds = pd.Series([10, 5, 0], index=times)
168
-
169
- result = temperature.faiman(irrads, temps, wind_speed=winds)
170
- expected = pd.Series([0.0, 18.446, 5.0], index=times)
171
- assert_series_equal(expected, result)
172
-
173
-
174
- def test__temperature_model_params():
175
- params = temperature._temperature_model_params('sapm',
176
- 'open_rack_glass_glass')
177
- assert params == temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
178
- 'open_rack_glass_glass']
179
- with pytest.raises(KeyError):
180
- temperature._temperature_model_params('sapm', 'not_a_parameter_set')
181
-
182
-
183
- def _read_pvwatts_8760(filename):
184
- df = pd.read_csv(filename,
185
- skiprows=17, # ignore location/simulation metadata
186
- skipfooter=1, # ignore "Totals" row
187
- engine='python')
188
- df['Year'] = 2019
189
- df.index = pd.to_datetime(df[['Year', 'Month', 'Day', 'Hour']])
190
- return df
191
-
192
-
193
- @pytest.mark.parametrize('filename,inoct', [
194
- ('pvwatts_8760_rackmount.csv', 45),
195
- ('pvwatts_8760_roofmount.csv', 49),
196
- ])
197
- def test_fuentes(filename, inoct):
198
- # Test against data exported from pvwatts.nrel.gov
199
- data = _read_pvwatts_8760(DATA_DIR / filename)
200
- data = data.iloc[:24*7, :] # just use one week
201
- inputs = {
202
- 'poa_global': data['Plane of Array Irradiance (W/m^2)'],
203
- 'temp_air': data['Ambient Temperature (C)'],
204
- 'wind_speed': data['Wind Speed (m/s)'],
205
- 'noct_installed': inoct,
206
- }
207
- expected_tcell = data['Cell Temperature (C)']
208
- expected_tcell.name = 'tmod'
209
- actual_tcell = temperature.fuentes(**inputs)
210
- # the SSC implementation of PVWatts diverges from the Fuentes model at
211
- # at night by setting Tcell=Tamb when POA=0. This not only means that
212
- # nighttime values are slightly different (Fuentes models cooling to sky
213
- # at night), but because of the thermal inertia, there is a transient
214
- # error after dawn as well. Test each case separately:
215
- is_night = inputs['poa_global'] == 0
216
- is_dawn = is_night.shift(1) & ~is_night
217
- is_daytime = (inputs['poa_global'] > 0) & ~is_dawn
218
- # the accuracy is probably higher than 3 digits here, but the PVWatts
219
- # export data has low precision so can only test up to 3 digits
220
- assert_series_equal(expected_tcell[is_daytime].round(3),
221
- actual_tcell[is_daytime].round(3))
222
- # use lower precision for dawn times to accommodate the dawn transient
223
- error = actual_tcell[is_dawn] - expected_tcell[is_dawn]
224
- assert (error.abs() < 0.1).all()
225
- # sanity check on night values -- Fuentes not much lower than PVWatts
226
- night_difference = expected_tcell[is_night] - actual_tcell[is_night]
227
- assert night_difference.max() < 6
228
- assert night_difference.min() > 0
229
-
230
-
231
- @pytest.mark.parametrize('tz', [None, 'Etc/GMT+5'])
232
- def test_fuentes_timezone(tz):
233
- index = pd.date_range('2019-01-01', freq='h', periods=3, tz=tz)
234
-
235
- df = pd.DataFrame({'poa_global': 1000, 'temp_air': 20, 'wind_speed': 1},
236
- index)
237
-
238
- out = temperature.fuentes(df['poa_global'], df['temp_air'],
239
- df['wind_speed'], noct_installed=45)
240
-
241
- assert_series_equal(out, pd.Series([47.85, 50.85, 50.85], index=index,
242
- name='tmod'))
243
-
244
-
245
- def test_noct_sam():
246
- poa_global, temp_air, wind_speed, noct, module_efficiency = (
247
- 1000., 25., 1., 45., 0.2)
248
- expected = 55.230790492
249
- result = temperature.noct_sam(poa_global, temp_air, wind_speed, noct,
250
- module_efficiency)
251
- assert_allclose(result, expected)
252
- # test with different types
253
- result = temperature.noct_sam(np.array(poa_global), np.array(temp_air),
254
- np.array(wind_speed), np.array(noct),
255
- np.array(module_efficiency))
256
- assert_allclose(result, expected)
257
- dr = pd.date_range(start='2020-01-01 12:00:00', end='2020-01-01 13:00:00',
258
- freq='1h')
259
- result = temperature.noct_sam(pd.Series(index=dr, data=poa_global),
260
- pd.Series(index=dr, data=temp_air),
261
- pd.Series(index=dr, data=wind_speed),
262
- pd.Series(index=dr, data=noct),
263
- module_efficiency)
264
- assert_series_equal(result, pd.Series(index=dr, data=expected))
265
-
266
-
267
- def test_noct_sam_against_sam():
268
- # test is constructed to reproduce output from SAM v2020.11.29.
269
- # SAM calculation is the default Detailed PV System model (CEC diode model,
270
- # NOCT cell temperature model), with the only change being the soiling
271
- # loss is set to 0. Weather input is TMY3 for Phoenix AZ.
272
- # Values are taken from the Jan 1 12:00:00 timestamp.
273
- poa_total, temp_air, wind_speed, noct, module_efficiency = (
274
- 860.673, 25, 3, 46.4, 0.20551)
275
- poa_total_after_refl = 851.458 # from SAM output
276
- # compute effective irradiance
277
- # spectral loss coefficients fixed in lib_cec6par.cpp
278
- a = np.flipud([0.918093, 0.086257, -0.024459, 0.002816, -0.000126])
279
- # reproduce SAM air mass calculation
280
- zen = 56.4284
281
- elev = 358
282
- air_mass = 1. / (tools.cosd(zen) + 0.5057 * (96.080 - zen)**-1.634)
283
- air_mass *= np.exp(-0.0001184 * elev)
284
- f1 = np.polyval(a, air_mass)
285
- effective_irradiance = f1 * poa_total_after_refl
286
- transmittance_absorptance = 0.9
287
- array_height = 1
288
- mount_standoff = 4.0
289
- result = temperature.noct_sam(poa_total, temp_air, wind_speed, noct,
290
- module_efficiency, effective_irradiance,
291
- transmittance_absorptance, array_height,
292
- mount_standoff)
293
- expected = 43.0655
294
- # rtol from limited SAM output precision
295
- assert_allclose(result, expected, rtol=1e-5)
296
-
297
-
298
- def test_noct_sam_options():
299
- poa_global, temp_air, wind_speed, noct, module_efficiency = (
300
- 1000., 25., 1., 45., 0.2)
301
- effective_irradiance = 1100.
302
- transmittance_absorptance = 0.8
303
- array_height = 2
304
- mount_standoff = 2.0
305
- result = temperature.noct_sam(poa_global, temp_air, wind_speed, noct,
306
- module_efficiency, effective_irradiance,
307
- transmittance_absorptance, array_height,
308
- mount_standoff)
309
- expected = 60.477703576
310
- assert_allclose(result, expected)
311
-
312
-
313
- def test_noct_sam_errors():
314
- with pytest.raises(ValueError):
315
- temperature.noct_sam(1000., 25., 1., 34., 0.2, array_height=3)
316
-
317
-
318
- def test_prilliman():
319
- # test against values calculated using pvl_MAmodel_2, see pvlib #1081
320
- times = pd.date_range('2019-01-01', freq='5min', periods=8)
321
- cell_temperature = pd.Series([0, 1, 3, 6, 10, 15, 21, 27], index=times)
322
- wind_speed = pd.Series([0, 1, 2, 3, 2, 1, 2, 3])
323
-
324
- # default coeffs
325
- expected = pd.Series([0, 0, 0.7047457, 2.21176412, 4.45584299, 7.63635512,
326
- 12.26808265, 18.00305776], index=times)
327
- actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=10)
328
- assert_series_equal(expected, actual)
329
-
330
- # custom coeffs
331
- coefficients = [0.0046, 4.5537e-4, -2.2586e-4, -1.5661e-5]
332
- expected = pd.Series([0, 0, 0.70716941, 2.2199537, 4.47537694, 7.6676931,
333
- 12.30423167, 18.04215198], index=times)
334
- actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=10,
335
- coefficients=coefficients)
336
- assert_series_equal(expected, actual)
337
-
338
- # even very short inputs < 20 minutes total still work
339
- times = pd.date_range('2019-01-01', freq='1min', periods=8)
340
- cell_temperature = pd.Series([0, 1, 3, 6, 10, 15, 21, 27], index=times)
341
- wind_speed = pd.Series([0, 1, 2, 3, 2, 1, 2, 3])
342
- expected = pd.Series([0, 0, 0.53557976, 1.49270094, 2.85940173,
343
- 4.63914366, 7.09641845, 10.24899272], index=times)
344
- actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=12)
345
- assert_series_equal(expected, actual)
346
-
347
-
348
- def test_prilliman_coarse():
349
- # if the input series time step is >= 20 min, input is returned unchanged,
350
- # and a warning is emitted
351
- times = pd.date_range('2019-01-01', freq='30min', periods=3)
352
- cell_temperature = pd.Series([0, 1, 3], index=times)
353
- wind_speed = pd.Series([0, 1, 2])
354
- msg = re.escape("temperature.prilliman only applies smoothing when the "
355
- "sampling interval is shorter than 20 minutes (input "
356
- "sampling interval: 30.0 minutes); returning "
357
- "input temperature series unchanged")
358
- with pytest.warns(UserWarning, match=msg):
359
- actual = temperature.prilliman(cell_temperature, wind_speed)
360
- assert_series_equal(cell_temperature, actual)
361
-
362
-
363
- def test_prilliman_nans():
364
- # nans in inputs are handled appropriately; nans in input tcell
365
- # are ignored but nans in wind speed cause nan in output
366
- times = pd.date_range('2019-01-01', freq='1min', periods=8)
367
- cell_temperature = pd.Series([0, 1, 3, 6, 10, np.nan, 21, 27], index=times)
368
- wind_speed = pd.Series([0, 1, 2, 3, 2, 1, np.nan, 3])
369
- actual = temperature.prilliman(cell_temperature, wind_speed)
370
- expected = pd.Series([True, True, True, True, True, True, False, True],
371
- index=times)
372
- assert_series_equal(actual.notnull(), expected)
373
-
374
- # check that nan temperatures do not mess up the weighted average;
375
- # the original implementation did not set weight=0 for nan values,
376
- # so the numerator of the weighted average ignored nans but the
377
- # denominator (total weight) still included the weight for the nan.
378
- cell_temperature = pd.Series([1, 1, 1, 1, 1, np.nan, 1, 1], index=times)
379
- wind_speed = pd.Series(1, index=times)
380
- actual = temperature.prilliman(cell_temperature, wind_speed)
381
- # original implementation would return some values < 1 here
382
- expected = pd.Series(1., index=times)
383
- assert_series_equal(actual, expected)
384
-
385
-
386
- def test_glm_conversions():
387
- # it is easiest and sufficient to test conversion from & to the same model
388
- glm = temperature.GenericLinearModel(module_efficiency=0.1,
389
- absorptance=0.9)
390
-
391
- inp = {'u0': 25.0, 'u1': 6.84}
392
- glm.use_faiman(**inp)
393
- out = glm.to_faiman()
394
- for k, v in inp.items():
395
- assert np.isclose(out[k], v)
396
-
397
- inp = {'u_c': 25, 'u_v': 4}
398
- glm.use_pvsyst(**inp)
399
- out = glm.to_pvsyst()
400
- for k, v in inp.items():
401
- assert np.isclose(out[k], v)
402
-
403
- # test with optional parameters
404
- inp = {'u_c': 25, 'u_v': 4,
405
- 'module_efficiency': 0.15,
406
- 'alpha_absorption': 0.95}
407
- glm.use_pvsyst(**inp)
408
- out = glm.to_pvsyst()
409
- for k, v in inp.items():
410
- assert np.isclose(out[k], v)
411
-
412
- inp = {'noct': 47}
413
- glm.use_noct_sam(**inp)
414
- out = glm.to_noct_sam()
415
- for k, v in inp.items():
416
- assert np.isclose(out[k], v)
417
-
418
- # test with optional parameters
419
- inp = {'noct': 47,
420
- 'module_efficiency': 0.15,
421
- 'transmittance_absorptance': 0.95}
422
- glm.use_noct_sam(**inp)
423
- out = glm.to_noct_sam()
424
- for k, v in inp.items():
425
- assert np.isclose(out[k], v)
426
-
427
- inp = {'a': -3.5, 'b': -0.1}
428
- glm.use_sapm(**inp)
429
- out = glm.to_sapm()
430
- for k, v in inp.items():
431
- assert np.isclose(out[k], v)
432
-
433
-
434
- def test_glm_simulations():
435
-
436
- glm = temperature.GenericLinearModel(module_efficiency=0.1,
437
- absorptance=0.9)
438
- wind = np.array([1.4, 1/.51, 5.4])
439
- weather = (800, 20, wind)
440
-
441
- inp = {'u0': 20.0, 'u1': 5.0}
442
- glm.use_faiman(**inp)
443
- out = glm(*weather)
444
- expected = temperature.faiman(*weather, **inp)
445
- assert np.allclose(out, expected)
446
-
447
- out = glm(*weather)
448
- assert np.allclose(out, expected)
449
-
450
- out = glm(*weather, module_efficiency=0.1)
451
- assert np.allclose(out, expected)
452
-
453
- inp = glm.get_generic_linear()
454
- out = temperature.generic_linear(*weather, **inp)
455
- assert np.allclose(out, expected)
456
-
457
-
458
- def test_glm_repr():
459
-
460
- glm = temperature.GenericLinearModel(module_efficiency=0.1,
461
- absorptance=0.9)
462
- inp = {'u0': 20.0, 'u1': 5.0}
463
- glm.use_faiman(**inp)
464
- expected = ("GenericLinearModel: {"
465
- "'u_const': 16.0, "
466
- "'du_wind': 4.0, "
467
- "'eta': 0.1, "
468
- "'alpha': 0.9}")
469
-
470
- assert glm.__repr__() == expected
pvlib/tests/test_tools.py DELETED
@@ -1,146 +0,0 @@
1
- import pytest
2
-
3
- from pvlib import tools
4
- import numpy as np
5
- import pandas as pd
6
- from numpy.testing import assert_allclose
7
-
8
-
9
- @pytest.mark.parametrize('keys, input_dict, expected', [
10
- (['a', 'b'], {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2}),
11
- (['a', 'b', 'd'], {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2}),
12
- (['a'], {}, {}),
13
- (['a'], {'b': 2}, {})
14
- ])
15
- def test_build_kwargs(keys, input_dict, expected):
16
- kwargs = tools._build_kwargs(keys, input_dict)
17
- assert kwargs == expected
18
-
19
-
20
- def _obj_test_golden_sect(params, loc):
21
- return params[loc] * (1. - params['c'] * params[loc]**params['n'])
22
-
23
-
24
- @pytest.mark.parametrize('params, lb, ub, expected, func', [
25
- ({'c': 1., 'n': 1.}, 0., 1., 0.5, _obj_test_golden_sect),
26
- ({'c': 1e6, 'n': 6.}, 0., 1., 0.07230200263994839, _obj_test_golden_sect),
27
- ({'c': 0.2, 'n': 0.3}, 0., 100., 89.14332727531685, _obj_test_golden_sect)
28
- ])
29
- def test__golden_sect_DataFrame(params, lb, ub, expected, func):
30
- v, x = tools._golden_sect_DataFrame(params, lb, ub, func)
31
- assert np.isclose(x, expected, atol=1e-8)
32
-
33
-
34
- def test__golden_sect_DataFrame_atol():
35
- params = {'c': 0.2, 'n': 0.3}
36
- expected = 89.14332727531685
37
- v, x = tools._golden_sect_DataFrame(
38
- params, 0., 100., _obj_test_golden_sect, atol=1e-12)
39
- assert np.isclose(x, expected, atol=1e-12)
40
-
41
-
42
- def test__golden_sect_DataFrame_vector():
43
- params = {'c': np.array([1., 2.]), 'n': np.array([1., 1.])}
44
- lower = np.array([0., 0.001])
45
- upper = np.array([1.1, 1.2])
46
- expected = np.array([0.5, 0.25])
47
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
48
- _obj_test_golden_sect)
49
- assert np.allclose(x, expected, atol=1e-8)
50
- # some upper and lower bounds equal
51
- params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
52
- lower = np.array([0., 0.001, 1.])
53
- upper = np.array([1., 1.2, 1.])
54
- expected = np.array([0.5, 0.25, 1.0]) # x values for maxima
55
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
56
- _obj_test_golden_sect)
57
- assert np.allclose(x, expected, atol=1e-8)
58
- # all upper and lower bounds equal, arrays of length 1
59
- params = {'c': np.array([1.]), 'n': np.array([1.])}
60
- lower = np.array([1.])
61
- upper = np.array([1.])
62
- expected = np.array([1.]) # x values for maxima
63
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
64
- _obj_test_golden_sect)
65
- assert np.allclose(x, expected, atol=1e-8)
66
-
67
-
68
- def test__golden_sect_DataFrame_nans():
69
- # nan in bounds
70
- params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
71
- lower = np.array([0., 0.001, np.nan])
72
- upper = np.array([1.1, 1.2, 1.])
73
- expected = np.array([0.5, 0.25, np.nan])
74
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
75
- _obj_test_golden_sect)
76
- assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
77
- # nan in function values
78
- params = {'c': np.array([1., 2., np.nan]), 'n': np.array([1., 1., 1.])}
79
- lower = np.array([0., 0.001, 0.])
80
- upper = np.array([1.1, 1.2, 1.])
81
- expected = np.array([0.5, 0.25, np.nan])
82
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
83
- _obj_test_golden_sect)
84
- assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
85
- # all nan in bounds
86
- params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
87
- lower = np.array([np.nan, np.nan, np.nan])
88
- upper = np.array([1.1, 1.2, 1.])
89
- expected = np.array([np.nan, np.nan, np.nan])
90
- v, x = tools._golden_sect_DataFrame(params, lower, upper,
91
- _obj_test_golden_sect)
92
- assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
93
-
94
-
95
- def test_degrees_to_index_1():
96
- """Test that _degrees_to_index raises an error when something other than
97
- 'latitude' or 'longitude' is passed."""
98
- with pytest.raises(IndexError): # invalid value for coordinate argument
99
- tools._degrees_to_index(degrees=22.0, coordinate='width')
100
-
101
-
102
- @pytest.mark.parametrize('args, args_idx', [
103
- # no pandas.Series or pandas.DataFrame args
104
- ((1,), None),
105
- (([1],), None),
106
- ((np.array(1),), None),
107
- ((np.array([1]),), None),
108
- # has pandas.Series or pandas.DataFrame args
109
- ((pd.DataFrame([1], index=[1]),), 0),
110
- ((pd.Series([1], index=[1]),), 0),
111
- ((1, pd.Series([1], index=[1]),), 1),
112
- ((1, pd.DataFrame([1], index=[1]),), 1),
113
- # first pandas.Series or pandas.DataFrame is used
114
- ((1, pd.Series([1], index=[1]), pd.DataFrame([2], index=[2]),), 1),
115
- ((1, pd.DataFrame([1], index=[1]), pd.Series([2], index=[2]),), 1),
116
- ])
117
- def test_get_pandas_index(args, args_idx):
118
- index = tools.get_pandas_index(*args)
119
-
120
- if args_idx is None:
121
- assert index is None
122
- else:
123
- pd.testing.assert_index_equal(args[args_idx].index, index)
124
-
125
-
126
- @pytest.mark.parametrize('data_in,expected', [
127
- (np.array([1, 2, 3, 4, 5]),
128
- np.array([0.2, 0.4, 0.6, 0.8, 1])),
129
- (np.array([[0, 1, 2], [0, 3, 6]]),
130
- np.array([[0, 0.5, 1], [0, 0.5, 1]])),
131
- (pd.Series([1, 2, 3, 4, 5]),
132
- pd.Series([0.2, 0.4, 0.6, 0.8, 1])),
133
- (pd.DataFrame({"a": [0, 1, 2], "b": [0, 2, 8]}),
134
- pd.DataFrame({"a": [0, 0.5, 1], "b": [0, 0.25, 1]})),
135
- # test with NaN and all zeroes
136
- (pd.DataFrame({"a": [0, np.nan, 1], "b": [0, 0, 0]}),
137
- pd.DataFrame({"a": [0, np.nan, 1], "b": [np.nan]*3})),
138
- # test with negative values
139
- (np.array([1, 2, -3, 4, -5]),
140
- np.array([0.2, 0.4, -0.6, 0.8, -1])),
141
- (pd.Series([-2, np.nan, 1]),
142
- pd.Series([-1, np.nan, 0.5])),
143
- ])
144
- def test_normalize_max2one(data_in, expected):
145
- result = tools.normalize_max2one(data_in)
146
- assert_allclose(result, expected)