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.
- pvlib/__init__.py +1 -0
- pvlib/_deprecation.py +73 -0
- pvlib/atmosphere.py +77 -7
- pvlib/bifacial/infinite_sheds.py +4 -3
- pvlib/bifacial/utils.py +2 -1
- pvlib/clearsky.py +35 -22
- pvlib/iam.py +4 -4
- pvlib/iotools/midc.py +1 -1
- pvlib/iotools/psm3.py +1 -1
- pvlib/iotools/pvgis.py +10 -12
- pvlib/iotools/tmy.py +3 -69
- pvlib/irradiance.py +112 -55
- pvlib/ivtools/sdm.py +75 -52
- pvlib/location.py +73 -33
- pvlib/modelchain.py +18 -35
- pvlib/pvsystem.py +139 -94
- pvlib/snow.py +64 -28
- pvlib/solarposition.py +46 -30
- pvlib/spa.py +4 -2
- pvlib/spectrum/__init__.py +0 -1
- pvlib/spectrum/irradiance.py +2 -64
- pvlib/spectrum/mismatch.py +3 -3
- pvlib/spectrum/spectrl2.py +2 -1
- pvlib/temperature.py +49 -3
- pvlib/tools.py +6 -5
- {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/METADATA +14 -11
- pvlib-0.12.0.dist-info/RECORD +75 -0
- {pvlib-0.11.1.dist-info → pvlib-0.12.0.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/aod550_tcwv_20121101_test.nc +0 -0
- 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.dat +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_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/tmy_45.000_8.000_userhorizon.json +0 -1
- pvlib/data/variables_style_rules.csv +0 -56
- 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 -407
- 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_albedo.py +0 -84
- pvlib/tests/test_atmosphere.py +0 -204
- pvlib/tests/test_clearsky.py +0 -878
- pvlib/tests/test_conftest.py +0 -81
- pvlib/tests/test_iam.py +0 -555
- pvlib/tests/test_inverter.py +0 -213
- pvlib/tests/test_irradiance.py +0 -1441
- 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 -2495
- 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 -933
- pvlib/tests/test_spa.py +0 -425
- 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.1.dist-info/RECORD +0 -192
- {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
- {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
- {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
pvlib/tests/test_temperature.py
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
import pytest
|
|
5
|
-
from .conftest import DATA_DIR, assert_series_equal
|
|
6
|
-
from numpy.testing import assert_allclose
|
|
7
|
-
|
|
8
|
-
from pvlib import temperature, tools
|
|
9
|
-
from pvlib._deprecation import pvlibDeprecationWarning
|
|
10
|
-
|
|
11
|
-
import re
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@pytest.fixture
|
|
15
|
-
def sapm_default():
|
|
16
|
-
return temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
|
|
17
|
-
'open_rack_glass_glass']
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def test_sapm_cell(sapm_default):
|
|
21
|
-
default = temperature.sapm_cell(900, 20, 5, sapm_default['a'],
|
|
22
|
-
sapm_default['b'], sapm_default['deltaT'])
|
|
23
|
-
assert_allclose(default, 43.509, 1e-3)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def test_sapm_module(sapm_default):
|
|
27
|
-
default = temperature.sapm_module(900, 20, 5, sapm_default['a'],
|
|
28
|
-
sapm_default['b'])
|
|
29
|
-
assert_allclose(default, 40.809, 1e-3)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def test_sapm_cell_from_module(sapm_default):
|
|
33
|
-
default = temperature.sapm_cell_from_module(50, 900,
|
|
34
|
-
sapm_default['deltaT'])
|
|
35
|
-
assert_allclose(default, 50 + 900 / 1000 * sapm_default['deltaT'])
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def test_sapm_ndarray(sapm_default):
|
|
39
|
-
temps = np.array([0, 10, 5])
|
|
40
|
-
irrads = np.array([0, 500, 0])
|
|
41
|
-
winds = np.array([10, 5, 0])
|
|
42
|
-
cell_temps = temperature.sapm_cell(irrads, temps, winds, sapm_default['a'],
|
|
43
|
-
sapm_default['b'],
|
|
44
|
-
sapm_default['deltaT'])
|
|
45
|
-
module_temps = temperature.sapm_module(irrads, temps, winds,
|
|
46
|
-
sapm_default['a'],
|
|
47
|
-
sapm_default['b'])
|
|
48
|
-
expected_cell = np.array([0., 23.06066166, 5.])
|
|
49
|
-
expected_module = np.array([0., 21.56066166, 5.])
|
|
50
|
-
assert_allclose(expected_cell, cell_temps, 1e-3)
|
|
51
|
-
assert_allclose(expected_module, module_temps, 1e-3)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_sapm_series(sapm_default):
|
|
55
|
-
times = pd.date_range(start='2015-01-01', end='2015-01-02', freq='12h')
|
|
56
|
-
temps = pd.Series([0, 10, 5], index=times)
|
|
57
|
-
irrads = pd.Series([0, 500, 0], index=times)
|
|
58
|
-
winds = pd.Series([10, 5, 0], index=times)
|
|
59
|
-
cell_temps = temperature.sapm_cell(irrads, temps, winds, sapm_default['a'],
|
|
60
|
-
sapm_default['b'],
|
|
61
|
-
sapm_default['deltaT'])
|
|
62
|
-
module_temps = temperature.sapm_module(irrads, temps, winds,
|
|
63
|
-
sapm_default['a'],
|
|
64
|
-
sapm_default['b'])
|
|
65
|
-
expected_cell = pd.Series([0., 23.06066166, 5.], index=times)
|
|
66
|
-
expected_module = pd.Series([0., 21.56066166, 5.], index=times)
|
|
67
|
-
assert_series_equal(expected_cell, cell_temps)
|
|
68
|
-
assert_series_equal(expected_module, module_temps)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_pvsyst_cell_default():
|
|
72
|
-
result = temperature.pvsyst_cell(900, 20, 5)
|
|
73
|
-
assert_allclose(result, 45.137, 0.001)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def test_pvsyst_cell_kwargs():
|
|
77
|
-
result = temperature.pvsyst_cell(900, 20, wind_speed=5.0, u_c=23.5,
|
|
78
|
-
u_v=6.25, module_efficiency=0.1)
|
|
79
|
-
assert_allclose(result, 33.315, 0.001)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_pvsyst_cell_ndarray():
|
|
83
|
-
temps = np.array([0, 10, 5])
|
|
84
|
-
irrads = np.array([0, 500, 0])
|
|
85
|
-
winds = np.array([10, 5, 0])
|
|
86
|
-
result = temperature.pvsyst_cell(irrads, temps, wind_speed=winds)
|
|
87
|
-
expected = np.array([0.0, 23.965517, 5.0])
|
|
88
|
-
assert_allclose(expected, result)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def test_pvsyst_cell_series():
|
|
92
|
-
times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12h")
|
|
93
|
-
temps = pd.Series([0, 10, 5], index=times)
|
|
94
|
-
irrads = pd.Series([0, 500, 0], index=times)
|
|
95
|
-
winds = pd.Series([10, 5, 0], index=times)
|
|
96
|
-
|
|
97
|
-
result = temperature.pvsyst_cell(irrads, temps, wind_speed=winds)
|
|
98
|
-
expected = pd.Series([0.0, 23.965517, 5.0], index=times)
|
|
99
|
-
assert_series_equal(expected, result)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def test_faiman_default():
|
|
103
|
-
result = temperature.faiman(900, 20, 5)
|
|
104
|
-
assert_allclose(result, 35.203, atol=0.001)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def test_faiman_kwargs():
|
|
108
|
-
result = temperature.faiman(900, 20, wind_speed=5.0, u0=22.0, u1=6.)
|
|
109
|
-
assert_allclose(result, 37.308, atol=0.001)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def test_faiman_list():
|
|
113
|
-
temps = [0, 10, 5]
|
|
114
|
-
irrads = [0, 500, 0]
|
|
115
|
-
winds = [10, 5, 0]
|
|
116
|
-
result = temperature.faiman(irrads, temps, wind_speed=winds)
|
|
117
|
-
expected = np.array([0.0, 18.446, 5.0])
|
|
118
|
-
assert_allclose(expected, result, atol=0.001)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def test_faiman_ndarray():
|
|
122
|
-
temps = np.array([0, 10, 5])
|
|
123
|
-
irrads = np.array([0, 500, 0])
|
|
124
|
-
winds = np.array([10, 5, 0])
|
|
125
|
-
result = temperature.faiman(irrads, temps, wind_speed=winds)
|
|
126
|
-
expected = np.array([0.0, 18.446, 5.0])
|
|
127
|
-
assert_allclose(expected, result, atol=0.001)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def test_faiman_rad_no_ir():
|
|
131
|
-
expected = temperature.faiman(900, 20, 5)
|
|
132
|
-
result = temperature.faiman_rad(900, 20, 5)
|
|
133
|
-
assert_allclose(result, expected)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def test_faiman_rad_ir():
|
|
137
|
-
ir_down = np.array([0, 100, 200, 315.6574, 400])
|
|
138
|
-
expected = [-11.111, -7.591, -4.071, -0.000, 2.969]
|
|
139
|
-
result = temperature.faiman_rad(0, 0, 0, ir_down)
|
|
140
|
-
assert_allclose(result, expected, atol=0.001)
|
|
141
|
-
|
|
142
|
-
sky_view = np.array([1.0, 0.5, 0.0])
|
|
143
|
-
expected = [-4.071, -2.036, 0.000]
|
|
144
|
-
result = temperature.faiman_rad(0, 0, 0, ir_down=200,
|
|
145
|
-
sky_view=sky_view)
|
|
146
|
-
assert_allclose(result, expected, atol=0.001)
|
|
147
|
-
|
|
148
|
-
emissivity = np.array([1.0, 0.88, 0.5, 0.0])
|
|
149
|
-
expected = [-4.626, -4.071, -2.313, 0.000]
|
|
150
|
-
result = temperature.faiman_rad(0, 0, 0, ir_down=200,
|
|
151
|
-
emissivity=emissivity)
|
|
152
|
-
assert_allclose(result, expected, atol=0.001)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def test_ross():
|
|
156
|
-
result = temperature.ross(np.array([1000., 600., 1000.]),
|
|
157
|
-
np.array([20., 40., 60.]),
|
|
158
|
-
np.array([40., 100., 20.]))
|
|
159
|
-
expected = np.array([45., 100., 60.])
|
|
160
|
-
assert_allclose(expected, result)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def test_faiman_series():
|
|
164
|
-
times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12h")
|
|
165
|
-
temps = pd.Series([0, 10, 5], index=times)
|
|
166
|
-
irrads = pd.Series([0, 500, 0], index=times)
|
|
167
|
-
winds = pd.Series([10, 5, 0], index=times)
|
|
168
|
-
|
|
169
|
-
result = temperature.faiman(irrads, temps, wind_speed=winds)
|
|
170
|
-
expected = pd.Series([0.0, 18.446, 5.0], index=times)
|
|
171
|
-
assert_series_equal(expected, result)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def test__temperature_model_params():
|
|
175
|
-
params = temperature._temperature_model_params('sapm',
|
|
176
|
-
'open_rack_glass_glass')
|
|
177
|
-
assert params == temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
|
|
178
|
-
'open_rack_glass_glass']
|
|
179
|
-
with pytest.raises(KeyError):
|
|
180
|
-
temperature._temperature_model_params('sapm', 'not_a_parameter_set')
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def _read_pvwatts_8760(filename):
|
|
184
|
-
df = pd.read_csv(filename,
|
|
185
|
-
skiprows=17, # ignore location/simulation metadata
|
|
186
|
-
skipfooter=1, # ignore "Totals" row
|
|
187
|
-
engine='python')
|
|
188
|
-
df['Year'] = 2019
|
|
189
|
-
df.index = pd.to_datetime(df[['Year', 'Month', 'Day', 'Hour']])
|
|
190
|
-
return df
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
@pytest.mark.parametrize('filename,inoct', [
|
|
194
|
-
('pvwatts_8760_rackmount.csv', 45),
|
|
195
|
-
('pvwatts_8760_roofmount.csv', 49),
|
|
196
|
-
])
|
|
197
|
-
def test_fuentes(filename, inoct):
|
|
198
|
-
# Test against data exported from pvwatts.nrel.gov
|
|
199
|
-
data = _read_pvwatts_8760(DATA_DIR / filename)
|
|
200
|
-
data = data.iloc[:24*7, :] # just use one week
|
|
201
|
-
inputs = {
|
|
202
|
-
'poa_global': data['Plane of Array Irradiance (W/m^2)'],
|
|
203
|
-
'temp_air': data['Ambient Temperature (C)'],
|
|
204
|
-
'wind_speed': data['Wind Speed (m/s)'],
|
|
205
|
-
'noct_installed': inoct,
|
|
206
|
-
}
|
|
207
|
-
expected_tcell = data['Cell Temperature (C)']
|
|
208
|
-
expected_tcell.name = 'tmod'
|
|
209
|
-
actual_tcell = temperature.fuentes(**inputs)
|
|
210
|
-
# the SSC implementation of PVWatts diverges from the Fuentes model at
|
|
211
|
-
# at night by setting Tcell=Tamb when POA=0. This not only means that
|
|
212
|
-
# nighttime values are slightly different (Fuentes models cooling to sky
|
|
213
|
-
# at night), but because of the thermal inertia, there is a transient
|
|
214
|
-
# error after dawn as well. Test each case separately:
|
|
215
|
-
is_night = inputs['poa_global'] == 0
|
|
216
|
-
is_dawn = is_night.shift(1) & ~is_night
|
|
217
|
-
is_daytime = (inputs['poa_global'] > 0) & ~is_dawn
|
|
218
|
-
# the accuracy is probably higher than 3 digits here, but the PVWatts
|
|
219
|
-
# export data has low precision so can only test up to 3 digits
|
|
220
|
-
assert_series_equal(expected_tcell[is_daytime].round(3),
|
|
221
|
-
actual_tcell[is_daytime].round(3))
|
|
222
|
-
# use lower precision for dawn times to accommodate the dawn transient
|
|
223
|
-
error = actual_tcell[is_dawn] - expected_tcell[is_dawn]
|
|
224
|
-
assert (error.abs() < 0.1).all()
|
|
225
|
-
# sanity check on night values -- Fuentes not much lower than PVWatts
|
|
226
|
-
night_difference = expected_tcell[is_night] - actual_tcell[is_night]
|
|
227
|
-
assert night_difference.max() < 6
|
|
228
|
-
assert night_difference.min() > 0
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@pytest.mark.parametrize('tz', [None, 'Etc/GMT+5'])
|
|
232
|
-
def test_fuentes_timezone(tz):
|
|
233
|
-
index = pd.date_range('2019-01-01', freq='h', periods=3, tz=tz)
|
|
234
|
-
|
|
235
|
-
df = pd.DataFrame({'poa_global': 1000, 'temp_air': 20, 'wind_speed': 1},
|
|
236
|
-
index)
|
|
237
|
-
|
|
238
|
-
out = temperature.fuentes(df['poa_global'], df['temp_air'],
|
|
239
|
-
df['wind_speed'], noct_installed=45)
|
|
240
|
-
|
|
241
|
-
assert_series_equal(out, pd.Series([47.85, 50.85, 50.85], index=index,
|
|
242
|
-
name='tmod'))
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
def test_noct_sam():
|
|
246
|
-
poa_global, temp_air, wind_speed, noct, module_efficiency = (
|
|
247
|
-
1000., 25., 1., 45., 0.2)
|
|
248
|
-
expected = 55.230790492
|
|
249
|
-
result = temperature.noct_sam(poa_global, temp_air, wind_speed, noct,
|
|
250
|
-
module_efficiency)
|
|
251
|
-
assert_allclose(result, expected)
|
|
252
|
-
# test with different types
|
|
253
|
-
result = temperature.noct_sam(np.array(poa_global), np.array(temp_air),
|
|
254
|
-
np.array(wind_speed), np.array(noct),
|
|
255
|
-
np.array(module_efficiency))
|
|
256
|
-
assert_allclose(result, expected)
|
|
257
|
-
dr = pd.date_range(start='2020-01-01 12:00:00', end='2020-01-01 13:00:00',
|
|
258
|
-
freq='1h')
|
|
259
|
-
result = temperature.noct_sam(pd.Series(index=dr, data=poa_global),
|
|
260
|
-
pd.Series(index=dr, data=temp_air),
|
|
261
|
-
pd.Series(index=dr, data=wind_speed),
|
|
262
|
-
pd.Series(index=dr, data=noct),
|
|
263
|
-
module_efficiency)
|
|
264
|
-
assert_series_equal(result, pd.Series(index=dr, data=expected))
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def test_noct_sam_against_sam():
|
|
268
|
-
# test is constructed to reproduce output from SAM v2020.11.29.
|
|
269
|
-
# SAM calculation is the default Detailed PV System model (CEC diode model,
|
|
270
|
-
# NOCT cell temperature model), with the only change being the soiling
|
|
271
|
-
# loss is set to 0. Weather input is TMY3 for Phoenix AZ.
|
|
272
|
-
# Values are taken from the Jan 1 12:00:00 timestamp.
|
|
273
|
-
poa_total, temp_air, wind_speed, noct, module_efficiency = (
|
|
274
|
-
860.673, 25, 3, 46.4, 0.20551)
|
|
275
|
-
poa_total_after_refl = 851.458 # from SAM output
|
|
276
|
-
# compute effective irradiance
|
|
277
|
-
# spectral loss coefficients fixed in lib_cec6par.cpp
|
|
278
|
-
a = np.flipud([0.918093, 0.086257, -0.024459, 0.002816, -0.000126])
|
|
279
|
-
# reproduce SAM air mass calculation
|
|
280
|
-
zen = 56.4284
|
|
281
|
-
elev = 358
|
|
282
|
-
air_mass = 1. / (tools.cosd(zen) + 0.5057 * (96.080 - zen)**-1.634)
|
|
283
|
-
air_mass *= np.exp(-0.0001184 * elev)
|
|
284
|
-
f1 = np.polyval(a, air_mass)
|
|
285
|
-
effective_irradiance = f1 * poa_total_after_refl
|
|
286
|
-
transmittance_absorptance = 0.9
|
|
287
|
-
array_height = 1
|
|
288
|
-
mount_standoff = 4.0
|
|
289
|
-
result = temperature.noct_sam(poa_total, temp_air, wind_speed, noct,
|
|
290
|
-
module_efficiency, effective_irradiance,
|
|
291
|
-
transmittance_absorptance, array_height,
|
|
292
|
-
mount_standoff)
|
|
293
|
-
expected = 43.0655
|
|
294
|
-
# rtol from limited SAM output precision
|
|
295
|
-
assert_allclose(result, expected, rtol=1e-5)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
def test_noct_sam_options():
|
|
299
|
-
poa_global, temp_air, wind_speed, noct, module_efficiency = (
|
|
300
|
-
1000., 25., 1., 45., 0.2)
|
|
301
|
-
effective_irradiance = 1100.
|
|
302
|
-
transmittance_absorptance = 0.8
|
|
303
|
-
array_height = 2
|
|
304
|
-
mount_standoff = 2.0
|
|
305
|
-
result = temperature.noct_sam(poa_global, temp_air, wind_speed, noct,
|
|
306
|
-
module_efficiency, effective_irradiance,
|
|
307
|
-
transmittance_absorptance, array_height,
|
|
308
|
-
mount_standoff)
|
|
309
|
-
expected = 60.477703576
|
|
310
|
-
assert_allclose(result, expected)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
def test_noct_sam_errors():
|
|
314
|
-
with pytest.raises(ValueError):
|
|
315
|
-
temperature.noct_sam(1000., 25., 1., 34., 0.2, array_height=3)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
def test_prilliman():
|
|
319
|
-
# test against values calculated using pvl_MAmodel_2, see pvlib #1081
|
|
320
|
-
times = pd.date_range('2019-01-01', freq='5min', periods=8)
|
|
321
|
-
cell_temperature = pd.Series([0, 1, 3, 6, 10, 15, 21, 27], index=times)
|
|
322
|
-
wind_speed = pd.Series([0, 1, 2, 3, 2, 1, 2, 3])
|
|
323
|
-
|
|
324
|
-
# default coeffs
|
|
325
|
-
expected = pd.Series([0, 0, 0.7047457, 2.21176412, 4.45584299, 7.63635512,
|
|
326
|
-
12.26808265, 18.00305776], index=times)
|
|
327
|
-
actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=10)
|
|
328
|
-
assert_series_equal(expected, actual)
|
|
329
|
-
|
|
330
|
-
# custom coeffs
|
|
331
|
-
coefficients = [0.0046, 4.5537e-4, -2.2586e-4, -1.5661e-5]
|
|
332
|
-
expected = pd.Series([0, 0, 0.70716941, 2.2199537, 4.47537694, 7.6676931,
|
|
333
|
-
12.30423167, 18.04215198], index=times)
|
|
334
|
-
actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=10,
|
|
335
|
-
coefficients=coefficients)
|
|
336
|
-
assert_series_equal(expected, actual)
|
|
337
|
-
|
|
338
|
-
# even very short inputs < 20 minutes total still work
|
|
339
|
-
times = pd.date_range('2019-01-01', freq='1min', periods=8)
|
|
340
|
-
cell_temperature = pd.Series([0, 1, 3, 6, 10, 15, 21, 27], index=times)
|
|
341
|
-
wind_speed = pd.Series([0, 1, 2, 3, 2, 1, 2, 3])
|
|
342
|
-
expected = pd.Series([0, 0, 0.53557976, 1.49270094, 2.85940173,
|
|
343
|
-
4.63914366, 7.09641845, 10.24899272], index=times)
|
|
344
|
-
actual = temperature.prilliman(cell_temperature, wind_speed, unit_mass=12)
|
|
345
|
-
assert_series_equal(expected, actual)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
def test_prilliman_coarse():
|
|
349
|
-
# if the input series time step is >= 20 min, input is returned unchanged,
|
|
350
|
-
# and a warning is emitted
|
|
351
|
-
times = pd.date_range('2019-01-01', freq='30min', periods=3)
|
|
352
|
-
cell_temperature = pd.Series([0, 1, 3], index=times)
|
|
353
|
-
wind_speed = pd.Series([0, 1, 2])
|
|
354
|
-
msg = re.escape("temperature.prilliman only applies smoothing when the "
|
|
355
|
-
"sampling interval is shorter than 20 minutes (input "
|
|
356
|
-
"sampling interval: 30.0 minutes); returning "
|
|
357
|
-
"input temperature series unchanged")
|
|
358
|
-
with pytest.warns(UserWarning, match=msg):
|
|
359
|
-
actual = temperature.prilliman(cell_temperature, wind_speed)
|
|
360
|
-
assert_series_equal(cell_temperature, actual)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
def test_prilliman_nans():
|
|
364
|
-
# nans in inputs are handled appropriately; nans in input tcell
|
|
365
|
-
# are ignored but nans in wind speed cause nan in output
|
|
366
|
-
times = pd.date_range('2019-01-01', freq='1min', periods=8)
|
|
367
|
-
cell_temperature = pd.Series([0, 1, 3, 6, 10, np.nan, 21, 27], index=times)
|
|
368
|
-
wind_speed = pd.Series([0, 1, 2, 3, 2, 1, np.nan, 3])
|
|
369
|
-
actual = temperature.prilliman(cell_temperature, wind_speed)
|
|
370
|
-
expected = pd.Series([True, True, True, True, True, True, False, True],
|
|
371
|
-
index=times)
|
|
372
|
-
assert_series_equal(actual.notnull(), expected)
|
|
373
|
-
|
|
374
|
-
# check that nan temperatures do not mess up the weighted average;
|
|
375
|
-
# the original implementation did not set weight=0 for nan values,
|
|
376
|
-
# so the numerator of the weighted average ignored nans but the
|
|
377
|
-
# denominator (total weight) still included the weight for the nan.
|
|
378
|
-
cell_temperature = pd.Series([1, 1, 1, 1, 1, np.nan, 1, 1], index=times)
|
|
379
|
-
wind_speed = pd.Series(1, index=times)
|
|
380
|
-
actual = temperature.prilliman(cell_temperature, wind_speed)
|
|
381
|
-
# original implementation would return some values < 1 here
|
|
382
|
-
expected = pd.Series(1., index=times)
|
|
383
|
-
assert_series_equal(actual, expected)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
def test_glm_conversions():
|
|
387
|
-
# it is easiest and sufficient to test conversion from & to the same model
|
|
388
|
-
glm = temperature.GenericLinearModel(module_efficiency=0.1,
|
|
389
|
-
absorptance=0.9)
|
|
390
|
-
|
|
391
|
-
inp = {'u0': 25.0, 'u1': 6.84}
|
|
392
|
-
glm.use_faiman(**inp)
|
|
393
|
-
out = glm.to_faiman()
|
|
394
|
-
for k, v in inp.items():
|
|
395
|
-
assert np.isclose(out[k], v)
|
|
396
|
-
|
|
397
|
-
inp = {'u_c': 25, 'u_v': 4}
|
|
398
|
-
glm.use_pvsyst(**inp)
|
|
399
|
-
out = glm.to_pvsyst()
|
|
400
|
-
for k, v in inp.items():
|
|
401
|
-
assert np.isclose(out[k], v)
|
|
402
|
-
|
|
403
|
-
# test with optional parameters
|
|
404
|
-
inp = {'u_c': 25, 'u_v': 4,
|
|
405
|
-
'module_efficiency': 0.15,
|
|
406
|
-
'alpha_absorption': 0.95}
|
|
407
|
-
glm.use_pvsyst(**inp)
|
|
408
|
-
out = glm.to_pvsyst()
|
|
409
|
-
for k, v in inp.items():
|
|
410
|
-
assert np.isclose(out[k], v)
|
|
411
|
-
|
|
412
|
-
inp = {'noct': 47}
|
|
413
|
-
glm.use_noct_sam(**inp)
|
|
414
|
-
out = glm.to_noct_sam()
|
|
415
|
-
for k, v in inp.items():
|
|
416
|
-
assert np.isclose(out[k], v)
|
|
417
|
-
|
|
418
|
-
# test with optional parameters
|
|
419
|
-
inp = {'noct': 47,
|
|
420
|
-
'module_efficiency': 0.15,
|
|
421
|
-
'transmittance_absorptance': 0.95}
|
|
422
|
-
glm.use_noct_sam(**inp)
|
|
423
|
-
out = glm.to_noct_sam()
|
|
424
|
-
for k, v in inp.items():
|
|
425
|
-
assert np.isclose(out[k], v)
|
|
426
|
-
|
|
427
|
-
inp = {'a': -3.5, 'b': -0.1}
|
|
428
|
-
glm.use_sapm(**inp)
|
|
429
|
-
out = glm.to_sapm()
|
|
430
|
-
for k, v in inp.items():
|
|
431
|
-
assert np.isclose(out[k], v)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
def test_glm_simulations():
|
|
435
|
-
|
|
436
|
-
glm = temperature.GenericLinearModel(module_efficiency=0.1,
|
|
437
|
-
absorptance=0.9)
|
|
438
|
-
wind = np.array([1.4, 1/.51, 5.4])
|
|
439
|
-
weather = (800, 20, wind)
|
|
440
|
-
|
|
441
|
-
inp = {'u0': 20.0, 'u1': 5.0}
|
|
442
|
-
glm.use_faiman(**inp)
|
|
443
|
-
out = glm(*weather)
|
|
444
|
-
expected = temperature.faiman(*weather, **inp)
|
|
445
|
-
assert np.allclose(out, expected)
|
|
446
|
-
|
|
447
|
-
out = glm(*weather)
|
|
448
|
-
assert np.allclose(out, expected)
|
|
449
|
-
|
|
450
|
-
out = glm(*weather, module_efficiency=0.1)
|
|
451
|
-
assert np.allclose(out, expected)
|
|
452
|
-
|
|
453
|
-
inp = glm.get_generic_linear()
|
|
454
|
-
out = temperature.generic_linear(*weather, **inp)
|
|
455
|
-
assert np.allclose(out, expected)
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
def test_glm_repr():
|
|
459
|
-
|
|
460
|
-
glm = temperature.GenericLinearModel(module_efficiency=0.1,
|
|
461
|
-
absorptance=0.9)
|
|
462
|
-
inp = {'u0': 20.0, 'u1': 5.0}
|
|
463
|
-
glm.use_faiman(**inp)
|
|
464
|
-
expected = ("GenericLinearModel: {"
|
|
465
|
-
"'u_const': 16.0, "
|
|
466
|
-
"'du_wind': 4.0, "
|
|
467
|
-
"'eta': 0.1, "
|
|
468
|
-
"'alpha': 0.9}")
|
|
469
|
-
|
|
470
|
-
assert glm.__repr__() == expected
|
pvlib/tests/test_tools.py
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
from pvlib import tools
|
|
4
|
-
import numpy as np
|
|
5
|
-
import pandas as pd
|
|
6
|
-
from numpy.testing import assert_allclose
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@pytest.mark.parametrize('keys, input_dict, expected', [
|
|
10
|
-
(['a', 'b'], {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2}),
|
|
11
|
-
(['a', 'b', 'd'], {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2}),
|
|
12
|
-
(['a'], {}, {}),
|
|
13
|
-
(['a'], {'b': 2}, {})
|
|
14
|
-
])
|
|
15
|
-
def test_build_kwargs(keys, input_dict, expected):
|
|
16
|
-
kwargs = tools._build_kwargs(keys, input_dict)
|
|
17
|
-
assert kwargs == expected
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _obj_test_golden_sect(params, loc):
|
|
21
|
-
return params[loc] * (1. - params['c'] * params[loc]**params['n'])
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@pytest.mark.parametrize('params, lb, ub, expected, func', [
|
|
25
|
-
({'c': 1., 'n': 1.}, 0., 1., 0.5, _obj_test_golden_sect),
|
|
26
|
-
({'c': 1e6, 'n': 6.}, 0., 1., 0.07230200263994839, _obj_test_golden_sect),
|
|
27
|
-
({'c': 0.2, 'n': 0.3}, 0., 100., 89.14332727531685, _obj_test_golden_sect)
|
|
28
|
-
])
|
|
29
|
-
def test__golden_sect_DataFrame(params, lb, ub, expected, func):
|
|
30
|
-
v, x = tools._golden_sect_DataFrame(params, lb, ub, func)
|
|
31
|
-
assert np.isclose(x, expected, atol=1e-8)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def test__golden_sect_DataFrame_atol():
|
|
35
|
-
params = {'c': 0.2, 'n': 0.3}
|
|
36
|
-
expected = 89.14332727531685
|
|
37
|
-
v, x = tools._golden_sect_DataFrame(
|
|
38
|
-
params, 0., 100., _obj_test_golden_sect, atol=1e-12)
|
|
39
|
-
assert np.isclose(x, expected, atol=1e-12)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test__golden_sect_DataFrame_vector():
|
|
43
|
-
params = {'c': np.array([1., 2.]), 'n': np.array([1., 1.])}
|
|
44
|
-
lower = np.array([0., 0.001])
|
|
45
|
-
upper = np.array([1.1, 1.2])
|
|
46
|
-
expected = np.array([0.5, 0.25])
|
|
47
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
48
|
-
_obj_test_golden_sect)
|
|
49
|
-
assert np.allclose(x, expected, atol=1e-8)
|
|
50
|
-
# some upper and lower bounds equal
|
|
51
|
-
params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
|
|
52
|
-
lower = np.array([0., 0.001, 1.])
|
|
53
|
-
upper = np.array([1., 1.2, 1.])
|
|
54
|
-
expected = np.array([0.5, 0.25, 1.0]) # x values for maxima
|
|
55
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
56
|
-
_obj_test_golden_sect)
|
|
57
|
-
assert np.allclose(x, expected, atol=1e-8)
|
|
58
|
-
# all upper and lower bounds equal, arrays of length 1
|
|
59
|
-
params = {'c': np.array([1.]), 'n': np.array([1.])}
|
|
60
|
-
lower = np.array([1.])
|
|
61
|
-
upper = np.array([1.])
|
|
62
|
-
expected = np.array([1.]) # x values for maxima
|
|
63
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
64
|
-
_obj_test_golden_sect)
|
|
65
|
-
assert np.allclose(x, expected, atol=1e-8)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def test__golden_sect_DataFrame_nans():
|
|
69
|
-
# nan in bounds
|
|
70
|
-
params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
|
|
71
|
-
lower = np.array([0., 0.001, np.nan])
|
|
72
|
-
upper = np.array([1.1, 1.2, 1.])
|
|
73
|
-
expected = np.array([0.5, 0.25, np.nan])
|
|
74
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
75
|
-
_obj_test_golden_sect)
|
|
76
|
-
assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
|
|
77
|
-
# nan in function values
|
|
78
|
-
params = {'c': np.array([1., 2., np.nan]), 'n': np.array([1., 1., 1.])}
|
|
79
|
-
lower = np.array([0., 0.001, 0.])
|
|
80
|
-
upper = np.array([1.1, 1.2, 1.])
|
|
81
|
-
expected = np.array([0.5, 0.25, np.nan])
|
|
82
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
83
|
-
_obj_test_golden_sect)
|
|
84
|
-
assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
|
|
85
|
-
# all nan in bounds
|
|
86
|
-
params = {'c': np.array([1., 2., 1.]), 'n': np.array([1., 1., 1.])}
|
|
87
|
-
lower = np.array([np.nan, np.nan, np.nan])
|
|
88
|
-
upper = np.array([1.1, 1.2, 1.])
|
|
89
|
-
expected = np.array([np.nan, np.nan, np.nan])
|
|
90
|
-
v, x = tools._golden_sect_DataFrame(params, lower, upper,
|
|
91
|
-
_obj_test_golden_sect)
|
|
92
|
-
assert np.allclose(x, expected, atol=1e-8, equal_nan=True)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def test_degrees_to_index_1():
|
|
96
|
-
"""Test that _degrees_to_index raises an error when something other than
|
|
97
|
-
'latitude' or 'longitude' is passed."""
|
|
98
|
-
with pytest.raises(IndexError): # invalid value for coordinate argument
|
|
99
|
-
tools._degrees_to_index(degrees=22.0, coordinate='width')
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@pytest.mark.parametrize('args, args_idx', [
|
|
103
|
-
# no pandas.Series or pandas.DataFrame args
|
|
104
|
-
((1,), None),
|
|
105
|
-
(([1],), None),
|
|
106
|
-
((np.array(1),), None),
|
|
107
|
-
((np.array([1]),), None),
|
|
108
|
-
# has pandas.Series or pandas.DataFrame args
|
|
109
|
-
((pd.DataFrame([1], index=[1]),), 0),
|
|
110
|
-
((pd.Series([1], index=[1]),), 0),
|
|
111
|
-
((1, pd.Series([1], index=[1]),), 1),
|
|
112
|
-
((1, pd.DataFrame([1], index=[1]),), 1),
|
|
113
|
-
# first pandas.Series or pandas.DataFrame is used
|
|
114
|
-
((1, pd.Series([1], index=[1]), pd.DataFrame([2], index=[2]),), 1),
|
|
115
|
-
((1, pd.DataFrame([1], index=[1]), pd.Series([2], index=[2]),), 1),
|
|
116
|
-
])
|
|
117
|
-
def test_get_pandas_index(args, args_idx):
|
|
118
|
-
index = tools.get_pandas_index(*args)
|
|
119
|
-
|
|
120
|
-
if args_idx is None:
|
|
121
|
-
assert index is None
|
|
122
|
-
else:
|
|
123
|
-
pd.testing.assert_index_equal(args[args_idx].index, index)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@pytest.mark.parametrize('data_in,expected', [
|
|
127
|
-
(np.array([1, 2, 3, 4, 5]),
|
|
128
|
-
np.array([0.2, 0.4, 0.6, 0.8, 1])),
|
|
129
|
-
(np.array([[0, 1, 2], [0, 3, 6]]),
|
|
130
|
-
np.array([[0, 0.5, 1], [0, 0.5, 1]])),
|
|
131
|
-
(pd.Series([1, 2, 3, 4, 5]),
|
|
132
|
-
pd.Series([0.2, 0.4, 0.6, 0.8, 1])),
|
|
133
|
-
(pd.DataFrame({"a": [0, 1, 2], "b": [0, 2, 8]}),
|
|
134
|
-
pd.DataFrame({"a": [0, 0.5, 1], "b": [0, 0.25, 1]})),
|
|
135
|
-
# test with NaN and all zeroes
|
|
136
|
-
(pd.DataFrame({"a": [0, np.nan, 1], "b": [0, 0, 0]}),
|
|
137
|
-
pd.DataFrame({"a": [0, np.nan, 1], "b": [np.nan]*3})),
|
|
138
|
-
# test with negative values
|
|
139
|
-
(np.array([1, 2, -3, 4, -5]),
|
|
140
|
-
np.array([0.2, 0.4, -0.6, 0.8, -1])),
|
|
141
|
-
(pd.Series([-2, np.nan, 1]),
|
|
142
|
-
pd.Series([-1, np.nan, 0.5])),
|
|
143
|
-
])
|
|
144
|
-
def test_normalize_max2one(data_in, expected):
|
|
145
|
-
result = tools.normalize_max2one(data_in)
|
|
146
|
-
assert_allclose(result, expected)
|