pvlib 0.11.1__py3-none-any.whl → 0.11.2__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/_deprecation.py +73 -0
- pvlib/atmosphere.py +79 -0
- pvlib/clearsky.py +35 -22
- pvlib/data/pvgis_tmy_test.csv +8761 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.csv +8789 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.epw +8768 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.json +1 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.txt +8761 -0
- pvlib/data/tmy_45.000_8.000_userhorizon.json +1 -1
- pvlib/iam.py +4 -4
- pvlib/iotools/midc.py +1 -1
- pvlib/iotools/pvgis.py +0 -10
- pvlib/irradiance.py +98 -55
- pvlib/ivtools/sdm.py +75 -52
- pvlib/pvsystem.py +132 -84
- pvlib/solarposition.py +46 -30
- pvlib/spa.py +4 -2
- pvlib/spectrum/irradiance.py +2 -1
- pvlib/spectrum/spectrl2.py +2 -1
- pvlib/temperature.py +49 -3
- pvlib/tests/iotools/test_pvgis.py +9 -9
- pvlib/tests/ivtools/test_sdm.py +23 -1
- pvlib/tests/test__deprecation.py +97 -0
- pvlib/tests/test_atmosphere.py +147 -0
- pvlib/tests/test_clearsky.py +7 -1
- pvlib/tests/test_conftest.py +0 -44
- pvlib/tests/test_irradiance.py +56 -10
- pvlib/tests/test_pvsystem.py +17 -1
- pvlib/tests/test_solarposition.py +33 -0
- pvlib/tests/test_spa.py +29 -0
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/METADATA +11 -10
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/RECORD +36 -37
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/WHEEL +1 -1
- pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
- pvlib/data/pvgis_tmy_test.dat +0 -8761
- pvlib/data/tmy_45.000_8.000_2005_2020.csv +0 -8789
- pvlib/data/tmy_45.000_8.000_2005_2020.epw +0 -8768
- pvlib/data/tmy_45.000_8.000_2005_2020.json +0 -1
- pvlib/data/tmy_45.000_8.000_2005_2020.txt +0 -8761
- pvlib/data/variables_style_rules.csv +0 -56
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/LICENSE +0 -0
- {pvlib-0.11.1.dist-info → pvlib-0.11.2.dist-info}/top_level.txt +0 -0
pvlib/temperature.py
CHANGED
|
@@ -118,13 +118,25 @@ def sapm_cell(poa_global, temp_air, wind_speed, a, b, deltaT,
|
|
|
118
118
|
+===============+================+=======+=========+=====================+
|
|
119
119
|
| glass/glass | open rack | -3.47 | -0.0594 | 3 |
|
|
120
120
|
+---------------+----------------+-------+---------+---------------------+
|
|
121
|
-
| glass/glass | close
|
|
121
|
+
| glass/glass | close mount | -2.98 | -0.0471 | 1 |
|
|
122
122
|
+---------------+----------------+-------+---------+---------------------+
|
|
123
123
|
| glass/polymer | open rack | -3.56 | -0.075 | 3 |
|
|
124
124
|
+---------------+----------------+-------+---------+---------------------+
|
|
125
125
|
| glass/polymer | insulated back | -2.81 | -0.0455 | 0 |
|
|
126
126
|
+---------------+----------------+-------+---------+---------------------+
|
|
127
127
|
|
|
128
|
+
Mounting cases can be described in terms of air flow across and around the
|
|
129
|
+
rear-facing surface of the module:
|
|
130
|
+
|
|
131
|
+
* "open rack" refers to mounting that allows relatively free air flow.
|
|
132
|
+
This case is typical of ground-mounted systems on fixed racking or
|
|
133
|
+
single axis trackers.
|
|
134
|
+
* "close mount" refers to limited or restricted air flow. This case is
|
|
135
|
+
typical of roof-mounted systems with some gap behind the module.
|
|
136
|
+
* "insulated back" refers to systems with no air flow contacting the rear
|
|
137
|
+
surface of the module. This case is typical of building-integrated PV
|
|
138
|
+
systems, or systems laid flat on a ground surface.
|
|
139
|
+
|
|
128
140
|
References
|
|
129
141
|
----------
|
|
130
142
|
.. [1] King, D. et al, 2004, "Sandia Photovoltaic Array Performance
|
|
@@ -199,13 +211,25 @@ def sapm_module(poa_global, temp_air, wind_speed, a, b):
|
|
|
199
211
|
+===============+================+=======+=========+=====================+
|
|
200
212
|
| glass/glass | open rack | -3.47 | -0.0594 | 3 |
|
|
201
213
|
+---------------+----------------+-------+---------+---------------------+
|
|
202
|
-
| glass/glass | close
|
|
214
|
+
| glass/glass | close mount | -2.98 | -0.0471 | 1 |
|
|
203
215
|
+---------------+----------------+-------+---------+---------------------+
|
|
204
216
|
| glass/polymer | open rack | -3.56 | -0.075 | 3 |
|
|
205
217
|
+---------------+----------------+-------+---------+---------------------+
|
|
206
218
|
| glass/polymer | insulated back | -2.81 | -0.0455 | 0 |
|
|
207
219
|
+---------------+----------------+-------+---------+---------------------+
|
|
208
220
|
|
|
221
|
+
Mounting cases can be described in terms of air flow across and around the
|
|
222
|
+
rear-facing surface of the module:
|
|
223
|
+
|
|
224
|
+
* "open rack" refers to mounting that allows relatively free air flow.
|
|
225
|
+
This case is typical of ground-mounted systems on fixed racking or
|
|
226
|
+
single axis trackers.
|
|
227
|
+
* "close mount" refers to limited or restricted air flow. This case is
|
|
228
|
+
typical of roof-mounted systems with some gap behind the module.
|
|
229
|
+
* "insulated back" refers to systems with no air flow contacting the rear
|
|
230
|
+
surface of the module. This case is typical of building-integrated PV
|
|
231
|
+
systems, or systems laid flat on a ground surface.
|
|
232
|
+
|
|
209
233
|
References
|
|
210
234
|
----------
|
|
211
235
|
.. [1] King, D. et al, 2004, "Sandia Photovoltaic Array Performance
|
|
@@ -269,13 +293,25 @@ def sapm_cell_from_module(module_temperature, poa_global, deltaT,
|
|
|
269
293
|
+===============+================+=======+=========+=====================+
|
|
270
294
|
| glass/glass | open rack | -3.47 | -0.0594 | 3 |
|
|
271
295
|
+---------------+----------------+-------+---------+---------------------+
|
|
272
|
-
| glass/glass | close
|
|
296
|
+
| glass/glass | close mount | -2.98 | -0.0471 | 1 |
|
|
273
297
|
+---------------+----------------+-------+---------+---------------------+
|
|
274
298
|
| glass/polymer | open rack | -3.56 | -0.075 | 3 |
|
|
275
299
|
+---------------+----------------+-------+---------+---------------------+
|
|
276
300
|
| glass/polymer | insulated back | -2.81 | -0.0455 | 0 |
|
|
277
301
|
+---------------+----------------+-------+---------+---------------------+
|
|
278
302
|
|
|
303
|
+
Mounting cases can be described in terms of air flow across and around the
|
|
304
|
+
rear-facing surface of the module:
|
|
305
|
+
|
|
306
|
+
* "open rack" refers to mounting that allows relatively free air flow.
|
|
307
|
+
This case is typical of ground-mounted systems on fixed racking or
|
|
308
|
+
single axis trackers.
|
|
309
|
+
* "close mount" refers to limited or restricted air flow. This case is
|
|
310
|
+
typical of roof-mounted systems with some gap behind the module.
|
|
311
|
+
* "insulated back" refers to systems with no air flow contacting the rear
|
|
312
|
+
surface of the module. This case is typical of building-integrated PV
|
|
313
|
+
systems, or systems laid flat on a ground surface.
|
|
314
|
+
|
|
279
315
|
References
|
|
280
316
|
----------
|
|
281
317
|
.. [1] King, D. et al, 2004, "Sandia Photovoltaic Array Performance
|
|
@@ -360,6 +396,16 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,
|
|
|
360
396
|
| insulated | 15.0 | 0.0 |
|
|
361
397
|
+--------------+---------------+---------------+
|
|
362
398
|
|
|
399
|
+
Mounting cases can be described in terms of air flow across and around the
|
|
400
|
+
rear-facing surface of the module:
|
|
401
|
+
|
|
402
|
+
* "freestanding" refers to mounting that allows relatively free air
|
|
403
|
+
circulation around the modules. This case is typical of ground-mounted
|
|
404
|
+
systems on tilted, fixed racking or single axis trackers.
|
|
405
|
+
* "insulated" refers to mounting with air flow across only the front
|
|
406
|
+
surface. This case is typical of roof-mounted systems with no gap
|
|
407
|
+
behind the module.
|
|
408
|
+
|
|
363
409
|
References
|
|
364
410
|
----------
|
|
365
411
|
.. [1] "PVsyst 7 Help", [Online]. Available:
|
|
@@ -304,7 +304,7 @@ def test_read_pvgis_hourly_empty_file():
|
|
|
304
304
|
# PVGIS TMY tests
|
|
305
305
|
@pytest.fixture
|
|
306
306
|
def expected():
|
|
307
|
-
return pd.read_csv(DATA_DIR / 'pvgis_tmy_test.
|
|
307
|
+
return pd.read_csv(DATA_DIR / 'pvgis_tmy_test.csv', index_col='time(UTC)')
|
|
308
308
|
|
|
309
309
|
|
|
310
310
|
@pytest.fixture
|
|
@@ -315,7 +315,7 @@ def userhorizon_expected():
|
|
|
315
315
|
@pytest.fixture
|
|
316
316
|
def month_year_expected():
|
|
317
317
|
return [
|
|
318
|
-
|
|
318
|
+
2018, 2007, 2009, 2013, 2008, 2006, 2011, 2010, 2020, 2006, 2007, 2016]
|
|
319
319
|
|
|
320
320
|
|
|
321
321
|
@pytest.fixture
|
|
@@ -323,10 +323,10 @@ def inputs_expected():
|
|
|
323
323
|
return {
|
|
324
324
|
'location': {'latitude': 45.0, 'longitude': 8.0, 'elevation': 250.0},
|
|
325
325
|
'meteo_data': {
|
|
326
|
-
'radiation_db': 'PVGIS-
|
|
326
|
+
'radiation_db': 'PVGIS-SARAH3',
|
|
327
327
|
'meteo_db': 'ERA5',
|
|
328
328
|
'year_min': 2005,
|
|
329
|
-
'year_max':
|
|
329
|
+
'year_max': 2023,
|
|
330
330
|
'use_horizon': True,
|
|
331
331
|
'horizon_db': 'DEM-calculated'}}
|
|
332
332
|
|
|
@@ -564,14 +564,14 @@ def test_read_pvgis_horizon_invalid_coords():
|
|
|
564
564
|
|
|
565
565
|
|
|
566
566
|
def test_read_pvgis_tmy_map_variables(pvgis_tmy_mapped_columns):
|
|
567
|
-
fn = DATA_DIR / 'tmy_45.000_8.
|
|
567
|
+
fn = DATA_DIR / 'tmy_45.000_8.000_2005_2023.json'
|
|
568
568
|
actual, _, _, _ = read_pvgis_tmy(fn, map_variables=True)
|
|
569
569
|
assert all(c in pvgis_tmy_mapped_columns for c in actual.columns)
|
|
570
570
|
|
|
571
571
|
|
|
572
572
|
def test_read_pvgis_tmy_json(expected, month_year_expected, inputs_expected,
|
|
573
573
|
meta_expected):
|
|
574
|
-
fn = DATA_DIR / 'tmy_45.000_8.
|
|
574
|
+
fn = DATA_DIR / 'tmy_45.000_8.000_2005_2023.json'
|
|
575
575
|
# infer outputformat from file extensions
|
|
576
576
|
pvgis_data = read_pvgis_tmy(fn, map_variables=False)
|
|
577
577
|
_compare_pvgis_tmy_json(expected, month_year_expected, inputs_expected,
|
|
@@ -588,7 +588,7 @@ def test_read_pvgis_tmy_json(expected, month_year_expected, inputs_expected,
|
|
|
588
588
|
|
|
589
589
|
|
|
590
590
|
def test_read_pvgis_tmy_epw(expected, epw_meta):
|
|
591
|
-
fn = DATA_DIR / 'tmy_45.000_8.
|
|
591
|
+
fn = DATA_DIR / 'tmy_45.000_8.000_2005_2023.epw'
|
|
592
592
|
# infer outputformat from file extensions
|
|
593
593
|
pvgis_data = read_pvgis_tmy(fn, map_variables=False)
|
|
594
594
|
_compare_pvgis_tmy_epw(expected, epw_meta, pvgis_data)
|
|
@@ -603,7 +603,7 @@ def test_read_pvgis_tmy_epw(expected, epw_meta):
|
|
|
603
603
|
|
|
604
604
|
def test_read_pvgis_tmy_csv(expected, month_year_expected, inputs_expected,
|
|
605
605
|
meta_expected, csv_meta):
|
|
606
|
-
fn = DATA_DIR / 'tmy_45.000_8.
|
|
606
|
+
fn = DATA_DIR / 'tmy_45.000_8.000_2005_2023.csv'
|
|
607
607
|
# infer outputformat from file extensions
|
|
608
608
|
pvgis_data = read_pvgis_tmy(fn, map_variables=False)
|
|
609
609
|
_compare_pvgis_tmy_csv(expected, month_year_expected, inputs_expected,
|
|
@@ -620,7 +620,7 @@ def test_read_pvgis_tmy_csv(expected, month_year_expected, inputs_expected,
|
|
|
620
620
|
|
|
621
621
|
|
|
622
622
|
def test_read_pvgis_tmy_basic(expected, meta_expected):
|
|
623
|
-
fn = DATA_DIR / 'tmy_45.000_8.
|
|
623
|
+
fn = DATA_DIR / 'tmy_45.000_8.000_2005_2023.txt'
|
|
624
624
|
# XXX: can't infer outputformat from file extensions for basic
|
|
625
625
|
with pytest.raises(ValueError, match="pvgis format 'txt' was unknown"):
|
|
626
626
|
read_pvgis_tmy(fn, map_variables=False)
|
pvlib/tests/ivtools/test_sdm.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pandas as pd
|
|
3
|
+
from scipy import optimize
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
from numpy.testing import assert_allclose
|
|
6
7
|
|
|
7
8
|
from pvlib.ivtools import sdm
|
|
8
9
|
from pvlib import pvsystem
|
|
9
|
-
from pvlib._deprecation import pvlibDeprecationWarning
|
|
10
10
|
|
|
11
11
|
from pvlib.tests.conftest import requires_pysam, requires_statsmodels
|
|
12
12
|
|
|
@@ -80,6 +80,25 @@ def test_fit_desoto():
|
|
|
80
80
|
rtol=1e-4)
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
def test_fit_desoto_init_guess(mocker):
|
|
84
|
+
init_guess_array = np.array([9.4, 3.0e-10, 0.3, 125., 1.6])
|
|
85
|
+
init_guess = {k: v for k, v in zip(
|
|
86
|
+
['IL_0', 'Io_0', 'Rs_0', 'Rsh_0', 'a_0'], init_guess_array)}
|
|
87
|
+
spy = mocker.spy(optimize, 'root')
|
|
88
|
+
result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
|
|
89
|
+
alpha_sc=0.005658, beta_voc=-0.13788,
|
|
90
|
+
cells_in_series=60, init_guess=init_guess)
|
|
91
|
+
np.testing.assert_array_equal(init_guess_array, spy.call_args[1]['x0'])
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_fit_desoto_init_bad_key():
|
|
95
|
+
init_guess = {'IL_0': 6., 'bad_key': 0}
|
|
96
|
+
with pytest.raises(ValueError, match='is not a valid name;'):
|
|
97
|
+
result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
|
|
98
|
+
alpha_sc=0.005658, beta_voc=-0.13788,
|
|
99
|
+
cells_in_series=60, init_guess=init_guess)
|
|
100
|
+
|
|
101
|
+
|
|
83
102
|
def test_fit_desoto_failure():
|
|
84
103
|
with pytest.raises(RuntimeError) as exc:
|
|
85
104
|
sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
|
|
@@ -121,6 +140,9 @@ def test_fit_desoto_sandia(cec_params_cansol_cs5p_220p):
|
|
|
121
140
|
expected = pd.Series(params)
|
|
122
141
|
assert np.allclose(modeled[params.keys()].values,
|
|
123
142
|
expected[params.keys()].values, rtol=5e-2)
|
|
143
|
+
assert_allclose(result['dEgdT'], -0.0002677)
|
|
144
|
+
assert_allclose(result['EgRef'], 1.3112547292120638)
|
|
145
|
+
assert_allclose(result['cells_in_series'], specs['cells_in_series'])
|
|
124
146
|
|
|
125
147
|
|
|
126
148
|
def _read_iv_curves_for_test(datafile, npts):
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test the _deprecation module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from pvlib import _deprecation
|
|
8
|
+
from .conftest import fail_on_pvlib_version
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.xfail(strict=True,
|
|
14
|
+
reason='fail_on_pvlib_version should cause test to fail')
|
|
15
|
+
@fail_on_pvlib_version('0.0')
|
|
16
|
+
def test_fail_on_pvlib_version():
|
|
17
|
+
pass # pragma: no cover
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@fail_on_pvlib_version('100000.0')
|
|
21
|
+
def test_fail_on_pvlib_version_pass():
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.xfail(strict=True, reason='ensure that the test is called')
|
|
26
|
+
@fail_on_pvlib_version('100000.0')
|
|
27
|
+
def test_fail_on_pvlib_version_fail_in_test():
|
|
28
|
+
raise Exception
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# set up to test using fixtures with function decorated with
|
|
32
|
+
# conftest.fail_on_pvlib_version
|
|
33
|
+
@pytest.fixture
|
|
34
|
+
def some_data():
|
|
35
|
+
return "some data"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def alt_func(*args):
|
|
39
|
+
return args
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def deprec_func():
|
|
44
|
+
return _deprecation.deprecated(
|
|
45
|
+
"350.8", alternative="alt_func", name="deprec_func", removal="350.9"
|
|
46
|
+
)(alt_func)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@fail_on_pvlib_version('350.9')
|
|
50
|
+
def test_use_fixture_with_decorator(some_data, deprec_func):
|
|
51
|
+
# test that the correct data is returned by the some_data fixture
|
|
52
|
+
assert some_data == "some data"
|
|
53
|
+
with pytest.warns(_deprecation.pvlibDeprecationWarning):
|
|
54
|
+
# test for custom deprecation warning provided by pvlib
|
|
55
|
+
deprec_func(some_data)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.fixture
|
|
59
|
+
def renamed_kwarg_func():
|
|
60
|
+
"""Returns a function decorated by renamed_kwarg_warning.
|
|
61
|
+
This function is called 'func' and has a docstring equal to 'docstring'.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
@_deprecation.renamed_kwarg_warning(
|
|
65
|
+
"0.1.0", "old_kwarg", "new_kwarg", "0.2.0"
|
|
66
|
+
)
|
|
67
|
+
def func(new_kwarg):
|
|
68
|
+
"""docstring"""
|
|
69
|
+
return new_kwarg
|
|
70
|
+
|
|
71
|
+
return func
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_renamed_kwarg_warning(renamed_kwarg_func):
|
|
75
|
+
# assert decorated function name and docstring are unchanged
|
|
76
|
+
assert renamed_kwarg_func.__name__ == "func"
|
|
77
|
+
assert renamed_kwarg_func.__doc__ == "docstring"
|
|
78
|
+
|
|
79
|
+
# assert no warning is raised when using the new kwarg
|
|
80
|
+
with warnings.catch_warnings():
|
|
81
|
+
warnings.simplefilter("error")
|
|
82
|
+
assert renamed_kwarg_func(new_kwarg=1) == 1 # as keyword argument
|
|
83
|
+
assert renamed_kwarg_func(1) == 1 # as positional argument
|
|
84
|
+
|
|
85
|
+
# assert a warning is raised when using the old kwarg
|
|
86
|
+
with pytest.warns(Warning, match="Parameter 'old_kwarg' has been renamed"):
|
|
87
|
+
assert renamed_kwarg_func(old_kwarg=1) == 1
|
|
88
|
+
|
|
89
|
+
# assert an error is raised when using both the old and new kwarg
|
|
90
|
+
with pytest.raises(ValueError, match="they refer to the same parameter."):
|
|
91
|
+
renamed_kwarg_func(old_kwarg=1, new_kwarg=2)
|
|
92
|
+
|
|
93
|
+
# assert when not providing any of them
|
|
94
|
+
with pytest.raises(
|
|
95
|
+
TypeError, match="missing 1 required positional argument"
|
|
96
|
+
):
|
|
97
|
+
renamed_kwarg_func()
|
pvlib/tests/test_atmosphere.py
CHANGED
|
@@ -88,6 +88,153 @@ def test_gueymard94_pw():
|
|
|
88
88
|
assert_allclose(pws, expected, atol=0.01)
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def test_tdew_to_rh_to_tdew():
|
|
92
|
+
|
|
93
|
+
# dewpoint temp calculated with wmo and aekr coefficients
|
|
94
|
+
dewpoint_original = pd.Series([
|
|
95
|
+
15.0, 20.0, 25.0, 12.0, 8.0
|
|
96
|
+
])
|
|
97
|
+
|
|
98
|
+
temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
|
|
99
|
+
|
|
100
|
+
# Calculate relative humidity using pandas series as input
|
|
101
|
+
relative_humidity = atmosphere.rh_from_tdew(
|
|
102
|
+
temp_air=temperature_ambient,
|
|
103
|
+
temp_dew=dewpoint_original
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
dewpoint_calculated = atmosphere.tdew_from_rh(
|
|
107
|
+
temp_air=temperature_ambient,
|
|
108
|
+
relative_humidity=relative_humidity
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# test
|
|
112
|
+
pd.testing.assert_series_equal(
|
|
113
|
+
dewpoint_original,
|
|
114
|
+
dewpoint_calculated,
|
|
115
|
+
check_names=False
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_rh_from_tdew():
|
|
120
|
+
|
|
121
|
+
dewpoint = pd.Series([
|
|
122
|
+
15.0, 20.0, 25.0, 12.0, 8.0
|
|
123
|
+
])
|
|
124
|
+
|
|
125
|
+
# relative humidity calculated with wmo and aekr coefficients
|
|
126
|
+
relative_humidity_wmo = pd.Series([
|
|
127
|
+
72.95185312581116, 73.81500029087906, 74.6401272083123,
|
|
128
|
+
82.27063889868842, 87.39018119185337
|
|
129
|
+
])
|
|
130
|
+
relative_humidity_aekr = pd.Series([
|
|
131
|
+
72.93876680928582, 73.8025121880607, 74.62820502423823,
|
|
132
|
+
82.26135295757305, 87.38323744820416
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
|
|
136
|
+
|
|
137
|
+
# Calculate relative humidity using pandas series as input
|
|
138
|
+
rh_series = atmosphere.rh_from_tdew(
|
|
139
|
+
temp_air=temperature_ambient,
|
|
140
|
+
temp_dew=dewpoint
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
pd.testing.assert_series_equal(
|
|
144
|
+
rh_series,
|
|
145
|
+
relative_humidity_wmo,
|
|
146
|
+
check_names=False
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Calulate relative humidity using pandas series as input
|
|
150
|
+
# with AEKR coefficients
|
|
151
|
+
rh_series_aekr = atmosphere.rh_from_tdew(
|
|
152
|
+
temp_air=temperature_ambient,
|
|
153
|
+
temp_dew=dewpoint,
|
|
154
|
+
coeff=(6.1094, 17.625, 243.04)
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
pd.testing.assert_series_equal(
|
|
158
|
+
rh_series_aekr,
|
|
159
|
+
relative_humidity_aekr,
|
|
160
|
+
check_names=False
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Calculate relative humidity using array as input
|
|
164
|
+
rh_array = atmosphere.rh_from_tdew(
|
|
165
|
+
temp_air=temperature_ambient.to_numpy(),
|
|
166
|
+
temp_dew=dewpoint.to_numpy()
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
np.testing.assert_allclose(rh_array, relative_humidity_wmo.to_numpy())
|
|
170
|
+
|
|
171
|
+
# Calculate relative humidity using float as input
|
|
172
|
+
rh_float = atmosphere.rh_from_tdew(
|
|
173
|
+
temp_air=temperature_ambient.iloc[0],
|
|
174
|
+
temp_dew=dewpoint.iloc[0]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
assert np.isclose(rh_float, relative_humidity_wmo.iloc[0])
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# Unit tests
|
|
181
|
+
def test_tdew_from_rh():
|
|
182
|
+
|
|
183
|
+
dewpoint = pd.Series([
|
|
184
|
+
15.0, 20.0, 25.0, 12.0, 8.0
|
|
185
|
+
])
|
|
186
|
+
|
|
187
|
+
# relative humidity calculated with wmo and aekr coefficients
|
|
188
|
+
relative_humidity_wmo = pd.Series([
|
|
189
|
+
72.95185312581116, 73.81500029087906, 74.6401272083123,
|
|
190
|
+
82.27063889868842, 87.39018119185337
|
|
191
|
+
])
|
|
192
|
+
relative_humidity_aekr = pd.Series([
|
|
193
|
+
72.93876680928582, 73.8025121880607, 74.62820502423823,
|
|
194
|
+
82.26135295757305, 87.38323744820416
|
|
195
|
+
])
|
|
196
|
+
|
|
197
|
+
temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
|
|
198
|
+
|
|
199
|
+
# test as series
|
|
200
|
+
dewpoint_series = atmosphere.tdew_from_rh(
|
|
201
|
+
temp_air=temperature_ambient,
|
|
202
|
+
relative_humidity=relative_humidity_wmo
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
pd.testing.assert_series_equal(
|
|
206
|
+
dewpoint_series, dewpoint, check_names=False
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# test as series with AEKR coefficients
|
|
210
|
+
dewpoint_series_aekr = atmosphere.tdew_from_rh(
|
|
211
|
+
temp_air=temperature_ambient,
|
|
212
|
+
relative_humidity=relative_humidity_aekr,
|
|
213
|
+
coeff=(6.1094, 17.625, 243.04)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
pd.testing.assert_series_equal(
|
|
217
|
+
dewpoint_series_aekr, dewpoint,
|
|
218
|
+
check_names=False
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# test as numpy array
|
|
222
|
+
dewpoint_array = atmosphere.tdew_from_rh(
|
|
223
|
+
temp_air=temperature_ambient.to_numpy(),
|
|
224
|
+
relative_humidity=relative_humidity_wmo.to_numpy()
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
np.testing.assert_allclose(dewpoint_array, dewpoint.to_numpy())
|
|
228
|
+
|
|
229
|
+
# test as float
|
|
230
|
+
dewpoint_float = atmosphere.tdew_from_rh(
|
|
231
|
+
temp_air=temperature_ambient.iloc[0],
|
|
232
|
+
relative_humidity=relative_humidity_wmo.iloc[0]
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
assert np.isclose(dewpoint_float, dewpoint.iloc[0])
|
|
236
|
+
|
|
237
|
+
|
|
91
238
|
def test_first_solar_spectral_correction_deprecated():
|
|
92
239
|
with pytest.warns(pvlibDeprecationWarning,
|
|
93
240
|
match='Use pvlib.spectrum.spectral_factor_firstsolar'):
|
pvlib/tests/test_clearsky.py
CHANGED
|
@@ -674,10 +674,16 @@ def test_detect_clearsky_missing_index(detect_clearsky_data):
|
|
|
674
674
|
|
|
675
675
|
def test_detect_clearsky_not_enough_data(detect_clearsky_data):
|
|
676
676
|
expected, cs = detect_clearsky_data
|
|
677
|
-
with pytest.raises(ValueError, match='
|
|
677
|
+
with pytest.raises(ValueError, match='times has only'):
|
|
678
678
|
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=60)
|
|
679
679
|
|
|
680
680
|
|
|
681
|
+
def test_detect_clearsky_window_too_short(detect_clearsky_data):
|
|
682
|
+
expected, cs = detect_clearsky_data
|
|
683
|
+
with pytest.raises(ValueError, match="Samples per window of "):
|
|
684
|
+
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=2)
|
|
685
|
+
|
|
686
|
+
|
|
681
687
|
@pytest.mark.parametrize("window_length", [5, 10, 15, 20, 25])
|
|
682
688
|
def test_detect_clearsky_optimizer_not_failed(
|
|
683
689
|
detect_clearsky_data, window_length
|
pvlib/tests/test_conftest.py
CHANGED
|
@@ -1,50 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
import pandas
|
|
3
2
|
|
|
4
3
|
from pvlib.tests import conftest
|
|
5
|
-
from pvlib.tests.conftest import fail_on_pvlib_version
|
|
6
|
-
|
|
7
|
-
from pvlib._deprecation import pvlibDeprecationWarning, deprecated
|
|
8
|
-
|
|
9
|
-
@pytest.mark.xfail(strict=True,
|
|
10
|
-
reason='fail_on_pvlib_version should cause test to fail')
|
|
11
|
-
@fail_on_pvlib_version('0.0')
|
|
12
|
-
def test_fail_on_pvlib_version():
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@fail_on_pvlib_version('100000.0')
|
|
17
|
-
def test_fail_on_pvlib_version_pass():
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@pytest.mark.xfail(strict=True, reason='ensure that the test is called')
|
|
22
|
-
@fail_on_pvlib_version('100000.0')
|
|
23
|
-
def test_fail_on_pvlib_version_fail_in_test():
|
|
24
|
-
raise Exception
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# set up to test using fixtures with function decorated with
|
|
28
|
-
# conftest.fail_on_pvlib_version
|
|
29
|
-
@pytest.fixture()
|
|
30
|
-
def some_data():
|
|
31
|
-
return "some data"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def alt_func(*args):
|
|
35
|
-
return args
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
deprec_func = deprecated('350.8', alternative='alt_func',
|
|
39
|
-
name='deprec_func', removal='350.9')(alt_func)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@fail_on_pvlib_version('350.9')
|
|
43
|
-
def test_use_fixture_with_decorator(some_data):
|
|
44
|
-
# test that the correct data is returned by the some_data fixture
|
|
45
|
-
assert some_data == "some data"
|
|
46
|
-
with pytest.warns(pvlibDeprecationWarning): # test for deprecation warning
|
|
47
|
-
deprec_func(some_data)
|
|
48
4
|
|
|
49
5
|
|
|
50
6
|
@pytest.mark.parametrize('function_name', ['assert_index_equal',
|
pvlib/tests/test_irradiance.py
CHANGED
|
@@ -15,7 +15,8 @@ from .conftest import (
|
|
|
15
15
|
assert_frame_equal,
|
|
16
16
|
assert_series_equal,
|
|
17
17
|
requires_ephem,
|
|
18
|
-
requires_numba
|
|
18
|
+
requires_numba,
|
|
19
|
+
fail_on_pvlib_version,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
from pvlib._deprecation import pvlibDeprecationWarning
|
|
@@ -1063,7 +1064,7 @@ def test_dirindex(times):
|
|
|
1063
1064
|
np.array([0., 79.73860422, 1042.48031487, 257.20751138]),
|
|
1064
1065
|
index=times
|
|
1065
1066
|
)
|
|
1066
|
-
|
|
1067
|
+
dni_clear = pd.Series(
|
|
1067
1068
|
np.array([0., 316.1949056, 939.95469881, 646.22886049]),
|
|
1068
1069
|
index=times
|
|
1069
1070
|
)
|
|
@@ -1073,7 +1074,7 @@ def test_dirindex(times):
|
|
|
1073
1074
|
)
|
|
1074
1075
|
pressure = 93193.
|
|
1075
1076
|
tdew = 10.
|
|
1076
|
-
out = irradiance.dirindex(ghi, ghi_clearsky,
|
|
1077
|
+
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clear,
|
|
1077
1078
|
zenith, times, pressure=pressure,
|
|
1078
1079
|
temp_dew=tdew)
|
|
1079
1080
|
dirint_close_values = irradiance.dirint(ghi, zenith, times,
|
|
@@ -1094,6 +1095,20 @@ def test_dirindex(times):
|
|
|
1094
1095
|
equal_nan=True)
|
|
1095
1096
|
|
|
1096
1097
|
|
|
1098
|
+
@fail_on_pvlib_version("0.13")
|
|
1099
|
+
def test_dirindex_ghi_clearsky_deprecation():
|
|
1100
|
+
times = pd.DatetimeIndex(['2014-06-24T18-1200'])
|
|
1101
|
+
ghi = pd.Series([1038.62], index=times)
|
|
1102
|
+
ghi_clearsky = pd.Series([1042.48031487], index=times)
|
|
1103
|
+
dni_clearsky = pd.Series([939.95469881], index=times)
|
|
1104
|
+
zenith = pd.Series([10.56413562], index=times)
|
|
1105
|
+
pressure, tdew = 93193, 10
|
|
1106
|
+
with pytest.warns(pvlibDeprecationWarning, match='ghi_clear'):
|
|
1107
|
+
irradiance.dirindex(
|
|
1108
|
+
ghi=ghi, ghi_clearsky=ghi_clearsky, dni_clear=dni_clearsky,
|
|
1109
|
+
zenith=zenith, times=times, pressure=pressure, temp_dew=tdew)
|
|
1110
|
+
|
|
1111
|
+
|
|
1097
1112
|
def test_dirindex_min_cos_zenith_max_zenith():
|
|
1098
1113
|
# map out behavior under difficult conditions with various
|
|
1099
1114
|
# limiting kwargs settings
|
|
@@ -1101,38 +1116,51 @@ def test_dirindex_min_cos_zenith_max_zenith():
|
|
|
1101
1116
|
times = pd.DatetimeIndex(['2014-06-24T12-0700', '2014-06-24T18-0700'])
|
|
1102
1117
|
ghi = pd.Series([0, 1], index=times)
|
|
1103
1118
|
ghi_clearsky = pd.Series([0, 1], index=times)
|
|
1104
|
-
|
|
1119
|
+
dni_clear = pd.Series([0, 5], index=times)
|
|
1105
1120
|
solar_zenith = pd.Series([90, 89.99], index=times)
|
|
1106
1121
|
|
|
1107
|
-
out = irradiance.dirindex(ghi, ghi_clearsky,
|
|
1122
|
+
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clear, solar_zenith,
|
|
1108
1123
|
times)
|
|
1109
1124
|
expected = pd.Series([nan, nan], index=times)
|
|
1110
1125
|
assert_series_equal(out, expected)
|
|
1111
1126
|
|
|
1112
|
-
out = irradiance.dirindex(ghi, ghi_clearsky,
|
|
1127
|
+
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clear, solar_zenith,
|
|
1113
1128
|
times, min_cos_zenith=0)
|
|
1114
1129
|
expected = pd.Series([nan, nan], index=times)
|
|
1115
1130
|
assert_series_equal(out, expected)
|
|
1116
1131
|
|
|
1117
|
-
out = irradiance.dirindex(ghi, ghi_clearsky,
|
|
1132
|
+
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clear, solar_zenith,
|
|
1118
1133
|
times, max_zenith=90)
|
|
1119
1134
|
expected = pd.Series([nan, nan], index=times)
|
|
1120
1135
|
assert_series_equal(out, expected)
|
|
1121
1136
|
|
|
1122
|
-
out = irradiance.dirindex(ghi, ghi_clearsky,
|
|
1137
|
+
out = irradiance.dirindex(ghi, ghi_clearsky, dni_clear, solar_zenith,
|
|
1123
1138
|
times, min_cos_zenith=0, max_zenith=100)
|
|
1124
1139
|
expected = pd.Series([nan, 5.], index=times)
|
|
1125
1140
|
assert_series_equal(out, expected)
|
|
1126
1141
|
|
|
1127
1142
|
|
|
1143
|
+
@fail_on_pvlib_version("0.13")
|
|
1144
|
+
def test_dirindex_dni_clearsky_deprecation():
|
|
1145
|
+
times = pd.DatetimeIndex(['2014-06-24T12-0700', '2014-06-24T18-0700'])
|
|
1146
|
+
ghi = pd.Series([0, 1], index=times)
|
|
1147
|
+
ghi_clearsky = pd.Series([0, 1], index=times)
|
|
1148
|
+
dni_clear = pd.Series([0, 5], index=times)
|
|
1149
|
+
solar_zenith = pd.Series([90, 89.99], index=times)
|
|
1150
|
+
with pytest.warns(pvlibDeprecationWarning, match='dni_clear'):
|
|
1151
|
+
irradiance.dirindex(ghi, ghi_clearsky, dni_clearsky=dni_clear,
|
|
1152
|
+
zenith=solar_zenith, times=times,
|
|
1153
|
+
min_cos_zenith=0)
|
|
1154
|
+
|
|
1155
|
+
|
|
1128
1156
|
def test_dni():
|
|
1129
1157
|
ghi = pd.Series([90, 100, 100, 100, 100])
|
|
1130
1158
|
dhi = pd.Series([100, 90, 50, 50, 50])
|
|
1131
1159
|
zenith = pd.Series([80, 100, 85, 70, 85])
|
|
1132
|
-
|
|
1160
|
+
dni_clear = pd.Series([50, 50, 200, 50, 300])
|
|
1133
1161
|
|
|
1134
1162
|
dni = irradiance.dni(ghi, dhi, zenith,
|
|
1135
|
-
|
|
1163
|
+
dni_clear=dni_clear, clearsky_tolerance=2)
|
|
1136
1164
|
assert_series_equal(dni,
|
|
1137
1165
|
pd.Series([float('nan'), float('nan'), 400,
|
|
1138
1166
|
146.190220008, 573.685662283]))
|
|
@@ -1143,6 +1171,17 @@ def test_dni():
|
|
|
1143
1171
|
146.190220008, 573.685662283]))
|
|
1144
1172
|
|
|
1145
1173
|
|
|
1174
|
+
@fail_on_pvlib_version("0.13")
|
|
1175
|
+
def test_dni_dni_clearsky_deprecation():
|
|
1176
|
+
ghi = pd.Series([90, 100, 100, 100, 100])
|
|
1177
|
+
dhi = pd.Series([100, 90, 50, 50, 50])
|
|
1178
|
+
zenith = pd.Series([80, 100, 85, 70, 85])
|
|
1179
|
+
dni_clear = pd.Series([50, 50, 200, 50, 300])
|
|
1180
|
+
with pytest.warns(pvlibDeprecationWarning, match='dni_clear'):
|
|
1181
|
+
irradiance.dni(ghi, dhi, zenith,
|
|
1182
|
+
clearsky_dni=dni_clear, clearsky_tolerance=2)
|
|
1183
|
+
|
|
1184
|
+
|
|
1146
1185
|
@pytest.mark.parametrize(
|
|
1147
1186
|
'surface_tilt,surface_azimuth,solar_zenith,' +
|
|
1148
1187
|
'solar_azimuth,aoi_expected,aoi_proj_expected',
|
|
@@ -1235,6 +1274,13 @@ def test_clearsky_index():
|
|
|
1235
1274
|
assert_series_equal(out, expected)
|
|
1236
1275
|
|
|
1237
1276
|
|
|
1277
|
+
@fail_on_pvlib_version("0.13")
|
|
1278
|
+
def test_clearsky_index_clearsky_ghi_deprecation():
|
|
1279
|
+
with pytest.warns(pvlibDeprecationWarning, match='ghi_clear'):
|
|
1280
|
+
ghi, clearsky_ghi = 200, 300
|
|
1281
|
+
irradiance.clearsky_index(ghi, clearsky_ghi=clearsky_ghi)
|
|
1282
|
+
|
|
1283
|
+
|
|
1238
1284
|
def test_clearness_index():
|
|
1239
1285
|
ghi = np.array([-1, 0, 1, 1000])
|
|
1240
1286
|
solar_zenith = np.array([180, 90, 89.999, 0])
|