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.
Files changed (147) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/atmosphere.py +40 -40
  3. pvlib/bifacial/infinite_sheds.py +4 -3
  4. pvlib/bifacial/utils.py +2 -1
  5. pvlib/iotools/__init__.py +6 -0
  6. pvlib/iotools/psm3.py +1 -1
  7. pvlib/iotools/psm4.py +819 -0
  8. pvlib/iotools/pvgis.py +10 -2
  9. pvlib/iotools/tmy.py +3 -69
  10. pvlib/irradiance.py +38 -15
  11. pvlib/ivtools/sdm/__init__.py +20 -0
  12. pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
  13. pvlib/ivtools/sdm/cec.py +93 -0
  14. pvlib/ivtools/sdm/desoto.py +401 -0
  15. pvlib/ivtools/sdm/pvsyst.py +630 -0
  16. pvlib/location.py +73 -33
  17. pvlib/modelchain.py +19 -36
  18. pvlib/pvsystem.py +114 -65
  19. pvlib/snow.py +64 -28
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/tools.py +6 -5
  24. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/METADATA +6 -5
  25. pvlib-0.12.1a1.dist-info/RECORD +80 -0
  26. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/WHEEL +1 -1
  27. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  28. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  29. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  30. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  31. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  32. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  33. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  34. pvlib/data/CRN_with_problems.txt +0 -3
  35. pvlib/data/ET-M772BH550GL.PAN +0 -75
  36. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  37. pvlib/data/PVsyst_demo.csv +0 -10757
  38. pvlib/data/PVsyst_demo_model.csv +0 -3588
  39. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  40. pvlib/data/abq19056.dat +0 -6
  41. pvlib/data/bishop88_numerical_precision.csv +0 -101
  42. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  43. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  44. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  45. pvlib/data/cams_mcclear_monthly.csv +0 -42
  46. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  47. pvlib/data/cams_radiation_monthly.csv +0 -47
  48. pvlib/data/detect_clearsky_data.csv +0 -35
  49. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  50. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  51. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  52. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  53. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  54. pvlib/data/ivtools_numdiff.csv +0 -52
  55. pvlib/data/midc_20181014.txt +0 -1441
  56. pvlib/data/midc_raw_20181018.txt +0 -1441
  57. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  58. pvlib/data/msn19056.dat +0 -6
  59. pvlib/data/precise_iv_curves1.json +0 -10251
  60. pvlib/data/precise_iv_curves2.json +0 -10251
  61. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  62. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  63. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  64. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  65. pvlib/data/pvgis_tmy_meta.json +0 -32
  66. pvlib/data/pvgis_tmy_test.csv +0 -8761
  67. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  68. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  69. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  70. pvlib/data/spectrl2_example_spectra.csv +0 -123
  71. pvlib/data/surfrad-slv16001.dat +0 -1442
  72. pvlib/data/test_psm3_2017.csv +0 -17521
  73. pvlib/data/test_psm3_2019_5min.csv +0 -289
  74. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  75. pvlib/data/test_read_psm3.csv +0 -17523
  76. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  77. pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
  78. pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
  79. pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
  80. pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
  81. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  82. pvlib/ivtools/sdm.py +0 -1379
  83. pvlib/spa_c_files/README.md +0 -81
  84. pvlib/spa_c_files/cspa_py.pxd +0 -43
  85. pvlib/spa_c_files/spa_py.pyx +0 -30
  86. pvlib/tests/__init__.py +0 -0
  87. pvlib/tests/bifacial/__init__.py +0 -0
  88. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  89. pvlib/tests/bifacial/test_losses_models.py +0 -54
  90. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  91. pvlib/tests/bifacial/test_utils.py +0 -192
  92. pvlib/tests/conftest.py +0 -476
  93. pvlib/tests/iotools/__init__.py +0 -0
  94. pvlib/tests/iotools/test_acis.py +0 -213
  95. pvlib/tests/iotools/test_bsrn.py +0 -131
  96. pvlib/tests/iotools/test_crn.py +0 -95
  97. pvlib/tests/iotools/test_epw.py +0 -23
  98. pvlib/tests/iotools/test_midc.py +0 -89
  99. pvlib/tests/iotools/test_panond.py +0 -32
  100. pvlib/tests/iotools/test_psm3.py +0 -198
  101. pvlib/tests/iotools/test_pvgis.py +0 -644
  102. pvlib/tests/iotools/test_sodapro.py +0 -298
  103. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  104. pvlib/tests/iotools/test_solargis.py +0 -68
  105. pvlib/tests/iotools/test_solcast.py +0 -324
  106. pvlib/tests/iotools/test_solrad.py +0 -152
  107. pvlib/tests/iotools/test_srml.py +0 -124
  108. pvlib/tests/iotools/test_surfrad.py +0 -75
  109. pvlib/tests/iotools/test_tmy.py +0 -133
  110. pvlib/tests/ivtools/__init__.py +0 -0
  111. pvlib/tests/ivtools/test_sde.py +0 -230
  112. pvlib/tests/ivtools/test_sdm.py +0 -429
  113. pvlib/tests/ivtools/test_utils.py +0 -173
  114. pvlib/tests/spectrum/__init__.py +0 -0
  115. pvlib/tests/spectrum/conftest.py +0 -40
  116. pvlib/tests/spectrum/test_irradiance.py +0 -138
  117. pvlib/tests/spectrum/test_mismatch.py +0 -304
  118. pvlib/tests/spectrum/test_response.py +0 -124
  119. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  120. pvlib/tests/test__deprecation.py +0 -97
  121. pvlib/tests/test_albedo.py +0 -84
  122. pvlib/tests/test_atmosphere.py +0 -351
  123. pvlib/tests/test_clearsky.py +0 -884
  124. pvlib/tests/test_conftest.py +0 -37
  125. pvlib/tests/test_iam.py +0 -555
  126. pvlib/tests/test_inverter.py +0 -213
  127. pvlib/tests/test_irradiance.py +0 -1487
  128. pvlib/tests/test_location.py +0 -356
  129. pvlib/tests/test_modelchain.py +0 -2020
  130. pvlib/tests/test_numerical_precision.py +0 -124
  131. pvlib/tests/test_pvarray.py +0 -71
  132. pvlib/tests/test_pvsystem.py +0 -2511
  133. pvlib/tests/test_scaling.py +0 -207
  134. pvlib/tests/test_shading.py +0 -391
  135. pvlib/tests/test_singlediode.py +0 -608
  136. pvlib/tests/test_snow.py +0 -212
  137. pvlib/tests/test_soiling.py +0 -230
  138. pvlib/tests/test_solarposition.py +0 -966
  139. pvlib/tests/test_spa.py +0 -454
  140. pvlib/tests/test_temperature.py +0 -470
  141. pvlib/tests/test_tools.py +0 -146
  142. pvlib/tests/test_tracking.py +0 -474
  143. pvlib/tests/test_transformer.py +0 -60
  144. pvlib-0.11.2.dist-info/RECORD +0 -191
  145. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/AUTHORS.md +0 -0
  146. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/LICENSE +0 -0
  147. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/top_level.txt +0 -0
@@ -1,429 +0,0 @@
1
- import numpy as np
2
- import pandas as pd
3
- from scipy import optimize
4
-
5
- import pytest
6
- from numpy.testing import assert_allclose
7
-
8
- from pvlib.ivtools import sdm
9
- from pvlib import pvsystem
10
-
11
- from pvlib.tests.conftest import requires_pysam, requires_statsmodels
12
-
13
- from ..conftest import DATA_DIR
14
-
15
-
16
- @pytest.fixture
17
- def get_test_iv_params():
18
- return {'IL': 8.0, 'I0': 5e-10, 'Rsh': 1000, 'Rs': 0.2, 'nNsVth': 1.61864}
19
-
20
-
21
- @pytest.fixture
22
- def cec_params_cansol_cs5p_220p():
23
- return {'ivcurve': {'V_mp_ref': 46.6, 'I_mp_ref': 4.73, 'V_oc_ref': 58.3,
24
- 'I_sc_ref': 5.05},
25
- 'specs': {'alpha_sc': 0.0025, 'beta_voc': -0.19659,
26
- 'gamma_pmp': -0.43, 'cells_in_series': 96},
27
- 'params': {'I_L_ref': 5.056, 'I_o_ref': 1.01e-10,
28
- 'R_sh_ref': 837.51, 'R_s': 1.004, 'a_ref': 2.3674,
29
- 'Adjust': 2.3}}
30
-
31
-
32
- @requires_pysam
33
- def test_fit_cec_sam(cec_params_cansol_cs5p_220p):
34
- input_data = cec_params_cansol_cs5p_220p['ivcurve']
35
- specs = cec_params_cansol_cs5p_220p['specs']
36
- I_L_ref, I_o_ref, R_s, R_sh_ref, a_ref, Adjust = \
37
- sdm.fit_cec_sam(
38
- celltype='polySi', v_mp=input_data['V_mp_ref'],
39
- i_mp=input_data['I_mp_ref'], v_oc=input_data['V_oc_ref'],
40
- i_sc=input_data['I_sc_ref'], alpha_sc=specs['alpha_sc'],
41
- beta_voc=specs['beta_voc'],
42
- gamma_pmp=specs['gamma_pmp'],
43
- cells_in_series=specs['cells_in_series'])
44
- expected = pd.Series(cec_params_cansol_cs5p_220p['params'])
45
- modeled = pd.Series(index=expected.index, data=np.nan)
46
- modeled['a_ref'] = a_ref
47
- modeled['I_L_ref'] = I_L_ref
48
- modeled['I_o_ref'] = I_o_ref
49
- modeled['R_s'] = R_s
50
- modeled['R_sh_ref'] = R_sh_ref
51
- modeled['Adjust'] = Adjust
52
- assert np.allclose(modeled.values, expected.values, rtol=5e-2)
53
-
54
-
55
- @requires_pysam
56
- def test_fit_cec_sam_estimation_failure(cec_params_cansol_cs5p_220p):
57
- # Failing to estimate the parameters for the CEC SDM model should raise an
58
- # exception.
59
- with pytest.raises(RuntimeError):
60
- sdm.fit_cec_sam(celltype='polySi', v_mp=0.45, i_mp=5.25, v_oc=0.55,
61
- i_sc=5.5, alpha_sc=0.00275, beta_voc=0.00275,
62
- gamma_pmp=0.0055, cells_in_series=1, temp_ref=25)
63
-
64
-
65
- def test_fit_desoto():
66
- result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
67
- alpha_sc=0.005658, beta_voc=-0.13788,
68
- cells_in_series=60)
69
- result_expected = {'I_L_ref': 9.45232,
70
- 'I_o_ref': 3.22460e-10,
71
- 'R_s': 0.297814,
72
- 'R_sh_ref': 125.798,
73
- 'a_ref': 1.59128,
74
- 'alpha_sc': 0.005658,
75
- 'EgRef': 1.121,
76
- 'dEgdT': -0.0002677,
77
- 'irrad_ref': 1000,
78
- 'temp_ref': 25}
79
- assert np.allclose(pd.Series(result), pd.Series(result_expected),
80
- rtol=1e-4)
81
-
82
-
83
- def test_fit_desoto_init_guess(mocker):
84
- init_guess_array = np.array([9.4, 3.0e-10, 0.3, 125., 1.6])
85
- init_guess = {k: v for k, v in zip(
86
- ['IL_0', 'Io_0', 'Rs_0', 'Rsh_0', 'a_0'], init_guess_array)}
87
- spy = mocker.spy(optimize, 'root')
88
- result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
89
- alpha_sc=0.005658, beta_voc=-0.13788,
90
- cells_in_series=60, init_guess=init_guess)
91
- np.testing.assert_array_equal(init_guess_array, spy.call_args[1]['x0'])
92
-
93
-
94
- def test_fit_desoto_init_bad_key():
95
- init_guess = {'IL_0': 6., 'bad_key': 0}
96
- with pytest.raises(ValueError, match='is not a valid name;'):
97
- result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
98
- alpha_sc=0.005658, beta_voc=-0.13788,
99
- cells_in_series=60, init_guess=init_guess)
100
-
101
-
102
- def test_fit_desoto_failure():
103
- with pytest.raises(RuntimeError) as exc:
104
- sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
105
- alpha_sc=0.005658, beta_voc=-0.13788,
106
- cells_in_series=10)
107
- assert ('Parameter estimation failed') in str(exc.value)
108
-
109
-
110
- @requires_statsmodels
111
- def test_fit_desoto_sandia(cec_params_cansol_cs5p_220p):
112
- # this test computes a set of IV curves for the input fixture, fits
113
- # the De Soto model to the calculated IV curves, and compares the fitted
114
- # parameters to the starting values
115
- params = cec_params_cansol_cs5p_220p['params']
116
- params.pop('Adjust')
117
- specs = cec_params_cansol_cs5p_220p['specs']
118
- effective_irradiance = np.array([400., 500., 600., 700., 800., 900.,
119
- 1000.])
120
- temp_cell = np.array([15., 25., 35., 45.])
121
- ee = np.tile(effective_irradiance, len(temp_cell))
122
- tc = np.repeat(temp_cell, len(effective_irradiance))
123
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
124
- ee, tc, alpha_sc=specs['alpha_sc'], **params)
125
- ivcurve_params = dict(photocurrent=IL, saturation_current=I0,
126
- resistance_series=Rs, resistance_shunt=Rsh,
127
- nNsVth=nNsVth)
128
- sim_ivcurves = pvsystem.singlediode(**ivcurve_params).to_dict('series')
129
- v = np.linspace(0., sim_ivcurves['v_oc'], 300)
130
- i = pvsystem.i_from_v(voltage=v, **ivcurve_params)
131
- sim_ivcurves.update(v=v.T, i=i.T, ee=ee, tc=tc)
132
-
133
- result = sdm.fit_desoto_sandia(sim_ivcurves, specs)
134
- modeled = pd.Series(index=params.keys(), data=np.nan)
135
- modeled['a_ref'] = result['a_ref']
136
- modeled['I_L_ref'] = result['I_L_ref']
137
- modeled['I_o_ref'] = result['I_o_ref']
138
- modeled['R_s'] = result['R_s']
139
- modeled['R_sh_ref'] = result['R_sh_ref']
140
- expected = pd.Series(params)
141
- assert np.allclose(modeled[params.keys()].values,
142
- expected[params.keys()].values, rtol=5e-2)
143
- assert_allclose(result['dEgdT'], -0.0002677)
144
- assert_allclose(result['EgRef'], 1.3112547292120638)
145
- assert_allclose(result['cells_in_series'], specs['cells_in_series'])
146
-
147
-
148
- def _read_iv_curves_for_test(datafile, npts):
149
- """ read constants and npts IV curves from datafile """
150
- iv_specs = dict.fromkeys(['cells_in_series', 'alpha_sc', 'beta_voc',
151
- 'descr'])
152
- ivcurves = dict.fromkeys(['i_sc', 'i_mp', 'v_mp', 'v_oc', 'poa', 'tc',
153
- 'ee'])
154
-
155
- infilen = DATA_DIR / datafile
156
- with infilen.open(mode='r') as f:
157
-
158
- Ns, aIsc, bVoc, descr = f.readline().split(',')
159
-
160
- iv_specs.update(
161
- cells_in_series=int(Ns), alpha_sc=float(aIsc),
162
- beta_voc=float(bVoc), descr=descr)
163
-
164
- strN, strM = f.readline().split(',')
165
- N = int(strN)
166
- M = int(strM)
167
-
168
- isc = np.empty(N)
169
- imp = np.empty(N)
170
- vmp = np.empty(N)
171
- voc = np.empty(N)
172
- ee = np.empty(N)
173
- poa = np.empty(N)
174
- tc = np.empty(N)
175
- v = np.empty((N, M))
176
- i = np.empty((N, M))
177
- v[:] = np.nan # fill with nan
178
- i[:] = np.nan
179
-
180
- for k in range(N):
181
- tmp = (float(x) for x in f.readline().split(','))
182
- isc[k], imp[k], vmp[k], voc[k], poa[k], tc[k], ee[k] = tmp
183
- # read voltage and current
184
- tmp = [float(x) for x in f.readline().split(',')]
185
- while len(tmp) < M:
186
- tmp.append(np.nan)
187
- v[k, :] = tmp
188
- tmp = [float(x) for x in f.readline().split(',')]
189
- while len(tmp) < M:
190
- tmp.append(np.nan)
191
- i[k, :] = tmp
192
-
193
- ivcurves['i_sc'] = isc[:npts]
194
- ivcurves['i_mp'] = imp[:npts]
195
- ivcurves['v_oc'] = voc[:npts]
196
- ivcurves['v_mp'] = vmp[:npts]
197
- ivcurves['ee'] = ee[:npts]
198
- ivcurves['tc'] = tc[:npts]
199
- ivcurves['v'] = v[:npts]
200
- ivcurves['i'] = i[:npts]
201
- ivcurves['p_mp'] = ivcurves['v_mp'] * ivcurves['i_mp'] # power
202
-
203
- return iv_specs, ivcurves
204
-
205
-
206
- def _read_pvsyst_expected(datafile):
207
- """ Read Pvsyst model parameters and diode equation values for each
208
- IV curve
209
- """
210
- pvsyst_specs = dict.fromkeys(['cells_in_series', 'alpha_sc', 'beta_voc',
211
- 'descr'])
212
- # order required to match file being read
213
- paramlist = [
214
- 'I_L_ref', 'I_o_ref', 'EgRef', 'R_sh_ref', 'R_sh_0', 'R_sh_exp', 'R_s',
215
- 'gamma_ref', 'mu_gamma']
216
- varlist = ['iph', 'io', 'rs', 'rsh', 'u']
217
- pvsyst = dict.fromkeys(paramlist + varlist)
218
-
219
- infilen = DATA_DIR / datafile
220
- with infilen.open(mode='r') as f:
221
-
222
- Ns, aIsc, bVoc, descr = f.readline().split(',')
223
-
224
- pvsyst_specs.update(
225
- cells_in_series=int(Ns), alpha_sc=float(aIsc),
226
- beta_voc=float(bVoc), descr=descr)
227
-
228
- tmp = [float(x) for x in f.readline().split(',')]
229
- # I_L_ref, I_o_ref, EgRef, R_s, R_sh_ref, R_sh_0, R_sh_exp, gamma_ref,
230
- # mu_gamma
231
- pvsyst.update(zip(paramlist, tmp))
232
-
233
- strN = f.readline()
234
- N = int(strN)
235
-
236
- Iph = np.empty(N)
237
- Io = np.empty(N)
238
- Rsh = np.empty(N)
239
- Rs = np.empty(N)
240
- u = np.empty(N)
241
-
242
- for k in range(N):
243
- tmp = [float(x) for x in f.readline().split(',')]
244
- Iph[k], Io[k], Rsh[k], Rs[k], u[k] = tmp
245
-
246
- pvsyst.update(zip(varlist, [Iph, Io, Rs, Rsh, u]))
247
-
248
- return pvsyst_specs, pvsyst
249
-
250
-
251
- @requires_statsmodels
252
- def test_fit_pvsyst_sandia(npts=3000):
253
-
254
- # get IV curve data
255
- iv_specs, ivcurves = _read_iv_curves_for_test('PVsyst_demo.csv', npts)
256
-
257
- # get known Pvsyst model parameters and five parameters from each fitted
258
- # IV curve
259
- pvsyst_specs, pvsyst = _read_pvsyst_expected('PVsyst_demo_model.csv')
260
-
261
- modeled = sdm.fit_pvsyst_sandia(ivcurves, iv_specs)
262
-
263
- # calculate IV curves using the fitted model, for comparison with input
264
- # IV curves
265
- param_res = pvsystem.calcparams_pvsyst(
266
- effective_irradiance=ivcurves['ee'], temp_cell=ivcurves['tc'],
267
- alpha_sc=iv_specs['alpha_sc'], gamma_ref=modeled['gamma_ref'],
268
- mu_gamma=modeled['mu_gamma'], I_L_ref=modeled['I_L_ref'],
269
- I_o_ref=modeled['I_o_ref'], R_sh_ref=modeled['R_sh_ref'],
270
- R_sh_0=modeled['R_sh_0'], R_s=modeled['R_s'],
271
- cells_in_series=iv_specs['cells_in_series'], EgRef=modeled['EgRef'])
272
- iv_res = pvsystem.singlediode(*param_res)
273
-
274
- # assertions
275
- assert np.allclose(
276
- ivcurves['p_mp'], iv_res['p_mp'], equal_nan=True, rtol=0.038)
277
- assert np.allclose(
278
- ivcurves['v_mp'], iv_res['v_mp'], equal_nan=True, rtol=0.029)
279
- assert np.allclose(
280
- ivcurves['i_mp'], iv_res['i_mp'], equal_nan=True, rtol=0.021)
281
- assert np.allclose(
282
- ivcurves['i_sc'], iv_res['i_sc'], equal_nan=True, rtol=0.003)
283
- assert np.allclose(
284
- ivcurves['v_oc'], iv_res['v_oc'], equal_nan=True, rtol=0.019)
285
- # cells_in_series, alpha_sc, beta_voc, descr
286
- assert all((iv_specs[k] == pvsyst_specs[k]) for k in iv_specs.keys())
287
- # I_L_ref, I_o_ref, EgRef, R_sh_ref, R_sh_0, R_sh_exp, R_s, gamma_ref,
288
- # mu_gamma
289
- assert np.isclose(modeled['I_L_ref'], pvsyst['I_L_ref'], rtol=6.5e-5)
290
- assert np.isclose(modeled['I_o_ref'], pvsyst['I_o_ref'], rtol=0.15)
291
- assert np.isclose(modeled['R_s'], pvsyst['R_s'], rtol=0.0035)
292
- assert np.isclose(modeled['R_sh_ref'], pvsyst['R_sh_ref'], rtol=0.091)
293
- assert np.isclose(modeled['R_sh_0'], pvsyst['R_sh_0'], rtol=0.013)
294
- assert np.isclose(modeled['EgRef'], pvsyst['EgRef'], rtol=0.037)
295
- assert np.isclose(modeled['gamma_ref'], pvsyst['gamma_ref'], rtol=0.0045)
296
- assert np.isclose(modeled['mu_gamma'], pvsyst['mu_gamma'], rtol=0.064)
297
-
298
- # Iph, Io, Rsh, Rs, u
299
- mask = np.ones(modeled['u'].shape, dtype=bool)
300
- # exclude one curve with different convergence
301
- umask = mask.copy()
302
- umask[2540] = False
303
- assert all(modeled['u'][umask] == pvsyst['u'][:npts][umask])
304
- assert np.allclose(
305
- modeled['iph'][modeled['u']], pvsyst['iph'][:npts][modeled['u']],
306
- equal_nan=True, rtol=0.0009)
307
- assert np.allclose(
308
- modeled['io'][modeled['u']], pvsyst['io'][:npts][modeled['u']],
309
- equal_nan=True, rtol=0.096)
310
- assert np.allclose(
311
- modeled['rs'][modeled['u']], pvsyst['rs'][:npts][modeled['u']],
312
- equal_nan=True, rtol=0.035)
313
- # exclude one curve with Rsh outside 63% tolerance
314
- rshmask = modeled['u'].copy()
315
- rshmask[2545] = False
316
- assert np.allclose(
317
- modeled['rsh'][rshmask], pvsyst['rsh'][:npts][rshmask],
318
- equal_nan=True, rtol=0.63)
319
-
320
-
321
- @pytest.mark.parametrize('vmp, imp, iph, io, rs, rsh, nnsvth, expected', [
322
- (2., 2., 2., 2., 2., 2., 2., np.nan),
323
- (2., 2., 0., 2., 2., 2., 2., np.nan),
324
- (2., 2., 2., 0., 2., 2., 2., np.nan),
325
- (2., 2., 2., 2., 0., 2., 2., np.nan),
326
- (2., 2., 2., 2., 2., 0., 2., np.nan),
327
- (2., 2., 2., 2., 2., 2., 0., np.nan)])
328
- def test__update_rsh_fixed_pt_nans(vmp, imp, iph, io, rs, rsh, nnsvth,
329
- expected):
330
- outrsh = sdm._update_rsh_fixed_pt(vmp, imp, iph, io, rs, rsh, nnsvth)
331
- assert np.all(np.isnan(outrsh))
332
-
333
-
334
- def test__update_rsh_fixed_pt_vmp0():
335
- outrsh = sdm._update_rsh_fixed_pt(vmp=0., imp=2., iph=2., io=2., rs=2.,
336
- rsh=2., nnsvth=2.)
337
- assert_allclose(outrsh, np.array([502.]), atol=.0001)
338
-
339
-
340
- def test__update_rsh_fixed_pt_vector():
341
- outrsh = sdm._update_rsh_fixed_pt(rsh=np.array([-1., 3, .5, 2.]),
342
- rs=np.array([1., -.5, 2., 2.]),
343
- io=np.array([.2, .3, -.4, 2.]),
344
- iph=np.array([-.1, 1, 3., 2.]),
345
- nnsvth=np.array([4., -.2, .1, 2.]),
346
- imp=np.array([.2, .2, -1., 2.]),
347
- vmp=np.array([0., -1, 0., 0.]))
348
- assert np.all(np.isnan(outrsh[0:3]))
349
- assert_allclose(outrsh[3], np.array([502.]), atol=.0001)
350
-
351
-
352
- @pytest.mark.parametrize('voc, iph, io, rs, rsh, nnsvth, expected', [
353
- (2., 2., 2., 2., 2., 2., 0.5911),
354
- (2., 2., 2., 0., 2., 2., 0.5911),
355
- (2., 2., 0., 2., 2., 2., 0.),
356
- (2., 0., 2., 2., 2., 2., 1.0161e-4),
357
- (0., 2., 2., 2., 2., 2., 17.9436)])
358
- def test__update_io(voc, iph, io, rs, rsh, nnsvth, expected):
359
- outio = sdm._update_io(voc, iph, io, rs, rsh, nnsvth)
360
- assert_allclose(outio, expected, atol=.0001)
361
-
362
-
363
- @pytest.mark.parametrize('voc, iph, io, rs, rsh, nnsvth', [
364
- (2., 2., 2., 2., 2., 0.),
365
- (-1., -1., -1., -1., -1., -1.)])
366
- def test__update_io_nan(voc, iph, io, rs, rsh, nnsvth):
367
- outio = sdm._update_io(voc, iph, io, rs, rsh, nnsvth)
368
- assert np.isnan(outio)
369
-
370
-
371
- @pytest.mark.parametrize('vmp, imp, iph, io, rs, rsh, nnsvth, expected', [
372
- (2., 2., 2., 2., 2., 2., 2., (1.8726, 2.)),
373
- (2., 0., 2., 2., 2., 2., 2., (1.8726, 3.4537)),
374
- (2., 2., 0., 2., 2., 2., 2., (1.2650, 0.8526)),
375
- (0., 2., 2., 2., 2., 2., 2., (1.5571, 2.))])
376
- def test__calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth, expected):
377
- theta, phi = sdm._calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth)
378
- assert_allclose(theta, expected[0], atol=.0001)
379
- assert_allclose(phi, expected[1], atol=.0001)
380
-
381
-
382
- @pytest.mark.parametrize('vmp, imp, iph, io, rs, rsh, nnsvth', [
383
- (2., 2., 2., 0., 2., 2., 2.),
384
- (2., 2., 2., 2., 2., 2., 0.),
385
- (2., 0., 2., 2., 2., 0., 2.)])
386
- def test__calc_theta_phi_exact_both_nan(vmp, imp, iph, io, rs, rsh, nnsvth):
387
- theta, phi = sdm._calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth)
388
- assert np.isnan(theta)
389
- assert np.isnan(phi)
390
-
391
-
392
- def test__calc_theta_phi_exact_one_nan():
393
- theta, phi = sdm._calc_theta_phi_exact(imp=2., iph=2., vmp=2., io=2.,
394
- nnsvth=2., rs=0., rsh=2.)
395
- assert np.isnan(theta)
396
- assert_allclose(phi, 2., atol=.0001)
397
-
398
-
399
- def test__calc_theta_phi_exact_vector():
400
- theta, phi = sdm._calc_theta_phi_exact(imp=np.array([1., -1.]),
401
- iph=np.array([-1., 1.]),
402
- vmp=np.array([1., -1.]),
403
- io=np.array([-1., 1.]),
404
- nnsvth=np.array([1., -1.]),
405
- rs=np.array([-1., 1.]),
406
- rsh=np.array([1., -1.]))
407
- assert np.isnan(theta[0])
408
- assert np.isnan(theta[1])
409
- assert np.isnan(phi[0])
410
- assert_allclose(phi[1], 2.2079, atol=.0001)
411
-
412
-
413
- def test_pvsyst_temperature_coeff():
414
- # test for consistency with dP/dT estimated with secant rule
415
- params = {'alpha_sc': 0., 'gamma_ref': 1.1, 'mu_gamma': 0.,
416
- 'I_L_ref': 6., 'I_o_ref': 5.e-9, 'R_sh_ref': 200.,
417
- 'R_sh_0': 2000., 'R_s': 0.5, 'cells_in_series': 60}
418
- expected = -0.004886706494879083
419
- # params defines a Pvsyst model for a notional module.
420
- # expected value is created by calculating power at 1000 W/m2, and cell
421
- # temperature of 24 and 26C, using pvsystem.calcparams_pvsyst and
422
- # pvsystem.singlediode. The derivative (value for expected) is estimated
423
- # as the slope (p_mp at 26C - p_mp at 24C) / 2
424
- # using the secant rule for derivatives.
425
- gamma_pdc = sdm.pvsyst_temperature_coeff(
426
- params['alpha_sc'], params['gamma_ref'], params['mu_gamma'],
427
- params['I_L_ref'], params['I_o_ref'], params['R_sh_ref'],
428
- params['R_sh_0'], params['R_s'], params['cells_in_series'])
429
- assert_allclose(gamma_pdc, expected, rtol=0.0005)
@@ -1,173 +0,0 @@
1
- import numpy as np
2
- import pandas as pd
3
- import pytest
4
- from pvlib.ivtools.utils import _numdiff, rectify_iv_curve, astm_e1036
5
- from pvlib.ivtools.utils import _schumaker_qspline
6
-
7
- from ..conftest import DATA_DIR
8
-
9
-
10
- @pytest.fixture
11
- def ivcurve():
12
- voltage = np.array([0., 1., 5., 10., 25., 25.00001, 30., 28., 45., 47.,
13
- 49., 51., np.nan])
14
- current = np.array([7., 6., 6., 5., 4., 3., 2.7, 2.5, np.nan, 0.5, -1., 0.,
15
- np.nan])
16
- return voltage, current
17
-
18
-
19
- def test__numdiff():
20
- iv = pd.read_csv(DATA_DIR / 'ivtools_numdiff.csv',
21
- names=['I', 'V', 'dIdV', 'd2IdV2'], dtype=float)
22
- df, d2f = _numdiff(iv.V, iv.I)
23
- assert np.allclose(iv.dIdV, df, equal_nan=True)
24
- assert np.allclose(iv.d2IdV2, d2f, equal_nan=True)
25
-
26
-
27
- def test_rectify_iv_curve(ivcurve):
28
- voltage, current = ivcurve
29
-
30
- vexp_no_dec = np.array([0., 1., 5., 10., 25., 25.00001, 28., 30., 47.,
31
- 51.])
32
- iexp_no_dec = np.array([7., 6., 6., 5., 4., 3., 2.5, 2.7, 0.5, 0.])
33
- v, i = rectify_iv_curve(voltage, current)
34
- np.testing.assert_allclose(v, vexp_no_dec, atol=.0001)
35
- np.testing.assert_allclose(i, iexp_no_dec, atol=.0001)
36
-
37
- vexp = np.array([0., 1., 5., 10., 25., 28., 30., 47., 51.])
38
- iexp = np.array([7., 6., 6., 5., 3.5, 2.5, 2.7, 0.5, 0.])
39
- v, i = rectify_iv_curve(voltage, current, decimals=4)
40
- np.testing.assert_allclose(v, vexp, atol=.0001)
41
- np.testing.assert_allclose(i, iexp, atol=.0001)
42
-
43
-
44
- @pytest.mark.parametrize('x,y,expected', [
45
- (np.array([0., 1., 2., 3., 4., 1., 2., 3., 4., 5.]),
46
- np.array([2., 1., 0., 1., 2., 3., 2., 1., 2., 3.]),
47
- (np.array([[0., -1., 2.], [-0.5, -1., 1.], [-0.75, -0.5, 3.],
48
- [0.75, -1.5, 0.375], [0.125, -1.25, 2.5625], [1.5, 0., 0.],
49
- [-0.5, -1., 2.], [-0.25, 1.5, 0.375], [0.75, -1.5, 1.375],
50
- [0.5, 1., 1.], [1.5, 0., 1.], [0.0278, -0.3333, 2.1667],
51
- [-0.75, 1.5, 1.625], [-0.25, 1.5, 1.375], [0.1667, 0., 2.],
52
- [0., 1., 2.]]),
53
- np.array([0., 1., 1., 1.5, 1.5, 2., 2., 2.5, 2.5, 3., 3., 3., 3.5, 3.5,
54
- 4., 4., 5.]),
55
- np.array([2., 1., 3., 0.375, 2.5625, 0., 2., 0.375, 1.375, 1., 1.,
56
- 2.1667, 1.625, 1.375, 2., 2., 3.]),
57
- np.array([0., 0., 0., 1., 1., 0., 0., 1., 1., 0., 0., 1., 1., 1., 0., 0.,
58
- 0.]))),
59
- (np.array([1., 2., 3., 4., 5.]),
60
- np.array([-2., -1., 0., 1., 2.]),
61
- (np.array([[0., 1., -2.], [0., 1., -1.], [0., 1., 0.], [0., 1., 1.]]),
62
- np.array([1., 2., 3., 4., 5.]),
63
- np.array([-2., -1., 0., 1., 2.]),
64
- np.array([0., 0., 0., 0., 0.]))),
65
- (np.array([-.5, -.1, 0., .2, .3]),
66
- np.array([-5., -1., .2, .5, 2.]),
67
- (np.array([[2.2727, 9.0909, -5.], [63.0303, 10.9091, -1.],
68
- [-72.7273, 17.2121, -.297], [-11.8182, 2.6667, .2],
69
- [6.0606, .303, .3485], [122.7273, 2.7273, .5]]),
70
- np.array([-.5, -.1, -.05, 0., .1, .2, .3]),
71
- np.array([-5., -1., -.297, .2, .3485, .5, 2.]),
72
- np.array([0., 0., 1., 0., 1., 0., 0.])))])
73
- def test__schmumaker_qspline(x, y, expected):
74
- [t, c, yhat, kflag] = _schumaker_qspline(x, y)
75
- np.testing.assert_allclose(c, expected[0], atol=0.0001)
76
- np.testing.assert_allclose(t, expected[1], atol=0.0001)
77
- np.testing.assert_allclose(yhat, expected[2], atol=0.0001)
78
- np.testing.assert_allclose(kflag, expected[3], atol=0.0001)
79
-
80
-
81
- @pytest.fixture
82
- def i_array():
83
- i = np.array([8.09403993, 8.09382549, 8.09361103, 8.09339656, 8.09318205,
84
- 8.09296748, 8.09275275, 8.09253771, 8.09232204, 8.09210506,
85
- 8.09188538, 8.09166014, 8.09142342, 8.09116305, 8.09085392,
86
- 8.09044425, 8.08982734, 8.08878333, 8.08685945, 8.08312463,
87
- 8.07566926, 8.06059856, 8.03005836, 7.96856869, 7.8469714,
88
- 7.61489584, 7.19789314, 6.51138396, 5.49373476, 4.13267172,
89
- 2.46021487, 0.52838624, -1.61055289])
90
- return i
91
-
92
-
93
- @pytest.fixture
94
- def v_array():
95
- v = np.array([-0.005, 0.015, 0.035, 0.055, 0.075, 0.095, 0.115, 0.135,
96
- 0.155, 0.175, 0.195, 0.215, 0.235, 0.255, 0.275, 0.295,
97
- 0.315, 0.335, 0.355, 0.375, 0.395, 0.415, 0.435, 0.455,
98
- 0.475, 0.495, 0.515, 0.535, 0.555, 0.575, 0.595, 0.615,
99
- 0.635])
100
- return v
101
-
102
-
103
- # astm_e1036 tests
104
- def test_astm_e1036(v_array, i_array):
105
- result = astm_e1036(v_array, i_array)
106
- expected = {'voc': 0.6195097477985162,
107
- 'isc': 8.093986320386227,
108
- 'vmp': 0.494283417170082,
109
- 'imp': 7.626088301548568,
110
- 'pmp': 3.7694489853302127,
111
- 'ff': 0.7517393078504361}
112
- fit = result.pop('mp_fit')
113
- expected_fit = np.array(
114
- [3.6260726, 0.49124176, -0.24644747, -0.26442383, -0.1223237])
115
- assert fit.coef == pytest.approx(expected_fit)
116
- assert result == pytest.approx(expected)
117
-
118
-
119
- def test_astm_e1036_fit_order(v_array, i_array):
120
- result = astm_e1036(v_array, i_array, mp_fit_order=3)
121
- fit = result.pop('mp_fit')
122
- expected_fit = np.array(
123
- [3.64081697, 0.49124176, -0.3720477, -0.26442383])
124
- assert fit.coef == pytest.approx(expected_fit)
125
-
126
-
127
- def test_astm_e1036_est_isc_voc(v_array, i_array):
128
- '''
129
- Test the case in which Isc and Voc estimates are
130
- valid without a linear fit
131
- '''
132
- v = v_array
133
- i = i_array
134
- v = np.append(v, [0.001, 0.6201])
135
- i = np.append(i, [8.09397560e+00, 7.10653445e-04])
136
- result = astm_e1036(v, i)
137
- expected = {'voc': 0.6201,
138
- 'isc': 8.093975598317805,
139
- 'vmp': 0.494283417170082,
140
- 'imp': 7.626088301548568,
141
- 'pmp': 3.7694489853302127,
142
- 'ff': 0.751024747526615}
143
- result.pop('mp_fit')
144
- assert result == pytest.approx(expected)
145
-
146
-
147
- def test_astm_e1036_mpfit_limits(v_array, i_array):
148
- result = astm_e1036(v_array,
149
- i_array,
150
- imax_limits=(0.85, 1.1),
151
- vmax_limits=(0.85, 1.1))
152
- expected = {'voc': 0.6195097477985162,
153
- 'isc': 8.093986320386227,
154
- 'vmp': 0.49464214190725303,
155
- 'imp': 7.620032530519718,
156
- 'pmp': 3.769189212299219,
157
- 'ff': 0.7516875014460312}
158
- result.pop('mp_fit')
159
- assert result == pytest.approx(expected)
160
-
161
-
162
- def test_astm_e1036_fit_points(v_array, i_array):
163
- i = i_array
164
- i[3] = 8.1 # ensure an interesting change happens
165
- result = astm_e1036(v_array, i, voc_points=4, isc_points=4)
166
- expected = {'voc': 0.619337073271274,
167
- 'isc': 8.093160893325297,
168
- 'vmp': 0.494283417170082,
169
- 'imp': 7.626088301548568,
170
- 'pmp': 3.7694489853302127,
171
- 'ff': 0.7520255886236707}
172
- result.pop('mp_fit')
173
- assert result == pytest.approx(expected)
File without changes
@@ -1,40 +0,0 @@
1
- import numpy as np
2
- import pytest
3
- import pandas as pd
4
-
5
- from ..conftest import DATA_DIR
6
-
7
- SPECTRL2_TEST_DATA = DATA_DIR / 'spectrl2_example_spectra.csv'
8
-
9
-
10
- @pytest.fixture
11
- def spectrl2_data():
12
- # reference spectra generated with solar_utils==0.3
13
- """
14
- expected = solar_utils.spectrl2(
15
- units=1,
16
- location=[40, -80, -5],
17
- datetime=[2020, 3, 15, 10, 45, 59],
18
- weather=[1013, 15],
19
- orientation=[0, 180],
20
- atmospheric_conditions=[1.14, 0.65, 0.344, 0.1, 1.42],
21
- albedo=[0.3, 0.7, 0.8, 1.3, 2.5, 4.0] + [0.2]*6,
22
- )
23
- """
24
- kwargs = {
25
- 'surface_tilt': 0,
26
- 'relative_airmass': 1.4899535986910446,
27
- 'apparent_zenith': 47.912086486816406,
28
- 'aoi': 47.91208648681641,
29
- 'ground_albedo': 0.2,
30
- 'surface_pressure': 101300,
31
- 'ozone': 0.344,
32
- 'precipitable_water': 1.42,
33
- 'aerosol_turbidity_500nm': 0.1,
34
- 'dayofyear': 75
35
- }
36
- df = pd.read_csv(SPECTRL2_TEST_DATA, index_col=0)
37
- # convert um to nm
38
- df['wavelength'] = np.round(df['wavelength'] * 1000, 1)
39
- df[['specdif', 'specdir', 'specetr', 'specglo']] /= 1000
40
- return kwargs, df