pvlib 0.11.2__py3-none-any.whl → 0.12.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvlib/__init__.py +1 -0
- pvlib/atmosphere.py +40 -40
- pvlib/bifacial/infinite_sheds.py +4 -3
- pvlib/bifacial/utils.py +2 -1
- pvlib/iotools/__init__.py +6 -0
- pvlib/iotools/psm3.py +1 -1
- pvlib/iotools/psm4.py +819 -0
- pvlib/iotools/pvgis.py +10 -2
- pvlib/iotools/tmy.py +3 -69
- pvlib/irradiance.py +38 -15
- pvlib/ivtools/sdm/__init__.py +20 -0
- pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
- pvlib/ivtools/sdm/cec.py +93 -0
- pvlib/ivtools/sdm/desoto.py +401 -0
- pvlib/ivtools/sdm/pvsyst.py +630 -0
- pvlib/location.py +73 -33
- pvlib/modelchain.py +19 -36
- pvlib/pvsystem.py +114 -65
- pvlib/snow.py +64 -28
- pvlib/spectrum/__init__.py +0 -1
- pvlib/spectrum/irradiance.py +2 -64
- pvlib/spectrum/mismatch.py +3 -3
- pvlib/tools.py +6 -5
- {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/METADATA +6 -5
- pvlib-0.12.1a1.dist-info/RECORD +80 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/WHEEL +1 -1
- pvlib/data/BIRD_08_16_2012.csv +0 -8761
- pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
- pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
- pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
- pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
- pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
- pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
- pvlib/data/CRN_with_problems.txt +0 -3
- pvlib/data/ET-M772BH550GL.PAN +0 -75
- pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
- pvlib/data/PVsyst_demo.csv +0 -10757
- pvlib/data/PVsyst_demo_model.csv +0 -3588
- pvlib/data/SRML-day-EUPO1801.txt +0 -1441
- pvlib/data/abq19056.dat +0 -6
- pvlib/data/bishop88_numerical_precision.csv +0 -101
- pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
- pvlib/data/bsrn-pay0616.dat.gz +0 -0
- pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
- pvlib/data/cams_mcclear_monthly.csv +0 -42
- pvlib/data/cams_radiation_1min_verbose.csv +0 -72
- pvlib/data/cams_radiation_monthly.csv +0 -47
- pvlib/data/detect_clearsky_data.csv +0 -35
- pvlib/data/detect_clearsky_threshold_data.csv +0 -126
- pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
- pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
- pvlib/data/inverter_fit_snl_meas.csv +0 -127
- pvlib/data/inverter_fit_snl_sim.csv +0 -19
- pvlib/data/ivtools_numdiff.csv +0 -52
- pvlib/data/midc_20181014.txt +0 -1441
- pvlib/data/midc_raw_20181018.txt +0 -1441
- pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
- pvlib/data/msn19056.dat +0 -6
- pvlib/data/precise_iv_curves1.json +0 -10251
- pvlib/data/precise_iv_curves2.json +0 -10251
- pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
- pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
- pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
- pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
- pvlib/data/pvgis_tmy_meta.json +0 -32
- pvlib/data/pvgis_tmy_test.csv +0 -8761
- pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
- pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
- pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
- pvlib/data/spectrl2_example_spectra.csv +0 -123
- pvlib/data/surfrad-slv16001.dat +0 -1442
- pvlib/data/test_psm3_2017.csv +0 -17521
- pvlib/data/test_psm3_2019_5min.csv +0 -289
- pvlib/data/test_psm3_tmy-2017.csv +0 -8761
- pvlib/data/test_read_psm3.csv +0 -17523
- pvlib/data/test_read_pvgis_horizon.csv +0 -49
- pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
- pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
- pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
- pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
- pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
- pvlib/ivtools/sdm.py +0 -1379
- pvlib/spa_c_files/README.md +0 -81
- pvlib/spa_c_files/cspa_py.pxd +0 -43
- pvlib/spa_c_files/spa_py.pyx +0 -30
- pvlib/tests/__init__.py +0 -0
- pvlib/tests/bifacial/__init__.py +0 -0
- pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
- pvlib/tests/bifacial/test_losses_models.py +0 -54
- pvlib/tests/bifacial/test_pvfactors.py +0 -82
- pvlib/tests/bifacial/test_utils.py +0 -192
- pvlib/tests/conftest.py +0 -476
- pvlib/tests/iotools/__init__.py +0 -0
- pvlib/tests/iotools/test_acis.py +0 -213
- pvlib/tests/iotools/test_bsrn.py +0 -131
- pvlib/tests/iotools/test_crn.py +0 -95
- pvlib/tests/iotools/test_epw.py +0 -23
- pvlib/tests/iotools/test_midc.py +0 -89
- pvlib/tests/iotools/test_panond.py +0 -32
- pvlib/tests/iotools/test_psm3.py +0 -198
- pvlib/tests/iotools/test_pvgis.py +0 -644
- pvlib/tests/iotools/test_sodapro.py +0 -298
- pvlib/tests/iotools/test_solaranywhere.py +0 -287
- pvlib/tests/iotools/test_solargis.py +0 -68
- pvlib/tests/iotools/test_solcast.py +0 -324
- pvlib/tests/iotools/test_solrad.py +0 -152
- pvlib/tests/iotools/test_srml.py +0 -124
- pvlib/tests/iotools/test_surfrad.py +0 -75
- pvlib/tests/iotools/test_tmy.py +0 -133
- pvlib/tests/ivtools/__init__.py +0 -0
- pvlib/tests/ivtools/test_sde.py +0 -230
- pvlib/tests/ivtools/test_sdm.py +0 -429
- pvlib/tests/ivtools/test_utils.py +0 -173
- pvlib/tests/spectrum/__init__.py +0 -0
- pvlib/tests/spectrum/conftest.py +0 -40
- pvlib/tests/spectrum/test_irradiance.py +0 -138
- pvlib/tests/spectrum/test_mismatch.py +0 -304
- pvlib/tests/spectrum/test_response.py +0 -124
- pvlib/tests/spectrum/test_spectrl2.py +0 -72
- pvlib/tests/test__deprecation.py +0 -97
- pvlib/tests/test_albedo.py +0 -84
- pvlib/tests/test_atmosphere.py +0 -351
- pvlib/tests/test_clearsky.py +0 -884
- pvlib/tests/test_conftest.py +0 -37
- pvlib/tests/test_iam.py +0 -555
- pvlib/tests/test_inverter.py +0 -213
- pvlib/tests/test_irradiance.py +0 -1487
- pvlib/tests/test_location.py +0 -356
- pvlib/tests/test_modelchain.py +0 -2020
- pvlib/tests/test_numerical_precision.py +0 -124
- pvlib/tests/test_pvarray.py +0 -71
- pvlib/tests/test_pvsystem.py +0 -2511
- pvlib/tests/test_scaling.py +0 -207
- pvlib/tests/test_shading.py +0 -391
- pvlib/tests/test_singlediode.py +0 -608
- pvlib/tests/test_snow.py +0 -212
- pvlib/tests/test_soiling.py +0 -230
- pvlib/tests/test_solarposition.py +0 -966
- pvlib/tests/test_spa.py +0 -454
- pvlib/tests/test_temperature.py +0 -470
- pvlib/tests/test_tools.py +0 -146
- pvlib/tests/test_tracking.py +0 -474
- pvlib/tests/test_transformer.py +0 -60
- pvlib-0.11.2.dist-info/RECORD +0 -191
- {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/AUTHORS.md +0 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/LICENSE +0 -0
- {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/top_level.txt +0 -0
pvlib/tests/test_conftest.py
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
from pvlib.tests import conftest
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@pytest.mark.parametrize('function_name', ['assert_index_equal',
|
|
7
|
-
'assert_series_equal',
|
|
8
|
-
'assert_frame_equal'])
|
|
9
|
-
@pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0'])
|
|
10
|
-
@pytest.mark.parametrize('check_less_precise', [True, False])
|
|
11
|
-
def test__check_pandas_assert_kwargs(mocker, function_name, pd_version,
|
|
12
|
-
check_less_precise):
|
|
13
|
-
# test that conftest._check_pandas_assert_kwargs returns appropriate
|
|
14
|
-
# kwargs for the assert_x_equal functions
|
|
15
|
-
|
|
16
|
-
# NOTE: be careful about mixing mocker.patch and pytest.MonkeyPatch!
|
|
17
|
-
# they do not coordinate their cleanups, so it is safest to only
|
|
18
|
-
# use one or the other. GH #1447
|
|
19
|
-
|
|
20
|
-
# patch the pandas assert; not interested in actually calling them,
|
|
21
|
-
# plus we want to spy on how they get called.
|
|
22
|
-
spy = mocker.patch('pandas.testing.' + function_name)
|
|
23
|
-
# patch pd.__version__ to exercise the two branches in
|
|
24
|
-
# conftest._check_pandas_assert_kwargs
|
|
25
|
-
mocker.patch('pandas.__version__', new=pd_version)
|
|
26
|
-
|
|
27
|
-
# finally, run the function and check what args got passed to pandas:
|
|
28
|
-
assert_function = getattr(conftest, function_name)
|
|
29
|
-
args = [None, None]
|
|
30
|
-
assert_function(*args, check_less_precise=check_less_precise)
|
|
31
|
-
if pd_version == '1.1.0':
|
|
32
|
-
tol = 1e-3 if check_less_precise else 1e-5
|
|
33
|
-
expected_kwargs = {'atol': tol, 'rtol': tol}
|
|
34
|
-
else:
|
|
35
|
-
expected_kwargs = {'check_less_precise': check_less_precise}
|
|
36
|
-
|
|
37
|
-
spy.assert_called_once_with(*args, **expected_kwargs)
|
pvlib/tests/test_iam.py
DELETED
|
@@ -1,555 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Created on Wed Oct 2 10:14:16 2019
|
|
3
|
-
|
|
4
|
-
@author: cwhanse
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import numpy as np
|
|
8
|
-
import pandas as pd
|
|
9
|
-
|
|
10
|
-
import pytest
|
|
11
|
-
from .conftest import assert_series_equal
|
|
12
|
-
from numpy.testing import assert_allclose
|
|
13
|
-
|
|
14
|
-
from pvlib import iam as _iam
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_ashrae():
|
|
18
|
-
thetas = np.array([-90., -67.5, -45., -22.5, 0., 22.5, 45., 67.5, 89., 90.,
|
|
19
|
-
np.nan])
|
|
20
|
-
expected = np.array([0, 0.9193437, 0.97928932, 0.99588039, 1., 0.99588039,
|
|
21
|
-
0.97928932, 0.9193437, 0, 0, np.nan])
|
|
22
|
-
iam = _iam.ashrae(thetas, .05)
|
|
23
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
24
|
-
iam_series = _iam.ashrae(pd.Series(thetas))
|
|
25
|
-
assert_series_equal(iam_series, pd.Series(expected))
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def test_ashrae_scalar():
|
|
29
|
-
thetas = -45.
|
|
30
|
-
iam = _iam.ashrae(thetas, .05)
|
|
31
|
-
expected = 0.97928932
|
|
32
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
33
|
-
thetas = np.nan
|
|
34
|
-
iam = _iam.ashrae(thetas, .05)
|
|
35
|
-
expected = np.nan
|
|
36
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def test_physical():
|
|
40
|
-
aoi = np.array([-90., -67.5, -45., -22.5, 0., 22.5, 45., 67.5, 90.,
|
|
41
|
-
np.nan])
|
|
42
|
-
expected = np.array([0, 0.8893998, 0.98797788, 0.99926198, 1, 0.99926198,
|
|
43
|
-
0.98797788, 0.8893998, 0, np.nan])
|
|
44
|
-
iam = _iam.physical(aoi, 1.526, 0.002, 4)
|
|
45
|
-
assert_allclose(iam, expected, atol=1e-7, equal_nan=True)
|
|
46
|
-
|
|
47
|
-
# GitHub issue 397
|
|
48
|
-
aoi = pd.Series(aoi)
|
|
49
|
-
iam = _iam.physical(aoi, 1.526, 0.002, 4)
|
|
50
|
-
expected = pd.Series(expected)
|
|
51
|
-
assert_series_equal(iam, expected)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_physical_n1_L0():
|
|
55
|
-
aoi = np.array([0, 22.5, 45, 67.5, 90, 100, np.nan])
|
|
56
|
-
expected = np.array([1, 1, 1, 1, 0, 0, np.nan])
|
|
57
|
-
iam = _iam.physical(aoi, n=1, L=0)
|
|
58
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
59
|
-
|
|
60
|
-
aoi = pd.Series(aoi)
|
|
61
|
-
expected = pd.Series(expected)
|
|
62
|
-
iam = _iam.physical(aoi, n=1, L=0)
|
|
63
|
-
assert_series_equal(iam, expected)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_physical_ar():
|
|
67
|
-
aoi = np.array([0, 22.5, 45, 67.5, 90, 100, np.nan])
|
|
68
|
-
expected = np.array([1, 0.99944171, 0.9917463, 0.91506158, 0, 0, np.nan])
|
|
69
|
-
iam = _iam.physical(aoi, n_ar=1.29)
|
|
70
|
-
assert_allclose(iam, expected, atol=1e-7, equal_nan=True)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def test_physical_noar():
|
|
74
|
-
aoi = np.array([0, 22.5, 45, 67.5, 90, 100, np.nan])
|
|
75
|
-
expected = _iam.physical(aoi)
|
|
76
|
-
iam0 = _iam.physical(aoi, n_ar=1)
|
|
77
|
-
iam1 = _iam.physical(aoi, n_ar=1.526)
|
|
78
|
-
assert_allclose(iam0, expected, equal_nan=True)
|
|
79
|
-
assert_allclose(iam1, expected, equal_nan=True)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_physical_scalar():
|
|
83
|
-
aoi = -45.
|
|
84
|
-
iam = _iam.physical(aoi, 1.526, 0.002, 4)
|
|
85
|
-
expected = 0.98797788
|
|
86
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
87
|
-
aoi = np.nan
|
|
88
|
-
iam = _iam.physical(aoi, 1.526, 0.002, 4)
|
|
89
|
-
expected = np.nan
|
|
90
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def test_martin_ruiz():
|
|
94
|
-
|
|
95
|
-
aoi = 45.
|
|
96
|
-
a_r = 0.16
|
|
97
|
-
expected = 0.98986965
|
|
98
|
-
|
|
99
|
-
# will fail if default values change
|
|
100
|
-
iam = _iam.martin_ruiz(aoi)
|
|
101
|
-
assert_allclose(iam, expected)
|
|
102
|
-
|
|
103
|
-
# will fail if parameter names change
|
|
104
|
-
iam = _iam.martin_ruiz(aoi=aoi, a_r=a_r)
|
|
105
|
-
assert_allclose(iam, expected)
|
|
106
|
-
|
|
107
|
-
a_r = 0.18
|
|
108
|
-
aoi = [-100, -60, 0, 60, 100, np.nan, np.inf]
|
|
109
|
-
expected = [0.0, 0.9414631, 1.0, 0.9414631, 0.0, np.nan, 0.0]
|
|
110
|
-
|
|
111
|
-
# check out of range of inputs as list
|
|
112
|
-
iam = _iam.martin_ruiz(aoi, a_r)
|
|
113
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
114
|
-
|
|
115
|
-
# check out of range of inputs as array
|
|
116
|
-
iam = _iam.martin_ruiz(np.array(aoi), a_r)
|
|
117
|
-
assert_allclose(iam, expected, equal_nan=True)
|
|
118
|
-
|
|
119
|
-
# check out of range of inputs as Series
|
|
120
|
-
aoi = pd.Series(aoi)
|
|
121
|
-
expected = pd.Series(expected)
|
|
122
|
-
iam = _iam.martin_ruiz(aoi, a_r)
|
|
123
|
-
assert_series_equal(iam, expected)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def test_martin_ruiz_exception():
|
|
127
|
-
|
|
128
|
-
with pytest.raises(ValueError):
|
|
129
|
-
_iam.martin_ruiz(0.0, a_r=0.0)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def test_martin_ruiz_diffuse():
|
|
133
|
-
|
|
134
|
-
surface_tilt = 30.
|
|
135
|
-
a_r = 0.16
|
|
136
|
-
expected = (0.9549735, 0.7944426)
|
|
137
|
-
|
|
138
|
-
# will fail if default values change
|
|
139
|
-
iam = _iam.martin_ruiz_diffuse(surface_tilt)
|
|
140
|
-
assert_allclose(iam, expected)
|
|
141
|
-
|
|
142
|
-
# will fail if parameter names change
|
|
143
|
-
iam = _iam.martin_ruiz_diffuse(surface_tilt=surface_tilt, a_r=a_r)
|
|
144
|
-
assert_allclose(iam, expected)
|
|
145
|
-
|
|
146
|
-
a_r = 0.18
|
|
147
|
-
surface_tilt = [0, 30, 90, 120, 180, np.nan, np.inf]
|
|
148
|
-
expected_sky = [0.9407678, 0.9452250, 0.9407678, 0.9055541, 0.0000000,
|
|
149
|
-
np.nan, np.nan]
|
|
150
|
-
expected_gnd = [0.0000000, 0.7610849, 0.9407678, 0.9483508, 0.9407678,
|
|
151
|
-
np.nan, np.nan]
|
|
152
|
-
|
|
153
|
-
# check various inputs as list
|
|
154
|
-
iam = _iam.martin_ruiz_diffuse(surface_tilt, a_r)
|
|
155
|
-
assert_allclose(iam[0], expected_sky, atol=1e-7, equal_nan=True)
|
|
156
|
-
assert_allclose(iam[1], expected_gnd, atol=1e-7, equal_nan=True)
|
|
157
|
-
|
|
158
|
-
# check various inputs as array
|
|
159
|
-
iam = _iam.martin_ruiz_diffuse(np.array(surface_tilt), a_r)
|
|
160
|
-
assert_allclose(iam[0], expected_sky, atol=1e-7, equal_nan=True)
|
|
161
|
-
assert_allclose(iam[1], expected_gnd, atol=1e-7, equal_nan=True)
|
|
162
|
-
|
|
163
|
-
# check various inputs as Series
|
|
164
|
-
surface_tilt = pd.Series(surface_tilt)
|
|
165
|
-
expected_sky = pd.Series(expected_sky, name='iam_sky')
|
|
166
|
-
expected_gnd = pd.Series(expected_gnd, name='iam_ground')
|
|
167
|
-
iam = _iam.martin_ruiz_diffuse(surface_tilt, a_r)
|
|
168
|
-
assert_series_equal(iam[0], expected_sky)
|
|
169
|
-
assert_series_equal(iam[1], expected_gnd)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def test_iam_interp():
|
|
173
|
-
|
|
174
|
-
aoi_meas = [0.0, 45.0, 65.0, 75.0]
|
|
175
|
-
iam_meas = [1.0, 0.9, 0.8, 0.6]
|
|
176
|
-
|
|
177
|
-
# simple default linear method
|
|
178
|
-
aoi = 55.0
|
|
179
|
-
expected = 0.85
|
|
180
|
-
iam = _iam.interp(aoi, aoi_meas, iam_meas)
|
|
181
|
-
assert_allclose(iam, expected)
|
|
182
|
-
|
|
183
|
-
# simple non-default method
|
|
184
|
-
aoi = 55.0
|
|
185
|
-
expected = 0.8878062
|
|
186
|
-
iam = _iam.interp(aoi, aoi_meas, iam_meas, method='cubic')
|
|
187
|
-
assert_allclose(iam, expected)
|
|
188
|
-
|
|
189
|
-
# check with all reference values
|
|
190
|
-
aoi = aoi_meas
|
|
191
|
-
expected = iam_meas
|
|
192
|
-
iam = _iam.interp(aoi, aoi_meas, iam_meas)
|
|
193
|
-
assert_allclose(iam, expected)
|
|
194
|
-
|
|
195
|
-
# check normalization and Series
|
|
196
|
-
aoi = pd.Series(aoi)
|
|
197
|
-
expected = pd.Series(expected)
|
|
198
|
-
iam_mult = np.multiply(0.9, iam_meas)
|
|
199
|
-
iam = _iam.interp(aoi, aoi_meas, iam_mult, normalize=True)
|
|
200
|
-
assert_series_equal(iam, expected)
|
|
201
|
-
|
|
202
|
-
# check beyond reference values
|
|
203
|
-
aoi = [-45, 0, 45, 85, 90, 95, 100, 105, 110]
|
|
204
|
-
expected = [0.9, 1.0, 0.9, 0.4, 0.3, 0.2, 0.1, 0.0, 0.0]
|
|
205
|
-
iam = _iam.interp(aoi, aoi_meas, iam_meas)
|
|
206
|
-
assert_allclose(iam, expected)
|
|
207
|
-
|
|
208
|
-
# check exception clause
|
|
209
|
-
with pytest.raises(ValueError):
|
|
210
|
-
_iam.interp(0.0, [0], [1])
|
|
211
|
-
|
|
212
|
-
# check exception clause
|
|
213
|
-
with pytest.raises(ValueError):
|
|
214
|
-
_iam.interp(0.0, [0, 90], [1, -1])
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
@pytest.mark.parametrize('aoi,expected', [
|
|
218
|
-
(45, 0.9975036250000002),
|
|
219
|
-
(np.array([[-30, 30, 100, np.nan]]),
|
|
220
|
-
np.array([[0, 1.007572, 0, np.nan]])),
|
|
221
|
-
(pd.Series([80]), pd.Series([0.597472]))
|
|
222
|
-
])
|
|
223
|
-
def test_sapm(sapm_module_params, aoi, expected):
|
|
224
|
-
|
|
225
|
-
out = _iam.sapm(aoi, sapm_module_params)
|
|
226
|
-
|
|
227
|
-
if isinstance(aoi, pd.Series):
|
|
228
|
-
assert_series_equal(out, expected, check_less_precise=4)
|
|
229
|
-
else:
|
|
230
|
-
assert_allclose(out, expected, atol=1e-4)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
def test_sapm_limits():
|
|
234
|
-
module_parameters = {'B0': 5, 'B1': 0, 'B2': 0, 'B3': 0, 'B4': 0, 'B5': 0}
|
|
235
|
-
assert _iam.sapm(1, module_parameters) == 5
|
|
236
|
-
|
|
237
|
-
module_parameters = {'B0': 5, 'B1': 0, 'B2': 0, 'B3': 0, 'B4': 0, 'B5': 0}
|
|
238
|
-
assert _iam.sapm(1, module_parameters, upper=1) == 1
|
|
239
|
-
|
|
240
|
-
module_parameters = {'B0': -5, 'B1': 0, 'B2': 0, 'B3': 0, 'B4': 0, 'B5': 0}
|
|
241
|
-
assert _iam.sapm(1, module_parameters) == 0
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def test_marion_diffuse_model(mocker):
|
|
245
|
-
# 1: return values are correct
|
|
246
|
-
# 2: the underlying models are called appropriately
|
|
247
|
-
ashrae_expected = {
|
|
248
|
-
'sky': 0.9596085829811408,
|
|
249
|
-
'horizon': 0.8329070417832541,
|
|
250
|
-
'ground': 0.719823559106309
|
|
251
|
-
}
|
|
252
|
-
physical_expected = {
|
|
253
|
-
'sky': 0.9539178294437575,
|
|
254
|
-
'horizon': 0.7652650139134007,
|
|
255
|
-
'ground': 0.6387140117795903
|
|
256
|
-
}
|
|
257
|
-
ashrae_spy = mocker.spy(_iam, 'ashrae')
|
|
258
|
-
physical_spy = mocker.spy(_iam, 'physical')
|
|
259
|
-
|
|
260
|
-
ashrae_actual = _iam.marion_diffuse('ashrae', 20)
|
|
261
|
-
assert ashrae_spy.call_count == 3 # one call for each of the 3 regions
|
|
262
|
-
assert physical_spy.call_count == 0
|
|
263
|
-
physical_actual = _iam.marion_diffuse('physical', 20)
|
|
264
|
-
assert ashrae_spy.call_count == 3
|
|
265
|
-
assert physical_spy.call_count == 3
|
|
266
|
-
|
|
267
|
-
for k, v in ashrae_expected.items():
|
|
268
|
-
assert_allclose(ashrae_actual[k], v)
|
|
269
|
-
|
|
270
|
-
for k, v in physical_expected.items():
|
|
271
|
-
assert_allclose(physical_actual[k], v)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def test_marion_diffuse_kwargs():
|
|
275
|
-
# kwargs get passed to underlying model
|
|
276
|
-
expected = {
|
|
277
|
-
'sky': 0.967489994422575,
|
|
278
|
-
'horizon': 0.8647842827418412,
|
|
279
|
-
'ground': 0.7700443455928433
|
|
280
|
-
}
|
|
281
|
-
actual = _iam.marion_diffuse('ashrae', 20, b=0.04)
|
|
282
|
-
|
|
283
|
-
for k, v in expected.items():
|
|
284
|
-
assert_allclose(actual[k], v)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def test_marion_diffuse_invalid():
|
|
288
|
-
with pytest.raises(ValueError):
|
|
289
|
-
_iam.marion_diffuse('not_a_model', 20)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
@pytest.mark.parametrize('region,N,expected', [
|
|
293
|
-
('sky', 180, 0.9596085829811408),
|
|
294
|
-
('horizon', 1800, 0.8329070417832541),
|
|
295
|
-
('ground', 180, 0.719823559106309)
|
|
296
|
-
])
|
|
297
|
-
def test_marion_integrate_scalar(region, N, expected):
|
|
298
|
-
actual = _iam.marion_integrate(_iam.ashrae, 20, region, N)
|
|
299
|
-
assert_allclose(actual, expected)
|
|
300
|
-
|
|
301
|
-
with np.errstate(invalid='ignore'):
|
|
302
|
-
actual = _iam.marion_integrate(_iam.ashrae, np.nan, region, N)
|
|
303
|
-
expected = np.nan
|
|
304
|
-
assert_allclose(actual, expected)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
@pytest.mark.parametrize('region,N,expected', [
|
|
308
|
-
('sky', 180, [0.9523611991069362, 0.9596085829811408, 0.9619811198105501]),
|
|
309
|
-
('horizon', 1800, [0.0, 0.8329070417832541, 0.8987287652347437]),
|
|
310
|
-
('ground', 180, [0.0, 0.719823559106309, 0.8186360238536674])
|
|
311
|
-
])
|
|
312
|
-
def test_marion_integrate_list(region, N, expected):
|
|
313
|
-
actual = _iam.marion_integrate(_iam.ashrae, [0, 20, 30], region, N)
|
|
314
|
-
assert_allclose(actual, expected)
|
|
315
|
-
|
|
316
|
-
with np.errstate(invalid='ignore'):
|
|
317
|
-
actual = _iam.marion_integrate(_iam.ashrae, [0, 20, np.nan], region, N)
|
|
318
|
-
assert_allclose(actual, [expected[0], expected[1], np.nan])
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
@pytest.mark.parametrize('region,N,expected', [
|
|
322
|
-
('sky', 180, [0.9523611991069362, 0.9596085829811408, 0.9619811198105501]),
|
|
323
|
-
('horizon', 1800, [0.0, 0.8329070417832541, 0.8987287652347437]),
|
|
324
|
-
('ground', 180, [0.0, 0.719823559106309, 0.8186360238536674])
|
|
325
|
-
])
|
|
326
|
-
def test_marion_integrate_series(region, N, expected):
|
|
327
|
-
idx = pd.date_range('2019-01-01', periods=3, freq='h')
|
|
328
|
-
tilt = pd.Series([0, 20, 30], index=idx)
|
|
329
|
-
expected = pd.Series(expected, index=idx)
|
|
330
|
-
actual = _iam.marion_integrate(_iam.ashrae, tilt, region, N)
|
|
331
|
-
assert_series_equal(actual, expected)
|
|
332
|
-
|
|
333
|
-
tilt.iloc[1] = np.nan
|
|
334
|
-
expected.iloc[1] = np.nan
|
|
335
|
-
with np.errstate(invalid='ignore'):
|
|
336
|
-
actual = _iam.marion_integrate(_iam.ashrae, tilt, region, N)
|
|
337
|
-
assert_allclose(actual, expected)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
def test_marion_integrate_ground_flat():
|
|
341
|
-
iam = _iam.marion_integrate(_iam.ashrae, 0, 'horizon', 1800)
|
|
342
|
-
assert_allclose(iam, 0)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def test_marion_integrate_invalid():
|
|
346
|
-
# check for invalid region string. this actually gets checked twice,
|
|
347
|
-
# with the difference being whether `num` is specified or not.
|
|
348
|
-
with pytest.raises(ValueError):
|
|
349
|
-
_iam.marion_integrate(_iam.ashrae, 0, 'bad')
|
|
350
|
-
|
|
351
|
-
with pytest.raises(ValueError):
|
|
352
|
-
_iam.marion_integrate(_iam.ashrae, 0, 'bad', 180)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
def test_schlick():
|
|
356
|
-
idx = pd.date_range('2019-01-01', freq='h', periods=9)
|
|
357
|
-
aoi = pd.Series([-180, -135, -90, -45, 0, 45, 90, 135, 180], idx)
|
|
358
|
-
expected = pd.Series([0, 0, 0, 0.99784451, 1.0, 0.99784451, 0, 0, 0], idx)
|
|
359
|
-
|
|
360
|
-
# scalars
|
|
361
|
-
for aoi_scalar, expected_scalar in zip(aoi, expected):
|
|
362
|
-
actual = _iam.schlick(aoi_scalar)
|
|
363
|
-
assert_allclose(expected_scalar, actual)
|
|
364
|
-
|
|
365
|
-
# numpy arrays
|
|
366
|
-
actual = _iam.schlick(aoi.values)
|
|
367
|
-
assert_allclose(expected.values, actual)
|
|
368
|
-
|
|
369
|
-
# pandas Series
|
|
370
|
-
actual = _iam.schlick(aoi)
|
|
371
|
-
assert_series_equal(expected, actual)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
def test_schlick_diffuse():
|
|
375
|
-
surface_tilt = np.array([0, 20, 70, 90])
|
|
376
|
-
# expected values calculated with marion_integrate and schlick
|
|
377
|
-
expected_sky = np.array([0.95238092, 0.96249934, 0.96228167, 0.95238094])
|
|
378
|
-
expected_ground = np.array([0, 0.62693858, 0.93218737, 0.95238094])
|
|
379
|
-
|
|
380
|
-
# numpy arrays
|
|
381
|
-
actual_sky, actual_ground = _iam.schlick_diffuse(surface_tilt)
|
|
382
|
-
assert_allclose(expected_sky, actual_sky)
|
|
383
|
-
assert_allclose(expected_ground, actual_ground, rtol=1e-6)
|
|
384
|
-
|
|
385
|
-
# scalars
|
|
386
|
-
for i in range(len(surface_tilt)):
|
|
387
|
-
actual_sky, actual_ground = _iam.schlick_diffuse(surface_tilt[i])
|
|
388
|
-
assert_allclose(expected_sky[i], actual_sky)
|
|
389
|
-
assert_allclose(expected_ground[i], actual_ground, rtol=1e-6)
|
|
390
|
-
|
|
391
|
-
# pandas Series
|
|
392
|
-
idx = pd.date_range('2019-01-01', freq='h', periods=len(surface_tilt))
|
|
393
|
-
actual_sky, actual_ground = _iam.schlick_diffuse(pd.Series(surface_tilt,
|
|
394
|
-
idx))
|
|
395
|
-
assert_series_equal(pd.Series(expected_sky, idx), actual_sky)
|
|
396
|
-
assert_series_equal(pd.Series(expected_ground, idx), actual_ground,
|
|
397
|
-
rtol=1e-6)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
@pytest.mark.parametrize('source,source_params,target,expected', [
|
|
401
|
-
('physical', {'n': 1.5, 'K': 4.5, 'L': 0.004}, 'martin_ruiz',
|
|
402
|
-
{'a_r': 0.174037}),
|
|
403
|
-
('physical', {'n': 1.5, 'K': 4.5, 'L': 0.004}, 'ashrae',
|
|
404
|
-
{'b': 0.042896}),
|
|
405
|
-
('ashrae', {'b': 0.15}, 'physical',
|
|
406
|
-
{'n': 0.991457, 'K': 4, 'L': 0.037813}),
|
|
407
|
-
('ashrae', {'b': 0.15}, 'martin_ruiz', {'a_r': 0.302390}),
|
|
408
|
-
('martin_ruiz', {'a_r': 0.15}, 'physical',
|
|
409
|
-
{'n': 1.240190, 'K': 4, 'L': 0.002791055}),
|
|
410
|
-
('martin_ruiz', {'a_r': 0.15}, 'ashrae', {'b': 0.025458})])
|
|
411
|
-
def test_convert(source, source_params, target, expected):
|
|
412
|
-
target_params = _iam.convert(source, source_params, target)
|
|
413
|
-
exp = [expected[k] for k in expected]
|
|
414
|
-
tar = [target_params[k] for k in expected]
|
|
415
|
-
assert_allclose(exp, tar, rtol=1e-05)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
@pytest.mark.parametrize('source,source_params', [
|
|
419
|
-
('ashrae', {'b': 0.15}),
|
|
420
|
-
('ashrae', {'b': 0.05}),
|
|
421
|
-
('martin_ruiz', {'a_r': 0.15})])
|
|
422
|
-
def test_convert_recover(source, source_params):
|
|
423
|
-
# convert isn't set up to handle both source and target = 'physical'
|
|
424
|
-
target_params = _iam.convert(source, source_params, source, xtol=1e-7)
|
|
425
|
-
exp = [source_params[k] for k in source_params]
|
|
426
|
-
tar = [target_params[k] for k in source_params]
|
|
427
|
-
assert_allclose(exp, tar, rtol=1e-05)
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
def test_convert_ashrae_physical_no_fix_n():
|
|
431
|
-
# convert ashrae to physical, without fixing n
|
|
432
|
-
source_params = {'b': 0.15}
|
|
433
|
-
target_params = _iam.convert('ashrae', source_params, 'physical',
|
|
434
|
-
fix_n=False)
|
|
435
|
-
expected = {'n': 0.989019, 'K': 4, 'L': 0.037382}
|
|
436
|
-
exp = [expected[k] for k in expected]
|
|
437
|
-
tar = [target_params[k] for k in expected]
|
|
438
|
-
assert_allclose(exp, tar, rtol=1e-05)
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
def test_convert_reverse_order_in_physical():
|
|
442
|
-
source_params = {'a_r': 0.25}
|
|
443
|
-
target_params = _iam.convert('martin_ruiz', source_params, 'physical')
|
|
444
|
-
expected = {'n': 1.691398, 'K': 4, 'L': 0.071633}
|
|
445
|
-
exp = [expected[k] for k in expected]
|
|
446
|
-
tar = [target_params[k] for k in expected]
|
|
447
|
-
assert_allclose(exp, tar, rtol=1e-05)
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
def test_convert_xtol():
|
|
451
|
-
source_params = {'b': 0.15}
|
|
452
|
-
target_params = _iam.convert('ashrae', source_params, 'physical',
|
|
453
|
-
xtol=1e-8)
|
|
454
|
-
expected = {'n': 0.9914568914, 'K': 4, 'L': 0.0378126985}
|
|
455
|
-
exp = [expected[k] for k in expected]
|
|
456
|
-
tar = [target_params[k] for k in expected]
|
|
457
|
-
assert_allclose(exp, tar, rtol=1e-6)
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
def test_convert_custom_weight_func():
|
|
461
|
-
aoi = np.linspace(0, 90, 91)
|
|
462
|
-
|
|
463
|
-
# convert physical to martin_ruiz, using custom weight function
|
|
464
|
-
source_params = {'n': 1.5, 'K': 4.5, 'L': 0.004}
|
|
465
|
-
source_iam = _iam.physical(aoi, **source_params)
|
|
466
|
-
|
|
467
|
-
# define custom weight function that takes in other arguments
|
|
468
|
-
def scaled_weight(aoi):
|
|
469
|
-
return 2. * aoi
|
|
470
|
-
|
|
471
|
-
# expected value calculated from computing residual function over
|
|
472
|
-
# a range of inputs, and taking minimum of these values
|
|
473
|
-
expected_min_res = 16.39724
|
|
474
|
-
|
|
475
|
-
actual_dict = _iam.convert('physical', source_params, 'martin_ruiz',
|
|
476
|
-
weight=scaled_weight)
|
|
477
|
-
actual_min_res = _iam._residual(aoi, source_iam, _iam.martin_ruiz,
|
|
478
|
-
[actual_dict['a_r']], scaled_weight)
|
|
479
|
-
|
|
480
|
-
assert np.isclose(expected_min_res, actual_min_res, atol=1e-06)
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
def test_convert_model_not_implemented():
|
|
484
|
-
with pytest.raises(NotImplementedError, match='model has not been'):
|
|
485
|
-
_iam.convert('ashrae', {'b': 0.1}, 'foo')
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
def test_convert_wrong_model_parameters():
|
|
489
|
-
with pytest.raises(ValueError, match='model was expecting'):
|
|
490
|
-
_iam.convert('ashrae', {'B': 0.1}, 'physical')
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
def test_convert__minimize_fails():
|
|
494
|
-
# to make scipy.optimize.minimize fail, we'll pass in a nonsense
|
|
495
|
-
# weight function that only outputs nans
|
|
496
|
-
def nan_weight(aoi):
|
|
497
|
-
return np.nan
|
|
498
|
-
|
|
499
|
-
with pytest.raises(RuntimeError, match='Optimizer exited unsuccessfully'):
|
|
500
|
-
_iam.convert('ashrae', {'b': 0.1}, 'physical', weight=nan_weight)
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
def test_fit():
|
|
504
|
-
aoi = np.linspace(0, 90, 5)
|
|
505
|
-
perturb = np.array([1.2, 1.01, 0.95, 1, 0.98])
|
|
506
|
-
perturbed_iam = _iam.martin_ruiz(aoi, a_r=0.14) * perturb
|
|
507
|
-
|
|
508
|
-
expected_a_r = 0.14
|
|
509
|
-
|
|
510
|
-
actual_dict = _iam.fit(aoi, perturbed_iam, 'martin_ruiz')
|
|
511
|
-
actual_a_r = actual_dict['a_r']
|
|
512
|
-
|
|
513
|
-
assert np.isclose(expected_a_r, actual_a_r, atol=1e-04)
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
def test_fit_custom_weight_func():
|
|
517
|
-
# define custom weight function that takes in other arguments
|
|
518
|
-
def scaled_weight(aoi):
|
|
519
|
-
return 2. * aoi
|
|
520
|
-
|
|
521
|
-
aoi = np.linspace(0, 90, 5)
|
|
522
|
-
perturb = np.array([1.2, 1.01, 0.95, 1, 0.98])
|
|
523
|
-
perturbed_iam = _iam.martin_ruiz(aoi, a_r=0.14) * perturb
|
|
524
|
-
|
|
525
|
-
expected_a_r = 0.14
|
|
526
|
-
|
|
527
|
-
actual_dict = _iam.fit(aoi, perturbed_iam, 'martin_ruiz',
|
|
528
|
-
weight=scaled_weight)
|
|
529
|
-
actual_a_r = actual_dict['a_r']
|
|
530
|
-
|
|
531
|
-
assert np.isclose(expected_a_r, actual_a_r, atol=1e-04)
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
def test_fit_model_not_implemented():
|
|
535
|
-
with pytest.raises(NotImplementedError, match='model has not been'):
|
|
536
|
-
_iam.fit(np.array([0, 10]), np.array([1, 0.99]), 'foo')
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
def test_fit__minimize_fails():
|
|
540
|
-
# to make scipy.optimize.minimize fail, we'll pass in a nonsense
|
|
541
|
-
# weight function that only outputs nans
|
|
542
|
-
def nan_weight(aoi):
|
|
543
|
-
return np.nan
|
|
544
|
-
|
|
545
|
-
with pytest.raises(RuntimeError, match='Optimizer exited unsuccessfully'):
|
|
546
|
-
_iam.fit(np.array([0, 10]), np.array([1, 0.99]), 'physical',
|
|
547
|
-
weight=nan_weight)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
def test__residual_zero_outside_range():
|
|
551
|
-
# check that _residual annihilates any weights that come from aoi
|
|
552
|
-
# outside of interval [0, 90] (this is important for `iam.fit`, when
|
|
553
|
-
# the `measured_aoi` contains angles outside this range
|
|
554
|
-
residual = _iam._residual(101, _iam.ashrae(101), _iam.martin_ruiz, [0.16])
|
|
555
|
-
assert residual == 0.0
|