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.
- pvlib/__init__.py +3 -2
- pvlib/atmosphere.py +23 -173
- pvlib/bifacial/infinite_sheds.py +88 -277
- pvlib/bifacial/utils.py +270 -28
- pvlib/data/adr-library-cec-inverters-2019-03-05.csv +5009 -0
- pvlib/data/precise_iv_curves1.json +10251 -0
- pvlib/data/precise_iv_curves2.json +10251 -0
- pvlib/data/precise_iv_curves_parameter_sets1.csv +33 -0
- pvlib/data/precise_iv_curves_parameter_sets2.csv +33 -0
- pvlib/data/test_psm3_2017.csv +17521 -17521
- pvlib/data/test_psm3_2019_5min.csv +288 -288
- pvlib/data/test_read_psm3.csv +17522 -17522
- pvlib/data/test_read_pvgis_horizon.csv +49 -0
- pvlib/data/variables_style_rules.csv +3 -0
- pvlib/iam.py +207 -51
- pvlib/inverter.py +6 -1
- pvlib/iotools/__init__.py +7 -2
- pvlib/iotools/acis.py +516 -0
- pvlib/iotools/midc.py +4 -4
- pvlib/iotools/psm3.py +59 -42
- pvlib/iotools/pvgis.py +84 -28
- pvlib/iotools/sodapro.py +8 -6
- pvlib/iotools/srml.py +121 -18
- pvlib/iotools/surfrad.py +2 -2
- pvlib/iotools/tmy.py +146 -102
- pvlib/irradiance.py +270 -15
- pvlib/ivtools/sde.py +14 -20
- pvlib/ivtools/sdm.py +31 -20
- pvlib/ivtools/utils.py +127 -6
- pvlib/location.py +3 -2
- pvlib/modelchain.py +67 -70
- pvlib/pvarray.py +225 -0
- pvlib/pvsystem.py +169 -539
- pvlib/shading.py +43 -2
- pvlib/singlediode.py +216 -66
- pvlib/snow.py +36 -15
- pvlib/soiling.py +3 -3
- pvlib/spa.py +327 -368
- pvlib/spectrum/__init__.py +8 -2
- pvlib/spectrum/mismatch.py +335 -0
- pvlib/temperature.py +124 -13
- pvlib/tests/bifacial/test_infinite_sheds.py +44 -106
- pvlib/tests/bifacial/test_utils.py +102 -5
- pvlib/tests/conftest.py +0 -31
- pvlib/tests/iotools/test_acis.py +213 -0
- pvlib/tests/iotools/test_midc.py +6 -6
- pvlib/tests/iotools/test_psm3.py +7 -5
- pvlib/tests/iotools/test_pvgis.py +21 -14
- pvlib/tests/iotools/test_sodapro.py +1 -1
- pvlib/tests/iotools/test_srml.py +71 -6
- pvlib/tests/iotools/test_tmy.py +43 -8
- pvlib/tests/ivtools/test_sde.py +19 -17
- pvlib/tests/ivtools/test_sdm.py +9 -4
- pvlib/tests/ivtools/test_utils.py +96 -1
- pvlib/tests/test_atmosphere.py +8 -64
- pvlib/tests/test_clearsky.py +0 -1
- pvlib/tests/test_iam.py +74 -1
- pvlib/tests/test_irradiance.py +56 -2
- pvlib/tests/test_location.py +1 -1
- pvlib/tests/test_modelchain.py +33 -76
- pvlib/tests/test_pvarray.py +46 -0
- pvlib/tests/test_pvsystem.py +366 -201
- pvlib/tests/test_shading.py +35 -0
- pvlib/tests/test_singlediode.py +306 -29
- pvlib/tests/test_snow.py +84 -1
- pvlib/tests/test_soiling.py +8 -7
- pvlib/tests/test_solarposition.py +7 -7
- pvlib/tests/test_spa.py +6 -7
- pvlib/tests/test_spectrum.py +145 -1
- pvlib/tests/test_temperature.py +29 -11
- pvlib/tests/test_tools.py +41 -0
- pvlib/tests/test_tracking.py +0 -149
- pvlib/tools.py +49 -25
- pvlib/tracking.py +1 -269
- pvlib-0.10.0.dist-info/AUTHORS.md +35 -0
- {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/LICENSE +5 -2
- {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/METADATA +3 -13
- {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/RECORD +80 -75
- {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/WHEEL +1 -1
- pvlib/data/adr-library-2013-10-01.csv +0 -1762
- pvlib/forecast.py +0 -1211
- pvlib/iotools/ecmwf_macc.py +0 -312
- pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
- pvlib/tests/test_forecast.py +0 -228
- pvlib-0.9.4a1.dist-info/AUTHORS.md +0 -32
- {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
|
-
|
|
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
|
|
83
|
-
|
|
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
|
|
87
|
-
|
|
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
|
pvlib/tests/iotools/test_midc.py
CHANGED
|
@@ -27,9 +27,9 @@ MIDC_RAW_SHORT_HEADER_TESTFILE = (
|
|
|
27
27
|
# '?site=UAT&begin=20181018&end=20181019')
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def test_midc__format_index():
|
|
31
31
|
data = pd.read_csv(MIDC_TESTFILE)
|
|
32
|
-
data = midc.
|
|
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
|
|
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.
|
|
45
|
+
data = midc._format_index(data)
|
|
46
46
|
assert data.index[0].tz == pytz.timezone('Etc/GMT+8')
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def
|
|
49
|
+
def test_midc__format_index_raw():
|
|
50
50
|
data = pd.read_csv(MIDC_RAW_TESTFILE)
|
|
51
|
-
data = midc.
|
|
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')
|
pvlib/tests/iotools/test_psm3.py
CHANGED
|
@@ -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', '
|
|
174
|
-
'
|
|
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
|
-
'
|
|
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
|
-
|
|
193
|
-
|
|
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()
|