pvlib 0.11.1__py3-none-any.whl → 0.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/_deprecation.py +73 -0
  3. pvlib/atmosphere.py +77 -7
  4. pvlib/bifacial/infinite_sheds.py +4 -3
  5. pvlib/bifacial/utils.py +2 -1
  6. pvlib/clearsky.py +35 -22
  7. pvlib/iam.py +4 -4
  8. pvlib/iotools/midc.py +1 -1
  9. pvlib/iotools/psm3.py +1 -1
  10. pvlib/iotools/pvgis.py +10 -12
  11. pvlib/iotools/tmy.py +3 -69
  12. pvlib/irradiance.py +112 -55
  13. pvlib/ivtools/sdm.py +75 -52
  14. pvlib/location.py +73 -33
  15. pvlib/modelchain.py +18 -35
  16. pvlib/pvsystem.py +139 -94
  17. pvlib/snow.py +64 -28
  18. pvlib/solarposition.py +46 -30
  19. pvlib/spa.py +4 -2
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/spectrum/spectrl2.py +2 -1
  24. pvlib/temperature.py +49 -3
  25. pvlib/tools.py +6 -5
  26. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/METADATA +14 -11
  27. pvlib-0.12.0.dist-info/RECORD +75 -0
  28. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/WHEEL +1 -1
  29. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  30. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  31. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  32. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  33. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  34. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  35. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  36. pvlib/data/CRN_with_problems.txt +0 -3
  37. pvlib/data/ET-M772BH550GL.PAN +0 -75
  38. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  39. pvlib/data/PVsyst_demo.csv +0 -10757
  40. pvlib/data/PVsyst_demo_model.csv +0 -3588
  41. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  42. pvlib/data/abq19056.dat +0 -6
  43. pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
  44. pvlib/data/bishop88_numerical_precision.csv +0 -101
  45. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  46. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  47. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  48. pvlib/data/cams_mcclear_monthly.csv +0 -42
  49. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  50. pvlib/data/cams_radiation_monthly.csv +0 -47
  51. pvlib/data/detect_clearsky_data.csv +0 -35
  52. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  53. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  54. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  55. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  56. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  57. pvlib/data/ivtools_numdiff.csv +0 -52
  58. pvlib/data/midc_20181014.txt +0 -1441
  59. pvlib/data/midc_raw_20181018.txt +0 -1441
  60. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  61. pvlib/data/msn19056.dat +0 -6
  62. pvlib/data/precise_iv_curves1.json +0 -10251
  63. pvlib/data/precise_iv_curves2.json +0 -10251
  64. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  65. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  66. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  67. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  68. pvlib/data/pvgis_tmy_meta.json +0 -32
  69. pvlib/data/pvgis_tmy_test.dat +0 -8761
  70. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  71. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  72. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  73. pvlib/data/spectrl2_example_spectra.csv +0 -123
  74. pvlib/data/surfrad-slv16001.dat +0 -1442
  75. pvlib/data/test_psm3_2017.csv +0 -17521
  76. pvlib/data/test_psm3_2019_5min.csv +0 -289
  77. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  78. pvlib/data/test_read_psm3.csv +0 -17523
  79. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  80. pvlib/data/tmy_45.000_8.000_2005_2020.csv +0 -8789
  81. pvlib/data/tmy_45.000_8.000_2005_2020.epw +0 -8768
  82. pvlib/data/tmy_45.000_8.000_2005_2020.json +0 -1
  83. pvlib/data/tmy_45.000_8.000_2005_2020.txt +0 -8761
  84. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  85. pvlib/data/variables_style_rules.csv +0 -56
  86. pvlib/spa_c_files/README.md +0 -81
  87. pvlib/spa_c_files/cspa_py.pxd +0 -43
  88. pvlib/spa_c_files/spa_py.pyx +0 -30
  89. pvlib/tests/__init__.py +0 -0
  90. pvlib/tests/bifacial/__init__.py +0 -0
  91. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  92. pvlib/tests/bifacial/test_losses_models.py +0 -54
  93. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  94. pvlib/tests/bifacial/test_utils.py +0 -192
  95. pvlib/tests/conftest.py +0 -476
  96. pvlib/tests/iotools/__init__.py +0 -0
  97. pvlib/tests/iotools/test_acis.py +0 -213
  98. pvlib/tests/iotools/test_bsrn.py +0 -131
  99. pvlib/tests/iotools/test_crn.py +0 -95
  100. pvlib/tests/iotools/test_epw.py +0 -23
  101. pvlib/tests/iotools/test_midc.py +0 -89
  102. pvlib/tests/iotools/test_panond.py +0 -32
  103. pvlib/tests/iotools/test_psm3.py +0 -198
  104. pvlib/tests/iotools/test_pvgis.py +0 -644
  105. pvlib/tests/iotools/test_sodapro.py +0 -298
  106. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  107. pvlib/tests/iotools/test_solargis.py +0 -68
  108. pvlib/tests/iotools/test_solcast.py +0 -324
  109. pvlib/tests/iotools/test_solrad.py +0 -152
  110. pvlib/tests/iotools/test_srml.py +0 -124
  111. pvlib/tests/iotools/test_surfrad.py +0 -75
  112. pvlib/tests/iotools/test_tmy.py +0 -133
  113. pvlib/tests/ivtools/__init__.py +0 -0
  114. pvlib/tests/ivtools/test_sde.py +0 -230
  115. pvlib/tests/ivtools/test_sdm.py +0 -407
  116. pvlib/tests/ivtools/test_utils.py +0 -173
  117. pvlib/tests/spectrum/__init__.py +0 -0
  118. pvlib/tests/spectrum/conftest.py +0 -40
  119. pvlib/tests/spectrum/test_irradiance.py +0 -138
  120. pvlib/tests/spectrum/test_mismatch.py +0 -304
  121. pvlib/tests/spectrum/test_response.py +0 -124
  122. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  123. pvlib/tests/test_albedo.py +0 -84
  124. pvlib/tests/test_atmosphere.py +0 -204
  125. pvlib/tests/test_clearsky.py +0 -878
  126. pvlib/tests/test_conftest.py +0 -81
  127. pvlib/tests/test_iam.py +0 -555
  128. pvlib/tests/test_inverter.py +0 -213
  129. pvlib/tests/test_irradiance.py +0 -1441
  130. pvlib/tests/test_location.py +0 -356
  131. pvlib/tests/test_modelchain.py +0 -2020
  132. pvlib/tests/test_numerical_precision.py +0 -124
  133. pvlib/tests/test_pvarray.py +0 -71
  134. pvlib/tests/test_pvsystem.py +0 -2495
  135. pvlib/tests/test_scaling.py +0 -207
  136. pvlib/tests/test_shading.py +0 -391
  137. pvlib/tests/test_singlediode.py +0 -608
  138. pvlib/tests/test_snow.py +0 -212
  139. pvlib/tests/test_soiling.py +0 -230
  140. pvlib/tests/test_solarposition.py +0 -933
  141. pvlib/tests/test_spa.py +0 -425
  142. pvlib/tests/test_temperature.py +0 -470
  143. pvlib/tests/test_tools.py +0 -146
  144. pvlib/tests/test_tracking.py +0 -474
  145. pvlib/tests/test_transformer.py +0 -60
  146. pvlib-0.11.1.dist-info/RECORD +0 -192
  147. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
  148. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
  149. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
@@ -1,81 +0,0 @@
1
- import pytest
2
- import pandas
3
-
4
- 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
-
49
-
50
- @pytest.mark.parametrize('function_name', ['assert_index_equal',
51
- 'assert_series_equal',
52
- 'assert_frame_equal'])
53
- @pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0'])
54
- @pytest.mark.parametrize('check_less_precise', [True, False])
55
- def test__check_pandas_assert_kwargs(mocker, function_name, pd_version,
56
- check_less_precise):
57
- # test that conftest._check_pandas_assert_kwargs returns appropriate
58
- # kwargs for the assert_x_equal functions
59
-
60
- # NOTE: be careful about mixing mocker.patch and pytest.MonkeyPatch!
61
- # they do not coordinate their cleanups, so it is safest to only
62
- # use one or the other. GH #1447
63
-
64
- # patch the pandas assert; not interested in actually calling them,
65
- # plus we want to spy on how they get called.
66
- spy = mocker.patch('pandas.testing.' + function_name)
67
- # patch pd.__version__ to exercise the two branches in
68
- # conftest._check_pandas_assert_kwargs
69
- mocker.patch('pandas.__version__', new=pd_version)
70
-
71
- # finally, run the function and check what args got passed to pandas:
72
- assert_function = getattr(conftest, function_name)
73
- args = [None, None]
74
- assert_function(*args, check_less_precise=check_less_precise)
75
- if pd_version == '1.1.0':
76
- tol = 1e-3 if check_less_precise else 1e-5
77
- expected_kwargs = {'atol': tol, 'rtol': tol}
78
- else:
79
- expected_kwargs = {'check_less_precise': check_less_precise}
80
-
81
- 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