pvlib 0.9.5__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 +6 -171
- pvlib/bifacial/infinite_sheds.py +30 -267
- pvlib/bifacial/utils.py +225 -5
- pvlib/data/test_psm3_2017.csv +17521 -17521
- 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 +17 -4
- 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 +32 -31
- 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 +151 -0
- pvlib/ivtools/sde.py +11 -7
- pvlib/ivtools/sdm.py +16 -10
- pvlib/ivtools/utils.py +6 -6
- pvlib/location.py +3 -2
- pvlib/modelchain.py +67 -70
- pvlib/pvsystem.py +160 -532
- pvlib/shading.py +41 -0
- pvlib/singlediode.py +215 -65
- 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 +1 -8
- pvlib/tests/bifacial/test_infinite_sheds.py +0 -111
- pvlib/tests/bifacial/test_utils.py +101 -4
- 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 +3 -3
- 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/test_atmosphere.py +6 -62
- pvlib/tests/test_iam.py +12 -0
- pvlib/tests/test_irradiance.py +40 -2
- pvlib/tests/test_location.py +1 -1
- pvlib/tests/test_modelchain.py +33 -76
- pvlib/tests/test_pvsystem.py +366 -201
- pvlib/tests/test_shading.py +28 -0
- pvlib/tests/test_singlediode.py +166 -30
- pvlib/tests/test_soiling.py +8 -7
- pvlib/tests/test_spa.py +6 -7
- pvlib/tests/test_spectrum.py +145 -1
- pvlib/tests/test_temperature.py +0 -7
- pvlib/tests/test_tools.py +25 -0
- pvlib/tests/test_tracking.py +0 -149
- pvlib/tools.py +26 -1
- pvlib/tracking.py +1 -269
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/METADATA +1 -9
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/RECORD +67 -68
- 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.5.dist-info → pvlib-0.10.0.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/LICENSE +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/WHEEL +0 -0
- {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
pvlib/tests/test_shading.py
CHANGED
|
@@ -7,6 +7,34 @@ import pytest
|
|
|
7
7
|
from pvlib import shading
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def test_system():
|
|
12
|
+
syst = {'height': 1.0,
|
|
13
|
+
'pitch': 2.,
|
|
14
|
+
'surface_tilt': 30.,
|
|
15
|
+
'surface_azimuth': 180.,
|
|
16
|
+
'rotation': -30.} # rotation of right edge relative to horizontal
|
|
17
|
+
syst['gcr'] = 1.0 / syst['pitch']
|
|
18
|
+
return syst
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test__ground_angle(test_system):
|
|
22
|
+
ts = test_system
|
|
23
|
+
x = np.array([0., 0.5, 1.0])
|
|
24
|
+
angles = shading.ground_angle(
|
|
25
|
+
ts['surface_tilt'], ts['gcr'], x)
|
|
26
|
+
expected_angles = np.array([0., 5.866738789543952, 9.896090638982903])
|
|
27
|
+
assert np.allclose(angles, expected_angles)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test__ground_angle_zero_gcr():
|
|
31
|
+
surface_tilt = 30.0
|
|
32
|
+
x = np.array([0.0, 0.5, 1.0])
|
|
33
|
+
angles = shading.ground_angle(surface_tilt, 0, x)
|
|
34
|
+
expected_angles = np.array([0, 0, 0])
|
|
35
|
+
assert np.allclose(angles, expected_angles)
|
|
36
|
+
|
|
37
|
+
|
|
10
38
|
@pytest.fixture
|
|
11
39
|
def surface_tilt():
|
|
12
40
|
idx = pd.date_range('2019-01-01', freq='h', periods=3)
|
pvlib/tests/test_singlediode.py
CHANGED
|
@@ -8,6 +8,7 @@ import scipy
|
|
|
8
8
|
from pvlib import pvsystem
|
|
9
9
|
from pvlib.singlediode import (bishop88_mpp, estimate_voc, VOLTAGE_BUILTIN,
|
|
10
10
|
bishop88, bishop88_i_from_v, bishop88_v_from_i)
|
|
11
|
+
from pvlib._deprecation import pvlibDeprecationWarning
|
|
11
12
|
import pytest
|
|
12
13
|
from .conftest import DATA_DIR
|
|
13
14
|
|
|
@@ -25,22 +26,16 @@ def test_method_spr_e20_327(method, cec_module_spr_e20_327):
|
|
|
25
26
|
I_L_ref=spr_e20_327['I_L_ref'], I_o_ref=spr_e20_327['I_o_ref'],
|
|
26
27
|
R_sh_ref=spr_e20_327['R_sh_ref'], R_s=spr_e20_327['R_s'],
|
|
27
28
|
EgRef=1.121, dEgdT=-0.0002677)
|
|
28
|
-
il, io, rs, rsh, nnsvt = x
|
|
29
29
|
pvs = pvsystem.singlediode(*x, method='lambertw')
|
|
30
30
|
out = pvsystem.singlediode(*x, method=method)
|
|
31
|
-
|
|
32
|
-
assert np.isclose(pvs['i_sc'],
|
|
33
|
-
assert np.isclose(pvs['v_oc'],
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
assert np.isclose(
|
|
38
|
-
assert np.isclose(
|
|
39
|
-
assert np.isclose(pvs['p_mp'], pmp)
|
|
40
|
-
assert np.isclose(pvs['i_x'], ix)
|
|
41
|
-
pvs_ixx = pvsystem.i_from_v(rsh, rs, nnsvt, (voc + vmp)/2, io, il,
|
|
42
|
-
method='lambertw')
|
|
43
|
-
assert np.isclose(pvs_ixx, ixx)
|
|
31
|
+
|
|
32
|
+
assert np.isclose(pvs['i_sc'], out['i_sc'])
|
|
33
|
+
assert np.isclose(pvs['v_oc'], out['v_oc'])
|
|
34
|
+
assert np.isclose(pvs['i_mp'], out['i_mp'])
|
|
35
|
+
assert np.isclose(pvs['v_mp'], out['v_mp'])
|
|
36
|
+
assert np.isclose(pvs['p_mp'], out['p_mp'])
|
|
37
|
+
assert np.isclose(pvs['i_x'], out['i_x'])
|
|
38
|
+
assert np.isclose(pvs['i_xx'], out['i_xx'])
|
|
44
39
|
|
|
45
40
|
|
|
46
41
|
@pytest.mark.parametrize('method', ['brentq', 'newton'])
|
|
@@ -53,23 +48,16 @@ def test_newton_fs_495(method, cec_module_fs_495):
|
|
|
53
48
|
I_L_ref=fs_495['I_L_ref'], I_o_ref=fs_495['I_o_ref'],
|
|
54
49
|
R_sh_ref=fs_495['R_sh_ref'], R_s=fs_495['R_s'],
|
|
55
50
|
EgRef=1.475, dEgdT=-0.0003)
|
|
56
|
-
il, io, rs, rsh, nnsvt = x
|
|
57
|
-
x += (101, )
|
|
58
51
|
pvs = pvsystem.singlediode(*x, method='lambertw')
|
|
59
52
|
out = pvsystem.singlediode(*x, method=method)
|
|
60
|
-
|
|
61
|
-
assert np.isclose(pvs['i_sc'],
|
|
62
|
-
assert np.isclose(pvs['v_oc'],
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
assert np.isclose(
|
|
67
|
-
assert np.isclose(
|
|
68
|
-
assert np.isclose(pvs['p_mp'], pmp)
|
|
69
|
-
assert np.isclose(pvs['i_x'], ix)
|
|
70
|
-
pvs_ixx = pvsystem.i_from_v(rsh, rs, nnsvt, (voc + vmp)/2, io, il,
|
|
71
|
-
method='lambertw')
|
|
72
|
-
assert np.isclose(pvs_ixx, ixx)
|
|
53
|
+
|
|
54
|
+
assert np.isclose(pvs['i_sc'], out['i_sc'])
|
|
55
|
+
assert np.isclose(pvs['v_oc'], out['v_oc'])
|
|
56
|
+
assert np.isclose(pvs['i_mp'], out['i_mp'])
|
|
57
|
+
assert np.isclose(pvs['v_mp'], out['v_mp'])
|
|
58
|
+
assert np.isclose(pvs['p_mp'], out['p_mp'])
|
|
59
|
+
assert np.isclose(pvs['i_x'], out['i_x'])
|
|
60
|
+
assert np.isclose(pvs['i_xx'], out['i_xx'])
|
|
73
61
|
|
|
74
62
|
|
|
75
63
|
def build_precise_iv_curve_dataframe(file_csv, file_json):
|
|
@@ -180,6 +168,19 @@ def test_singlediode_precision(method, precise_iv_curves):
|
|
|
180
168
|
assert np.allclose(pc['i_xx'], outs['i_xx'], atol=1e-6, rtol=0)
|
|
181
169
|
|
|
182
170
|
|
|
171
|
+
def test_singlediode_lambert_negative_voc():
|
|
172
|
+
|
|
173
|
+
# Those values result in a negative v_oc out of `_lambertw_v_from_i`
|
|
174
|
+
x = np.array([0., 1.480501e-11, 0.178, 8000., 1.797559])
|
|
175
|
+
outs = pvsystem.singlediode(*x, method='lambertw')
|
|
176
|
+
assert outs['v_oc'] == 0
|
|
177
|
+
|
|
178
|
+
# Testing for an array
|
|
179
|
+
x = np.array([x, x]).T
|
|
180
|
+
outs = pvsystem.singlediode(*x, method='lambertw')
|
|
181
|
+
assert np.array_equal(outs['v_oc'], [0, 0])
|
|
182
|
+
|
|
183
|
+
|
|
183
184
|
@pytest.mark.parametrize('method', ['lambertw'])
|
|
184
185
|
def test_ivcurve_pnts_precision(method, precise_iv_curves):
|
|
185
186
|
"""
|
|
@@ -189,7 +190,10 @@ def test_ivcurve_pnts_precision(method, precise_iv_curves):
|
|
|
189
190
|
x, pc = precise_iv_curves
|
|
190
191
|
pc_i, pc_v = np.stack(pc['Currents']), np.stack(pc['Voltages'])
|
|
191
192
|
ivcurve_pnts = len(pc['Currents'][0])
|
|
192
|
-
|
|
193
|
+
|
|
194
|
+
with pytest.warns(pvlibDeprecationWarning, match='ivcurve_pnts'):
|
|
195
|
+
outs = pvsystem.singlediode(method=method, ivcurve_pnts=ivcurve_pnts,
|
|
196
|
+
**x)
|
|
193
197
|
|
|
194
198
|
assert np.allclose(pc_i, outs['i'], atol=1e-10, rtol=0)
|
|
195
199
|
assert np.allclose(pc_v, outs['v'], atol=1e-10, rtol=0)
|
|
@@ -421,3 +425,135 @@ def test_pvsyst_breakdown(method, brk_params, recomb_params, poa, temp_cell,
|
|
|
421
425
|
|
|
422
426
|
vsc_88 = bishop88_v_from_i(isc_88, *x, **y, method=method)
|
|
423
427
|
assert np.isclose(vsc_88, 0.0, *tol)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
@pytest.fixture
|
|
431
|
+
def bishop88_arguments():
|
|
432
|
+
pvsyst_fs_495 = get_pvsyst_fs_495()
|
|
433
|
+
# evaluate PVSyst model with thin-film recombination loss current
|
|
434
|
+
# at reference conditions
|
|
435
|
+
x = pvsystem.calcparams_pvsyst(
|
|
436
|
+
effective_irradiance=pvsyst_fs_495['irrad_ref'],
|
|
437
|
+
temp_cell=pvsyst_fs_495['temp_ref'],
|
|
438
|
+
alpha_sc=pvsyst_fs_495['alpha_sc'],
|
|
439
|
+
gamma_ref=pvsyst_fs_495['gamma_ref'],
|
|
440
|
+
mu_gamma=pvsyst_fs_495['mu_gamma'], I_L_ref=pvsyst_fs_495['I_L_ref'],
|
|
441
|
+
I_o_ref=pvsyst_fs_495['I_o_ref'], R_sh_ref=pvsyst_fs_495['R_sh_ref'],
|
|
442
|
+
R_sh_0=pvsyst_fs_495['R_sh_0'], R_sh_exp=pvsyst_fs_495['R_sh_exp'],
|
|
443
|
+
R_s=pvsyst_fs_495['R_s'],
|
|
444
|
+
cells_in_series=pvsyst_fs_495['cells_in_series'],
|
|
445
|
+
EgRef=pvsyst_fs_495['EgRef']
|
|
446
|
+
)
|
|
447
|
+
y = dict(d2mutau=pvsyst_fs_495['d2mutau'],
|
|
448
|
+
NsVbi=VOLTAGE_BUILTIN*pvsyst_fs_495['cells_in_series'])
|
|
449
|
+
# Convert (*x, **y) in a bishop88_.* call to dict of arguments
|
|
450
|
+
args_dict = {
|
|
451
|
+
'photocurrent': x[0],
|
|
452
|
+
'saturation_current': x[1],
|
|
453
|
+
'resistance_series': x[2],
|
|
454
|
+
'resistance_shunt': x[3],
|
|
455
|
+
'nNsVth': x[4],
|
|
456
|
+
}
|
|
457
|
+
args_dict.update(y)
|
|
458
|
+
return args_dict
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
@pytest.mark.parametrize('method, method_kwargs', [
|
|
462
|
+
('newton', {
|
|
463
|
+
'tol': 1e-8,
|
|
464
|
+
'rtol': 1e-8,
|
|
465
|
+
'maxiter': 30,
|
|
466
|
+
}),
|
|
467
|
+
('brentq', {
|
|
468
|
+
'xtol': 1e-8,
|
|
469
|
+
'rtol': 1e-8,
|
|
470
|
+
'maxiter': 30,
|
|
471
|
+
})
|
|
472
|
+
])
|
|
473
|
+
def test_bishop88_kwargs_transfer(method, method_kwargs, mocker,
|
|
474
|
+
bishop88_arguments):
|
|
475
|
+
"""test method_kwargs modifying optimizer does not break anything"""
|
|
476
|
+
# patch method namespace at singlediode module namespace
|
|
477
|
+
optimizer_mock = mocker.patch('pvlib.singlediode.' + method)
|
|
478
|
+
|
|
479
|
+
# check kwargs passed to bishop_.* are a subset of the call args
|
|
480
|
+
# since they are called with more keyword arguments
|
|
481
|
+
|
|
482
|
+
bishop88_i_from_v(0, **bishop88_arguments, method=method,
|
|
483
|
+
method_kwargs=method_kwargs)
|
|
484
|
+
_, kwargs = optimizer_mock.call_args
|
|
485
|
+
assert method_kwargs.items() <= kwargs.items()
|
|
486
|
+
|
|
487
|
+
bishop88_v_from_i(0, **bishop88_arguments, method=method,
|
|
488
|
+
method_kwargs=method_kwargs)
|
|
489
|
+
_, kwargs = optimizer_mock.call_args
|
|
490
|
+
assert method_kwargs.items() <= kwargs.items()
|
|
491
|
+
|
|
492
|
+
bishop88_mpp(**bishop88_arguments, method=method,
|
|
493
|
+
method_kwargs=method_kwargs)
|
|
494
|
+
_, kwargs = optimizer_mock.call_args
|
|
495
|
+
assert method_kwargs.items() <= kwargs.items()
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
@pytest.mark.parametrize('method, method_kwargs', [
|
|
499
|
+
('newton', {
|
|
500
|
+
'tol': 1e-4,
|
|
501
|
+
'rtol': 1e-4,
|
|
502
|
+
'maxiter': 20,
|
|
503
|
+
'_inexistent_param': "0.01"
|
|
504
|
+
}),
|
|
505
|
+
('brentq', {
|
|
506
|
+
'xtol': 1e-4,
|
|
507
|
+
'rtol': 1e-4,
|
|
508
|
+
'maxiter': 20,
|
|
509
|
+
'_inexistent_param': "0.01"
|
|
510
|
+
})
|
|
511
|
+
])
|
|
512
|
+
def test_bishop88_kwargs_fails(method, method_kwargs, bishop88_arguments):
|
|
513
|
+
"""test invalid method_kwargs passed onto the optimizer fail"""
|
|
514
|
+
|
|
515
|
+
pytest.raises(TypeError, bishop88_i_from_v,
|
|
516
|
+
0, **bishop88_arguments, method=method,
|
|
517
|
+
method_kwargs=method_kwargs)
|
|
518
|
+
|
|
519
|
+
pytest.raises(TypeError, bishop88_v_from_i,
|
|
520
|
+
0, **bishop88_arguments, method=method,
|
|
521
|
+
method_kwargs=method_kwargs)
|
|
522
|
+
|
|
523
|
+
pytest.raises(TypeError, bishop88_mpp,
|
|
524
|
+
**bishop88_arguments, method=method,
|
|
525
|
+
method_kwargs=method_kwargs)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
@pytest.mark.parametrize('method', ['newton', 'brentq'])
|
|
529
|
+
def test_bishop88_full_output_kwarg(method, bishop88_arguments):
|
|
530
|
+
"""test call to bishop88_.* with full_output=True return values are ok"""
|
|
531
|
+
method_kwargs = {'full_output': True}
|
|
532
|
+
|
|
533
|
+
ret_val = bishop88_i_from_v(0, **bishop88_arguments, method=method,
|
|
534
|
+
method_kwargs=method_kwargs)
|
|
535
|
+
assert isinstance(ret_val, tuple) # ret_val must be a tuple
|
|
536
|
+
assert len(ret_val) == 2 # of two elements
|
|
537
|
+
assert isinstance(ret_val[0], float) # first one has bishop88 result
|
|
538
|
+
assert isinstance(ret_val[1], tuple) # second is output from optimizer
|
|
539
|
+
# any root finder returns at least 2 elements with full_output=True
|
|
540
|
+
assert len(ret_val[1]) >= 2
|
|
541
|
+
|
|
542
|
+
ret_val = bishop88_v_from_i(0, **bishop88_arguments, method=method,
|
|
543
|
+
method_kwargs=method_kwargs)
|
|
544
|
+
assert isinstance(ret_val, tuple) # ret_val must be a tuple
|
|
545
|
+
assert len(ret_val) == 2 # of two elements
|
|
546
|
+
assert isinstance(ret_val[0], float) # first one has bishop88 result
|
|
547
|
+
assert isinstance(ret_val[1], tuple) # second is output from optimizer
|
|
548
|
+
# any root finder returns at least 2 elements with full_output=True
|
|
549
|
+
assert len(ret_val[1]) >= 2
|
|
550
|
+
|
|
551
|
+
ret_val = bishop88_mpp(**bishop88_arguments, method=method,
|
|
552
|
+
method_kwargs=method_kwargs)
|
|
553
|
+
assert isinstance(ret_val, tuple) # ret_val must be a tuple
|
|
554
|
+
assert len(ret_val) == 2 # of two elements
|
|
555
|
+
assert isinstance(ret_val[0], tuple) # first one has bishop88 result
|
|
556
|
+
assert len(ret_val[0]) == 3 # of three elements (I,V,P)
|
|
557
|
+
assert isinstance(ret_val[1], tuple) # second is output from optimizer
|
|
558
|
+
# any root finder returns at least 2 elements with full_output=True
|
|
559
|
+
assert len(ret_val[1]) >= 2
|
pvlib/tests/test_soiling.py
CHANGED
|
@@ -92,7 +92,7 @@ def test_hsu_no_cleaning(rainfall_input, expected_output):
|
|
|
92
92
|
tilt = 0.
|
|
93
93
|
expected_no_cleaning = expected_output
|
|
94
94
|
|
|
95
|
-
result = hsu(rainfall=rainfall, cleaning_threshold=10.,
|
|
95
|
+
result = hsu(rainfall=rainfall, cleaning_threshold=10., surface_tilt=tilt,
|
|
96
96
|
pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc,
|
|
97
97
|
rain_accum_period=pd.Timedelta('1h'))
|
|
98
98
|
assert_series_equal(result, expected_no_cleaning)
|
|
@@ -108,7 +108,7 @@ def test_hsu(rainfall_input, expected_output_2):
|
|
|
108
108
|
tilt = 0.
|
|
109
109
|
|
|
110
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,
|
|
111
|
+
result = hsu(rainfall=rainfall, cleaning_threshold=0.5, surface_tilt=tilt,
|
|
112
112
|
pm2_5=pm2_5, pm10=pm10, depo_veloc=depo_veloc,
|
|
113
113
|
rain_accum_period=pd.Timedelta('3h'))
|
|
114
114
|
|
|
@@ -120,8 +120,8 @@ def test_hsu_defaults(rainfall_input, expected_output_1):
|
|
|
120
120
|
Test Soiling HSU function with default deposition velocity and default rain
|
|
121
121
|
accumulation period.
|
|
122
122
|
"""
|
|
123
|
-
result = hsu(rainfall=rainfall_input, cleaning_threshold=0.5,
|
|
124
|
-
pm2_5=1.0e-2, pm10=2.0e-2)
|
|
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
125
|
assert np.allclose(result.values, expected_output_1)
|
|
126
126
|
|
|
127
127
|
|
|
@@ -138,7 +138,7 @@ def test_hsu_variable_time_intervals(rainfall_input, expected_output_3):
|
|
|
138
138
|
rain['new_time'] = rain.index + rain['mins_added']
|
|
139
139
|
rain_var_times = rain.set_index('new_time').iloc[:, 0]
|
|
140
140
|
result = hsu(
|
|
141
|
-
rainfall=rain_var_times, cleaning_threshold=0.5,
|
|
141
|
+
rainfall=rain_var_times, cleaning_threshold=0.5, surface_tilt=50.0,
|
|
142
142
|
pm2_5=1, pm10=2, depo_veloc=depo_veloc,
|
|
143
143
|
rain_accum_period=pd.Timedelta('2h'))
|
|
144
144
|
assert np.allclose(result, expected_output_3)
|
|
@@ -147,8 +147,9 @@ def test_hsu_variable_time_intervals(rainfall_input, expected_output_3):
|
|
|
147
147
|
@pytest.fixture
|
|
148
148
|
def greensboro_rain():
|
|
149
149
|
# get TMY3 data with rain
|
|
150
|
-
greensboro, _ = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990
|
|
151
|
-
|
|
150
|
+
greensboro, _ = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990,
|
|
151
|
+
map_variables=True)
|
|
152
|
+
return greensboro['Lprecip depth (mm)']
|
|
152
153
|
|
|
153
154
|
|
|
154
155
|
@pytest.fixture
|
pvlib/tests/test_spa.py
CHANGED
|
@@ -154,13 +154,12 @@ class SpaBase:
|
|
|
154
154
|
def test_moon_ascending_longitude(self):
|
|
155
155
|
assert_almost_equal(X4, self.spa.moon_ascending_longitude(JCE), 6)
|
|
156
156
|
|
|
157
|
-
def
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
assert_almost_equal(dEpsilon,
|
|
163
|
-
JCE, X0, X1, X2, X3, X4), 6)
|
|
157
|
+
def test_longitude_obliquity_nutation(self):
|
|
158
|
+
out = np.empty((2,))
|
|
159
|
+
self.spa.longitude_obliquity_nutation(JCE, X0, X1, X2, X3, X4, out)
|
|
160
|
+
_dPsi, _dEpsilon = out[0], out[1]
|
|
161
|
+
assert_almost_equal(dPsi, _dPsi, 6)
|
|
162
|
+
assert_almost_equal(dEpsilon, _dEpsilon, 6)
|
|
164
163
|
|
|
165
164
|
def test_mean_ecliptic_obliquity(self):
|
|
166
165
|
assert_almost_equal(epsilon0, self.spa.mean_ecliptic_obliquity(JME), 6)
|
pvlib/tests/test_spectrum.py
CHANGED
|
@@ -4,7 +4,7 @@ import pandas as pd
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from pvlib import spectrum
|
|
6
6
|
|
|
7
|
-
from .conftest import DATA_DIR
|
|
7
|
+
from .conftest import DATA_DIR, assert_series_equal
|
|
8
8
|
|
|
9
9
|
SPECTRL2_TEST_DATA = DATA_DIR / 'spectrl2_example_spectra.csv'
|
|
10
10
|
|
|
@@ -171,3 +171,147 @@ def test_calc_spectral_mismatch_field(spectrl2_data):
|
|
|
171
171
|
mm = spectrum.calc_spectral_mismatch_field(sr, e_sun=e_sun)
|
|
172
172
|
assert mm.index is e_sun.index
|
|
173
173
|
assert_allclose(mm, expected, rtol=1e-6)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize("module_type,expect", [
|
|
177
|
+
('cdte', np.array(
|
|
178
|
+
[[ 0.99051020, 0.97640320, 0.93975028],
|
|
179
|
+
[ 1.02928735, 1.01881074, 0.98578821],
|
|
180
|
+
[ 1.04750335, 1.03814456, 1.00623986]])),
|
|
181
|
+
('monosi', np.array(
|
|
182
|
+
[[ 0.97769770, 1.02043409, 1.03574032],
|
|
183
|
+
[ 0.98630905, 1.03055092, 1.04736262],
|
|
184
|
+
[ 0.98828494, 1.03299036, 1.05026561]])),
|
|
185
|
+
('polysi', np.array(
|
|
186
|
+
[[ 0.97704080, 1.01705849, 1.02613202],
|
|
187
|
+
[ 0.98992828, 1.03173953, 1.04260662],
|
|
188
|
+
[ 0.99352435, 1.03588785, 1.04730718]])),
|
|
189
|
+
('cigs', np.array(
|
|
190
|
+
[[ 0.97459190, 1.02821696, 1.05067895],
|
|
191
|
+
[ 0.97529378, 1.02967497, 1.05289307],
|
|
192
|
+
[ 0.97269159, 1.02730558, 1.05075651]])),
|
|
193
|
+
('asi', np.array(
|
|
194
|
+
[[ 1.05552750, 0.87707583, 0.72243772],
|
|
195
|
+
[ 1.11225204, 0.93665901, 0.78487953],
|
|
196
|
+
[ 1.14555295, 0.97084011, 0.81994083]]))
|
|
197
|
+
])
|
|
198
|
+
def test_spectral_factor_firstsolar(module_type, expect):
|
|
199
|
+
ams = np.array([1, 3, 5])
|
|
200
|
+
pws = np.array([1, 3, 5])
|
|
201
|
+
ams, pws = np.meshgrid(ams, pws)
|
|
202
|
+
out = spectrum.spectral_factor_firstsolar(pws, ams, module_type)
|
|
203
|
+
assert_allclose(out, expect, atol=0.001)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_spectral_factor_firstsolar_supplied():
|
|
207
|
+
# use the cdte coeffs
|
|
208
|
+
coeffs = (0.87102, -0.040543, -0.00929202, 0.10052, 0.073062, -0.0034187)
|
|
209
|
+
out = spectrum.spectral_factor_firstsolar(1, 1, coefficients=coeffs)
|
|
210
|
+
expected = 0.99134828
|
|
211
|
+
assert_allclose(out, expected, atol=1e-3)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def test_spectral_factor_firstsolar_ambiguous():
|
|
215
|
+
with pytest.raises(TypeError):
|
|
216
|
+
spectrum.spectral_factor_firstsolar(1, 1)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_spectral_factor_firstsolar_ambiguous_both():
|
|
220
|
+
# use the cdte coeffs
|
|
221
|
+
coeffs = (0.87102, -0.040543, -0.00929202, 0.10052, 0.073062, -0.0034187)
|
|
222
|
+
with pytest.raises(TypeError):
|
|
223
|
+
spectrum.spectral_factor_firstsolar(1, 1, 'cdte', coefficients=coeffs)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_spectral_factor_firstsolar_large_airmass():
|
|
227
|
+
# test that airmass > 10 is treated same as airmass==10
|
|
228
|
+
m_eq10 = spectrum.spectral_factor_firstsolar(1, 10, 'monosi')
|
|
229
|
+
m_gt10 = spectrum.spectral_factor_firstsolar(1, 15, 'monosi')
|
|
230
|
+
assert_allclose(m_eq10, m_gt10)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_spectral_factor_firstsolar_low_airmass():
|
|
234
|
+
with pytest.warns(UserWarning, match='Exceptionally low air mass'):
|
|
235
|
+
_ = spectrum.spectral_factor_firstsolar(1, 0.1, 'monosi')
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_spectral_factor_firstsolar_range():
|
|
239
|
+
with pytest.warns(UserWarning, match='Exceptionally high pw values'):
|
|
240
|
+
out = spectrum.spectral_factor_firstsolar(np.array([.1, 3, 10]),
|
|
241
|
+
np.array([1, 3, 5]),
|
|
242
|
+
module_type='monosi')
|
|
243
|
+
expected = np.array([0.96080878, 1.03055092, np.nan])
|
|
244
|
+
assert_allclose(out, expected, atol=1e-3)
|
|
245
|
+
with pytest.warns(UserWarning, match='Exceptionally high pw values'):
|
|
246
|
+
out = spectrum.spectral_factor_firstsolar(6, 1.5,
|
|
247
|
+
max_precipitable_water=5,
|
|
248
|
+
module_type='monosi')
|
|
249
|
+
with pytest.warns(UserWarning, match='Exceptionally low pw values'):
|
|
250
|
+
out = spectrum.spectral_factor_firstsolar(np.array([0, 3, 8]),
|
|
251
|
+
np.array([1, 3, 5]),
|
|
252
|
+
module_type='monosi')
|
|
253
|
+
expected = np.array([0.96080878, 1.03055092, 1.04932727])
|
|
254
|
+
assert_allclose(out, expected, atol=1e-3)
|
|
255
|
+
with pytest.warns(UserWarning, match='Exceptionally low pw values'):
|
|
256
|
+
out = spectrum.spectral_factor_firstsolar(0.2, 1.5,
|
|
257
|
+
min_precipitable_water=1,
|
|
258
|
+
module_type='monosi')
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@pytest.mark.parametrize('airmass,expected', [
|
|
262
|
+
(1.5, 1.00028714375),
|
|
263
|
+
(np.array([[10, np.nan]]), np.array([[0.999535, 0]])),
|
|
264
|
+
(pd.Series([5]), pd.Series([1.0387675]))
|
|
265
|
+
])
|
|
266
|
+
def test_spectral_factor_sapm(sapm_module_params, airmass, expected):
|
|
267
|
+
|
|
268
|
+
out = spectrum.spectral_factor_sapm(airmass, sapm_module_params)
|
|
269
|
+
|
|
270
|
+
if isinstance(airmass, pd.Series):
|
|
271
|
+
assert_series_equal(out, expected, check_less_precise=4)
|
|
272
|
+
else:
|
|
273
|
+
assert_allclose(out, expected, atol=1e-4)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@pytest.mark.parametrize("module_type,expected", [
|
|
277
|
+
('asi', np.array([0.9108, 0.9897, 0.9707, 1.0265, 1.0798, 0.9537])),
|
|
278
|
+
('perovskite', np.array([0.9422, 0.9932, 0.9868, 1.0183, 1.0604, 0.9737])),
|
|
279
|
+
('cdte', np.array([0.9824, 1.0000, 1.0065, 1.0117, 1.042, 0.9979])),
|
|
280
|
+
('multisi', np.array([0.9907, 0.9979, 1.0203, 1.0081, 1.0058, 1.019])),
|
|
281
|
+
('monosi', np.array([0.9935, 0.9987, 1.0264, 1.0074, 0.9999, 1.0263])),
|
|
282
|
+
('cigs', np.array([1.0014, 1.0011, 1.0270, 1.0082, 1.0029, 1.026])),
|
|
283
|
+
])
|
|
284
|
+
def test_spectral_factor_caballero(module_type, expected):
|
|
285
|
+
ams = np.array([3.0, 1.5, 3.0, 1.5, 1.5, 3.0])
|
|
286
|
+
aods = np.array([1.0, 1.0, 0.02, 0.02, 0.08, 0.08])
|
|
287
|
+
pws = np.array([1.42, 1.42, 1.42, 1.42, 4.0, 1.0])
|
|
288
|
+
out = spectrum.spectral_factor_caballero(pws, ams, aods,
|
|
289
|
+
module_type=module_type)
|
|
290
|
+
assert np.allclose(expected, out, atol=1e-3)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def test_spectral_factor_caballero_supplied():
|
|
294
|
+
# use the cdte coeffs
|
|
295
|
+
coeffs = (
|
|
296
|
+
1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
|
|
297
|
+
-0.0182, 0, 0.0095, 0.0068, 0, 1)
|
|
298
|
+
out = spectrum.spectral_factor_caballero(1, 1, 1, coefficients=coeffs)
|
|
299
|
+
expected = 1.0021964
|
|
300
|
+
assert_allclose(out, expected, atol=1e-3)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def test_spectral_factor_caballero_supplied_redundant():
|
|
304
|
+
# Error when specifying both module_type and coefficients
|
|
305
|
+
coeffs = (
|
|
306
|
+
1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
|
|
307
|
+
-0.0182, 0, 0.0095, 0.0068, 0, 1)
|
|
308
|
+
with pytest.raises(ValueError):
|
|
309
|
+
spectrum.spectral_factor_caballero(1, 1, 1, module_type='cdte',
|
|
310
|
+
coefficients=coeffs)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def test_spectral_factor_caballero_supplied_ambiguous():
|
|
314
|
+
# Error when specifying neither module_type nor coefficients
|
|
315
|
+
with pytest.raises(ValueError):
|
|
316
|
+
spectrum.spectral_factor_caballero(1, 1, 1, module_type=None,
|
|
317
|
+
coefficients=None)
|
pvlib/tests/test_temperature.py
CHANGED
|
@@ -99,13 +99,6 @@ def test_pvsyst_cell_series():
|
|
|
99
99
|
assert_series_equal(expected, result)
|
|
100
100
|
|
|
101
101
|
|
|
102
|
-
def test_pvsyst_cell_eta_m_deprecated():
|
|
103
|
-
with pytest.warns(pvlibDeprecationWarning):
|
|
104
|
-
result = temperature.pvsyst_cell(900, 20, wind_speed=5.0, u_c=23.5,
|
|
105
|
-
u_v=6.25, eta_m=0.1)
|
|
106
|
-
assert_allclose(result, 33.315, 0.001)
|
|
107
|
-
|
|
108
|
-
|
|
109
102
|
def test_faiman_default():
|
|
110
103
|
result = temperature.faiman(900, 20, 5)
|
|
111
104
|
assert_allclose(result, 35.203, atol=0.001)
|
pvlib/tests/test_tools.py
CHANGED
|
@@ -2,6 +2,7 @@ import pytest
|
|
|
2
2
|
|
|
3
3
|
from pvlib import tools
|
|
4
4
|
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
@pytest.mark.parametrize('keys, input_dict, expected', [
|
|
@@ -95,3 +96,27 @@ def test_degrees_to_index_1():
|
|
|
95
96
|
'latitude' or 'longitude' is passed."""
|
|
96
97
|
with pytest.raises(IndexError): # invalid value for coordinate argument
|
|
97
98
|
tools._degrees_to_index(degrees=22.0, coordinate='width')
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@pytest.mark.parametrize('args, args_idx', [
|
|
102
|
+
# no pandas.Series or pandas.DataFrame args
|
|
103
|
+
((1,), None),
|
|
104
|
+
(([1],), None),
|
|
105
|
+
((np.array(1),), None),
|
|
106
|
+
((np.array([1]),), None),
|
|
107
|
+
# has pandas.Series or pandas.DataFrame args
|
|
108
|
+
((pd.DataFrame([1], index=[1]),), 0),
|
|
109
|
+
((pd.Series([1], index=[1]),), 0),
|
|
110
|
+
((1, pd.Series([1], index=[1]),), 1),
|
|
111
|
+
((1, pd.DataFrame([1], index=[1]),), 1),
|
|
112
|
+
# first pandas.Series or pandas.DataFrame is used
|
|
113
|
+
((1, pd.Series([1], index=[1]), pd.DataFrame([2], index=[2]),), 1),
|
|
114
|
+
((1, pd.DataFrame([1], index=[1]), pd.Series([2], index=[2]),), 1),
|
|
115
|
+
])
|
|
116
|
+
def test_get_pandas_index(args, args_idx):
|
|
117
|
+
index = tools.get_pandas_index(*args)
|
|
118
|
+
|
|
119
|
+
if args_idx is None:
|
|
120
|
+
assert index is None
|
|
121
|
+
else:
|
|
122
|
+
pd.testing.assert_index_equal(args[args_idx].index, index)
|