pvlib 0.9.4a1__py3-none-any.whl → 0.10.0__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 (86) hide show
  1. pvlib/__init__.py +3 -2
  2. pvlib/atmosphere.py +23 -173
  3. pvlib/bifacial/infinite_sheds.py +88 -277
  4. pvlib/bifacial/utils.py +270 -28
  5. pvlib/data/adr-library-cec-inverters-2019-03-05.csv +5009 -0
  6. pvlib/data/precise_iv_curves1.json +10251 -0
  7. pvlib/data/precise_iv_curves2.json +10251 -0
  8. pvlib/data/precise_iv_curves_parameter_sets1.csv +33 -0
  9. pvlib/data/precise_iv_curves_parameter_sets2.csv +33 -0
  10. pvlib/data/test_psm3_2017.csv +17521 -17521
  11. pvlib/data/test_psm3_2019_5min.csv +288 -288
  12. pvlib/data/test_read_psm3.csv +17522 -17522
  13. pvlib/data/test_read_pvgis_horizon.csv +49 -0
  14. pvlib/data/variables_style_rules.csv +3 -0
  15. pvlib/iam.py +207 -51
  16. pvlib/inverter.py +6 -1
  17. pvlib/iotools/__init__.py +7 -2
  18. pvlib/iotools/acis.py +516 -0
  19. pvlib/iotools/midc.py +4 -4
  20. pvlib/iotools/psm3.py +59 -42
  21. pvlib/iotools/pvgis.py +84 -28
  22. pvlib/iotools/sodapro.py +8 -6
  23. pvlib/iotools/srml.py +121 -18
  24. pvlib/iotools/surfrad.py +2 -2
  25. pvlib/iotools/tmy.py +146 -102
  26. pvlib/irradiance.py +270 -15
  27. pvlib/ivtools/sde.py +14 -20
  28. pvlib/ivtools/sdm.py +31 -20
  29. pvlib/ivtools/utils.py +127 -6
  30. pvlib/location.py +3 -2
  31. pvlib/modelchain.py +67 -70
  32. pvlib/pvarray.py +225 -0
  33. pvlib/pvsystem.py +169 -539
  34. pvlib/shading.py +43 -2
  35. pvlib/singlediode.py +216 -66
  36. pvlib/snow.py +36 -15
  37. pvlib/soiling.py +3 -3
  38. pvlib/spa.py +327 -368
  39. pvlib/spectrum/__init__.py +8 -2
  40. pvlib/spectrum/mismatch.py +335 -0
  41. pvlib/temperature.py +124 -13
  42. pvlib/tests/bifacial/test_infinite_sheds.py +44 -106
  43. pvlib/tests/bifacial/test_utils.py +102 -5
  44. pvlib/tests/conftest.py +0 -31
  45. pvlib/tests/iotools/test_acis.py +213 -0
  46. pvlib/tests/iotools/test_midc.py +6 -6
  47. pvlib/tests/iotools/test_psm3.py +7 -5
  48. pvlib/tests/iotools/test_pvgis.py +21 -14
  49. pvlib/tests/iotools/test_sodapro.py +1 -1
  50. pvlib/tests/iotools/test_srml.py +71 -6
  51. pvlib/tests/iotools/test_tmy.py +43 -8
  52. pvlib/tests/ivtools/test_sde.py +19 -17
  53. pvlib/tests/ivtools/test_sdm.py +9 -4
  54. pvlib/tests/ivtools/test_utils.py +96 -1
  55. pvlib/tests/test_atmosphere.py +8 -64
  56. pvlib/tests/test_clearsky.py +0 -1
  57. pvlib/tests/test_iam.py +74 -1
  58. pvlib/tests/test_irradiance.py +56 -2
  59. pvlib/tests/test_location.py +1 -1
  60. pvlib/tests/test_modelchain.py +33 -76
  61. pvlib/tests/test_pvarray.py +46 -0
  62. pvlib/tests/test_pvsystem.py +366 -201
  63. pvlib/tests/test_shading.py +35 -0
  64. pvlib/tests/test_singlediode.py +306 -29
  65. pvlib/tests/test_snow.py +84 -1
  66. pvlib/tests/test_soiling.py +8 -7
  67. pvlib/tests/test_solarposition.py +7 -7
  68. pvlib/tests/test_spa.py +6 -7
  69. pvlib/tests/test_spectrum.py +145 -1
  70. pvlib/tests/test_temperature.py +29 -11
  71. pvlib/tests/test_tools.py +41 -0
  72. pvlib/tests/test_tracking.py +0 -149
  73. pvlib/tools.py +49 -25
  74. pvlib/tracking.py +1 -269
  75. pvlib-0.10.0.dist-info/AUTHORS.md +35 -0
  76. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/LICENSE +5 -2
  77. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/METADATA +3 -13
  78. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/RECORD +80 -75
  79. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/WHEEL +1 -1
  80. pvlib/data/adr-library-2013-10-01.csv +0 -1762
  81. pvlib/forecast.py +0 -1211
  82. pvlib/iotools/ecmwf_macc.py +0 -312
  83. pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
  84. pvlib/tests/test_forecast.py +0 -228
  85. pvlib-0.9.4a1.dist-info/AUTHORS.md +0 -32
  86. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ test infinite sheds
5
5
  import numpy as np
6
6
  import pandas as pd
7
7
  from pvlib.bifacial import infinite_sheds
8
- from pvlib.tools import cosd
9
8
  from ..conftest import assert_series_equal
10
9
 
11
10
  import pytest
@@ -42,107 +41,6 @@ def test_system():
42
41
  return syst, pts, vfs_ground_sky
43
42
 
44
43
 
45
- def test__vf_ground_sky_integ(test_system):
46
- ts, pts, vfs_gnd_sky = test_system
47
- # pass rotation here since max_rows=1 for the hand-solved case in
48
- # the fixture test_system, which means the ground-to-sky view factor
49
- # isn't summed over enough rows for symmetry to hold.
50
- vf_integ = infinite_sheds._vf_ground_sky_integ(
51
- ts['rotation'], ts['surface_azimuth'],
52
- ts['gcr'], ts['height'], ts['pitch'],
53
- max_rows=1, npoints=3)
54
- expected_vf_integ = np.trapz(vfs_gnd_sky, pts)
55
- assert np.isclose(vf_integ, expected_vf_integ, rtol=0.1)
56
-
57
-
58
- def test__vf_row_sky_integ(test_system):
59
- ts, _, _ = test_system
60
- gcr = ts['gcr']
61
- surface_tilt = ts['surface_tilt']
62
- f_x = np.array([0., 0.5, 1.])
63
- shaded = []
64
- noshade = []
65
- for x in f_x:
66
- s, ns = infinite_sheds._vf_row_sky_integ(
67
- x, surface_tilt, gcr, npoints=100)
68
- shaded.append(s)
69
- noshade.append(ns)
70
-
71
- def analytic(gcr, surface_tilt, x):
72
- c = cosd(surface_tilt)
73
- a = 1. / gcr
74
- dx = np.sqrt(a**2 - 2 * a * c * x + x**2)
75
- return - a * (c**2 - 1) * np.arctanh((x - a * c) / dx) - c * dx
76
-
77
- expected_shade = 0.5 * (f_x * cosd(surface_tilt)
78
- - analytic(gcr, surface_tilt, 1 - f_x)
79
- + analytic(gcr, surface_tilt, 1.))
80
- expected_noshade = 0.5 * ((1 - f_x) * cosd(surface_tilt)
81
- + analytic(gcr, surface_tilt, 1. - f_x)
82
- - analytic(gcr, surface_tilt, 0.))
83
- shaded = np.array(shaded)
84
- noshade = np.array(noshade)
85
- assert np.allclose(shaded, expected_shade)
86
- assert np.allclose(noshade, expected_noshade)
87
-
88
-
89
- def test__poa_sky_diffuse_pv():
90
- dhi = np.array([np.nan, 0.0, 500.])
91
- f_x = np.array([0.2, 0.2, 0.5])
92
- vf_shade_sky_integ = np.array([1.0, 0.5, 0.2])
93
- vf_noshade_sky_integ = np.array([0.0, 0.5, 0.8])
94
- poa = infinite_sheds._poa_sky_diffuse_pv(
95
- f_x, dhi, vf_shade_sky_integ, vf_noshade_sky_integ)
96
- expected_poa = np.array([np.nan, 0.0, 500 * (0.5 * 0.2 + 0.5 * 0.8)])
97
- assert np.allclose(poa, expected_poa, equal_nan=True)
98
-
99
-
100
- def test__ground_angle(test_system):
101
- ts, _, _ = test_system
102
- x = np.array([0., 0.5, 1.0])
103
- angles = infinite_sheds._ground_angle(
104
- x, ts['surface_tilt'], ts['gcr'])
105
- expected_angles = np.array([0., 5.866738789543952, 9.896090638982903])
106
- assert np.allclose(angles, expected_angles)
107
-
108
-
109
- def test__vf_row_ground(test_system):
110
- ts, _, _ = test_system
111
- x = np.array([0., 0.5, 1.0])
112
- sqr3 = np.sqrt(3)
113
- vfs = infinite_sheds._vf_row_ground(
114
- x, ts['surface_tilt'], ts['gcr'])
115
- expected_vfs = np.array([
116
- 0.5 * (1. - sqr3 / 2),
117
- 0.5 * ((4 + sqr3 / 2) / np.sqrt(17 + 4 * sqr3) - sqr3 / 2),
118
- 0.5 * ((4 + sqr3) / np.sqrt(20 + 8 * sqr3) - sqr3 / 2)])
119
- assert np.allclose(vfs, expected_vfs)
120
-
121
-
122
- def test__vf_row_ground_integ(test_system):
123
- ts, _, _ = test_system
124
- gcr = ts['gcr']
125
- surface_tilt = ts['surface_tilt']
126
- f_x = np.array([0., 0.5, 1.0])
127
- shaded, noshade = infinite_sheds._vf_row_ground_integ(
128
- f_x, surface_tilt, gcr)
129
-
130
- def analytic(x, surface_tilt, gcr):
131
- c = cosd(surface_tilt)
132
- a = 1. / gcr
133
- dx = np.sqrt(a**2 + 2 * a * c * x + x**2)
134
- return c * dx - a * (c**2 - 1) * np.arctanh((a * c + x) / dx)
135
-
136
- expected_shade = 0.5 * (analytic(f_x, surface_tilt, gcr)
137
- - analytic(0., surface_tilt, gcr)
138
- - f_x * cosd(surface_tilt))
139
- expected_noshade = 0.5 * (analytic(1., surface_tilt, gcr)
140
- - analytic(f_x, surface_tilt, gcr)
141
- - (1. - f_x) * cosd(surface_tilt))
142
- assert np.allclose(shaded, expected_shade)
143
- assert np.allclose(noshade, expected_noshade)
144
-
145
-
146
44
  def test__poa_ground_shadows():
147
45
  poa_ground, f_gnd_beam, df, vf_gnd_sky = (300., 0.5, 0.5, 0.2)
148
46
  result = infinite_sheds._poa_ground_shadows(
@@ -254,7 +152,8 @@ def test__backside_tilt():
254
152
  assert np.allclose(back_az, np.array([0., 330., 90., 180.]))
255
153
 
256
154
 
257
- def test_get_irradiance():
155
+ @pytest.mark.parametrize("vectorize", [True, False])
156
+ def test_get_irradiance(vectorize):
258
157
  # singleton inputs
259
158
  solar_zenith = 0.
260
159
  solar_azimuth = 180.
@@ -274,7 +173,7 @@ def test_get_irradiance():
274
173
  surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
275
174
  gcr, height, pitch, ghi, dhi, dni, albedo, iam_front, iam_back,
276
175
  bifaciality=0.8, shade_factor=-0.02, transmission_factor=0,
277
- npoints=npoints)
176
+ npoints=npoints, vectorize=vectorize)
278
177
  expected_front_diffuse = np.array([300.])
279
178
  expected_front_direct = np.array([700.])
280
179
  expected_front_global = expected_front_diffuse + expected_front_direct
@@ -292,11 +191,11 @@ def test_get_irradiance():
292
191
  surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
293
192
  gcr, height, pitch, ghi, dhi, dni, albedo, iam_front, iam_back,
294
193
  bifaciality=0.8, shade_factor=-0.02, transmission_factor=0,
295
- npoints=npoints)
194
+ npoints=npoints, vectorize=vectorize)
296
195
  result_front = infinite_sheds.get_irradiance_poa(
297
196
  surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
298
197
  gcr, height, pitch, ghi, dhi, dni,
299
- albedo, iam=iam_front)
198
+ albedo, iam=iam_front, vectorize=vectorize)
300
199
  assert isinstance(result, pd.DataFrame)
301
200
  expected_poa_global = pd.Series(
302
201
  [1000., 500., result_front['poa_global'][2] * (1 + 0.8 * 0.98),
@@ -345,3 +244,42 @@ def test_get_irradiance_limiting_gcr():
345
244
  result['poa_back_sky_diffuse'])
346
245
  assert np.isclose(result['poa_front_ground_diffuse'],
347
246
  result['poa_back_ground_diffuse'])
247
+
248
+
249
+ def test_get_irradiance_with_haydavies():
250
+ # singleton inputs
251
+ solar_zenith = 0.
252
+ solar_azimuth = 180.
253
+ surface_tilt = 0.
254
+ surface_azimuth = 180.
255
+ gcr = 0.5
256
+ height = 1.
257
+ pitch = 1.
258
+ ghi = 1000.
259
+ dhi = 300.
260
+ dni = 700.
261
+ albedo = 0.
262
+ dni_extra = 1413.
263
+ model = 'haydavies'
264
+ iam_front = 1.0
265
+ iam_back = 1.0
266
+ npoints = 100
267
+ result = infinite_sheds.get_irradiance(
268
+ surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
269
+ gcr, height, pitch, ghi, dhi, dni, albedo, model, dni_extra,
270
+ iam_front, iam_back, bifaciality=0.8, shade_factor=-0.02,
271
+ transmission_factor=0, npoints=npoints)
272
+ expected_front_diffuse = np.array([151.38])
273
+ expected_front_direct = np.array([848.62])
274
+ expected_front_global = expected_front_diffuse + expected_front_direct
275
+ assert np.isclose(result['poa_front'], expected_front_global)
276
+ assert np.isclose(result['poa_front_diffuse'], expected_front_diffuse)
277
+ assert np.isclose(result['poa_front_direct'], expected_front_direct)
278
+ assert np.isclose(result['poa_global'], result['poa_front'])
279
+ # test for when dni_extra is not supplied
280
+ with pytest.raises(ValueError, match='supply dni_extra for haydavies'):
281
+ result = infinite_sheds.get_irradiance(
282
+ surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
283
+ gcr, height, pitch, ghi, dhi, dni, albedo, model, None,
284
+ iam_front, iam_back, bifaciality=0.8, shade_factor=-0.02,
285
+ transmission_factor=0, npoints=npoints)
@@ -4,6 +4,8 @@ test bifical.utils
4
4
  import numpy as np
5
5
  import pytest
6
6
  from pvlib.bifacial import utils
7
+ from pvlib.shading import masking_angle, ground_angle
8
+ from pvlib.tools import cosd
7
9
 
8
10
 
9
11
  @pytest.fixture
@@ -35,7 +37,7 @@ def test_system_fixed_tilt():
35
37
  c22 = (-2 - sqr3) / np.sqrt(1.25**2 + (2 + sqr3)**2) # right edge row 0
36
38
  c23 = (0 - sqr3) / np.sqrt(1.25**2 + (0 - sqr3)**2) # right edge row 1
37
39
  vf_2 = 0.5 * (c23 - c22 + c21 - c20) # vf at point 1
38
- vfs_ground_sky = np.array([vf_0, vf_1, vf_2])
40
+ vfs_ground_sky = np.array([[vf_0], [vf_1], [vf_2]])
39
41
  return syst, pts, vfs_ground_sky
40
42
 
41
43
 
@@ -79,10 +81,105 @@ def test__unshaded_ground_fraction(
79
81
  def test__vf_ground_sky_2d(test_system_fixed_tilt):
80
82
  # vector input
81
83
  ts, pts, vfs_gnd_sky = test_system_fixed_tilt
82
- vfs, _ = utils._vf_ground_sky_2d(pts, ts['rotation'], ts['gcr'],
83
- ts['pitch'], ts['height'], max_rows=1)
84
+ vfs = utils.vf_ground_sky_2d(ts['rotation'], ts['gcr'], pts,
85
+ ts['pitch'], ts['height'], max_rows=1)
84
86
  assert np.allclose(vfs, vfs_gnd_sky, rtol=0.1) # middle point vf is off
85
87
  # test with singleton x
86
- vf, _ = utils._vf_ground_sky_2d(pts[0], ts['rotation'], ts['gcr'],
87
- ts['pitch'], ts['height'], max_rows=1)
88
+ vf = utils.vf_ground_sky_2d(ts['rotation'], ts['gcr'], pts[0],
89
+ ts['pitch'], ts['height'], max_rows=1)
88
90
  assert np.isclose(vf, vfs_gnd_sky[0])
91
+
92
+
93
+ @pytest.mark.parametrize("vectorize", [True, False])
94
+ def test_vf_ground_sky_2d_integ(test_system_fixed_tilt, vectorize):
95
+ ts, pts, vfs_gnd_sky = test_system_fixed_tilt
96
+ # pass rotation here since max_rows=1 for the hand-solved case in
97
+ # the fixture test_system, which means the ground-to-sky view factor
98
+ # isn't summed over enough rows for symmetry to hold.
99
+ vf_integ = utils.vf_ground_sky_2d_integ(
100
+ ts['rotation'], ts['gcr'], ts['height'], ts['pitch'],
101
+ max_rows=1, npoints=3, vectorize=vectorize)
102
+ expected_vf_integ = np.trapz(vfs_gnd_sky, pts, axis=0)
103
+ assert np.isclose(vf_integ, expected_vf_integ, rtol=0.1)
104
+
105
+
106
+ def test_vf_row_sky_2d(test_system_fixed_tilt):
107
+ ts, _, _ = test_system_fixed_tilt
108
+ # with float input, fx at top of row
109
+ vf = utils.vf_row_sky_2d(ts['surface_tilt'], ts['gcr'], 1.)
110
+ expected = 0.5 * (1 + cosd(ts['surface_tilt']))
111
+ assert np.isclose(vf, expected)
112
+ # with array input
113
+ fx = np.array([0., 0.5, 1.])
114
+ vf = utils.vf_row_sky_2d(ts['surface_tilt'], ts['gcr'], fx)
115
+ phi = masking_angle(ts['surface_tilt'], ts['gcr'], fx)
116
+ expected = 0.5 * (1 + cosd(ts['surface_tilt'] + phi))
117
+ assert np.allclose(vf, expected)
118
+
119
+
120
+ def test_vf_row_sky_2d_integ(test_system_fixed_tilt):
121
+ ts, _, _ = test_system_fixed_tilt
122
+ # with float input, check end position
123
+ vf = utils.vf_row_sky_2d_integ(ts['surface_tilt'], ts['gcr'], 1., 1.)
124
+ expected = utils.vf_row_sky_2d(ts['surface_tilt'], ts['gcr'], 1.)
125
+ assert np.isclose(vf, expected)
126
+ # with array input
127
+ fx0 = np.array([0., 0.5])
128
+ fx1 = np.array([0., 0.8])
129
+ vf = utils.vf_row_sky_2d_integ(ts['surface_tilt'], ts['gcr'], fx0, fx1)
130
+ phi = masking_angle(ts['surface_tilt'], ts['gcr'], fx0[0])
131
+ y0 = 0.5 * (1 + cosd(ts['surface_tilt'] + phi))
132
+ x = np.arange(fx0[1], fx1[1], 1e-4)
133
+ phi_y = masking_angle(ts['surface_tilt'], ts['gcr'], x)
134
+ y = 0.5 * (1 + cosd(ts['surface_tilt'] + phi_y))
135
+ y1 = np.trapz(y, x) / (fx1[1] - fx0[1])
136
+ expected = np.array([y0, y1])
137
+ assert np.allclose(vf, expected, rtol=1e-3)
138
+ # with defaults (0, 1)
139
+ vf = utils.vf_row_sky_2d_integ(ts['surface_tilt'], ts['gcr'])
140
+ x = np.arange(0, 1, 1e-4)
141
+ phi_y = masking_angle(ts['surface_tilt'], ts['gcr'], x)
142
+ y = 0.5 * (1 + cosd(ts['surface_tilt'] + phi_y))
143
+ y1 = np.trapz(y, x) / (1 - 0)
144
+ assert np.allclose(vf, y1, rtol=1e-3)
145
+
146
+
147
+ def test_vf_row_ground_2d(test_system_fixed_tilt):
148
+ ts, _, _ = test_system_fixed_tilt
149
+ # with float input, fx at bottom of row
150
+ vf = utils.vf_row_ground_2d(ts['surface_tilt'], ts['gcr'], 0.)
151
+ expected = 0.5 * (1. - cosd(ts['surface_tilt']))
152
+ assert np.isclose(vf, expected)
153
+ # with array input
154
+ fx = np.array([0., 0.5, 1.0])
155
+ vf = utils.vf_row_ground_2d(ts['surface_tilt'], ts['gcr'], fx)
156
+ phi = ground_angle(ts['surface_tilt'], ts['gcr'], fx)
157
+ expected = 0.5 * (1 - cosd(phi - ts['surface_tilt']))
158
+ assert np.allclose(vf, expected)
159
+
160
+
161
+ def test_vf_ground_2d_integ(test_system_fixed_tilt):
162
+ ts, _, _ = test_system_fixed_tilt
163
+ # with float input, check end position
164
+ vf = utils.vf_row_ground_2d_integ(ts['surface_tilt'], ts['gcr'], 0., 0.)
165
+ expected = utils.vf_row_ground_2d(ts['surface_tilt'], ts['gcr'], 0.)
166
+ assert np.isclose(vf, expected)
167
+ # with array input
168
+ fx0 = np.array([0., 0.5])
169
+ fx1 = np.array([0., 0.8])
170
+ vf = utils.vf_row_ground_2d_integ(ts['surface_tilt'], ts['gcr'], fx0, fx1)
171
+ phi = ground_angle(ts['surface_tilt'], ts['gcr'], fx0[0])
172
+ y0 = 0.5 * (1 - cosd(phi - ts['surface_tilt']))
173
+ x = np.arange(fx0[1], fx1[1], 1e-4)
174
+ phi_y = ground_angle(ts['surface_tilt'], ts['gcr'], x)
175
+ y = 0.5 * (1 - cosd(phi_y - ts['surface_tilt']))
176
+ y1 = np.trapz(y, x) / (fx1[1] - fx0[1])
177
+ expected = np.array([y0, y1])
178
+ assert np.allclose(vf, expected, rtol=1e-2)
179
+ # with defaults (0, 1)
180
+ vf = utils.vf_row_ground_2d_integ(ts['surface_tilt'], ts['gcr'], 0, 1)
181
+ x = np.arange(0, 1, 1e-4)
182
+ phi_y = ground_angle(ts['surface_tilt'], ts['gcr'], x)
183
+ y = 0.5 * (1 - cosd(phi_y - ts['surface_tilt']))
184
+ y1 = np.trapz(y, x) / (1 - 0)
185
+ assert np.allclose(vf, y1, rtol=1e-2)
pvlib/tests/conftest.py CHANGED
@@ -141,23 +141,6 @@ def has_numba():
141
141
 
142
142
  requires_numba = pytest.mark.skipif(not has_numba(), reason="requires numba")
143
143
 
144
- try:
145
- import siphon
146
- has_siphon = True
147
- except ImportError:
148
- has_siphon = False
149
-
150
- requires_siphon = pytest.mark.skipif(not has_siphon,
151
- reason='requires siphon')
152
-
153
- try:
154
- import netCDF4 # noqa: F401
155
- has_netCDF4 = True
156
- except ImportError:
157
- has_netCDF4 = False
158
-
159
- requires_netCDF4 = pytest.mark.skipif(not has_netCDF4,
160
- reason='requires netCDF4')
161
144
 
162
145
  try:
163
146
  import pvfactors # noqa: F401
@@ -178,20 +161,6 @@ except ImportError:
178
161
  requires_pysam = pytest.mark.skipif(not has_pysam, reason="requires PySAM")
179
162
 
180
163
 
181
- try:
182
- import cftime # noqa: F401
183
-
184
- has_recent_cftime = parse_version(cftime.__version__) > parse_version(
185
- "1.1.0"
186
- )
187
- except ImportError:
188
- has_recent_cftime = False
189
-
190
- requires_recent_cftime = pytest.mark.skipif(
191
- not has_recent_cftime, reason="requires cftime > 1.1.0"
192
- )
193
-
194
-
195
164
  @pytest.fixture()
196
165
  def golden():
197
166
  return Location(39.742476, -105.1786, 'America/Denver', 1830.14)
@@ -0,0 +1,213 @@
1
+ """
2
+ tests for :mod:`pvlib.iotools.acis`
3
+ """
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ import pytest
8
+ from pvlib.iotools import (
9
+ get_acis_prism, get_acis_nrcc, get_acis_mpe,
10
+ get_acis_station_data, get_acis_available_stations
11
+ )
12
+ from ..conftest import RERUNS, RERUNS_DELAY, assert_frame_equal
13
+ from requests import HTTPError
14
+
15
+
16
+ @pytest.mark.remote_data
17
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
18
+ def test_get_acis_prism():
19
+ # map_variables=True
20
+ df, meta = get_acis_prism(40.001, -80.001, '2020-01-01', '2020-01-02')
21
+ expected = pd.DataFrame(
22
+ [
23
+ [0.5, 5, 0, 2.5, 0, 62, 0],
24
+ [0, 5, -3, 1, 0, 64, 0]
25
+ ],
26
+ columns=['precipitation', 'temp_air_max', 'temp_air_min',
27
+ 'temp_air_average', 'cooling_degree_days',
28
+ 'heating_degree_days', 'growing_degree_days'],
29
+ index=pd.to_datetime(['2020-01-01', '2020-01-02']),
30
+ )
31
+ assert_frame_equal(df, expected)
32
+ expected_meta = {'latitude': 40, 'longitude': -80, 'altitude': 298.0944}
33
+ assert meta == expected_meta
34
+
35
+ # map_variables=False
36
+ df, meta = get_acis_prism(40.001, -80.001, '2020-01-01', '2020-01-02',
37
+ map_variables=False)
38
+ expected.columns = ['pcpn', 'maxt', 'mint', 'avgt', 'cdd', 'hdd', 'gdd']
39
+ assert_frame_equal(df, expected)
40
+ expected_meta = {'lat': 40, 'lon': -80, 'elev': 298.0944}
41
+ assert meta == expected_meta
42
+
43
+
44
+ @pytest.mark.remote_data
45
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
46
+ @pytest.mark.parametrize('grid, expected', [
47
+ (1, [[0.51, 5, 0, 2.5, 0, 62, 0]]),
48
+ (3, [[0.51, 5, -1, 2.0, 0, 63, 0]])
49
+ ])
50
+ def test_get_acis_nrcc(grid, expected):
51
+ # map_variables=True
52
+ df, meta = get_acis_nrcc(40.001, -80.001, '2020-01-01', '2020-01-01', grid)
53
+ expected = pd.DataFrame(
54
+ expected,
55
+ columns=['precipitation', 'temp_air_max', 'temp_air_min',
56
+ 'temp_air_average', 'cooling_degree_days',
57
+ 'heating_degree_days', 'growing_degree_days'],
58
+ index=pd.to_datetime(['2020-01-01']),
59
+ )
60
+ assert_frame_equal(df, expected)
61
+ expected_meta = {'latitude': 40., 'longitude': -80., 'altitude': 356.9208}
62
+ assert meta == pytest.approx(expected_meta)
63
+
64
+ # map_variables=False
65
+ df, meta = get_acis_nrcc(40.001, -80.001, '2020-01-01', '2020-01-01', grid,
66
+ map_variables=False)
67
+ expected.columns = ['pcpn', 'maxt', 'mint', 'avgt', 'cdd', 'hdd', 'gdd']
68
+ assert_frame_equal(df, expected)
69
+ expected_meta = {'lat': 40., 'lon': -80., 'elev': 356.9208}
70
+ assert meta == pytest.approx(expected_meta)
71
+
72
+
73
+ @pytest.mark.remote_data
74
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
75
+ def test_get_acis_nrcc_error():
76
+ with pytest.raises(HTTPError, match='invalid grid'):
77
+ # 50 is not a valid dataset (or "grid", in ACIS lingo)
78
+ _ = get_acis_nrcc(40, -80, '2012-01-01', '2012-01-01', 50)
79
+
80
+
81
+ @pytest.mark.remote_data
82
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
83
+ def test_get_acis_mpe():
84
+ # map_variables=True
85
+ df, meta = get_acis_mpe(40.001, -80.001, '2020-01-01', '2020-01-02')
86
+ expected = pd.DataFrame(
87
+ {'precipitation': [0.4, 0.0]},
88
+ index=pd.to_datetime(['2020-01-01', '2020-01-02']),
89
+ )
90
+ assert_frame_equal(df, expected)
91
+ expected_meta = {'latitude': 40.0083, 'longitude': -79.9653}
92
+ assert meta == expected_meta
93
+
94
+ # map_variables=False
95
+ df, meta = get_acis_mpe(40.001, -80.001, '2020-01-01', '2020-01-02',
96
+ map_variables=False)
97
+ expected.columns = ['pcpn']
98
+ assert_frame_equal(df, expected)
99
+ expected_meta = {'lat': 40.0083, 'lon': -79.9653}
100
+ assert meta == expected_meta
101
+
102
+
103
+ @pytest.mark.remote_data
104
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
105
+ def test_get_acis_station_data():
106
+ # map_variables=True
107
+ df, meta = get_acis_station_data('ORD', '2020-01-10', '2020-01-12',
108
+ trace_val=-99)
109
+ expected = pd.DataFrame(
110
+ [[10., 2., 6., np.nan, 21.34, 0., 0., 0., 59., 0.],
111
+ [3., -4., -0.5, np.nan, 9.4, 5.3, 0., 0., 65., 0.],
112
+ [-1., -5., -3., np.nan, -99, -99, 5., 0., 68., 0.]],
113
+ columns=['temp_air_max', 'temp_air_min', 'temp_air_average',
114
+ 'temp_air_observation', 'precipitation', 'snowfall',
115
+ 'snowdepth', 'cooling_degree_days',
116
+ 'heating_degree_days', 'growing_degree_days'],
117
+ index=pd.to_datetime(['2020-01-10', '2020-01-11', '2020-01-12']),
118
+ )
119
+ assert_frame_equal(df, expected)
120
+ expected_meta = {
121
+ 'uid': 48,
122
+ 'state': 'IL',
123
+ 'name': 'CHICAGO OHARE INTL AP',
124
+ 'altitude': 204.8256,
125
+ 'latitude': 41.96017,
126
+ 'longitude': -87.93164
127
+ }
128
+ expected_meta = {
129
+ 'valid_daterange': [
130
+ ['1958-11-01', '2023-06-15'],
131
+ ['1958-11-01', '2023-06-15'],
132
+ ['1958-11-01', '2023-06-15'],
133
+ [],
134
+ ['1958-11-01', '2023-06-15'],
135
+ ['1958-11-01', '2023-06-15'],
136
+ ['1958-11-01', '2023-06-15'],
137
+ ['1958-11-01', '2023-06-15'],
138
+ ['1958-11-01', '2023-06-15'],
139
+ ['1958-11-01', '2023-06-15']
140
+ ],
141
+ 'name': 'CHICAGO OHARE INTL AP',
142
+ 'sids': ['94846 1', '111549 2', 'ORD 3', '72530 4', 'KORD 5',
143
+ 'USW00094846 6', 'ORD 7', 'USW00094846 32'],
144
+ 'county': '17031',
145
+ 'state': 'IL',
146
+ 'climdiv': 'IL02',
147
+ 'uid': 48,
148
+ 'tzo': -6.0,
149
+ 'sid_dates': [
150
+ ['94846 1', '1989-01-19', '9999-12-31'],
151
+ ['94846 1', '1958-10-30', '1989-01-01'],
152
+ ['111549 2', '1989-01-19', '9999-12-31'],
153
+ ['111549 2', '1958-10-30', '1989-01-01'],
154
+ ['ORD 3', '1989-01-19', '9999-12-31'],
155
+ ['ORD 3', '1958-10-30', '1989-01-01'],
156
+ ['72530 4', '1989-01-19', '9999-12-31'],
157
+ ['72530 4', '1958-10-30', '1989-01-01'],
158
+ ['KORD 5', '1989-01-19', '9999-12-31'],
159
+ ['KORD 5', '1958-10-30', '1989-01-01'],
160
+ ['USW00094846 6', '1989-01-19', '9999-12-31'],
161
+ ['USW00094846 6', '1958-10-30', '1989-01-01'],
162
+ ['ORD 7', '1989-01-19', '9999-12-31'],
163
+ ['ORD 7', '1958-10-30', '1989-01-01'],
164
+ ['USW00094846 32', '1989-01-19', '9999-12-31'],
165
+ ['USW00094846 32', '1958-10-30', '1989-01-01']],
166
+ 'altitude': 204.8256,
167
+ 'longitude': -87.93164,
168
+ 'latitude': 41.96017
169
+ }
170
+ # don't check valid dates since they get extended every day
171
+ meta.pop("valid_daterange")
172
+ expected_meta.pop("valid_daterange")
173
+ assert meta == expected_meta
174
+
175
+ # map_variables=False
176
+ df, meta = get_acis_station_data('ORD', '2020-01-10', '2020-01-12',
177
+ trace_val=-99, map_variables=False)
178
+ expected.columns = ['maxt', 'mint', 'avgt', 'obst', 'pcpn', 'snow',
179
+ 'snwd', 'cdd', 'hdd', 'gdd']
180
+ assert_frame_equal(df, expected)
181
+ expected_meta['lat'] = expected_meta.pop('latitude')
182
+ expected_meta['lon'] = expected_meta.pop('longitude')
183
+ expected_meta['elev'] = expected_meta.pop('altitude')
184
+ meta.pop("valid_daterange")
185
+ assert meta == expected_meta
186
+
187
+
188
+ @pytest.mark.remote_data
189
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
190
+ def test_get_acis_available_stations():
191
+ # use a very narrow bounding box to hopefully make this test less likely
192
+ # to fail due to new stations being added in the future
193
+ lat, lon = 39.8986, -80.1656
194
+ stations = get_acis_available_stations([lat - 0.0001, lat + 0.0001],
195
+ [lon - 0.0001, lon + 0.0001])
196
+ assert len(stations) == 1
197
+ station = stations.iloc[0]
198
+
199
+ # test the more relevant values
200
+ assert station['name'] == 'WAYNESBURG 1 E'
201
+ assert station['sids'] == ['369367 2', 'USC00369367 6', 'WYNP1 7']
202
+ assert station['state'] == 'PA'
203
+ assert station['altitude'] == 940.
204
+ assert station['tzo'] == -5.0
205
+ assert station['latitude'] == lat
206
+ assert station['longitude'] == lon
207
+
208
+ # check that start/end work as filters
209
+ stations = get_acis_available_stations([lat - 0.0001, lat + 0.0001],
210
+ [lon - 0.0001, lon + 0.0001],
211
+ start='1900-01-01',
212
+ end='1900-01-02')
213
+ assert stations.empty
@@ -27,9 +27,9 @@ MIDC_RAW_SHORT_HEADER_TESTFILE = (
27
27
  # '?site=UAT&begin=20181018&end=20181019')
28
28
 
29
29
 
30
- def test_midc_format_index():
30
+ def test_midc__format_index():
31
31
  data = pd.read_csv(MIDC_TESTFILE)
32
- data = midc.format_index(data)
32
+ data = midc._format_index(data)
33
33
  start = pd.Timestamp("20181014 00:00")
34
34
  start = start.tz_localize("MST")
35
35
  end = pd.Timestamp("20181014 23:59")
@@ -39,16 +39,16 @@ def test_midc_format_index():
39
39
  assert data.index[-1] == end
40
40
 
41
41
 
42
- def test_midc_format_index_tz_conversion():
42
+ def test_midc__format_index_tz_conversion():
43
43
  data = pd.read_csv(MIDC_TESTFILE)
44
44
  data = data.rename(columns={'MST': 'PST'})
45
- data = midc.format_index(data)
45
+ data = midc._format_index(data)
46
46
  assert data.index[0].tz == pytz.timezone('Etc/GMT+8')
47
47
 
48
48
 
49
- def test_midc_format_index_raw():
49
+ def test_midc__format_index_raw():
50
50
  data = pd.read_csv(MIDC_RAW_TESTFILE)
51
- data = midc.format_index_raw(data)
51
+ data = midc._format_index_raw(data)
52
52
  start = pd.Timestamp('20181018 00:00')
53
53
  start = start.tz_localize('MST')
54
54
  end = pd.Timestamp('20181018 23:59')
@@ -170,11 +170,11 @@ def test_read_psm3():
170
170
  def test_read_psm3_map_variables():
171
171
  """test read_psm3 map_variables=True"""
172
172
  data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)
173
- columns_mapped = ['Year', 'Month', 'Day', 'Hour', 'Minute', 'dhi', 'dni',
174
- 'ghi', 'dhi_clear', 'dni_clear', 'ghi_clear',
173
+ columns_mapped = ['Year', 'Month', 'Day', 'Hour', 'Minute', 'dhi', 'ghi',
174
+ 'dni', 'ghi_clear', 'dhi_clear', 'dni_clear',
175
175
  'Cloud Type', 'Dew Point', 'solar_zenith',
176
176
  'Fill Flag', 'albedo', 'wind_speed',
177
- 'precipitable_water', 'wind_direction',
177
+ 'wind_direction', 'precipitable_water',
178
178
  'relative_humidity', 'temp_air', 'pressure']
179
179
  data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)
180
180
  assert_index_equal(data.columns, pd.Index(columns_mapped))
@@ -189,8 +189,10 @@ def test_get_psm3_attribute_mapping(nrel_api_key):
189
189
  names=2019, interval=60,
190
190
  attributes=['ghi', 'wind_speed'],
191
191
  leap_day=False, map_variables=True)
192
- assert 'ghi' in data.columns
193
- assert 'wind_speed' in data.columns
192
+ # Check that columns are in the correct order (GH1647)
193
+ expected_columns = [
194
+ 'Year', 'Month', 'Day', 'Hour', 'Minute', 'ghi', 'wind_speed']
195
+ pd.testing.assert_index_equal(pd.Index(expected_columns), data.columns)
194
196
  assert 'latitude' in meta.keys()
195
197
  assert 'longitude' in meta.keys()
196
198
  assert 'altitude' in meta.keys()