pvlib 0.11.2__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 (139) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/atmosphere.py +0 -9
  3. pvlib/bifacial/infinite_sheds.py +4 -3
  4. pvlib/bifacial/utils.py +2 -1
  5. pvlib/iotools/psm3.py +1 -1
  6. pvlib/iotools/pvgis.py +10 -2
  7. pvlib/iotools/tmy.py +3 -69
  8. pvlib/irradiance.py +14 -0
  9. pvlib/location.py +73 -33
  10. pvlib/modelchain.py +18 -35
  11. pvlib/pvsystem.py +7 -10
  12. pvlib/snow.py +64 -28
  13. pvlib/spectrum/__init__.py +0 -1
  14. pvlib/spectrum/irradiance.py +0 -63
  15. pvlib/spectrum/mismatch.py +3 -3
  16. pvlib/tools.py +6 -5
  17. {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/METADATA +5 -3
  18. pvlib-0.12.0.dist-info/RECORD +75 -0
  19. {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/WHEEL +1 -1
  20. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  21. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  22. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  23. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  24. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  25. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  26. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  27. pvlib/data/CRN_with_problems.txt +0 -3
  28. pvlib/data/ET-M772BH550GL.PAN +0 -75
  29. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  30. pvlib/data/PVsyst_demo.csv +0 -10757
  31. pvlib/data/PVsyst_demo_model.csv +0 -3588
  32. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  33. pvlib/data/abq19056.dat +0 -6
  34. pvlib/data/bishop88_numerical_precision.csv +0 -101
  35. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  36. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  37. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  38. pvlib/data/cams_mcclear_monthly.csv +0 -42
  39. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  40. pvlib/data/cams_radiation_monthly.csv +0 -47
  41. pvlib/data/detect_clearsky_data.csv +0 -35
  42. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  43. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  44. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  45. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  46. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  47. pvlib/data/ivtools_numdiff.csv +0 -52
  48. pvlib/data/midc_20181014.txt +0 -1441
  49. pvlib/data/midc_raw_20181018.txt +0 -1441
  50. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  51. pvlib/data/msn19056.dat +0 -6
  52. pvlib/data/precise_iv_curves1.json +0 -10251
  53. pvlib/data/precise_iv_curves2.json +0 -10251
  54. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  55. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  56. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  57. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  58. pvlib/data/pvgis_tmy_meta.json +0 -32
  59. pvlib/data/pvgis_tmy_test.csv +0 -8761
  60. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  61. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  62. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  63. pvlib/data/spectrl2_example_spectra.csv +0 -123
  64. pvlib/data/surfrad-slv16001.dat +0 -1442
  65. pvlib/data/test_psm3_2017.csv +0 -17521
  66. pvlib/data/test_psm3_2019_5min.csv +0 -289
  67. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  68. pvlib/data/test_read_psm3.csv +0 -17523
  69. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  70. pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
  71. pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
  72. pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
  73. pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
  74. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  75. pvlib/spa_c_files/README.md +0 -81
  76. pvlib/spa_c_files/cspa_py.pxd +0 -43
  77. pvlib/spa_c_files/spa_py.pyx +0 -30
  78. pvlib/tests/__init__.py +0 -0
  79. pvlib/tests/bifacial/__init__.py +0 -0
  80. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  81. pvlib/tests/bifacial/test_losses_models.py +0 -54
  82. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  83. pvlib/tests/bifacial/test_utils.py +0 -192
  84. pvlib/tests/conftest.py +0 -476
  85. pvlib/tests/iotools/__init__.py +0 -0
  86. pvlib/tests/iotools/test_acis.py +0 -213
  87. pvlib/tests/iotools/test_bsrn.py +0 -131
  88. pvlib/tests/iotools/test_crn.py +0 -95
  89. pvlib/tests/iotools/test_epw.py +0 -23
  90. pvlib/tests/iotools/test_midc.py +0 -89
  91. pvlib/tests/iotools/test_panond.py +0 -32
  92. pvlib/tests/iotools/test_psm3.py +0 -198
  93. pvlib/tests/iotools/test_pvgis.py +0 -644
  94. pvlib/tests/iotools/test_sodapro.py +0 -298
  95. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  96. pvlib/tests/iotools/test_solargis.py +0 -68
  97. pvlib/tests/iotools/test_solcast.py +0 -324
  98. pvlib/tests/iotools/test_solrad.py +0 -152
  99. pvlib/tests/iotools/test_srml.py +0 -124
  100. pvlib/tests/iotools/test_surfrad.py +0 -75
  101. pvlib/tests/iotools/test_tmy.py +0 -133
  102. pvlib/tests/ivtools/__init__.py +0 -0
  103. pvlib/tests/ivtools/test_sde.py +0 -230
  104. pvlib/tests/ivtools/test_sdm.py +0 -429
  105. pvlib/tests/ivtools/test_utils.py +0 -173
  106. pvlib/tests/spectrum/__init__.py +0 -0
  107. pvlib/tests/spectrum/conftest.py +0 -40
  108. pvlib/tests/spectrum/test_irradiance.py +0 -138
  109. pvlib/tests/spectrum/test_mismatch.py +0 -304
  110. pvlib/tests/spectrum/test_response.py +0 -124
  111. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  112. pvlib/tests/test__deprecation.py +0 -97
  113. pvlib/tests/test_albedo.py +0 -84
  114. pvlib/tests/test_atmosphere.py +0 -351
  115. pvlib/tests/test_clearsky.py +0 -884
  116. pvlib/tests/test_conftest.py +0 -37
  117. pvlib/tests/test_iam.py +0 -555
  118. pvlib/tests/test_inverter.py +0 -213
  119. pvlib/tests/test_irradiance.py +0 -1487
  120. pvlib/tests/test_location.py +0 -356
  121. pvlib/tests/test_modelchain.py +0 -2020
  122. pvlib/tests/test_numerical_precision.py +0 -124
  123. pvlib/tests/test_pvarray.py +0 -71
  124. pvlib/tests/test_pvsystem.py +0 -2511
  125. pvlib/tests/test_scaling.py +0 -207
  126. pvlib/tests/test_shading.py +0 -391
  127. pvlib/tests/test_singlediode.py +0 -608
  128. pvlib/tests/test_snow.py +0 -212
  129. pvlib/tests/test_soiling.py +0 -230
  130. pvlib/tests/test_solarposition.py +0 -966
  131. pvlib/tests/test_spa.py +0 -454
  132. pvlib/tests/test_temperature.py +0 -470
  133. pvlib/tests/test_tools.py +0 -146
  134. pvlib/tests/test_tracking.py +0 -474
  135. pvlib/tests/test_transformer.py +0 -60
  136. pvlib-0.11.2.dist-info/RECORD +0 -191
  137. {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
  138. {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
  139. {pvlib-0.11.2.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
@@ -1,2511 +0,0 @@
1
- from collections import OrderedDict
2
- import itertools
3
-
4
- import numpy as np
5
- from numpy import nan, array
6
- import pandas as pd
7
-
8
- import pytest
9
- from .conftest import assert_series_equal, assert_frame_equal
10
- from numpy.testing import assert_allclose
11
- import unittest.mock as mock
12
-
13
- from pvlib import inverter, pvsystem
14
- from pvlib import iam as _iam
15
- from pvlib import irradiance
16
- from pvlib import spectrum
17
- from pvlib.location import Location
18
- from pvlib.pvsystem import FixedMount
19
- from pvlib import temperature
20
- from pvlib._deprecation import pvlibDeprecationWarning
21
- from pvlib.tools import cosd
22
- from pvlib.singlediode import VOLTAGE_BUILTIN
23
- from pvlib.tests.test_singlediode import get_pvsyst_fs_495
24
-
25
-
26
- @pytest.mark.parametrize('iam_model,model_params', [
27
- ('ashrae', {'b': 0.05}),
28
- ('physical', {'K': 4, 'L': 0.002, 'n': 1.526}),
29
- ('martin_ruiz', {'a_r': 0.16}),
30
- ])
31
- def test_PVSystem_get_iam(mocker, iam_model, model_params):
32
- m = mocker.spy(_iam, iam_model)
33
- system = pvsystem.PVSystem(module_parameters=model_params)
34
- thetas = 1
35
- iam = system.get_iam(thetas, iam_model=iam_model)
36
- m.assert_called_with(thetas, **model_params)
37
- assert iam < 1.
38
-
39
-
40
- def test_PVSystem_multi_array_get_iam():
41
- model_params = {'b': 0.05}
42
- system = pvsystem.PVSystem(
43
- arrays=[pvsystem.Array(mount=pvsystem.FixedMount(0, 180),
44
- module_parameters=model_params),
45
- pvsystem.Array(mount=pvsystem.FixedMount(0, 180),
46
- module_parameters=model_params)]
47
- )
48
- iam = system.get_iam((1, 5), iam_model='ashrae')
49
- assert len(iam) == 2
50
- assert iam[0] != iam[1]
51
- with pytest.raises(ValueError,
52
- match="Length mismatch for per-array parameter"):
53
- system.get_iam((1,), iam_model='ashrae')
54
-
55
-
56
- def test_PVSystem_get_iam_sapm(sapm_module_params, mocker):
57
- system = pvsystem.PVSystem(module_parameters=sapm_module_params)
58
- mocker.spy(_iam, 'sapm')
59
- aoi = 0
60
- out = system.get_iam(aoi, 'sapm')
61
- _iam.sapm.assert_called_once_with(aoi, sapm_module_params)
62
- assert_allclose(out, 1.0, atol=0.01)
63
-
64
-
65
- def test_PVSystem_get_iam_interp(mocker):
66
- interp_module_params = {'iam_ref': (1., 0.8), 'theta_ref': (0., 80.)}
67
- system = pvsystem.PVSystem(module_parameters=interp_module_params)
68
- spy = mocker.spy(_iam, 'interp')
69
- aoi = ((0., 40., 80.),)
70
- expected = (1., 0.9, 0.8)
71
- out = system.get_iam(aoi, iam_model='interp')
72
- assert_allclose(out, expected)
73
- spy.assert_called_once_with(aoi[0], **interp_module_params)
74
-
75
-
76
- def test__normalize_sam_product_names():
77
-
78
- BAD_NAMES = [' -.()[]:+/",', 'Module[1]']
79
- NORM_NAMES = ['____________', 'Module_1_']
80
-
81
- norm_names = pvsystem._normalize_sam_product_names(BAD_NAMES)
82
- assert list(norm_names) == NORM_NAMES
83
-
84
- BAD_NAMES = ['Module[1]', 'Module(1)']
85
- NORM_NAMES = ['Module_1_', 'Module_1_']
86
-
87
- with pytest.warns(UserWarning):
88
- norm_names = pvsystem._normalize_sam_product_names(BAD_NAMES)
89
- assert list(norm_names) == NORM_NAMES
90
-
91
- BAD_NAMES = ['Module[1]', 'Module[1]']
92
- NORM_NAMES = ['Module_1_', 'Module_1_']
93
-
94
- with pytest.warns(UserWarning):
95
- norm_names = pvsystem._normalize_sam_product_names(BAD_NAMES)
96
- assert list(norm_names) == NORM_NAMES
97
-
98
-
99
- def test_PVSystem_get_iam_invalid(sapm_module_params, mocker):
100
- system = pvsystem.PVSystem(module_parameters=sapm_module_params)
101
- with pytest.raises(ValueError):
102
- system.get_iam(45, iam_model='not_a_model')
103
-
104
-
105
- def test_retrieve_sam_raises_exceptions():
106
- """
107
- Raise an exception if an invalid parameter is provided to `retrieve_sam()`.
108
- """
109
- with pytest.raises(ValueError, match="Please provide either"):
110
- pvsystem.retrieve_sam()
111
- with pytest.raises(ValueError, match="Please provide either.*, not both."):
112
- pvsystem.retrieve_sam(name="this_surely_wont_work", path="wont_work")
113
- with pytest.raises(KeyError, match="Invalid name"):
114
- pvsystem.retrieve_sam(name="this_surely_wont_work")
115
- with pytest.raises(FileNotFoundError):
116
- pvsystem.retrieve_sam(path="this_surely_wont_work.csv")
117
-
118
-
119
- def test_retrieve_sam_databases():
120
- """Test the expected keys are retrieved from each database."""
121
- keys_per_database = {
122
- "cecmod": {'Technology', 'Bifacial', 'STC', 'PTC', 'A_c', 'Length',
123
- 'Width', 'N_s', 'I_sc_ref', 'V_oc_ref', 'I_mp_ref',
124
- 'V_mp_ref', 'alpha_sc', 'beta_oc', 'T_NOCT', 'a_ref',
125
- 'I_L_ref', 'I_o_ref', 'R_s', 'R_sh_ref', 'Adjust',
126
- 'gamma_r', 'BIPV', 'Version', 'Date'},
127
- "sandiamod": {'Vintage', 'Area', 'Material', 'Cells_in_Series',
128
- 'Parallel_Strings', 'Isco', 'Voco', 'Impo', 'Vmpo',
129
- 'Aisc', 'Aimp', 'C0', 'C1', 'Bvoco', 'Mbvoc', 'Bvmpo',
130
- 'Mbvmp', 'N', 'C2', 'C3', 'A0', 'A1', 'A2', 'A3', 'A4',
131
- 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'DTC', 'FD', 'A',
132
- 'B', 'C4', 'C5', 'IXO', 'IXXO', 'C6', 'C7', 'Notes'},
133
- "adrinverter": {'Manufacturer', 'Model', 'Source', 'Vac', 'Vintage',
134
- 'Pacmax', 'Pnom', 'Vnom', 'Vmin', 'Vmax',
135
- 'ADRCoefficients', 'Pnt', 'Vdcmax', 'Idcmax',
136
- 'MPPTLow', 'MPPTHi', 'TambLow', 'TambHi', 'Weight',
137
- 'PacFitErrMax', 'YearOfData'},
138
- "cecinverter": {'Vac', 'Paco', 'Pdco', 'Vdco', 'Pso', 'C0', 'C1', 'C2',
139
- 'C3', 'Pnt', 'Vdcmax', 'Idcmax', 'Mppt_low',
140
- 'Mppt_high', 'CEC_Date', 'CEC_Type'}
141
- } # fmt: skip
142
- item_per_database = {
143
- "cecmod": "Itek_Energy_LLC_iT_300_HE",
144
- "sandiamod": "Canadian_Solar_CS6X_300M__2013_",
145
- "adrinverter": "Sainty_Solar__SSI_4K4U_240V__CEC_2011_",
146
- "cecinverter": "ABB__PVI_3_0_OUTD_S_US__208V_",
147
- }
148
- # duplicate the cecinverter items for sandiainverter, for backwards compat
149
- keys_per_database["sandiainverter"] = keys_per_database["cecinverter"]
150
- item_per_database["sandiainverter"] = item_per_database["cecinverter"]
151
-
152
- for database in keys_per_database.keys():
153
- data = pvsystem.retrieve_sam(database)
154
- assert set(data.index) == keys_per_database[database]
155
- assert item_per_database[database] in data.columns
156
-
157
-
158
- def test_sapm(sapm_module_params):
159
-
160
- times = pd.date_range(start='2015-01-01', periods=5, freq='12h')
161
- effective_irradiance = pd.Series([-1000, 500, 1100, np.nan, 1000],
162
- index=times)
163
- temp_cell = pd.Series([10, 25, 50, 25, np.nan], index=times)
164
-
165
- out = pvsystem.sapm(effective_irradiance, temp_cell, sapm_module_params)
166
-
167
- expected = pd.DataFrame(np.array(
168
- [[-5.0608322, -4.65037767, np.nan, np.nan, np.nan,
169
- -4.91119927, -4.16721569],
170
- [2.545575, 2.28773882, 56.86182059, 47.21121608, 108.00693168,
171
- 2.48357383, 1.71782772],
172
- [5.65584763, 5.01709903, 54.1943277, 42.51861718, 213.32011294,
173
- 5.52987899, 3.46796463],
174
- [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
175
- [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]]),
176
- columns=['i_sc', 'i_mp', 'v_oc', 'v_mp', 'p_mp', 'i_x', 'i_xx'],
177
- index=times)
178
-
179
- assert_frame_equal(out, expected, check_less_precise=4)
180
-
181
- out = pvsystem.sapm(1000, 25, sapm_module_params)
182
-
183
- expected = OrderedDict()
184
- expected['i_sc'] = sapm_module_params['Isco']
185
- expected['i_mp'] = sapm_module_params['Impo']
186
- expected['v_oc'] = sapm_module_params['Voco']
187
- expected['v_mp'] = sapm_module_params['Vmpo']
188
- expected['p_mp'] = sapm_module_params['Impo'] * sapm_module_params['Vmpo']
189
- expected['i_x'] = sapm_module_params['IXO']
190
- expected['i_xx'] = sapm_module_params['IXXO']
191
-
192
- for k, v in expected.items():
193
- assert_allclose(out[k], v, atol=1e-4)
194
-
195
- # just make sure it works with Series input
196
- pvsystem.sapm(effective_irradiance, temp_cell,
197
- pd.Series(sapm_module_params))
198
-
199
-
200
- def test_PVSystem_sapm(sapm_module_params, mocker):
201
- mocker.spy(pvsystem, 'sapm')
202
- system = pvsystem.PVSystem(module_parameters=sapm_module_params)
203
- effective_irradiance = 500
204
- temp_cell = 25
205
- out = system.sapm(effective_irradiance, temp_cell)
206
- pvsystem.sapm.assert_called_once_with(effective_irradiance, temp_cell,
207
- sapm_module_params)
208
- assert_allclose(out['p_mp'], 100, 10)
209
-
210
-
211
- def test_PVSystem_multi_array_sapm(sapm_module_params):
212
- system = pvsystem.PVSystem(
213
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180),
214
- module_parameters=sapm_module_params),
215
- pvsystem.Array(pvsystem.FixedMount(0, 180),
216
- module_parameters=sapm_module_params)]
217
- )
218
- effective_irradiance = (100, 500)
219
- temp_cell = (15, 25)
220
- sapm_one, sapm_two = system.sapm(effective_irradiance, temp_cell)
221
- assert sapm_one['p_mp'] != sapm_two['p_mp']
222
- sapm_one_flip, sapm_two_flip = system.sapm(
223
- (effective_irradiance[1], effective_irradiance[0]),
224
- (temp_cell[1], temp_cell[0])
225
- )
226
- assert sapm_one_flip['p_mp'] == sapm_two['p_mp']
227
- assert sapm_two_flip['p_mp'] == sapm_one['p_mp']
228
- with pytest.raises(ValueError,
229
- match="Length mismatch for per-array parameter"):
230
- system.sapm(effective_irradiance, 10)
231
- with pytest.raises(ValueError,
232
- match="Length mismatch for per-array parameter"):
233
- system.sapm(500, temp_cell)
234
-
235
-
236
- def test_sapm_spectral_loss_deprecated(sapm_module_params):
237
- with pytest.warns(pvlibDeprecationWarning,
238
- match='Use pvlib.spectrum.spectral_factor_sapm'):
239
- pvsystem.sapm_spectral_loss(1, sapm_module_params)
240
-
241
-
242
- def test_PVSystem_sapm_spectral_loss(sapm_module_params, mocker):
243
- mocker.spy(spectrum, 'spectral_factor_sapm')
244
- system = pvsystem.PVSystem(module_parameters=sapm_module_params)
245
- airmass = 2
246
- out = system.sapm_spectral_loss(airmass)
247
- spectrum.spectral_factor_sapm.assert_called_once_with(airmass,
248
- sapm_module_params)
249
- assert_allclose(out, 1, atol=0.5)
250
-
251
-
252
- def test_PVSystem_multi_array_sapm_spectral_loss(sapm_module_params):
253
- system = pvsystem.PVSystem(
254
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180),
255
- module_parameters=sapm_module_params),
256
- pvsystem.Array(pvsystem.FixedMount(0, 180),
257
- module_parameters=sapm_module_params)]
258
- )
259
- loss_one, loss_two = system.sapm_spectral_loss(2)
260
- assert loss_one == loss_two
261
-
262
-
263
- # this test could be improved to cover all cell types.
264
- # could remove the need for specifying spectral coefficients if we don't
265
- # care about the return value at all
266
- @pytest.mark.parametrize('module_parameters,module_type,coefficients', [
267
- ({'Technology': 'mc-Si'}, 'multisi', None),
268
- ({'Material': 'Multi-c-Si'}, 'multisi', None),
269
- ({'first_solar_spectral_coefficients': (
270
- 0.84, -0.03, -0.008, 0.14, 0.04, -0.002)},
271
- None,
272
- (0.84, -0.03, -0.008, 0.14, 0.04, -0.002))
273
- ])
274
- def test_PVSystem_first_solar_spectral_loss(module_parameters, module_type,
275
- coefficients, mocker):
276
- mocker.spy(spectrum, 'spectral_factor_firstsolar')
277
- system = pvsystem.PVSystem(module_parameters=module_parameters)
278
- pw = 3
279
- airmass_absolute = 3
280
- out = system.first_solar_spectral_loss(pw, airmass_absolute)
281
- spectrum.spectral_factor_firstsolar.assert_called_once_with(
282
- pw, airmass_absolute, module_type, coefficients)
283
- assert_allclose(out, 1, atol=0.5)
284
-
285
-
286
- def test_PVSystem_multi_array_first_solar_spectral_loss():
287
- system = pvsystem.PVSystem(
288
- arrays=[
289
- pvsystem.Array(
290
- mount=pvsystem.FixedMount(0, 180),
291
- module_parameters={'Technology': 'mc-Si'},
292
- module_type='multisi'
293
- ),
294
- pvsystem.Array(
295
- mount=pvsystem.FixedMount(0, 180),
296
- module_parameters={'Technology': 'mc-Si'},
297
- module_type='multisi'
298
- )
299
- ]
300
- )
301
- loss_one, loss_two = system.first_solar_spectral_loss(1, 3)
302
- assert loss_one == loss_two
303
-
304
-
305
- @pytest.mark.parametrize('test_input,expected', [
306
- ([1000, 100, 5, 45], 1140.0510967821877),
307
- ([np.array([np.nan, 1000, 1000]),
308
- np.array([100, np.nan, 100]),
309
- np.array([1.1, 1.1, 1.1]),
310
- np.array([10, 10, 10])],
311
- np.array([np.nan, np.nan, 1081.1574])),
312
- ([pd.Series([1000]), pd.Series([100]), pd.Series([1.1]),
313
- pd.Series([10])],
314
- pd.Series([1081.1574]))
315
- ])
316
- def test_sapm_effective_irradiance(sapm_module_params, test_input, expected):
317
- test_input.append(sapm_module_params)
318
- out = pvsystem.sapm_effective_irradiance(*test_input)
319
- if isinstance(test_input, pd.Series):
320
- assert_series_equal(out, expected, check_less_precise=4)
321
- else:
322
- assert_allclose(out, expected, atol=1e-1)
323
-
324
-
325
- def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker):
326
- system = pvsystem.PVSystem(module_parameters=sapm_module_params)
327
- mocker.spy(pvsystem, 'sapm_effective_irradiance')
328
-
329
- poa_direct = 900
330
- poa_diffuse = 100
331
- airmass_absolute = 1.5
332
- aoi = 0
333
- p = (sapm_module_params['A4'], sapm_module_params['A3'],
334
- sapm_module_params['A2'], sapm_module_params['A1'],
335
- sapm_module_params['A0'])
336
- f1 = np.polyval(p, airmass_absolute)
337
- expected = f1 * (poa_direct + sapm_module_params['FD'] * poa_diffuse)
338
- out = system.sapm_effective_irradiance(
339
- poa_direct, poa_diffuse, airmass_absolute, aoi)
340
- pvsystem.sapm_effective_irradiance.assert_called_once_with(
341
- poa_direct, poa_diffuse, airmass_absolute, aoi, sapm_module_params)
342
- assert_allclose(out, expected, atol=0.1)
343
-
344
-
345
- def test_PVSystem_multi_array_sapm_effective_irradiance(sapm_module_params):
346
- system = pvsystem.PVSystem(
347
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180),
348
- module_parameters=sapm_module_params),
349
- pvsystem.Array(pvsystem.FixedMount(0, 180),
350
- module_parameters=sapm_module_params)]
351
- )
352
- poa_direct = (500, 900)
353
- poa_diffuse = (50, 100)
354
- aoi = (0, 10)
355
- airmass_absolute = 1.5
356
- irrad_one, irrad_two = system.sapm_effective_irradiance(
357
- poa_direct, poa_diffuse, airmass_absolute, aoi
358
- )
359
- assert irrad_one != irrad_two
360
-
361
-
362
- @pytest.fixture
363
- def two_array_system(pvsyst_module_params, cec_module_params):
364
- """Two-array PVSystem.
365
-
366
- Both arrays are identical.
367
- """
368
- temperature_model = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
369
- 'open_rack_glass_glass'
370
- ]
371
- # Need u_v to be non-zero so wind-speed changes cell temperature
372
- # under the pvsyst model.
373
- temperature_model['u_v'] = 1.0
374
- # parameter for fuentes temperature model
375
- temperature_model['noct_installed'] = 45
376
- # parameters for noct_sam temperature model
377
- temperature_model['noct'] = 45.
378
- temperature_model['module_efficiency'] = 0.2
379
- module_params = {**pvsyst_module_params, **cec_module_params}
380
- return pvsystem.PVSystem(
381
- arrays=[
382
- pvsystem.Array(
383
- mount=pvsystem.FixedMount(0, 180),
384
- temperature_model_parameters=temperature_model,
385
- module_parameters=module_params
386
- ),
387
- pvsystem.Array(
388
- mount=pvsystem.FixedMount(0, 180),
389
- temperature_model_parameters=temperature_model,
390
- module_parameters=module_params
391
- )
392
- ]
393
- )
394
-
395
-
396
- @pytest.mark.parametrize("poa_direct, poa_diffuse, aoi",
397
- [(20, (10, 10), (20, 20)),
398
- ((20, 20), (10,), (20, 20)),
399
- ((20, 20), (10, 10), 20)])
400
- def test_PVSystem_sapm_effective_irradiance_value_error(
401
- poa_direct, poa_diffuse, aoi, two_array_system):
402
- with pytest.raises(ValueError,
403
- match="Length mismatch for per-array parameter"):
404
- two_array_system.sapm_effective_irradiance(
405
- poa_direct, poa_diffuse, 10, aoi
406
- )
407
-
408
-
409
- def test_PVSystem_sapm_celltemp(mocker):
410
- a, b, deltaT = (-3.47, -0.0594, 3) # open_rack_glass_glass
411
- temp_model_params = {'a': a, 'b': b, 'deltaT': deltaT}
412
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
413
- mocker.spy(temperature, 'sapm_cell')
414
- temps = 25
415
- irrads = 1000
416
- winds = 1
417
- out = system.get_cell_temperature(irrads, temps, winds, model='sapm')
418
- temperature.sapm_cell.assert_called_once_with(irrads, temps, winds, a, b,
419
- deltaT)
420
- assert_allclose(out, 57, atol=1)
421
-
422
-
423
- def test_PVSystem_sapm_celltemp_kwargs(mocker):
424
- temp_model_params = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
425
- 'open_rack_glass_glass']
426
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
427
- mocker.spy(temperature, 'sapm_cell')
428
- temps = 25
429
- irrads = 1000
430
- winds = 1
431
- out = system.get_cell_temperature(irrads, temps, winds, model='sapm')
432
- temperature.sapm_cell.assert_called_once_with(irrads, temps, winds,
433
- temp_model_params['a'],
434
- temp_model_params['b'],
435
- temp_model_params['deltaT'])
436
- assert_allclose(out, 57, atol=1)
437
-
438
-
439
- def test_PVSystem_multi_array_sapm_celltemp_different_arrays():
440
- temp_model_one = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
441
- 'open_rack_glass_glass']
442
- temp_model_two = temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'][
443
- 'close_mount_glass_glass']
444
- system = pvsystem.PVSystem(
445
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180),
446
- temperature_model_parameters=temp_model_one),
447
- pvsystem.Array(pvsystem.FixedMount(0, 180),
448
- temperature_model_parameters=temp_model_two)]
449
- )
450
- temp_one, temp_two = system.get_cell_temperature(
451
- (1000, 1000), 25, 1, model='sapm'
452
- )
453
- assert temp_one != temp_two
454
-
455
-
456
- def test_PVSystem_pvsyst_celltemp(mocker):
457
- parameter_set = 'insulated'
458
- temp_model_params = temperature.TEMPERATURE_MODEL_PARAMETERS['pvsyst'][
459
- parameter_set]
460
- alpha_absorption = 0.85
461
- module_efficiency = 0.17
462
- module_parameters = {'alpha_absorption': alpha_absorption,
463
- 'module_efficiency': module_efficiency}
464
- system = pvsystem.PVSystem(module_parameters=module_parameters,
465
- temperature_model_parameters=temp_model_params)
466
- mocker.spy(temperature, 'pvsyst_cell')
467
- irrad = 800
468
- temp = 45
469
- wind = 0.5
470
- out = system.get_cell_temperature(irrad, temp, wind_speed=wind,
471
- model='pvsyst')
472
- temperature.pvsyst_cell.assert_called_once_with(
473
- irrad, temp, wind_speed=wind, u_c=temp_model_params['u_c'],
474
- u_v=temp_model_params['u_v'], module_efficiency=module_efficiency,
475
- alpha_absorption=alpha_absorption)
476
- assert (out < 90) and (out > 70)
477
-
478
-
479
- def test_PVSystem_faiman_celltemp(mocker):
480
- u0, u1 = 25.0, 6.84 # default values
481
- temp_model_params = {'u0': u0, 'u1': u1}
482
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
483
- mocker.spy(temperature, 'faiman')
484
- temps = 25
485
- irrads = 1000
486
- winds = 1
487
- out = system.get_cell_temperature(irrads, temps, winds, model='faiman')
488
- temperature.faiman.assert_called_once_with(irrads, temps, winds, u0, u1)
489
- assert_allclose(out, 56.4, atol=1e-1)
490
-
491
-
492
- def test_PVSystem_noct_celltemp(mocker):
493
- poa_global, temp_air, wind_speed, noct, module_efficiency = (
494
- 1000., 25., 1., 45., 0.2)
495
- expected = 55.230790492
496
- temp_model_params = {'noct': noct, 'module_efficiency': module_efficiency}
497
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
498
- mocker.spy(temperature, 'noct_sam')
499
- out = system.get_cell_temperature(poa_global, temp_air, wind_speed,
500
- model='noct_sam')
501
- temperature.noct_sam.assert_called_once_with(
502
- poa_global, temp_air, wind_speed, noct, module_efficiency,
503
- effective_irradiance=None)
504
- assert_allclose(out, expected)
505
- # different types
506
- out = system.get_cell_temperature(np.array(poa_global), np.array(temp_air),
507
- np.array(wind_speed), model='noct_sam')
508
- assert_allclose(out, expected)
509
- dr = pd.date_range(start='2020-01-01 12:00:00', end='2020-01-01 13:00:00',
510
- freq='1h')
511
- out = system.get_cell_temperature(pd.Series(index=dr, data=poa_global),
512
- pd.Series(index=dr, data=temp_air),
513
- pd.Series(index=dr, data=wind_speed),
514
- model='noct_sam')
515
- assert_series_equal(out, pd.Series(index=dr, data=expected))
516
- # now use optional arguments
517
- temp_model_params.update({'transmittance_absorptance': 0.8,
518
- 'array_height': 2,
519
- 'mount_standoff': 2.0})
520
- expected = 60.477703576
521
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
522
- out = system.get_cell_temperature(poa_global, temp_air, wind_speed,
523
- effective_irradiance=1100.,
524
- model='noct_sam')
525
- assert_allclose(out, expected)
526
-
527
-
528
- def test_PVSystem_noct_celltemp_error():
529
- poa_global, temp_air, wind_speed, module_efficiency = (1000., 25., 1., 0.2)
530
- temp_model_params = {'module_efficiency': module_efficiency}
531
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
532
- with pytest.raises(KeyError):
533
- system.get_cell_temperature(poa_global, temp_air, wind_speed,
534
- model='noct_sam')
535
-
536
-
537
- @pytest.mark.parametrize("model",
538
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
539
- def test_PVSystem_multi_array_celltemp_functions(model, two_array_system):
540
- times = pd.date_range(start='2020-08-25 11:00', freq='h', periods=3)
541
- irrad_one = pd.Series(1000, index=times)
542
- irrad_two = pd.Series(500, index=times)
543
- temp_air = pd.Series(25, index=times)
544
- wind_speed = pd.Series(1, index=times)
545
-
546
- temp_one, temp_two = two_array_system.get_cell_temperature(
547
- (irrad_one, irrad_two), temp_air, wind_speed, model=model)
548
- assert (temp_one != temp_two).all()
549
-
550
-
551
- @pytest.mark.parametrize("model",
552
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
553
- def test_PVSystem_multi_array_celltemp_multi_temp(model, two_array_system):
554
- times = pd.date_range(start='2020-08-25 11:00', freq='h', periods=3)
555
- irrad = pd.Series(1000, index=times)
556
- temp_air_one = pd.Series(25, index=times)
557
- temp_air_two = pd.Series(5, index=times)
558
- wind_speed = pd.Series(1, index=times)
559
- temp_one, temp_two = two_array_system.get_cell_temperature(
560
- (irrad, irrad),
561
- (temp_air_one, temp_air_two),
562
- wind_speed,
563
- model=model
564
- )
565
- assert (temp_one != temp_two).all()
566
- temp_one_swtich, temp_two_switch = two_array_system.get_cell_temperature(
567
- (irrad, irrad),
568
- (temp_air_two, temp_air_one),
569
- wind_speed,
570
- model=model
571
- )
572
- assert_series_equal(temp_one, temp_two_switch)
573
- assert_series_equal(temp_two, temp_one_swtich)
574
-
575
-
576
- @pytest.mark.parametrize("model",
577
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
578
- def test_PVSystem_multi_array_celltemp_multi_wind(model, two_array_system):
579
- times = pd.date_range(start='2020-08-25 11:00', freq='h', periods=3)
580
- irrad = pd.Series(1000, index=times)
581
- temp_air = pd.Series(25, index=times)
582
- wind_speed_one = pd.Series(1, index=times)
583
- wind_speed_two = pd.Series(5, index=times)
584
- temp_one, temp_two = two_array_system.get_cell_temperature(
585
- (irrad, irrad),
586
- temp_air,
587
- (wind_speed_one, wind_speed_two),
588
- model=model
589
- )
590
- assert (temp_one != temp_two).all()
591
- temp_one_swtich, temp_two_switch = two_array_system.get_cell_temperature(
592
- (irrad, irrad),
593
- temp_air,
594
- (wind_speed_two, wind_speed_one),
595
- model=model
596
- )
597
- assert_series_equal(temp_one, temp_two_switch)
598
- assert_series_equal(temp_two, temp_one_swtich)
599
-
600
-
601
- def test_PVSystem_get_cell_temperature_invalid():
602
- system = pvsystem.PVSystem()
603
- with pytest.raises(ValueError, match='not a valid'):
604
- system.get_cell_temperature(1000, 25, 1, 'not_a_model')
605
-
606
-
607
- @pytest.mark.parametrize("model",
608
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
609
- def test_PVSystem_multi_array_celltemp_temp_too_short(
610
- model, two_array_system):
611
- with pytest.raises(ValueError,
612
- match="Length mismatch for per-array parameter"):
613
- two_array_system.get_cell_temperature((1000, 1000), (1,), 1,
614
- model=model)
615
-
616
-
617
- @pytest.mark.parametrize("model",
618
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
619
- def test_PVSystem_multi_array_celltemp_temp_too_long(
620
- model, two_array_system):
621
- with pytest.raises(ValueError,
622
- match="Length mismatch for per-array parameter"):
623
- two_array_system.get_cell_temperature((1000, 1000), (1, 1, 1), 1,
624
- model=model)
625
-
626
-
627
- @pytest.mark.parametrize("model",
628
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
629
- def test_PVSystem_multi_array_celltemp_wind_too_short(
630
- model, two_array_system):
631
- with pytest.raises(ValueError,
632
- match="Length mismatch for per-array parameter"):
633
- two_array_system.get_cell_temperature((1000, 1000), 25, (1,),
634
- model=model)
635
-
636
-
637
- @pytest.mark.parametrize("model",
638
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
639
- def test_PVSystem_multi_array_celltemp_wind_too_long(
640
- model, two_array_system):
641
- with pytest.raises(ValueError,
642
- match="Length mismatch for per-array parameter"):
643
- two_array_system.get_cell_temperature((1000, 1000), 25, (1, 1, 1),
644
- model=model)
645
-
646
-
647
- @pytest.mark.parametrize("model",
648
- ['faiman', 'pvsyst', 'sapm', 'fuentes', 'noct_sam'])
649
- def test_PVSystem_multi_array_celltemp_poa_length_mismatch(
650
- model, two_array_system):
651
- with pytest.raises(ValueError,
652
- match="Length mismatch for per-array parameter"):
653
- two_array_system.get_cell_temperature(1000, 25, 1, model=model)
654
-
655
-
656
- def test_PVSystem_fuentes_celltemp(mocker):
657
- noct_installed = 45
658
- temp_model_params = {'noct_installed': noct_installed, 'surface_tilt': 0}
659
- system = pvsystem.PVSystem(temperature_model_parameters=temp_model_params)
660
- spy = mocker.spy(temperature, 'fuentes')
661
- index = pd.date_range('2019-01-01 11:00', freq='h', periods=3)
662
- temps = pd.Series(25, index)
663
- irrads = pd.Series(1000, index)
664
- winds = pd.Series(1, index)
665
- out = system.get_cell_temperature(irrads, temps, winds, model='fuentes')
666
- assert_series_equal(spy.call_args[0][0], irrads)
667
- assert_series_equal(spy.call_args[0][1], temps)
668
- assert_series_equal(spy.call_args[0][2], winds)
669
- assert spy.call_args[0][3] == noct_installed
670
- assert_series_equal(out, pd.Series([52.85, 55.85, 55.85], index,
671
- name='tmod'))
672
-
673
-
674
- def test_PVSystem_fuentes_module_height(mocker):
675
- # check that fuentes picks up Array.mount.module_height correctly
676
- # (temperature.fuentes defaults to 5 for module_height)
677
- array = pvsystem.Array(mount=FixedMount(module_height=3),
678
- temperature_model_parameters={'noct_installed': 45})
679
- spy = mocker.spy(temperature, 'fuentes')
680
- index = pd.date_range('2019-01-01 11:00', freq='h', periods=3)
681
- temps = pd.Series(25, index)
682
- irrads = pd.Series(1000, index)
683
- winds = pd.Series(1, index)
684
- _ = array.get_cell_temperature(irrads, temps, winds, model='fuentes')
685
- assert spy.call_args[1]['module_height'] == 3
686
-
687
-
688
- def test_Array__infer_temperature_model_params():
689
- array = pvsystem.Array(mount=FixedMount(0, 180,
690
- racking_model='open_rack'),
691
- module_parameters={},
692
- module_type='glass_polymer')
693
- expected = temperature.TEMPERATURE_MODEL_PARAMETERS[
694
- 'sapm']['open_rack_glass_polymer']
695
- assert expected == array._infer_temperature_model_params()
696
- array = pvsystem.Array(mount=FixedMount(0, 180,
697
- racking_model='freestanding'),
698
- module_parameters={},
699
- module_type='glass_polymer')
700
- expected = temperature.TEMPERATURE_MODEL_PARAMETERS[
701
- 'pvsyst']['freestanding']
702
- assert expected == array._infer_temperature_model_params()
703
- array = pvsystem.Array(mount=FixedMount(0, 180,
704
- racking_model='insulated'),
705
- module_parameters={},
706
- module_type=None)
707
- expected = temperature.TEMPERATURE_MODEL_PARAMETERS[
708
- 'pvsyst']['insulated']
709
- assert expected == array._infer_temperature_model_params()
710
-
711
-
712
- def test_Array__infer_cell_type():
713
- array = pvsystem.Array(mount=pvsystem.FixedMount(0, 180),
714
- module_parameters={})
715
- assert array._infer_cell_type() is None
716
-
717
-
718
- def _calcparams_correct_Python_type_numeric_type_cases():
719
- """
720
- An auxilary function used in the unit tests named
721
- ``test_calcparams_*_returns_correct_Python_type``.
722
-
723
- Returns
724
- -------
725
- Returns a list of tuples of functions intended for transforming a
726
- Python scalar into a numeric type: scalar, np.ndarray, or pandas.Series
727
- """
728
- return list(itertools.product(*(2 * [[
729
- # scalars (e.g. Python floats)
730
- lambda x: x,
731
- # np.ndarrays (0d and 1d-arrays)
732
- np.array,
733
- lambda x: np.array([x]),
734
- # pd.Series (1d-arrays)
735
- pd.Series
736
- ]])))
737
-
738
-
739
- def _calcparams_correct_Python_type_check(out_value, numeric_args):
740
- """
741
- An auxilary function used in the unit tests named
742
- ``test_calcparams_*_returns_correct_Python_type``.
743
-
744
- Parameters
745
- ----------
746
- out_value: numeric
747
- A value returned by a pvsystem.calcparams_ function.
748
-
749
- numeric_args: numeric
750
- An iterable of the numeric-type arguments to the pvsystem.calcparams_
751
- functions: ``effective_irradiance`` and ``temp_cell``.
752
-
753
- Returns
754
- -------
755
- bool indicating whether ``out_value`` has the correct Python type
756
- based on the Python types of ``effective_irradiance`` and
757
- ``temp_cell``.
758
- """
759
- if any(isinstance(a, pd.Series) for a in numeric_args):
760
- return isinstance(out_value, pd.Series)
761
- elif any(isinstance(a, np.ndarray) for a in numeric_args):
762
- return isinstance(out_value, np.ndarray) # 0d or 1d-arrays
763
- return np.isscalar(out_value)
764
-
765
-
766
- @pytest.mark.parametrize('numeric_type_funcs',
767
- _calcparams_correct_Python_type_numeric_type_cases())
768
- def test_calcparams_desoto_returns_correct_Python_type(numeric_type_funcs,
769
- cec_module_params):
770
- numeric_args = dict(
771
- effective_irradiance=numeric_type_funcs[0](800.0),
772
- temp_cell=numeric_type_funcs[1](25),
773
- )
774
- out = pvsystem.calcparams_desoto(
775
- **numeric_args,
776
- alpha_sc=cec_module_params['alpha_sc'],
777
- a_ref=cec_module_params['a_ref'],
778
- I_L_ref=cec_module_params['I_L_ref'],
779
- I_o_ref=cec_module_params['I_o_ref'],
780
- R_sh_ref=cec_module_params['R_sh_ref'],
781
- R_s=cec_module_params['R_s'],
782
- EgRef=1.121,
783
- dEgdT=-0.0002677
784
- )
785
-
786
- assert all(_calcparams_correct_Python_type_check(a, numeric_args.values())
787
- for a in out)
788
-
789
-
790
- @pytest.mark.parametrize('numeric_type_funcs',
791
- _calcparams_correct_Python_type_numeric_type_cases())
792
- def test_calcparams_cec_returns_correct_Python_type(numeric_type_funcs,
793
- cec_module_params):
794
- numeric_args = dict(
795
- effective_irradiance=numeric_type_funcs[0](800.0),
796
- temp_cell=numeric_type_funcs[1](25),
797
- )
798
- out = pvsystem.calcparams_cec(
799
- **numeric_args,
800
- alpha_sc=cec_module_params['alpha_sc'],
801
- a_ref=cec_module_params['a_ref'],
802
- I_L_ref=cec_module_params['I_L_ref'],
803
- I_o_ref=cec_module_params['I_o_ref'],
804
- R_sh_ref=cec_module_params['R_sh_ref'],
805
- R_s=cec_module_params['R_s'],
806
- Adjust=cec_module_params['Adjust'],
807
- EgRef=1.121,
808
- dEgdT=-0.0002677
809
- )
810
-
811
- assert all(_calcparams_correct_Python_type_check(a, numeric_args.values())
812
- for a in out)
813
-
814
-
815
- @pytest.mark.parametrize('numeric_type_funcs',
816
- _calcparams_correct_Python_type_numeric_type_cases())
817
- def test_calcparams_pvsyst_returns_correct_Python_type(numeric_type_funcs,
818
- pvsyst_module_params):
819
- numeric_args = dict(
820
- effective_irradiance=numeric_type_funcs[0](800.0),
821
- temp_cell=numeric_type_funcs[1](25),
822
- )
823
- out = pvsystem.calcparams_pvsyst(
824
- **numeric_args,
825
- alpha_sc=pvsyst_module_params['alpha_sc'],
826
- gamma_ref=pvsyst_module_params['gamma_ref'],
827
- mu_gamma=pvsyst_module_params['mu_gamma'],
828
- I_L_ref=pvsyst_module_params['I_L_ref'],
829
- I_o_ref=pvsyst_module_params['I_o_ref'],
830
- R_sh_ref=pvsyst_module_params['R_sh_ref'],
831
- R_sh_0=pvsyst_module_params['R_sh_0'],
832
- R_s=pvsyst_module_params['R_s'],
833
- cells_in_series=pvsyst_module_params['cells_in_series'],
834
- EgRef=pvsyst_module_params['EgRef']
835
- )
836
-
837
- assert all(_calcparams_correct_Python_type_check(a, numeric_args.values())
838
- for a in out)
839
-
840
-
841
- def test_calcparams_desoto_all_scalars(cec_module_params):
842
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
843
- effective_irradiance=800.0,
844
- temp_cell=25,
845
- alpha_sc=cec_module_params['alpha_sc'],
846
- a_ref=cec_module_params['a_ref'],
847
- I_L_ref=cec_module_params['I_L_ref'],
848
- I_o_ref=cec_module_params['I_o_ref'],
849
- R_sh_ref=cec_module_params['R_sh_ref'],
850
- R_s=cec_module_params['R_s'],
851
- EgRef=1.121,
852
- dEgdT=-0.0002677
853
- )
854
-
855
- assert np.isclose(IL, 6.036, atol=1e-4, rtol=0)
856
- assert np.isclose(I0, 1.94e-9, atol=1e-4, rtol=0)
857
- assert np.isclose(Rs, 0.094, atol=1e-4, rtol=0)
858
- assert np.isclose(Rsh, 19.65, atol=1e-4, rtol=0)
859
- assert np.isclose(nNsVth, 0.473, atol=1e-4, rtol=0)
860
-
861
-
862
- def test_calcparams_cec_all_scalars(cec_module_params):
863
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_cec(
864
- effective_irradiance=800.0,
865
- temp_cell=25,
866
- alpha_sc=cec_module_params['alpha_sc'],
867
- a_ref=cec_module_params['a_ref'],
868
- I_L_ref=cec_module_params['I_L_ref'],
869
- I_o_ref=cec_module_params['I_o_ref'],
870
- R_sh_ref=cec_module_params['R_sh_ref'],
871
- R_s=cec_module_params['R_s'],
872
- Adjust=cec_module_params['Adjust'],
873
- EgRef=1.121,
874
- dEgdT=-0.0002677
875
- )
876
-
877
- assert np.isclose(IL, 6.036, atol=1e-4, rtol=0)
878
- assert np.isclose(I0, 1.94e-9, atol=1e-4, rtol=0)
879
- assert np.isclose(Rs, 0.094, atol=1e-4, rtol=0)
880
- assert np.isclose(Rsh, 19.65, atol=1e-4, rtol=0)
881
- assert np.isclose(nNsVth, 0.473, atol=1e-4, rtol=0)
882
-
883
-
884
- def test_calcparams_pvsyst_all_scalars(pvsyst_module_params):
885
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_pvsyst(
886
- effective_irradiance=800.0,
887
- temp_cell=50,
888
- alpha_sc=pvsyst_module_params['alpha_sc'],
889
- gamma_ref=pvsyst_module_params['gamma_ref'],
890
- mu_gamma=pvsyst_module_params['mu_gamma'],
891
- I_L_ref=pvsyst_module_params['I_L_ref'],
892
- I_o_ref=pvsyst_module_params['I_o_ref'],
893
- R_sh_ref=pvsyst_module_params['R_sh_ref'],
894
- R_sh_0=pvsyst_module_params['R_sh_0'],
895
- R_s=pvsyst_module_params['R_s'],
896
- cells_in_series=pvsyst_module_params['cells_in_series'],
897
- EgRef=pvsyst_module_params['EgRef'])
898
-
899
- assert np.isclose(IL, 4.8200, atol=1e-4, rtol=0)
900
- assert np.isclose(I0, 1.47e-7, atol=1e-4, rtol=0)
901
- assert np.isclose(Rs, 0.500, atol=1e-4, rtol=0)
902
- assert np.isclose(Rsh, 305.757, atol=1e-4, rtol=0)
903
- assert np.isclose(nNsVth, 1.7961, atol=1e-4, rtol=0)
904
-
905
-
906
- def test_calcparams_desoto(cec_module_params):
907
- times = pd.date_range(start='2015-01-01', periods=3, freq='12h')
908
- df = pd.DataFrame({
909
- 'effective_irradiance': [0.0, 800.0, 800.0],
910
- 'temp_cell': [25, 25, 50]
911
- }, index=times)
912
-
913
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
914
- df['effective_irradiance'],
915
- df['temp_cell'],
916
- alpha_sc=cec_module_params['alpha_sc'],
917
- a_ref=cec_module_params['a_ref'],
918
- I_L_ref=cec_module_params['I_L_ref'],
919
- I_o_ref=cec_module_params['I_o_ref'],
920
- R_sh_ref=cec_module_params['R_sh_ref'],
921
- R_s=cec_module_params['R_s'],
922
- EgRef=1.121,
923
- dEgdT=-0.0002677
924
- )
925
-
926
- assert_series_equal(IL, pd.Series([0.0, 6.036, 6.096], index=times),
927
- check_less_precise=3)
928
- assert_series_equal(I0, pd.Series([0.0, 1.94e-9, 7.419e-8], index=times),
929
- check_less_precise=3)
930
- assert_series_equal(Rs, pd.Series([0.094, 0.094, 0.094], index=times),
931
- check_less_precise=3)
932
- assert_series_equal(Rsh, pd.Series([np.inf, 19.65, 19.65], index=times),
933
- check_less_precise=3)
934
- assert_series_equal(nNsVth, pd.Series([0.473, 0.473, 0.5127], index=times),
935
- check_less_precise=3)
936
-
937
-
938
- def test_calcparams_cec(cec_module_params):
939
- times = pd.date_range(start='2015-01-01', periods=3, freq='12h')
940
- df = pd.DataFrame({
941
- 'effective_irradiance': [0.0, 800.0, 800.0],
942
- 'temp_cell': [25, 25, 50]
943
- }, index=times)
944
-
945
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_cec(
946
- df['effective_irradiance'],
947
- df['temp_cell'],
948
- alpha_sc=cec_module_params['alpha_sc'],
949
- a_ref=cec_module_params['a_ref'],
950
- I_L_ref=cec_module_params['I_L_ref'],
951
- I_o_ref=cec_module_params['I_o_ref'],
952
- R_sh_ref=cec_module_params['R_sh_ref'],
953
- R_s=cec_module_params['R_s'],
954
- Adjust=cec_module_params['Adjust'],
955
- EgRef=1.121,
956
- dEgdT=-0.0002677
957
- )
958
-
959
- assert_series_equal(IL, pd.Series([0.0, 6.036, 6.0896], index=times),
960
- check_less_precise=3)
961
- assert_series_equal(I0, pd.Series([0.0, 1.94e-9, 7.419e-8], index=times),
962
- check_less_precise=3)
963
- assert_series_equal(Rs, pd.Series([0.094, 0.094, 0.094], index=times),
964
- check_less_precise=3)
965
- assert_series_equal(Rsh, pd.Series([np.inf, 19.65, 19.65], index=times),
966
- check_less_precise=3)
967
- assert_series_equal(nNsVth, pd.Series([0.473, 0.473, 0.5127], index=times),
968
- check_less_precise=3)
969
-
970
-
971
- def test_calcparams_cec_extra_params_propagation(cec_module_params, mocker):
972
- """
973
- See bug #1215.
974
-
975
- When calling `calcparams_cec`, the parameters `EgRef`, `dEgdT`, `irrad_ref`
976
- and `temp_ref` must not be ignored.
977
-
978
- Since, internally, this function is calling `calcparams_desoto`, this test
979
- checks that the latter is called with the expected parameters instead of
980
- some default values.
981
- """
982
- times = pd.date_range(start='2015-01-01', periods=3, freq='12h')
983
- effective_irradiance = pd.Series([0.0, 800.0, 800.0], index=times)
984
- temp_cell = pd.Series([25, 25, 50], index=times)
985
- extra_parameters = dict(
986
- EgRef=1.123,
987
- dEgdT=-0.0002688,
988
- irrad_ref=1100,
989
- temp_ref=23,
990
- )
991
- m = mocker.spy(pvsystem, 'calcparams_desoto')
992
- pvsystem.calcparams_cec(
993
- effective_irradiance=effective_irradiance,
994
- temp_cell=temp_cell,
995
- alpha_sc=cec_module_params['alpha_sc'],
996
- a_ref=cec_module_params['a_ref'],
997
- I_L_ref=cec_module_params['I_L_ref'],
998
- I_o_ref=cec_module_params['I_o_ref'],
999
- R_sh_ref=cec_module_params['R_sh_ref'],
1000
- R_s=cec_module_params['R_s'],
1001
- Adjust=cec_module_params['Adjust'],
1002
- **extra_parameters,
1003
- )
1004
- assert m.call_count == 1
1005
- assert m.call_args[1] == extra_parameters
1006
-
1007
-
1008
- def test_calcparams_pvsyst(pvsyst_module_params):
1009
- times = pd.date_range(start='2015-01-01', periods=2, freq='12h')
1010
- df = pd.DataFrame({
1011
- 'effective_irradiance': [0.0, 800.0],
1012
- 'temp_cell': [25, 50]
1013
- }, index=times)
1014
-
1015
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_pvsyst(
1016
- df['effective_irradiance'],
1017
- df['temp_cell'],
1018
- alpha_sc=pvsyst_module_params['alpha_sc'],
1019
- gamma_ref=pvsyst_module_params['gamma_ref'],
1020
- mu_gamma=pvsyst_module_params['mu_gamma'],
1021
- I_L_ref=pvsyst_module_params['I_L_ref'],
1022
- I_o_ref=pvsyst_module_params['I_o_ref'],
1023
- R_sh_ref=pvsyst_module_params['R_sh_ref'],
1024
- R_sh_0=pvsyst_module_params['R_sh_0'],
1025
- R_s=pvsyst_module_params['R_s'],
1026
- cells_in_series=pvsyst_module_params['cells_in_series'],
1027
- EgRef=pvsyst_module_params['EgRef'])
1028
-
1029
- assert_series_equal(
1030
- IL.round(decimals=3), pd.Series([0.0, 4.8200], index=times))
1031
- assert_series_equal(
1032
- I0.round(decimals=3), pd.Series([0.0, 1.47e-7], index=times))
1033
- assert_series_equal(
1034
- Rs.round(decimals=3), pd.Series([0.500, 0.500], index=times))
1035
- assert_series_equal(
1036
- Rsh.round(decimals=3), pd.Series([1000.0, 305.757], index=times))
1037
- assert_series_equal(
1038
- nNsVth.round(decimals=4), pd.Series([1.6186, 1.7961], index=times))
1039
-
1040
-
1041
- def test_PVSystem_calcparams_desoto(cec_module_params, mocker):
1042
- mocker.spy(pvsystem, 'calcparams_desoto')
1043
- module_parameters = cec_module_params.copy()
1044
- module_parameters['EgRef'] = 1.121
1045
- module_parameters['dEgdT'] = -0.0002677
1046
- system = pvsystem.PVSystem(module_parameters=module_parameters)
1047
- effective_irradiance = np.array([0, 800])
1048
- temp_cell = 25
1049
- IL, I0, Rs, Rsh, nNsVth = system.calcparams_desoto(effective_irradiance,
1050
- temp_cell)
1051
- pvsystem.calcparams_desoto.assert_called_once_with(
1052
- effective_irradiance,
1053
- temp_cell,
1054
- alpha_sc=cec_module_params['alpha_sc'],
1055
- a_ref=cec_module_params['a_ref'],
1056
- I_L_ref=cec_module_params['I_L_ref'],
1057
- I_o_ref=cec_module_params['I_o_ref'],
1058
- R_sh_ref=cec_module_params['R_sh_ref'],
1059
- R_s=cec_module_params['R_s'],
1060
- EgRef=module_parameters['EgRef'],
1061
- dEgdT=module_parameters['dEgdT']
1062
- )
1063
-
1064
- assert_allclose(IL, np.array([0.0, 6.036]), atol=1e-1)
1065
- assert_allclose(I0, np.array([2.0e-9, 2.0e-9]), atol=1.0e-9)
1066
- assert_allclose(Rs, np.array([0.1, 0.1]), atol=0.1)
1067
- assert_allclose(Rsh, np.array([np.inf, 20]), atol=1)
1068
- assert_allclose(nNsVth, np.array([0.5, 0.5]), atol=0.1)
1069
-
1070
-
1071
- def test_PVSystem_calcparams_pvsyst(pvsyst_module_params, mocker):
1072
- mocker.spy(pvsystem, 'calcparams_pvsyst')
1073
- module_parameters = pvsyst_module_params.copy()
1074
- system = pvsystem.PVSystem(module_parameters=module_parameters)
1075
- effective_irradiance = np.array([0, 800])
1076
- temp_cell = np.array([25, 50])
1077
- IL, I0, Rs, Rsh, nNsVth = system.calcparams_pvsyst(effective_irradiance,
1078
- temp_cell)
1079
- pvsystem.calcparams_pvsyst.assert_called_once_with(
1080
- effective_irradiance,
1081
- temp_cell,
1082
- alpha_sc=pvsyst_module_params['alpha_sc'],
1083
- gamma_ref=pvsyst_module_params['gamma_ref'],
1084
- mu_gamma=pvsyst_module_params['mu_gamma'],
1085
- I_L_ref=pvsyst_module_params['I_L_ref'],
1086
- I_o_ref=pvsyst_module_params['I_o_ref'],
1087
- R_sh_ref=pvsyst_module_params['R_sh_ref'],
1088
- R_sh_0=pvsyst_module_params['R_sh_0'],
1089
- R_s=pvsyst_module_params['R_s'],
1090
- cells_in_series=pvsyst_module_params['cells_in_series'],
1091
- EgRef=pvsyst_module_params['EgRef'],
1092
- R_sh_exp=pvsyst_module_params['R_sh_exp']
1093
- )
1094
-
1095
- assert_allclose(IL, np.array([0.0, 4.8200]), atol=1)
1096
- assert_allclose(I0, np.array([0.0, 1.47e-7]), atol=1.0e-5)
1097
- assert_allclose(Rs, np.array([0.5, 0.5]), atol=0.1)
1098
- assert_allclose(Rsh, np.array([1000, 305.757]), atol=50)
1099
- assert_allclose(nNsVth, np.array([1.6186, 1.7961]), atol=0.1)
1100
-
1101
-
1102
- @pytest.mark.parametrize('calcparams', [pvsystem.PVSystem.calcparams_pvsyst,
1103
- pvsystem.PVSystem.calcparams_desoto,
1104
- pvsystem.PVSystem.calcparams_cec])
1105
- def test_PVSystem_multi_array_calcparams(calcparams, two_array_system):
1106
- params_one, params_two = calcparams(
1107
- two_array_system, (1000, 500), (30, 20)
1108
- )
1109
- assert params_one != params_two
1110
-
1111
-
1112
- @pytest.mark.parametrize('calcparams, irrad, celltemp',
1113
- [ (f, irrad, celltemp)
1114
- for f in (pvsystem.PVSystem.calcparams_desoto,
1115
- pvsystem.PVSystem.calcparams_cec,
1116
- pvsystem.PVSystem.calcparams_pvsyst)
1117
- for irrad, celltemp in [(1, (1, 1)), ((1, 1), 1)]])
1118
- def test_PVSystem_multi_array_calcparams_value_error(
1119
- calcparams, irrad, celltemp, two_array_system):
1120
- with pytest.raises(ValueError,
1121
- match='Length mismatch for per-array parameter'):
1122
- calcparams(two_array_system, irrad, celltemp)
1123
-
1124
-
1125
- @pytest.fixture(params=[
1126
- { # Can handle all python scalar inputs
1127
- 'Rsh': 20.,
1128
- 'Rs': 0.1,
1129
- 'nNsVth': 0.5,
1130
- 'I': 3.,
1131
- 'I0': 6.e-7,
1132
- 'IL': 7.,
1133
- 'V_expected': 7.5049875193450521
1134
- },
1135
- { # Can handle all rank-0 array inputs
1136
- 'Rsh': np.array(20.),
1137
- 'Rs': np.array(0.1),
1138
- 'nNsVth': np.array(0.5),
1139
- 'I': np.array(3.),
1140
- 'I0': np.array(6.e-7),
1141
- 'IL': np.array(7.),
1142
- 'V_expected': np.array(7.5049875193450521)
1143
- },
1144
- { # Can handle all rank-1 singleton array inputs
1145
- 'Rsh': np.array([20.]),
1146
- 'Rs': np.array([0.1]),
1147
- 'nNsVth': np.array([0.5]),
1148
- 'I': np.array([3.]),
1149
- 'I0': np.array([6.e-7]),
1150
- 'IL': np.array([7.]),
1151
- 'V_expected': np.array([7.5049875193450521])
1152
- },
1153
- { # Can handle all rank-1 non-singleton array inputs with infinite shunt
1154
- # resistance, Rsh=inf gives V=Voc=nNsVth*(np.log(IL + I0) - np.log(I0)
1155
- # at I=0
1156
- 'Rsh': np.array([np.inf, 20.]),
1157
- 'Rs': np.array([0.1, 0.1]),
1158
- 'nNsVth': np.array([0.5, 0.5]),
1159
- 'I': np.array([0., 3.]),
1160
- 'I0': np.array([6.e-7, 6.e-7]),
1161
- 'IL': np.array([7., 7.]),
1162
- 'V_expected': np.array([0.5*(np.log(7. + 6.e-7) - np.log(6.e-7)),
1163
- 7.5049875193450521])
1164
- },
1165
- { # Can handle mixed inputs with a rank-2 array with infinite shunt
1166
- # resistance, Rsh=inf gives V=Voc=nNsVth*(np.log(IL + I0) - np.log(I0)
1167
- # at I=0
1168
- 'Rsh': np.array([[np.inf, np.inf], [np.inf, np.inf]]),
1169
- 'Rs': np.array([0.1]),
1170
- 'nNsVth': np.array(0.5),
1171
- 'I': 0.,
1172
- 'I0': np.array([6.e-7]),
1173
- 'IL': np.array([7.]),
1174
- 'V_expected': 0.5*(np.log(7. + 6.e-7) - np.log(6.e-7))*np.ones((2, 2))
1175
- },
1176
- { # Can handle ideal series and shunt, Rsh=inf and Rs=0 give
1177
- # V = nNsVth*(np.log(IL - I + I0) - np.log(I0))
1178
- 'Rsh': np.inf,
1179
- 'Rs': 0.,
1180
- 'nNsVth': 0.5,
1181
- 'I': np.array([7., 7./2., 0.]),
1182
- 'I0': 6.e-7,
1183
- 'IL': 7.,
1184
- 'V_expected': np.array([0., 0.5*(np.log(7. - 7./2. + 6.e-7) -
1185
- np.log(6.e-7)), 0.5*(np.log(7. + 6.e-7) -
1186
- np.log(6.e-7))])
1187
- },
1188
- { # Can handle only ideal series resistance, no closed form solution
1189
- 'Rsh': 20.,
1190
- 'Rs': 0.,
1191
- 'nNsVth': 0.5,
1192
- 'I': 3.,
1193
- 'I0': 6.e-7,
1194
- 'IL': 7.,
1195
- 'V_expected': 7.804987519345062
1196
- },
1197
- { # Can handle all python scalar inputs with big LambertW arg
1198
- 'Rsh': 500.,
1199
- 'Rs': 10.,
1200
- 'nNsVth': 4.06,
1201
- 'I': 0.,
1202
- 'I0': 6.e-10,
1203
- 'IL': 1.2,
1204
- 'V_expected': 86.320000493521079
1205
- },
1206
- { # Can handle all python scalar inputs with bigger LambertW arg
1207
- # 1000 W/m^2 on a Canadian Solar 220M with 20 C ambient temp
1208
- # github issue 225 (this appears to be from PR 226 not issue 225)
1209
- 'Rsh': 190.,
1210
- 'Rs': 1.065,
1211
- 'nNsVth': 2.89,
1212
- 'I': 0.,
1213
- 'I0': 7.05196029e-08,
1214
- 'IL': 10.491262,
1215
- 'V_expected': 54.303958833791455
1216
- },
1217
- { # Can handle all python scalar inputs with bigger LambertW arg
1218
- # 1000 W/m^2 on a Canadian Solar 220M with 20 C ambient temp
1219
- # github issue 225
1220
- 'Rsh': 381.68,
1221
- 'Rs': 1.065,
1222
- 'nNsVth': 2.681527737715915,
1223
- 'I': 0.,
1224
- 'I0': 1.8739027472625636e-09,
1225
- 'IL': 5.1366949999999996,
1226
- 'V_expected': 58.19323124611128
1227
- },
1228
- { # Verify mixed solution type indexing logic
1229
- 'Rsh': np.array([np.inf, 190., 381.68]),
1230
- 'Rs': 1.065,
1231
- 'nNsVth': np.array([2.89, 2.89, 2.681527737715915]),
1232
- 'I': 0.,
1233
- 'I0': np.array([7.05196029e-08, 7.05196029e-08, 1.8739027472625636e-09]),
1234
- 'IL': np.array([10.491262, 10.491262, 5.1366949999999996]),
1235
- 'V_expected': np.array([2.89*np.log1p(10.491262/7.05196029e-08),
1236
- 54.303958833791455, 58.19323124611128])
1237
- }])
1238
- def fixture_v_from_i(request):
1239
- return request.param
1240
-
1241
-
1242
- @pytest.mark.parametrize(
1243
- 'method, atol', [('lambertw', 1e-11), ('brentq', 1e-11), ('newton', 1e-8)]
1244
- )
1245
- def test_v_from_i(fixture_v_from_i, method, atol):
1246
- # Solution set loaded from fixture
1247
- Rsh = fixture_v_from_i['Rsh']
1248
- Rs = fixture_v_from_i['Rs']
1249
- nNsVth = fixture_v_from_i['nNsVth']
1250
- I = fixture_v_from_i['I']
1251
- I0 = fixture_v_from_i['I0']
1252
- IL = fixture_v_from_i['IL']
1253
- V_expected = fixture_v_from_i['V_expected']
1254
-
1255
- V = pvsystem.v_from_i(I, IL, I0, Rs, Rsh, nNsVth, method=method)
1256
-
1257
- assert isinstance(V, type(V_expected))
1258
- if isinstance(V, np.ndarray):
1259
- assert isinstance(V.dtype, type(V_expected.dtype))
1260
- assert V.shape == V_expected.shape
1261
- assert_allclose(V, V_expected, atol=atol)
1262
-
1263
-
1264
- def test_i_from_v_from_i(fixture_v_from_i):
1265
- # Solution set loaded from fixture
1266
- Rsh = fixture_v_from_i['Rsh']
1267
- Rs = fixture_v_from_i['Rs']
1268
- nNsVth = fixture_v_from_i['nNsVth']
1269
- current = fixture_v_from_i['I']
1270
- I0 = fixture_v_from_i['I0']
1271
- IL = fixture_v_from_i['IL']
1272
- V = fixture_v_from_i['V_expected']
1273
-
1274
- # Convergence criteria
1275
- atol = 1.e-11
1276
-
1277
- I_expected = pvsystem.i_from_v(V, IL, I0, Rs, Rsh, nNsVth,
1278
- method='lambertw')
1279
- assert_allclose(current, I_expected, atol=atol)
1280
-
1281
- current = pvsystem.i_from_v(V, IL, I0, Rs, Rsh, nNsVth)
1282
-
1283
- assert isinstance(current, type(I_expected))
1284
- if isinstance(current, np.ndarray):
1285
- assert isinstance(current.dtype, type(I_expected.dtype))
1286
- assert current.shape == I_expected.shape
1287
- assert_allclose(current, I_expected, atol=atol)
1288
-
1289
-
1290
- @pytest.fixture(params=[
1291
- { # Can handle all python scalar inputs
1292
- 'Rsh': 20.,
1293
- 'Rs': 0.1,
1294
- 'nNsVth': 0.5,
1295
- 'V': 7.5049875193450521,
1296
- 'I0': 6.e-7,
1297
- 'IL': 7.,
1298
- 'I_expected': 3.
1299
- },
1300
- { # Can handle all rank-0 array inputs
1301
- 'Rsh': np.array(20.),
1302
- 'Rs': np.array(0.1),
1303
- 'nNsVth': np.array(0.5),
1304
- 'V': np.array(7.5049875193450521),
1305
- 'I0': np.array(6.e-7),
1306
- 'IL': np.array(7.),
1307
- 'I_expected': np.array(3.)
1308
- },
1309
- { # Can handle all rank-1 singleton array inputs
1310
- 'Rsh': np.array([20.]),
1311
- 'Rs': np.array([0.1]),
1312
- 'nNsVth': np.array([0.5]),
1313
- 'V': np.array([7.5049875193450521]),
1314
- 'I0': np.array([6.e-7]),
1315
- 'IL': np.array([7.]),
1316
- 'I_expected': np.array([3.])
1317
- },
1318
- { # Can handle all rank-1 non-singleton array inputs with a zero
1319
- # series resistance, Rs=0 gives I=IL=Isc at V=0
1320
- 'Rsh': np.array([20., 20.]),
1321
- 'Rs': np.array([0., 0.1]),
1322
- 'nNsVth': np.array([0.5, 0.5]),
1323
- 'V': np.array([0., 7.5049875193450521]),
1324
- 'I0': np.array([6.e-7, 6.e-7]),
1325
- 'IL': np.array([7., 7.]),
1326
- 'I_expected': np.array([7., 3.])
1327
- },
1328
- { # Can handle mixed inputs with a rank-2 array with zero series
1329
- # resistance, Rs=0 gives I=IL=Isc at V=0
1330
- 'Rsh': np.array([20.]),
1331
- 'Rs': np.array([[0., 0.], [0., 0.]]),
1332
- 'nNsVth': np.array(0.5),
1333
- 'V': 0.,
1334
- 'I0': np.array([6.e-7]),
1335
- 'IL': np.array([7.]),
1336
- 'I_expected': np.array([[7., 7.], [7., 7.]])
1337
- },
1338
- { # Can handle ideal series and shunt, Rsh=inf and Rs=0 give
1339
- # V_oc = nNsVth*(np.log(IL + I0) - np.log(I0))
1340
- 'Rsh': np.inf,
1341
- 'Rs': 0.,
1342
- 'nNsVth': 0.5,
1343
- 'V': np.array([0., 0.5*(np.log(7. + 6.e-7) - np.log(6.e-7))/2.,
1344
- 0.5*(np.log(7. + 6.e-7) - np.log(6.e-7))]),
1345
- 'I0': 6.e-7,
1346
- 'IL': 7.,
1347
- 'I_expected': np.array([7., 7. - 6.e-7*np.expm1((np.log(7. + 6.e-7) -
1348
- np.log(6.e-7))/2.), 0.])
1349
- },
1350
- { # Can handle only ideal shunt resistance, no closed form solution
1351
- 'Rsh': np.inf,
1352
- 'Rs': 0.1,
1353
- 'nNsVth': 0.5,
1354
- 'V': 7.5049875193450521,
1355
- 'I0': 6.e-7,
1356
- 'IL': 7.,
1357
- 'I_expected': 3.2244873645510923
1358
- }])
1359
- def fixture_i_from_v(request):
1360
- return request.param
1361
-
1362
-
1363
- @pytest.mark.parametrize(
1364
- 'method, atol', [('lambertw', 1e-11), ('brentq', 1e-11), ('newton', 1e-11)]
1365
- )
1366
- def test_i_from_v(fixture_i_from_v, method, atol):
1367
- # Solution set loaded from fixture
1368
- Rsh = fixture_i_from_v['Rsh']
1369
- Rs = fixture_i_from_v['Rs']
1370
- nNsVth = fixture_i_from_v['nNsVth']
1371
- V = fixture_i_from_v['V']
1372
- I0 = fixture_i_from_v['I0']
1373
- IL = fixture_i_from_v['IL']
1374
- I_expected = fixture_i_from_v['I_expected']
1375
-
1376
- current = pvsystem.i_from_v(V, IL, I0, Rs, Rsh, nNsVth, method=method)
1377
-
1378
- assert isinstance(current, type(I_expected))
1379
- if isinstance(current, np.ndarray):
1380
- assert isinstance(current.dtype, type(I_expected.dtype))
1381
- assert current.shape == I_expected.shape
1382
- assert_allclose(current, I_expected, atol=atol)
1383
-
1384
-
1385
- def test_PVSystem_i_from_v(mocker):
1386
- system = pvsystem.PVSystem()
1387
- m = mocker.patch('pvlib.pvsystem.i_from_v', autospec=True)
1388
- args = (7.5049875193450521, 7, 6e-7, 0.1, 20, 0.5)
1389
- system.i_from_v(*args)
1390
- m.assert_called_once_with(*args)
1391
-
1392
-
1393
- def test_i_from_v_size():
1394
- with pytest.raises(ValueError):
1395
- pvsystem.i_from_v([7.5] * 3, 7., 6e-7, [0.1] * 2, 20, 0.5)
1396
- with pytest.raises(ValueError):
1397
- pvsystem.i_from_v([7.5] * 3, 7., 6e-7, [0.1] * 2, 20, 0.5,
1398
- method='brentq')
1399
- with pytest.raises(ValueError):
1400
- pvsystem.i_from_v([7.5] * 3, np.array([7., 7.]), 6e-7, 0.1, 20, 0.5,
1401
- method='newton')
1402
-
1403
-
1404
- def test_v_from_i_size():
1405
- with pytest.raises(ValueError):
1406
- pvsystem.v_from_i([3.] * 3, 7., 6e-7, [0.1] * 2, 20, 0.5)
1407
- with pytest.raises(ValueError):
1408
- pvsystem.v_from_i([3.] * 3, 7., 6e-7, [0.1] * 2, 20, 0.5,
1409
- method='brentq')
1410
- with pytest.raises(ValueError):
1411
- pvsystem.v_from_i([3.] * 3, np.array([7., 7.]), 6e-7, [0.1], 20, 0.5,
1412
- method='newton')
1413
-
1414
-
1415
- def test_mpp_floats():
1416
- """test max_power_point"""
1417
- IL, I0, Rs, Rsh, nNsVth = (7, 6e-7, .1, 20, .5)
1418
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='brentq')
1419
- expected = {'i_mp': 6.1362673597376753, # 6.1390251797935704, lambertw
1420
- 'v_mp': 6.2243393757884284, # 6.221535886625464, lambertw
1421
- 'p_mp': 38.194210547580511} # 38.194165464983037} lambertw
1422
- assert isinstance(out, dict)
1423
- for k, v in out.items():
1424
- assert np.isclose(v, expected[k])
1425
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='newton')
1426
- for k, v in out.items():
1427
- assert np.isclose(v, expected[k])
1428
-
1429
-
1430
- def test_mpp_recombination():
1431
- """test max_power_point"""
1432
- pvsyst_fs_495 = get_pvsyst_fs_495()
1433
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_pvsyst(
1434
- effective_irradiance=pvsyst_fs_495['irrad_ref'],
1435
- temp_cell=pvsyst_fs_495['temp_ref'],
1436
- alpha_sc=pvsyst_fs_495['alpha_sc'],
1437
- gamma_ref=pvsyst_fs_495['gamma_ref'],
1438
- mu_gamma=pvsyst_fs_495['mu_gamma'], I_L_ref=pvsyst_fs_495['I_L_ref'],
1439
- I_o_ref=pvsyst_fs_495['I_o_ref'], R_sh_ref=pvsyst_fs_495['R_sh_ref'],
1440
- R_sh_0=pvsyst_fs_495['R_sh_0'], R_sh_exp=pvsyst_fs_495['R_sh_exp'],
1441
- R_s=pvsyst_fs_495['R_s'],
1442
- cells_in_series=pvsyst_fs_495['cells_in_series'],
1443
- EgRef=pvsyst_fs_495['EgRef'])
1444
- out = pvsystem.max_power_point(
1445
- IL, I0, Rs, Rsh, nNsVth,
1446
- d2mutau=pvsyst_fs_495['d2mutau'],
1447
- NsVbi=VOLTAGE_BUILTIN*pvsyst_fs_495['cells_in_series'],
1448
- method='brentq')
1449
- expected_imp = pvsyst_fs_495['I_mp_ref']
1450
- expected_vmp = pvsyst_fs_495['V_mp_ref']
1451
- expected_pmp = expected_imp*expected_vmp
1452
- expected = {'i_mp': expected_imp,
1453
- 'v_mp': expected_vmp,
1454
- 'p_mp': expected_pmp}
1455
- assert isinstance(out, dict)
1456
- for k, v in out.items():
1457
- assert np.isclose(v, expected[k], 0.01)
1458
- out = pvsystem.max_power_point(
1459
- IL, I0, Rs, Rsh, nNsVth,
1460
- d2mutau=pvsyst_fs_495['d2mutau'],
1461
- NsVbi=VOLTAGE_BUILTIN*pvsyst_fs_495['cells_in_series'],
1462
- method='newton')
1463
- for k, v in out.items():
1464
- assert np.isclose(v, expected[k], 0.01)
1465
-
1466
-
1467
- def test_mpp_array():
1468
- """test max_power_point"""
1469
- IL, I0, Rs, Rsh, nNsVth = (np.array([7, 7]), 6e-7, .1, 20, .5)
1470
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='brentq')
1471
- expected = {'i_mp': [6.1362673597376753] * 2,
1472
- 'v_mp': [6.2243393757884284] * 2,
1473
- 'p_mp': [38.194210547580511] * 2}
1474
- assert isinstance(out, dict)
1475
- for k, v in out.items():
1476
- assert np.allclose(v, expected[k])
1477
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='newton')
1478
- for k, v in out.items():
1479
- assert np.allclose(v, expected[k])
1480
-
1481
-
1482
- def test_mpp_series():
1483
- """test max_power_point"""
1484
- idx = ['2008-02-17T11:30:00-0800', '2008-02-17T12:30:00-0800']
1485
- IL, I0, Rs, Rsh, nNsVth = (np.array([7, 7]), 6e-7, .1, 20, .5)
1486
- IL = pd.Series(IL, index=idx)
1487
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='brentq')
1488
- expected = pd.DataFrame({'i_mp': [6.1362673597376753] * 2,
1489
- 'v_mp': [6.2243393757884284] * 2,
1490
- 'p_mp': [38.194210547580511] * 2},
1491
- index=idx)
1492
- assert isinstance(out, pd.DataFrame)
1493
- for k, v in out.items():
1494
- assert np.allclose(v, expected[k])
1495
- out = pvsystem.max_power_point(IL, I0, Rs, Rsh, nNsVth, method='newton')
1496
- for k, v in out.items():
1497
- assert np.allclose(v, expected[k])
1498
-
1499
-
1500
- def test_singlediode_series(cec_module_params):
1501
- times = pd.date_range(start='2015-01-01', periods=2, freq='12h')
1502
- effective_irradiance = pd.Series([0.0, 800.0], index=times)
1503
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
1504
- effective_irradiance,
1505
- temp_cell=25,
1506
- alpha_sc=cec_module_params['alpha_sc'],
1507
- a_ref=cec_module_params['a_ref'],
1508
- I_L_ref=cec_module_params['I_L_ref'],
1509
- I_o_ref=cec_module_params['I_o_ref'],
1510
- R_sh_ref=cec_module_params['R_sh_ref'],
1511
- R_s=cec_module_params['R_s'],
1512
- EgRef=1.121,
1513
- dEgdT=-0.0002677
1514
- )
1515
- out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth)
1516
- assert isinstance(out, pd.DataFrame)
1517
-
1518
-
1519
- def test_singlediode_array():
1520
- # github issue 221
1521
- photocurrent = np.linspace(0, 10, 11)
1522
- resistance_shunt = 16
1523
- resistance_series = 0.094
1524
- nNsVth = 0.473
1525
- saturation_current = 1.943e-09
1526
-
1527
- sd = pvsystem.singlediode(photocurrent, saturation_current,
1528
- resistance_series, resistance_shunt, nNsVth,
1529
- method='lambertw')
1530
-
1531
- expected_i = np.array([
1532
- 0., 0.54614798740338, 1.435026463529, 2.3621366610078, 3.2953968319952,
1533
- 4.2303869378787, 5.1655276691892, 6.1000269648604, 7.0333996177802,
1534
- 7.9653036915959, 8.8954716265647])
1535
- expected_v = np.array([
1536
- 0., 7.0966259059555, 7.9961986643428, 8.2222496810656, 8.3255927555753,
1537
- 8.3766915453915, 8.3988872440242, 8.4027948807891, 8.3941399580559,
1538
- 8.3763655188855, 8.3517057522791])
1539
-
1540
- assert_allclose(sd['i_mp'], expected_i, atol=1e-8)
1541
- assert_allclose(sd['v_mp'], expected_v, atol=1e-8)
1542
-
1543
- sd = pvsystem.singlediode(photocurrent, saturation_current,
1544
- resistance_series, resistance_shunt, nNsVth)
1545
- expected = pvsystem.i_from_v(sd['v_mp'], photocurrent, saturation_current,
1546
- resistance_series, resistance_shunt, nNsVth,
1547
- method='lambertw')
1548
- assert_allclose(sd['i_mp'], expected, atol=1e-8)
1549
-
1550
-
1551
- def test_singlediode_floats():
1552
- out = pvsystem.singlediode(7., 6.e-7, .1, 20., .5, method='lambertw')
1553
- expected = {'i_xx': 4.264060478,
1554
- 'i_mp': 6.136267360,
1555
- 'v_oc': 8.106300147,
1556
- 'p_mp': 38.19421055,
1557
- 'i_x': 6.7558815684,
1558
- 'i_sc': 6.965172322,
1559
- 'v_mp': 6.224339375,
1560
- 'i': None,
1561
- 'v': None}
1562
- assert isinstance(out, dict)
1563
- for k, v in out.items():
1564
- if k in ['i', 'v']:
1565
- assert v is None
1566
- else:
1567
- assert_allclose(v, expected[k], atol=1e-6)
1568
-
1569
-
1570
- def test_singlediode_floats_expected():
1571
- out = pvsystem.singlediode(7., 6e-7, .1, 20., .5, method='lambertw')
1572
- expected = {'i_xx': 4.264060478,
1573
- 'i_mp': 6.136267360,
1574
- 'v_oc': 8.106300147,
1575
- 'p_mp': 38.19421055,
1576
- 'i_x': 6.7558815684,
1577
- 'i_sc': 6.965172322,
1578
- 'v_mp': 6.224339375}
1579
- assert isinstance(out, dict)
1580
- for k, v in out.items():
1581
- assert_allclose(v, expected[k], atol=1e-6)
1582
-
1583
-
1584
- def test_singlediode_series_expected(cec_module_params):
1585
- times = pd.date_range(start='2015-06-01', periods=3, freq='6h')
1586
- effective_irradiance = pd.Series([0.0, 400.0, 800.0], index=times)
1587
- IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
1588
- effective_irradiance,
1589
- temp_cell=25,
1590
- alpha_sc=cec_module_params['alpha_sc'],
1591
- a_ref=cec_module_params['a_ref'],
1592
- I_L_ref=cec_module_params['I_L_ref'],
1593
- I_o_ref=cec_module_params['I_o_ref'],
1594
- R_sh_ref=cec_module_params['R_sh_ref'],
1595
- R_s=cec_module_params['R_s'],
1596
- EgRef=1.121,
1597
- dEgdT=-0.0002677)
1598
-
1599
- out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth, method='lambertw')
1600
-
1601
- expected = OrderedDict([('i_sc', array([0., 3.01079860, 6.00726296])),
1602
- ('v_oc', array([0., 9.96959733, 10.29603253])),
1603
- ('i_mp', array([0., 2.656285960, 5.290525645])),
1604
- ('v_mp', array([0., 8.321092255, 8.409413795])),
1605
- ('p_mp', array([0., 22.10320053, 44.49021934])),
1606
- ('i_x', array([0., 2.884132006, 5.746202281])),
1607
- ('i_xx', array([0., 2.052691562, 3.909673879]))])
1608
-
1609
- for k, v in out.items():
1610
- assert_allclose(v, expected[k], atol=1e-2)
1611
-
1612
- out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth)
1613
-
1614
- expected['i_mp'] = pvsystem.i_from_v(out['v_mp'], IL, I0, Rs, Rsh, nNsVth,
1615
- method='lambertw')
1616
- expected['v_mp'] = pvsystem.v_from_i(out['i_mp'], IL, I0, Rs, Rsh, nNsVth,
1617
- method='lambertw')
1618
-
1619
- for k, v in out.items():
1620
- assert_allclose(v, expected[k], atol=1e-6)
1621
-
1622
-
1623
- def test_scale_voltage_current_power():
1624
- data = pd.DataFrame(
1625
- np.array([[2, 1.5, 10, 8, 12, 0.5, 1.5]]),
1626
- columns=['i_sc', 'i_mp', 'v_oc', 'v_mp', 'p_mp', 'i_x', 'i_xx'],
1627
- index=[0])
1628
- expected = pd.DataFrame(
1629
- np.array([[6, 4.5, 20, 16, 72, 1.5, 4.5]]),
1630
- columns=['i_sc', 'i_mp', 'v_oc', 'v_mp', 'p_mp', 'i_x', 'i_xx'],
1631
- index=[0])
1632
- out = pvsystem.scale_voltage_current_power(data, voltage=2, current=3)
1633
- assert_frame_equal(out, expected, check_less_precise=5)
1634
-
1635
-
1636
- def test_PVSystem_scale_voltage_current_power(mocker):
1637
- data = None
1638
- system = pvsystem.PVSystem(modules_per_string=2, strings_per_inverter=3)
1639
- m = mocker.patch(
1640
- 'pvlib.pvsystem.scale_voltage_current_power', autospec=True)
1641
- system.scale_voltage_current_power(data)
1642
- m.assert_called_once_with(data, voltage=2, current=3)
1643
-
1644
-
1645
- def test_PVSystem_multi_scale_voltage_current_power(mocker):
1646
- data = (1, 2)
1647
- system = pvsystem.PVSystem(
1648
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180),
1649
- modules_per_string=2, strings=3),
1650
- pvsystem.Array(pvsystem.FixedMount(0, 180),
1651
- modules_per_string=3, strings=5)]
1652
- )
1653
- m = mocker.patch(
1654
- 'pvlib.pvsystem.scale_voltage_current_power', autospec=True
1655
- )
1656
- system.scale_voltage_current_power(data)
1657
- m.assert_has_calls(
1658
- [mock.call(1, voltage=2, current=3),
1659
- mock.call(2, voltage=3, current=5)],
1660
- any_order=True
1661
- )
1662
- with pytest.raises(ValueError,
1663
- match="Length mismatch for per-array parameter"):
1664
- system.scale_voltage_current_power(None)
1665
-
1666
-
1667
- def test_PVSystem_get_ac_sandia(cec_inverter_parameters, mocker):
1668
- inv_fun = mocker.spy(inverter, 'sandia')
1669
- system = pvsystem.PVSystem(
1670
- inverter=cec_inverter_parameters['Name'],
1671
- inverter_parameters=cec_inverter_parameters,
1672
- )
1673
- vdcs = pd.Series(np.linspace(0, 50, 3))
1674
- idcs = pd.Series(np.linspace(0, 11, 3))
1675
- pdcs = idcs * vdcs
1676
- pacs = system.get_ac('sandia', pdcs, v_dc=vdcs)
1677
- inv_fun.assert_called_once()
1678
- assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000]))
1679
-
1680
-
1681
- def test_PVSystem_get_ac_sandia_multi(cec_inverter_parameters, mocker):
1682
- inv_fun = mocker.spy(inverter, 'sandia_multi')
1683
- system = pvsystem.PVSystem(
1684
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180)),
1685
- pvsystem.Array(pvsystem.FixedMount(0, 180))],
1686
- inverter=cec_inverter_parameters['Name'],
1687
- inverter_parameters=cec_inverter_parameters,
1688
- )
1689
- vdcs = pd.Series(np.linspace(0, 50, 3))
1690
- idcs = pd.Series(np.linspace(0, 11, 3)) / 2
1691
- pdcs = idcs * vdcs
1692
- pacs = system.get_ac('sandia', (pdcs, pdcs), v_dc=(vdcs, vdcs))
1693
- inv_fun.assert_called_once()
1694
- assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000]))
1695
- with pytest.raises(ValueError,
1696
- match="Length mismatch for per-array parameter"):
1697
- system.get_ac('sandia', vdcs, (pdcs, pdcs))
1698
- with pytest.raises(ValueError,
1699
- match="Length mismatch for per-array parameter"):
1700
- system.get_ac('sandia', vdcs, (pdcs,))
1701
- with pytest.raises(ValueError,
1702
- match="Length mismatch for per-array parameter"):
1703
- system.get_ac('sandia', (vdcs, vdcs), (pdcs, pdcs, pdcs))
1704
-
1705
-
1706
- def test_PVSystem_get_ac_pvwatts(pvwatts_system_defaults, mocker):
1707
- mocker.spy(inverter, 'pvwatts')
1708
- pdc = 50
1709
- out = pvwatts_system_defaults.get_ac('pvwatts', pdc)
1710
- inverter.pvwatts.assert_called_once_with(
1711
- pdc, **pvwatts_system_defaults.inverter_parameters)
1712
- assert out < pdc
1713
-
1714
-
1715
- def test_PVSystem_get_ac_pvwatts_kwargs(pvwatts_system_kwargs, mocker):
1716
- mocker.spy(inverter, 'pvwatts')
1717
- pdc = 50
1718
- out = pvwatts_system_kwargs.get_ac('pvwatts', pdc)
1719
- inverter.pvwatts.assert_called_once_with(
1720
- pdc, **pvwatts_system_kwargs.inverter_parameters)
1721
- assert out < pdc
1722
-
1723
-
1724
- def test_PVSystem_get_ac_pvwatts_multi(
1725
- pvwatts_system_defaults, pvwatts_system_kwargs, mocker):
1726
- mocker.spy(inverter, 'pvwatts_multi')
1727
- expected = [pd.Series([0.0, 48.123524, 86.400000]),
1728
- pd.Series([0.0, 45.893550, 85.500000])]
1729
- systems = [pvwatts_system_defaults, pvwatts_system_kwargs]
1730
- for base_sys, exp in zip(systems, expected):
1731
- system = pvsystem.PVSystem(
1732
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180)),
1733
- pvsystem.Array(pvsystem.FixedMount(0, 180),)],
1734
- inverter_parameters=base_sys.inverter_parameters,
1735
- )
1736
- pdcs = pd.Series([0., 25., 50.])
1737
- pacs = system.get_ac('pvwatts', (pdcs, pdcs))
1738
- assert_series_equal(pacs, exp)
1739
- assert inverter.pvwatts_multi.call_count == 2
1740
- with pytest.raises(ValueError,
1741
- match="Length mismatch for per-array parameter"):
1742
- system.get_ac('pvwatts', (pdcs,))
1743
- with pytest.raises(ValueError,
1744
- match="Length mismatch for per-array parameter"):
1745
- system.get_ac('pvwatts', pdcs)
1746
- with pytest.raises(ValueError,
1747
- match="Length mismatch for per-array parameter"):
1748
- system.get_ac('pvwatts', (pdcs, pdcs, pdcs))
1749
-
1750
-
1751
- @pytest.mark.parametrize('model', ['sandia', 'adr', 'pvwatts'])
1752
- def test_PVSystem_get_ac_single_array_tuple_input(
1753
- model,
1754
- pvwatts_system_defaults,
1755
- cec_inverter_parameters,
1756
- adr_inverter_parameters):
1757
- vdcs = {
1758
- 'sandia': pd.Series(np.linspace(0, 50, 3)),
1759
- 'pvwatts': None,
1760
- 'adr': pd.Series([135, 154, 390, 420, 551])
1761
- }
1762
- pdcs = {'adr': pd.Series([135, 1232, 1170, 420, 551]),
1763
- 'sandia': pd.Series(np.linspace(0, 11, 3)) * vdcs['sandia'],
1764
- 'pvwatts': 50}
1765
- inverter_parameters = {
1766
- 'sandia': cec_inverter_parameters,
1767
- 'adr': adr_inverter_parameters,
1768
- 'pvwatts': pvwatts_system_defaults.inverter_parameters
1769
- }
1770
- expected = {
1771
- 'adr': pd.Series([np.nan, 1161.5745, 1116.4459, 382.6679, np.nan]),
1772
- 'sandia': pd.Series([-0.020000, 132.004308, 250.000000])
1773
- }
1774
- system = pvsystem.PVSystem(
1775
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180))],
1776
- inverter_parameters=inverter_parameters[model]
1777
- )
1778
- ac = system.get_ac(p_dc=(pdcs[model],), v_dc=(vdcs[model],), model=model)
1779
- if model == 'pvwatts':
1780
- assert ac < pdcs['pvwatts']
1781
- else:
1782
- assert_series_equal(ac, expected[model])
1783
-
1784
-
1785
- def test_PVSystem_get_ac_adr(adr_inverter_parameters, mocker):
1786
- mocker.spy(inverter, 'adr')
1787
- system = pvsystem.PVSystem(
1788
- inverter_parameters=adr_inverter_parameters,
1789
- )
1790
- vdcs = pd.Series([135, 154, 390, 420, 551])
1791
- pdcs = pd.Series([135, 1232, 1170, 420, 551])
1792
- pacs = system.get_ac('adr', pdcs, vdcs)
1793
- assert_series_equal(pacs, pd.Series([np.nan, 1161.5745, 1116.4459,
1794
- 382.6679, np.nan]))
1795
- inverter.adr.assert_called_once_with(vdcs, pdcs,
1796
- system.inverter_parameters)
1797
-
1798
-
1799
- def test_PVSystem_get_ac_adr_multi(adr_inverter_parameters):
1800
- system = pvsystem.PVSystem(
1801
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180)),
1802
- pvsystem.Array(pvsystem.FixedMount(0, 180))],
1803
- inverter_parameters=adr_inverter_parameters,
1804
- )
1805
- pdcs = pd.Series([135, 1232, 1170, 420, 551])
1806
- with pytest.raises(ValueError,
1807
- match="The adr inverter function cannot be used"):
1808
- system.get_ac(model='adr', p_dc=pdcs)
1809
-
1810
-
1811
- def test_PVSystem_get_ac_invalid(cec_inverter_parameters):
1812
- system = pvsystem.PVSystem(
1813
- inverter_parameters=cec_inverter_parameters,
1814
- )
1815
- pdcs = pd.Series(np.linspace(0, 50, 3))
1816
- with pytest.raises(ValueError, match="is not a valid AC power model"):
1817
- system.get_ac(model='not_a_model', p_dc=pdcs)
1818
-
1819
-
1820
- def test_PVSystem_creation():
1821
- pv_system = pvsystem.PVSystem(module='blah', inverter='blarg')
1822
- # ensure that parameter attributes are dict-like. GH 294
1823
- pv_system.inverter_parameters['Paco'] = 1
1824
-
1825
-
1826
- def test_PVSystem_multiple_array_creation():
1827
- array_one = pvsystem.Array(pvsystem.FixedMount(surface_tilt=32))
1828
- array_two = pvsystem.Array(pvsystem.FixedMount(surface_tilt=15),
1829
- module_parameters={'pdc0': 1})
1830
- pv_system = pvsystem.PVSystem(arrays=[array_one, array_two])
1831
- assert pv_system.arrays[0].module_parameters == {}
1832
- assert pv_system.arrays[1].module_parameters == {'pdc0': 1}
1833
- assert pv_system.arrays == (array_one, array_two)
1834
-
1835
-
1836
- def test_PVSystem_get_aoi():
1837
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1838
- aoi = system.get_aoi(30, 225)
1839
- assert np.round(aoi, 4) == 42.7408
1840
-
1841
-
1842
- def test_PVSystem_multiple_array_get_aoi():
1843
- system = pvsystem.PVSystem(
1844
- arrays=[pvsystem.Array(pvsystem.FixedMount(surface_tilt=15,
1845
- surface_azimuth=135)),
1846
- pvsystem.Array(pvsystem.FixedMount(surface_tilt=32,
1847
- surface_azimuth=135))]
1848
- )
1849
- aoi_one, aoi_two = system.get_aoi(30, 225)
1850
- assert np.round(aoi_two, 4) == 42.7408
1851
- assert aoi_two != aoi_one
1852
- assert aoi_one > 0
1853
-
1854
-
1855
- @pytest.fixture
1856
- def solar_pos():
1857
- times = pd.date_range(start='20160101 1200-0700',
1858
- end='20160101 1800-0700', freq='6h')
1859
- location = Location(latitude=32, longitude=-111)
1860
- return location.get_solarposition(times)
1861
-
1862
-
1863
- def test_PVSystem_get_irradiance(solar_pos):
1864
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1865
- irrads = pd.DataFrame({'dni':[900,0], 'ghi':[600,0], 'dhi':[100,0]},
1866
- index=solar_pos.index)
1867
-
1868
- irradiance = system.get_irradiance(solar_pos['apparent_zenith'],
1869
- solar_pos['azimuth'],
1870
- irrads['dni'],
1871
- irrads['ghi'],
1872
- irrads['dhi'])
1873
- expected = pd.DataFrame(data=np.array(
1874
- [[883.65494055, 745.86141676, 137.79352379, 126.397131, 11.39639279],
1875
- [0., -0., 0., 0., 0.]]),
1876
- columns=['poa_global', 'poa_direct',
1877
- 'poa_diffuse', 'poa_sky_diffuse',
1878
- 'poa_ground_diffuse'],
1879
- index=solar_pos.index)
1880
- assert_frame_equal(irradiance, expected, check_less_precise=2)
1881
-
1882
-
1883
- def test_PVSystem_get_irradiance_float():
1884
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1885
- irrads = {'dni': 900., 'ghi': 600., 'dhi': 100.}
1886
- zenith = 55.366831
1887
- azimuth = 172.320038
1888
- irradiance = system.get_irradiance(zenith,
1889
- azimuth,
1890
- irrads['dni'],
1891
- irrads['ghi'],
1892
- irrads['dhi'])
1893
- expected = {'poa_global': 884.80903423, 'poa_direct': 745.84258835,
1894
- 'poa_diffuse': 138.96644588, 'poa_sky_diffuse': 127.57005309,
1895
- 'poa_ground_diffuse': 11.39639279}
1896
- for k, v in irradiance.items():
1897
- assert np.isclose(v, expected[k], rtol=1e-6)
1898
-
1899
-
1900
- def test_PVSystem_get_irradiance_albedo(solar_pos):
1901
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1902
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0],
1903
- 'albedo': [0.5, 0.5]},
1904
- index=solar_pos.index)
1905
- # albedo as a Series
1906
- irradiance = system.get_irradiance(solar_pos['apparent_zenith'],
1907
- solar_pos['azimuth'],
1908
- irrads['dni'],
1909
- irrads['ghi'],
1910
- irrads['dhi'],
1911
- albedo=irrads['albedo'])
1912
- expected = pd.DataFrame(data=np.array(
1913
- [[895.05134334, 745.86141676, 149.18992658, 126.397131, 22.79279558],
1914
- [0., -0., 0., 0., 0.]]),
1915
- columns=['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse',
1916
- 'poa_ground_diffuse'],
1917
- index=solar_pos.index)
1918
- assert_frame_equal(irradiance, expected, check_less_precise=2)
1919
-
1920
-
1921
- def test_PVSystem_get_irradiance_model(mocker, solar_pos):
1922
- spy_perez = mocker.spy(irradiance, 'perez')
1923
- spy_haydavies = mocker.spy(irradiance, 'haydavies')
1924
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1925
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1926
- index=solar_pos.index)
1927
- system.get_irradiance(solar_pos['apparent_zenith'],
1928
- solar_pos['azimuth'],
1929
- irrads['dni'],
1930
- irrads['ghi'],
1931
- irrads['dhi'])
1932
- spy_haydavies.assert_called_once()
1933
- system.get_irradiance(solar_pos['apparent_zenith'],
1934
- solar_pos['azimuth'],
1935
- irrads['dni'],
1936
- irrads['ghi'],
1937
- irrads['dhi'],
1938
- model='perez')
1939
- spy_perez.assert_called_once()
1940
-
1941
-
1942
- def test_PVSystem_multi_array_get_irradiance(solar_pos):
1943
- array_one = pvsystem.Array(pvsystem.FixedMount(surface_tilt=32,
1944
- surface_azimuth=135))
1945
- array_two = pvsystem.Array(pvsystem.FixedMount(surface_tilt=5,
1946
- surface_azimuth=150))
1947
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
1948
-
1949
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1950
- index=solar_pos.index)
1951
- array_one_expected = array_one.get_irradiance(
1952
- solar_pos['apparent_zenith'],
1953
- solar_pos['azimuth'],
1954
- irrads['dni'], irrads['ghi'], irrads['dhi']
1955
- )
1956
- array_two_expected = array_two.get_irradiance(
1957
- solar_pos['apparent_zenith'],
1958
- solar_pos['azimuth'],
1959
- irrads['dni'], irrads['ghi'], irrads['dhi']
1960
- )
1961
- array_one_irrad, array_two_irrad = system.get_irradiance(
1962
- solar_pos['apparent_zenith'],
1963
- solar_pos['azimuth'],
1964
- irrads['dni'], irrads['ghi'], irrads['dhi']
1965
- )
1966
- assert_frame_equal(
1967
- array_one_irrad, array_one_expected, check_less_precise=2
1968
- )
1969
- assert_frame_equal(
1970
- array_two_irrad, array_two_expected, check_less_precise=2
1971
- )
1972
-
1973
-
1974
- def test_PVSystem_multi_array_get_irradiance_multi_irrad(solar_pos):
1975
- """Test a system with two identical arrays but different irradiance.
1976
-
1977
- Because only the irradiance is different we expect the same output
1978
- when only one GHI/DHI/DNI input is given, but different output
1979
- for each array when different GHI/DHI/DNI input is given. For the later
1980
- case we verify that the correct irradiance data is passed to each array.
1981
- """
1982
- array_one = pvsystem.Array(pvsystem.FixedMount(0, 180))
1983
- array_two = pvsystem.Array(pvsystem.FixedMount(0, 180))
1984
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
1985
-
1986
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1987
- index=solar_pos.index)
1988
- irrads_two = pd.DataFrame(
1989
- {'dni': [0, 900], 'ghi': [0, 600], 'dhi': [0, 100]},
1990
- index=solar_pos.index
1991
- )
1992
- array_irrad = system.get_irradiance(
1993
- solar_pos['apparent_zenith'],
1994
- solar_pos['azimuth'],
1995
- (irrads['dhi'], irrads['dhi']),
1996
- (irrads['ghi'], irrads['ghi']),
1997
- (irrads['dni'], irrads['dni'])
1998
- )
1999
- assert_frame_equal(array_irrad[0], array_irrad[1])
2000
- array_irrad = system.get_irradiance(
2001
- solar_pos['apparent_zenith'],
2002
- solar_pos['azimuth'],
2003
- (irrads['dhi'], irrads_two['dhi']),
2004
- (irrads['ghi'], irrads_two['ghi']),
2005
- (irrads['dni'], irrads_two['dni'])
2006
- )
2007
- array_one_expected = array_one.get_irradiance(
2008
- solar_pos['apparent_zenith'],
2009
- solar_pos['azimuth'],
2010
- irrads['dhi'], irrads['ghi'], irrads['dni']
2011
- )
2012
- array_two_expected = array_two.get_irradiance(
2013
- solar_pos['apparent_zenith'],
2014
- solar_pos['azimuth'],
2015
- irrads_two['dhi'], irrads_two['ghi'], irrads_two['dni']
2016
- )
2017
- assert not array_irrad[0].equals(array_irrad[1])
2018
- assert_frame_equal(array_irrad[0], array_one_expected)
2019
- assert_frame_equal(array_irrad[1], array_two_expected)
2020
- with pytest.raises(ValueError,
2021
- match="Length mismatch for per-array parameter"):
2022
- system.get_irradiance(
2023
- solar_pos['apparent_zenith'],
2024
- solar_pos['azimuth'],
2025
- (irrads['dhi'], irrads_two['dhi'], irrads['dhi']),
2026
- (irrads['ghi'], irrads_two['ghi']),
2027
- irrads['dni']
2028
- )
2029
- array_irrad = system.get_irradiance(
2030
- solar_pos['apparent_zenith'],
2031
- solar_pos['azimuth'],
2032
- (irrads['dhi'], irrads_two['dhi']),
2033
- irrads['ghi'],
2034
- irrads['dni']
2035
- )
2036
- assert_frame_equal(array_irrad[0], array_one_expected)
2037
- assert not array_irrad[0].equals(array_irrad[1])
2038
-
2039
-
2040
- def test_Array_get_irradiance(solar_pos):
2041
- array = pvsystem.Array(pvsystem.FixedMount(surface_tilt=32,
2042
- surface_azimuth=135))
2043
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
2044
- index=solar_pos.index)
2045
- # defaults for kwargs
2046
- modeled = array.get_irradiance(
2047
- solar_pos['apparent_zenith'],
2048
- solar_pos['azimuth'],
2049
- irrads['dni'], irrads['ghi'], irrads['dhi']
2050
- )
2051
- expected = pd.DataFrame(
2052
- data=np.array(
2053
- [[883.65494055, 745.86141676, 137.79352379, 126.397131,
2054
- 11.39639279],
2055
- [0., -0., 0., 0., 0.]]),
2056
- columns=['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse',
2057
- 'poa_ground_diffuse'],
2058
- index=solar_pos.index
2059
- )
2060
- assert_frame_equal(modeled, expected, check_less_precise=5)
2061
- # with specified kwargs, use isotropic sky diffuse because it's easier
2062
- modeled = array.get_irradiance(
2063
- solar_pos['apparent_zenith'],
2064
- solar_pos['azimuth'],
2065
- irrads['dni'], irrads['ghi'], irrads['dhi'],
2066
- albedo=0.5, model='isotropic'
2067
- )
2068
- sky_diffuse = irradiance.isotropic(array.mount.surface_tilt, irrads['dhi'])
2069
- ground_diff = irradiance.get_ground_diffuse(
2070
- array.mount.surface_tilt, irrads['ghi'], 0.5, surface_type=None)
2071
- aoi = irradiance.aoi(array.mount.surface_tilt, array.mount.surface_azimuth,
2072
- solar_pos['apparent_zenith'], solar_pos['azimuth'])
2073
- direct = irrads['dni'] * cosd(aoi)
2074
- expected = sky_diffuse + ground_diff + direct
2075
- assert_series_equal(expected, expected, check_less_precise=5)
2076
-
2077
-
2078
- def test_PVSystem___repr__():
2079
- system = pvsystem.PVSystem(
2080
- module='blah', inverter='blarg', name='pv ftw',
2081
- temperature_model_parameters={'a': -3.56})
2082
-
2083
- expected = """PVSystem:
2084
- name: pv ftw
2085
- Array:
2086
- name: None
2087
- mount: FixedMount(surface_tilt=0, surface_azimuth=180, racking_model=None, module_height=None)
2088
- module: blah
2089
- albedo: 0.25
2090
- module_type: None
2091
- temperature_model_parameters: {'a': -3.56}
2092
- strings: 1
2093
- modules_per_string: 1
2094
- inverter: blarg""" # noqa: E501
2095
- assert system.__repr__() == expected
2096
-
2097
-
2098
- def test_PVSystem_multi_array___repr__():
2099
- system = pvsystem.PVSystem(
2100
- arrays=[pvsystem.Array(pvsystem.FixedMount(surface_tilt=30,
2101
- surface_azimuth=100)),
2102
- pvsystem.Array(pvsystem.FixedMount(surface_tilt=20,
2103
- surface_azimuth=220),
2104
- name='foo')],
2105
- inverter='blarg',
2106
- )
2107
- expected = """PVSystem:
2108
- name: None
2109
- Array:
2110
- name: None
2111
- mount: FixedMount(surface_tilt=30, surface_azimuth=100, racking_model=None, module_height=None)
2112
- module: None
2113
- albedo: 0.25
2114
- module_type: None
2115
- temperature_model_parameters: {}
2116
- strings: 1
2117
- modules_per_string: 1
2118
- Array:
2119
- name: foo
2120
- mount: FixedMount(surface_tilt=20, surface_azimuth=220, racking_model=None, module_height=None)
2121
- module: None
2122
- albedo: 0.25
2123
- module_type: None
2124
- temperature_model_parameters: {}
2125
- strings: 1
2126
- modules_per_string: 1
2127
- inverter: blarg""" # noqa: E501
2128
- assert expected == system.__repr__()
2129
-
2130
-
2131
- def test_Array___repr__():
2132
- array = pvsystem.Array(
2133
- mount=pvsystem.FixedMount(surface_tilt=10, surface_azimuth=100,
2134
- racking_model='close_mount'),
2135
- albedo=0.15, module_type='glass_glass',
2136
- temperature_model_parameters={'a': -3.56},
2137
- module_parameters={'foo': 'bar'},
2138
- modules_per_string=100,
2139
- strings=10, module='baz',
2140
- name='biz'
2141
- )
2142
- expected = """Array:
2143
- name: biz
2144
- mount: FixedMount(surface_tilt=10, surface_azimuth=100, racking_model='close_mount', module_height=None)
2145
- module: baz
2146
- albedo: 0.15
2147
- module_type: glass_glass
2148
- temperature_model_parameters: {'a': -3.56}
2149
- strings: 10
2150
- modules_per_string: 100""" # noqa: E501
2151
- assert array.__repr__() == expected
2152
-
2153
-
2154
- def test_pvwatts_dc_scalars():
2155
- expected = 88.65
2156
- out = pvsystem.pvwatts_dc(900, 30, 100, -0.003)
2157
- assert_allclose(out, expected)
2158
-
2159
-
2160
- def test_pvwatts_dc_arrays():
2161
- irrad_trans = np.array([np.nan, 900, 900])
2162
- temp_cell = np.array([30, np.nan, 30])
2163
- irrad_trans, temp_cell = np.meshgrid(irrad_trans, temp_cell)
2164
- expected = np.array([[nan, 88.65, 88.65],
2165
- [nan, nan, nan],
2166
- [nan, 88.65, 88.65]])
2167
- out = pvsystem.pvwatts_dc(irrad_trans, temp_cell, 100, -0.003)
2168
- assert_allclose(out, expected, equal_nan=True)
2169
-
2170
-
2171
- def test_pvwatts_dc_series():
2172
- irrad_trans = pd.Series([np.nan, 900, 900])
2173
- temp_cell = pd.Series([30, np.nan, 30])
2174
- expected = pd.Series(np.array([ nan, nan, 88.65]))
2175
- out = pvsystem.pvwatts_dc(irrad_trans, temp_cell, 100, -0.003)
2176
- assert_series_equal(expected, out)
2177
-
2178
-
2179
- def test_pvwatts_losses_default():
2180
- expected = 14.075660688264469
2181
- out = pvsystem.pvwatts_losses()
2182
- assert_allclose(out, expected)
2183
-
2184
-
2185
- def test_pvwatts_losses_arrays():
2186
- expected = np.array([nan, 14.934904])
2187
- age = np.array([nan, 1])
2188
- out = pvsystem.pvwatts_losses(age=age)
2189
- assert_allclose(out, expected)
2190
-
2191
-
2192
- def test_pvwatts_losses_series():
2193
- expected = pd.Series([nan, 14.934904])
2194
- age = pd.Series([nan, 1])
2195
- out = pvsystem.pvwatts_losses(age=age)
2196
- assert_series_equal(expected, out)
2197
-
2198
-
2199
- @pytest.fixture
2200
- def pvwatts_system_defaults():
2201
- module_parameters = {'pdc0': 100, 'gamma_pdc': -0.003}
2202
- inverter_parameters = {'pdc0': 90}
2203
- system = pvsystem.PVSystem(module_parameters=module_parameters,
2204
- inverter_parameters=inverter_parameters)
2205
- return system
2206
-
2207
-
2208
- @pytest.fixture
2209
- def pvwatts_system_kwargs():
2210
- module_parameters = {'pdc0': 100, 'gamma_pdc': -0.003, 'temp_ref': 20}
2211
- inverter_parameters = {'pdc0': 90, 'eta_inv_nom': 0.95, 'eta_inv_ref': 1.0}
2212
- system = pvsystem.PVSystem(module_parameters=module_parameters,
2213
- inverter_parameters=inverter_parameters)
2214
- return system
2215
-
2216
-
2217
- def test_PVSystem_pvwatts_dc(pvwatts_system_defaults, mocker):
2218
- mocker.spy(pvsystem, 'pvwatts_dc')
2219
- irrad = 900
2220
- temp_cell = 30
2221
- expected = 90
2222
- out = pvwatts_system_defaults.pvwatts_dc(irrad, temp_cell)
2223
- pvsystem.pvwatts_dc.assert_called_once_with(
2224
- irrad, temp_cell,
2225
- **pvwatts_system_defaults.arrays[0].module_parameters)
2226
- assert_allclose(expected, out, atol=10)
2227
-
2228
-
2229
- def test_PVSystem_pvwatts_dc_kwargs(pvwatts_system_kwargs, mocker):
2230
- mocker.spy(pvsystem, 'pvwatts_dc')
2231
- irrad = 900
2232
- temp_cell = 30
2233
- expected = 90
2234
- out = pvwatts_system_kwargs.pvwatts_dc(irrad, temp_cell)
2235
- pvsystem.pvwatts_dc.assert_called_once_with(
2236
- irrad, temp_cell, **pvwatts_system_kwargs.arrays[0].module_parameters)
2237
- assert_allclose(expected, out, atol=10)
2238
-
2239
-
2240
- def test_PVSystem_multiple_array_pvwatts_dc():
2241
- array_one_module_parameters = {
2242
- 'pdc0': 100, 'gamma_pdc': -0.003, 'temp_ref': 20
2243
- }
2244
- array_one = pvsystem.Array(
2245
- pvsystem.FixedMount(0, 180),
2246
- module_parameters=array_one_module_parameters
2247
- )
2248
- array_two_module_parameters = {
2249
- 'pdc0': 150, 'gamma_pdc': -0.002, 'temp_ref': 25
2250
- }
2251
- array_two = pvsystem.Array(
2252
- pvsystem.FixedMount(0, 180),
2253
- module_parameters=array_two_module_parameters
2254
- )
2255
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
2256
- irrad_one = 900
2257
- irrad_two = 500
2258
- temp_cell_one = 30
2259
- temp_cell_two = 20
2260
- expected_one = pvsystem.pvwatts_dc(irrad_one, temp_cell_one,
2261
- **array_one_module_parameters)
2262
- expected_two = pvsystem.pvwatts_dc(irrad_two, temp_cell_two,
2263
- **array_two_module_parameters)
2264
- dc_one, dc_two = system.pvwatts_dc((irrad_one, irrad_two),
2265
- (temp_cell_one, temp_cell_two))
2266
- assert dc_one == expected_one
2267
- assert dc_two == expected_two
2268
-
2269
-
2270
- def test_PVSystem_multiple_array_pvwatts_dc_value_error():
2271
- system = pvsystem.PVSystem(
2272
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180)),
2273
- pvsystem.Array(pvsystem.FixedMount(0, 180)),
2274
- pvsystem.Array(pvsystem.FixedMount(0, 180))]
2275
- )
2276
- error_message = 'Length mismatch for per-array parameter'
2277
- with pytest.raises(ValueError, match=error_message):
2278
- system.pvwatts_dc(10, (1, 1, 1))
2279
- with pytest.raises(ValueError, match=error_message):
2280
- system.pvwatts_dc((10, 10), (1, 1, 1))
2281
- with pytest.raises(ValueError, match=error_message):
2282
- system.pvwatts_dc((10, 10, 10, 10), (1, 1, 1))
2283
- with pytest.raises(ValueError, match=error_message):
2284
- system.pvwatts_dc((1, 1, 1), 1)
2285
- with pytest.raises(ValueError, match=error_message):
2286
- system.pvwatts_dc((1, 1, 1), (1,))
2287
- with pytest.raises(ValueError, match=error_message):
2288
- system.pvwatts_dc((1,), 1)
2289
- with pytest.raises(ValueError, match=error_message):
2290
- system.pvwatts_dc((1, 1, 1, 1), (1, 1))
2291
- with pytest.raises(ValueError, match=error_message):
2292
- system.pvwatts_dc(2, 3)
2293
- with pytest.raises(ValueError, match=error_message):
2294
- # ValueError is raised for non-tuple iterable with correct length
2295
- system.pvwatts_dc((1, 1, 1), pd.Series([1, 2, 3]))
2296
-
2297
-
2298
- def test_PVSystem_pvwatts_losses(pvwatts_system_defaults, mocker):
2299
- mocker.spy(pvsystem, 'pvwatts_losses')
2300
- age = 1
2301
- pvwatts_system_defaults.losses_parameters = dict(age=age)
2302
- expected = 15
2303
- out = pvwatts_system_defaults.pvwatts_losses()
2304
- pvsystem.pvwatts_losses.assert_called_once_with(age=age)
2305
- assert out < expected
2306
-
2307
-
2308
- def test_PVSystem_num_arrays():
2309
- system_one = pvsystem.PVSystem()
2310
- system_two = pvsystem.PVSystem(arrays=[
2311
- pvsystem.Array(pvsystem.FixedMount(0, 180)),
2312
- pvsystem.Array(pvsystem.FixedMount(0, 180))])
2313
- assert system_one.num_arrays == 1
2314
- assert system_two.num_arrays == 2
2315
-
2316
-
2317
- def test_PVSystem_at_least_one_array():
2318
- with pytest.raises(ValueError,
2319
- match="PVSystem must have at least one Array"):
2320
- pvsystem.PVSystem(arrays=[])
2321
-
2322
-
2323
- def test_PVSystem_single_array():
2324
- # GH 1831
2325
- single_array = pvsystem.Array(pvsystem.FixedMount())
2326
- system = pvsystem.PVSystem(arrays=single_array)
2327
- assert isinstance(system.arrays, tuple)
2328
- assert system.arrays[0] is single_array
2329
-
2330
-
2331
- def test_combine_loss_factors():
2332
- test_index = pd.date_range(start='1990/01/01T12:00', periods=365, freq='d')
2333
- loss_1 = pd.Series(.10, index=test_index)
2334
- loss_2 = pd.Series(.05, index=pd.date_range(start='1990/01/01T12:00',
2335
- periods=365*2, freq='d'))
2336
- loss_3 = pd.Series(.02, index=pd.date_range(start='1990/01/01',
2337
- periods=12, freq='MS'))
2338
- expected = pd.Series(.1621, index=test_index)
2339
- out = pvsystem.combine_loss_factors(test_index, loss_1, loss_2, loss_3)
2340
- assert_series_equal(expected, out)
2341
-
2342
-
2343
- def test_no_extra_kwargs():
2344
- with pytest.raises(TypeError, match="arbitrary_kwarg"):
2345
- pvsystem.PVSystem(arbitrary_kwarg='value')
2346
-
2347
-
2348
- def test_AbstractMount_constructor():
2349
- match = "Can't instantiate abstract class AbstractMount"
2350
- with pytest.raises(TypeError, match=match):
2351
- _ = pvsystem.AbstractMount()
2352
-
2353
-
2354
- @pytest.fixture
2355
- def fixed_mount():
2356
- return pvsystem.FixedMount(20, 180)
2357
-
2358
-
2359
- @pytest.fixture
2360
- def single_axis_tracker_mount():
2361
- return pvsystem.SingleAxisTrackerMount(axis_tilt=10, axis_azimuth=170,
2362
- max_angle=45, backtrack=False,
2363
- gcr=0.4, cross_axis_tilt=-5)
2364
-
2365
-
2366
- def test_FixedMount_constructor(fixed_mount):
2367
- assert fixed_mount.surface_tilt == 20
2368
- assert fixed_mount.surface_azimuth == 180
2369
-
2370
-
2371
- def test_FixedMount_get_orientation(fixed_mount):
2372
- expected = {'surface_tilt': 20, 'surface_azimuth': 180}
2373
- assert fixed_mount.get_orientation(45, 130) == expected
2374
-
2375
-
2376
- def test_SingleAxisTrackerMount_constructor(single_axis_tracker_mount):
2377
- expected = dict(axis_tilt=10, axis_azimuth=170, max_angle=45,
2378
- backtrack=False, gcr=0.4, cross_axis_tilt=-5)
2379
- for attr_name, expected_value in expected.items():
2380
- assert getattr(single_axis_tracker_mount, attr_name) == expected_value
2381
-
2382
-
2383
- def test_SingleAxisTrackerMount_get_orientation(single_axis_tracker_mount):
2384
- expected = {'surface_tilt': 19.29835284, 'surface_azimuth': 229.7643755}
2385
- actual = single_axis_tracker_mount.get_orientation(45, 190)
2386
- for key, expected_value in expected.items():
2387
- err_msg = f"{key} value incorrect"
2388
- assert actual[key] == pytest.approx(expected_value), err_msg
2389
-
2390
-
2391
- def test_SingleAxisTrackerMount_get_orientation_asymmetric_max():
2392
- mount = pvsystem.SingleAxisTrackerMount(max_angle=(-30, 45))
2393
- expected = {'surface_tilt': [45, 30], 'surface_azimuth': [90, 270]}
2394
- actual = mount.get_orientation([60, 60], [90, 270])
2395
- for key, expected_value in expected.items():
2396
- err_msg = f"{key} value incorrect"
2397
- assert actual[key] == pytest.approx(expected_value), err_msg
2398
-
2399
-
2400
- def test_dc_ohms_from_percent():
2401
- expected = .1425
2402
- out = pvsystem.dc_ohms_from_percent(38, 8, 3, 1, 1)
2403
- assert_allclose(out, expected)
2404
-
2405
-
2406
- def test_PVSystem_dc_ohms_from_percent(mocker):
2407
- mocker.spy(pvsystem, 'dc_ohms_from_percent')
2408
-
2409
- expected = .1425
2410
- system = pvsystem.PVSystem(losses_parameters={'dc_ohmic_percent': 3},
2411
- module_parameters={'I_mp_ref': 8,
2412
- 'V_mp_ref': 38})
2413
- out = system.dc_ohms_from_percent()
2414
-
2415
- pvsystem.dc_ohms_from_percent.assert_called_once_with(
2416
- dc_ohmic_percent=3,
2417
- vmp_ref=38,
2418
- imp_ref=8,
2419
- modules_per_string=1,
2420
- strings=1
2421
- )
2422
-
2423
- assert_allclose(out, expected)
2424
-
2425
-
2426
- def test_dc_ohmic_losses():
2427
- expected = 9.12
2428
- out = pvsystem.dc_ohmic_losses(.1425, 8)
2429
- assert_allclose(out, expected)
2430
-
2431
-
2432
- def test_Array_dc_ohms_from_percent(mocker):
2433
- mocker.spy(pvsystem, 'dc_ohms_from_percent')
2434
-
2435
- expected = .1425
2436
-
2437
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2438
- array_losses_parameters={'dc_ohmic_percent': 3},
2439
- module_parameters={'I_mp_ref': 8,
2440
- 'V_mp_ref': 38})
2441
- out = array.dc_ohms_from_percent()
2442
- pvsystem.dc_ohms_from_percent.assert_called_with(
2443
- dc_ohmic_percent=3,
2444
- vmp_ref=38,
2445
- imp_ref=8,
2446
- modules_per_string=1,
2447
- strings=1
2448
- )
2449
- assert_allclose(out, expected)
2450
-
2451
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2452
- array_losses_parameters={'dc_ohmic_percent': 3},
2453
- module_parameters={'Impo': 8,
2454
- 'Vmpo': 38})
2455
- out = array.dc_ohms_from_percent()
2456
- pvsystem.dc_ohms_from_percent.assert_called_with(
2457
- dc_ohmic_percent=3,
2458
- vmp_ref=38,
2459
- imp_ref=8,
2460
- modules_per_string=1,
2461
- strings=1
2462
- )
2463
- assert_allclose(out, expected)
2464
-
2465
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2466
- array_losses_parameters={'dc_ohmic_percent': 3},
2467
- module_parameters={'Impp': 8,
2468
- 'Vmpp': 38})
2469
- out = array.dc_ohms_from_percent()
2470
-
2471
- pvsystem.dc_ohms_from_percent.assert_called_with(
2472
- dc_ohmic_percent=3,
2473
- vmp_ref=38,
2474
- imp_ref=8,
2475
- modules_per_string=1,
2476
- strings=1
2477
- )
2478
- assert_allclose(out, expected)
2479
-
2480
- with pytest.raises(ValueError,
2481
- match=('Parameters for Vmp and Imp could not be found '
2482
- 'in the array module parameters. Module '
2483
- 'parameters must include one set of '
2484
- '{"V_mp_ref", "I_mp_Ref"}, '
2485
- '{"Vmpo", "Impo"}, or '
2486
- '{"Vmpp", "Impp"}.')):
2487
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2488
- array_losses_parameters={'dc_ohmic_percent': 3})
2489
- out = array.dc_ohms_from_percent()
2490
-
2491
-
2492
- @pytest.mark.parametrize('model,keys', [
2493
- ('sapm', ('a', 'b', 'deltaT')),
2494
- ('fuentes', ('noct_installed',)),
2495
- ('noct_sam', ('noct', 'module_efficiency'))
2496
- ])
2497
- def test_Array_temperature_missing_parameters(model, keys):
2498
- # test that a nice error is raised when required temp params are missing
2499
- array = pvsystem.Array(pvsystem.FixedMount(0, 180))
2500
- index = pd.date_range('2019-01-01', freq='h', periods=5)
2501
- temps = pd.Series(25, index)
2502
- irrads = pd.Series(1000, index)
2503
- winds = pd.Series(1, index)
2504
-
2505
- for key in keys:
2506
- match = f"Missing required parameter '{key}'"
2507
- params = {k: 1 for k in keys} # dummy values
2508
- params.pop(key) # remove each key in turn
2509
- array.temperature_model_parameters = params
2510
- with pytest.raises(KeyError, match=match):
2511
- array.get_cell_temperature(irrads, temps, winds, model)