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
pvlib/tests/test_snow.py DELETED
@@ -1,212 +0,0 @@
1
- import numpy as np
2
- import pandas as pd
3
-
4
- from .conftest import assert_series_equal
5
-
6
- from pvlib import snow
7
- from pvlib.tools import sind
8
-
9
- import pytest
10
-
11
-
12
- def test_fully_covered_nrel():
13
- dt = pd.date_range(start="2019-1-1 12:00:00", end="2019-1-1 18:00:00",
14
- freq='1h')
15
- snowfall_data = pd.Series([1, 5, .6, 4, .23, -5, 19], index=dt)
16
- expected = pd.Series([False, True, False, True, False, False, True],
17
- index=dt)
18
- fully_covered = snow.fully_covered_nrel(snowfall_data)
19
- assert_series_equal(expected, fully_covered)
20
-
21
-
22
- def test_coverage_nrel_hourly():
23
- surface_tilt = 45
24
- slide_amount_coefficient = 0.197
25
- dt = pd.date_range(start="2019-1-1 10:00:00", end="2019-1-1 17:00:00",
26
- freq='1h')
27
- poa_irradiance = pd.Series([400, 200, 100, 1234, 134, 982, 100, 100],
28
- index=dt)
29
- temp_air = pd.Series([10, 2, 10, 1234, 34, 982, 10, 10], index=dt)
30
- snowfall_data = pd.Series([1, .5, .6, .4, .23, -5, .1, .1], index=dt)
31
- snow_coverage = snow.coverage_nrel(
32
- snowfall_data, poa_irradiance, temp_air, surface_tilt,
33
- threshold_snowfall=0.6)
34
-
35
- slide_amt = slide_amount_coefficient * sind(surface_tilt)
36
- covered = 1.0 - slide_amt * np.array([0, 1, 2, 3, 4, 5, 6, 7])
37
- expected = pd.Series(covered, index=dt)
38
- assert_series_equal(expected, snow_coverage)
39
-
40
-
41
- def test_coverage_nrel_subhourly():
42
- surface_tilt = 45
43
- slide_amount_coefficient = 0.197
44
- dt = pd.date_range(start="2019-1-1 11:00:00", end="2019-1-1 14:00:00",
45
- freq='15min')
46
- poa_irradiance = pd.Series([400, 200, 100, 1234, 134, 982, 100, 100, 100,
47
- 100, 100, 100, 0],
48
- index=dt)
49
- temp_air = pd.Series([10, 2, 10, 1234, 34, 982, 10, 10, 10, 10, -10, -10,
50
- 10], index=dt)
51
- snowfall_data = pd.Series([1, .5, .6, .4, .23, -5, .1, .1, 0., 1., 0., 0.,
52
- 0.], index=dt)
53
- snow_coverage = snow.coverage_nrel(
54
- snowfall_data, poa_irradiance, temp_air, surface_tilt)
55
- slide_amt = slide_amount_coefficient * sind(surface_tilt) * 0.25
56
- covered = np.append(np.array([1., 1., 1., 1.]),
57
- 1.0 - slide_amt * np.array([1, 2, 3, 4, 5]))
58
- covered = np.append(covered, np.array([1., 1., 1., 1. - slide_amt]))
59
- expected = pd.Series(covered, index=dt)
60
- assert_series_equal(expected, snow_coverage)
61
-
62
-
63
- def test_fully_covered_nrel_irregular():
64
- # test when frequency is not specified and can't be inferred
65
- dt = pd.DatetimeIndex(["2019-1-1 11:00:00", "2019-1-1 14:30:00",
66
- "2019-1-1 15:07:00", "2019-1-1 14:00:00"])
67
- snowfall_data = pd.Series([1, .5, .6, .4], index=dt)
68
- snow_coverage = snow.fully_covered_nrel(snowfall_data,
69
- threshold_snowfall=0.5)
70
- covered = np.array([False, False, True, False])
71
- expected = pd.Series(covered, index=dt)
72
- assert_series_equal(expected, snow_coverage)
73
-
74
-
75
- def test_coverage_nrel_initial():
76
- surface_tilt = 45
77
- slide_amount_coefficient = 0.197
78
- dt = pd.date_range(start="2019-1-1 10:00:00", end="2019-1-1 17:00:00",
79
- freq='1h')
80
- poa_irradiance = pd.Series([400, 200, 100, 1234, 134, 982, 100, 100],
81
- index=dt)
82
- temp_air = pd.Series([10, 2, 10, 1234, 34, 982, 10, 10], index=dt)
83
- snowfall_data = pd.Series([0, .5, .6, .4, .23, -5, .1, .1], index=dt)
84
- snow_coverage = snow.coverage_nrel(
85
- snowfall_data, poa_irradiance, temp_air, surface_tilt,
86
- initial_coverage=0.5, threshold_snowfall=1.)
87
- slide_amt = slide_amount_coefficient * sind(surface_tilt)
88
- covered = 0.5 - slide_amt * np.array([0, 1, 2, 3, 4, 5, 6, 7])
89
- covered = np.where(covered < 0, 0., covered)
90
- expected = pd.Series(covered, index=dt)
91
- assert_series_equal(expected, snow_coverage)
92
-
93
-
94
- def test_dc_loss_nrel():
95
- num_strings = 8
96
- snow_coverage = pd.Series([1, 1, .5, .6, .2, .4, 0])
97
- expected = pd.Series([1, 1, .5, .625, .25, .5, 0])
98
- actual = snow.dc_loss_nrel(snow_coverage, num_strings)
99
- assert_series_equal(expected, actual)
100
-
101
-
102
- def test__townsend_effective_snow():
103
- snow_total = np.array([25.4, 25.4, 12.7, 2.54, 0, 0, 0, 0, 0, 0, 12.7,
104
- 25.4])
105
- snow_events = np.array([2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3])
106
- expected = np.array([19.05, 19.05, 12.7, 0, 0, 0, 0, 0, 0, 0, 9.525,
107
- 254 / 15])
108
- actual = snow._townsend_effective_snow(snow_total, snow_events)
109
- np.testing.assert_allclose(expected, actual, rtol=1e-07)
110
-
111
-
112
- def test_loss_townsend():
113
- # hand-calculated solution
114
- snow_total = np.array([25.4, 25.4, 12.7, 2.54, 0, 0, 0, 0, 0, 0, 12.7,
115
- 25.4])
116
- snow_events = np.array([2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3])
117
- surface_tilt = 20
118
- relative_humidity = np.array([80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
119
- 80, 80])
120
- temp_air = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
121
- poa_global = np.array([350000, 350000, 350000, 350000, 350000, 350000,
122
- 350000, 350000, 350000, 350000, 350000, 350000])
123
- angle_of_repose = 40
124
- string_factor = 1.0
125
- slant_height = 2.54
126
- lower_edge_height = 0.254
127
- expected = np.array([0.07696253, 0.07992262, 0.06216201, 0.01715392, 0, 0,
128
- 0, 0, 0, 0, 0.02643821, 0.06068194])
129
- actual = snow.loss_townsend(snow_total, snow_events, surface_tilt,
130
- relative_humidity, temp_air,
131
- poa_global, slant_height,
132
- lower_edge_height, string_factor,
133
- angle_of_repose)
134
- np.testing.assert_allclose(expected, actual, rtol=1e-05)
135
-
136
-
137
- @pytest.mark.parametrize(
138
- 'poa_global,surface_tilt,slant_height,lower_edge_height,string_factor,expected', # noQA: E501
139
- [
140
- (np.asarray(
141
- [60., 80., 100., 125., 175., 225., 225., 210., 175., 125., 90.,
142
- 60.], dtype=float) * 1000.,
143
- 2.,
144
- 79. / 39.37,
145
- 3. / 39.37,
146
- 1.0,
147
- np.asarray(
148
- [44, 34, 20, 9, 3, 1, 0, 0, 0, 2, 6, 25], dtype=float)
149
- ),
150
- (np.asarray(
151
- [60., 80., 100., 125., 175., 225., 225., 210., 175., 125., 90.,
152
- 60.], dtype=float) * 1000.,
153
- 5.,
154
- 316 / 39.37,
155
- 120. / 39.37,
156
- 0.75,
157
- np.asarray(
158
- [22, 16, 9, 4, 1, 0, 0, 0, 0, 1, 2, 12], dtype=float)
159
- ),
160
- (np.asarray(
161
- [60., 80., 100., 125., 175., 225., 225., 210., 175., 125., 90.,
162
- 60.], dtype=float) * 1000.,
163
- 23.,
164
- 158 / 39.27,
165
- 12 / 39.37,
166
- 0.75,
167
- np.asarray(
168
- [28, 21, 13, 6, 2, 0, 0, 0, 0, 1, 4, 16], dtype=float)
169
- ),
170
- (np.asarray(
171
- [80., 100., 125., 150., 225., 300., 300., 275., 225., 150., 115.,
172
- 80.], dtype=float) * 1000.,
173
- 52.,
174
- 39.5 / 39.37,
175
- 34. / 39.37,
176
- 0.75,
177
- np.asarray(
178
- [7, 5, 3, 1, 0, 0, 0, 0, 0, 0, 1, 4], dtype=float)
179
- ),
180
- (np.asarray(
181
- [80., 100., 125., 150., 225., 300., 300., 275., 225., 150., 115.,
182
- 80.], dtype=float) * 1000.,
183
- 60.,
184
- 39.5 / 39.37,
185
- 25. / 39.37,
186
- 1.,
187
- np.asarray(
188
- [7, 5, 3, 1, 0, 0, 0, 0, 0, 0, 1, 3], dtype=float)
189
- )
190
- ]
191
- )
192
- def test_loss_townsend_cases(poa_global, surface_tilt, slant_height,
193
- lower_edge_height, string_factor, expected):
194
- # test cases from Townsend, 1/27/2023, addeed by cwh
195
- # snow_total in inches, convert to cm for pvlib
196
- snow_total = np.asarray(
197
- [20, 15, 10, 4, 1.5, 0, 0, 0, 0, 1.5, 4, 15], dtype=float) * 2.54
198
- # snow events are an average for each month
199
- snow_events = np.asarray(
200
- [5, 4.2, 2.8, 1.3, 0.8, 0, 0, 0, 0, 0.5, 1.5, 4.5], dtype=float)
201
- # air temperature in C
202
- temp_air = np.asarray(
203
- [-6., -2., 1., 4., 7., 10., 13., 16., 14., 12., 7., -3.], dtype=float)
204
- # relative humidity in %
205
- relative_humidity = np.asarray(
206
- [78., 80., 75., 65., 60., 55., 55., 55., 50., 55., 60., 70.],
207
- dtype=float)
208
- actual = snow.loss_townsend(
209
- snow_total, snow_events, surface_tilt, relative_humidity, temp_air,
210
- poa_global, slant_height, lower_edge_height, string_factor)
211
- actual = np.around(actual * 100)
212
- assert np.allclose(expected, actual)
@@ -1,230 +0,0 @@
1
- """Test losses"""
2
-
3
- import datetime
4
- import numpy as np
5
- import pandas as pd
6
- from .conftest import assert_series_equal
7
- from pvlib.soiling import hsu, kimber
8
- from pvlib.iotools import read_tmy3
9
- from .conftest import DATA_DIR
10
- import pytest
11
-
12
-
13
- @pytest.fixture
14
- def expected_output():
15
- # Sample output (calculated manually)
16
- dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
17
- end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
18
-
19
- expected_no_cleaning = pd.Series(
20
- data=[0.96998483, 0.94623958, 0.92468139, 0.90465654, 0.88589707,
21
- 0.86826366, 0.85167258, 0.83606715, 0.82140458, 0.80764919,
22
- 0.79476875, 0.78273241, 0.77150951, 0.76106905, 0.75137932,
23
- 0.74240789, 0.73412165, 0.72648695, 0.71946981, 0.7130361,
24
- 0.70715176, 0.70178307, 0.69689677, 0.69246034],
25
- index=dt)
26
- return expected_no_cleaning
27
-
28
-
29
- @pytest.fixture
30
- def expected_output_1():
31
- dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
32
- end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
33
- expected_output_1 = pd.Series(
34
- data=[0.98484972, 0.97277367, 0.96167471, 0.95119603, 1.,
35
- 0.98484972, 0.97277367, 0.96167471, 1., 1.,
36
- 0.98484972, 0.97277367, 0.96167471, 0.95119603, 0.94118234,
37
- 0.93154854, 0.922242, 0.91322759, 0.90448058, 0.89598283,
38
- 0.88772062, 0.87968325, 0.8718622, 0.86425049],
39
- index=dt)
40
- return expected_output_1
41
-
42
-
43
- @pytest.fixture
44
- def expected_output_2():
45
- dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
46
- end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
47
- expected_output_2 = pd.Series(
48
- data=[0.95036261, 0.91178179, 0.87774818, 0.84732079, 1.,
49
- 1., 1., 0.95036261, 1., 1.,
50
- 1., 1., 0.95036261, 0.91178179, 0.87774818,
51
- 0.84732079, 0.8201171, 1., 1., 1.,
52
- 1., 0.95036261, 0.91178179, 0.87774818],
53
- index=dt)
54
- return expected_output_2
55
-
56
-
57
- @pytest.fixture
58
- def expected_output_3():
59
- dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
60
- end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
61
- timedelta = [0, 0, 0, 0, 0, 30, 0, 30, 0, 30, 0, -30,
62
- -30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
63
- dt_new = dt + pd.to_timedelta(timedelta, 'm')
64
- expected_output_3 = pd.Series(
65
- data=[0.96576705, 0.9387675, 0.91437615, 0.89186852, 1.,
66
- 1., 0.98093819, 0.9387675, 1., 1.,
67
- 1., 1., 0.96576705, 0.9387675, 0.90291005,
68
- 0.88122293, 0.86104089, 1., 1., 1.,
69
- 0.96576705, 0.9387675, 0.91437615, 0.89186852],
70
- index=dt_new)
71
- return expected_output_3
72
-
73
-
74
- @pytest.fixture
75
- def rainfall_input():
76
-
77
- dt = pd.date_range(start=pd.Timestamp(2019, 1, 1, 0, 0, 0),
78
- end=pd.Timestamp(2019, 1, 1, 23, 59, 0), freq='1h')
79
- rainfall = pd.Series(
80
- data=[0., 0., 0., 0., 1., 0., 0., 0., 0.5, 0.5, 0., 0., 0., 0., 0.,
81
- 0., 0.3, 0.3, 0.3, 0.3, 0., 0., 0., 0.], index=dt)
82
- return rainfall
83
-
84
-
85
- def test_hsu_no_cleaning(rainfall_input, expected_output):
86
- """Test Soiling HSU function"""
87
-
88
- rainfall = rainfall_input
89
- pm2_5 = 1.0
90
- pm10 = 2.0
91
- depo_veloc = {'2_5': 1.0e-5, '10': 1.0e-4}
92
- tilt = 0.
93
- expected_no_cleaning = expected_output
94
-
95
- result = hsu(rainfall=rainfall, cleaning_threshold=10., surface_tilt=tilt,
96
- pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc,
97
- rain_accum_period=pd.Timedelta('1h'))
98
- assert_series_equal(result, expected_no_cleaning)
99
-
100
-
101
- def test_hsu(rainfall_input, expected_output_2):
102
- """Test Soiling HSU function with cleanings"""
103
-
104
- rainfall = rainfall_input
105
- pm2_5 = 1.0
106
- pm10 = 2.0
107
- depo_veloc = {'2_5': 1.0e-4, '10': 1.0e-4}
108
- tilt = 0.
109
-
110
- # three cleaning events at 4:00-6:00, 8:00-11:00, and 17:00-20:00
111
- result = hsu(rainfall=rainfall, cleaning_threshold=0.5, surface_tilt=tilt,
112
- pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc,
113
- rain_accum_period=pd.Timedelta('3h'))
114
-
115
- assert_series_equal(result, expected_output_2)
116
-
117
-
118
- def test_hsu_defaults(rainfall_input, expected_output_1):
119
- """
120
- Test Soiling HSU function with default deposition velocity and default rain
121
- accumulation period.
122
- """
123
- result = hsu(rainfall=rainfall_input, cleaning_threshold=0.5,
124
- surface_tilt=0.0, pm2_5=1.0e-2, pm10=2.0e-2)
125
- assert np.allclose(result.values, expected_output_1)
126
-
127
-
128
- def test_hsu_variable_time_intervals(rainfall_input, expected_output_3):
129
- """
130
- Test Soiling HSU function with variable time intervals.
131
- """
132
- depo_veloc = {'2_5': 1.0e-4, '10': 1.0e-4}
133
- rain = pd.DataFrame(data=rainfall_input)
134
- # define time deltas in minutes
135
- timedelta = [0, 0, 0, 0, 0, 30, 0, 30, 0, 30, 0, -30,
136
- -30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
137
- rain['mins_added'] = pd.to_timedelta(timedelta, 'm')
138
- rain['new_time'] = rain.index + rain['mins_added']
139
- rain_var_times = rain.set_index('new_time').iloc[:, 0]
140
- result = hsu(
141
- rainfall=rain_var_times, cleaning_threshold=0.5, surface_tilt=50.0,
142
- pm2_5=1, pm10=2, depo_veloc=depo_veloc,
143
- rain_accum_period=pd.Timedelta('2h'))
144
- assert np.allclose(result, expected_output_3)
145
-
146
-
147
- @pytest.fixture
148
- def greensboro_rain():
149
- # get TMY3 data with rain
150
- greensboro, _ = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990,
151
- map_variables=True)
152
- return greensboro['Lprecip depth (mm)']
153
-
154
-
155
- @pytest.fixture
156
- def expected_kimber_nowash():
157
- return pd.read_csv(
158
- DATA_DIR / 'greensboro_kimber_soil_nowash.dat',
159
- parse_dates=True, index_col='timestamp')
160
-
161
-
162
- def test_kimber_nowash(greensboro_rain, expected_kimber_nowash):
163
- """Test Kimber soiling model with no manual washes"""
164
- # Greensboro typical expected annual rainfall is 8345mm
165
- assert greensboro_rain.sum() == 8345
166
- # calculate soiling with no wash dates
167
- nowash = kimber(greensboro_rain)
168
- # test no washes
169
- assert np.allclose(nowash.values, expected_kimber_nowash['soiling'].values)
170
-
171
-
172
- @pytest.fixture
173
- def expected_kimber_manwash():
174
- return pd.read_csv(
175
- DATA_DIR / 'greensboro_kimber_soil_manwash.dat',
176
- parse_dates=True, index_col='timestamp')
177
-
178
-
179
- def test_kimber_manwash(greensboro_rain, expected_kimber_manwash):
180
- """Test Kimber soiling model with a manual wash"""
181
- # a manual wash date
182
- manwash = [datetime.date(1990, 2, 15), ]
183
- # calculate soiling with manual wash
184
- manwash = kimber(greensboro_rain, manual_wash_dates=manwash)
185
- # test manual wash
186
- assert np.allclose(
187
- manwash.values,
188
- expected_kimber_manwash['soiling'].values)
189
-
190
-
191
- @pytest.fixture
192
- def expected_kimber_norain():
193
- # expected soiling reaches maximum
194
- soiling_loss_rate = 0.0015
195
- max_loss_rate = 0.3
196
- norain = np.ones(8760) * soiling_loss_rate/24
197
- norain[0] = 0.0
198
- norain = np.cumsum(norain)
199
- return np.where(norain > max_loss_rate, max_loss_rate, norain)
200
-
201
-
202
- def test_kimber_norain(greensboro_rain, expected_kimber_norain):
203
- """Test Kimber soiling model with no rain"""
204
- # a year with no rain
205
- norain = pd.Series(0, index=greensboro_rain.index)
206
- # calculate soiling with no rain
207
- norain = kimber(norain)
208
- # test no rain, soiling reaches maximum
209
- assert np.allclose(norain.values, expected_kimber_norain)
210
-
211
-
212
- @pytest.fixture
213
- def expected_kimber_initial_soil():
214
- # expected soiling reaches maximum
215
- soiling_loss_rate = 0.0015
216
- max_loss_rate = 0.3
217
- norain = np.ones(8760) * soiling_loss_rate/24
218
- norain[0] = 0.1
219
- norain = np.cumsum(norain)
220
- return np.where(norain > max_loss_rate, max_loss_rate, norain)
221
-
222
-
223
- def test_kimber_initial_soil(greensboro_rain, expected_kimber_initial_soil):
224
- """Test Kimber soiling model with initial soiling"""
225
- # a year with no rain
226
- norain = pd.Series(0, index=greensboro_rain.index)
227
- # calculate soiling with no rain
228
- norain = kimber(norain, initial_soiling=0.1)
229
- # test no rain, soiling reaches maximum
230
- assert np.allclose(norain.values, expected_kimber_initial_soil)