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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/_deprecation.py +73 -0
  3. pvlib/atmosphere.py +77 -7
  4. pvlib/bifacial/infinite_sheds.py +4 -3
  5. pvlib/bifacial/utils.py +2 -1
  6. pvlib/clearsky.py +35 -22
  7. pvlib/iam.py +4 -4
  8. pvlib/iotools/midc.py +1 -1
  9. pvlib/iotools/psm3.py +1 -1
  10. pvlib/iotools/pvgis.py +10 -12
  11. pvlib/iotools/tmy.py +3 -69
  12. pvlib/irradiance.py +112 -55
  13. pvlib/ivtools/sdm.py +75 -52
  14. pvlib/location.py +73 -33
  15. pvlib/modelchain.py +18 -35
  16. pvlib/pvsystem.py +139 -94
  17. pvlib/snow.py +64 -28
  18. pvlib/solarposition.py +46 -30
  19. pvlib/spa.py +4 -2
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/spectrum/spectrl2.py +2 -1
  24. pvlib/temperature.py +49 -3
  25. pvlib/tools.py +6 -5
  26. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/METADATA +14 -11
  27. pvlib-0.12.0.dist-info/RECORD +75 -0
  28. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/WHEEL +1 -1
  29. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  30. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  31. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  32. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  33. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  34. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  35. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  36. pvlib/data/CRN_with_problems.txt +0 -3
  37. pvlib/data/ET-M772BH550GL.PAN +0 -75
  38. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  39. pvlib/data/PVsyst_demo.csv +0 -10757
  40. pvlib/data/PVsyst_demo_model.csv +0 -3588
  41. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  42. pvlib/data/abq19056.dat +0 -6
  43. pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
  44. pvlib/data/bishop88_numerical_precision.csv +0 -101
  45. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  46. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  47. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  48. pvlib/data/cams_mcclear_monthly.csv +0 -42
  49. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  50. pvlib/data/cams_radiation_monthly.csv +0 -47
  51. pvlib/data/detect_clearsky_data.csv +0 -35
  52. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  53. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  54. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  55. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  56. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  57. pvlib/data/ivtools_numdiff.csv +0 -52
  58. pvlib/data/midc_20181014.txt +0 -1441
  59. pvlib/data/midc_raw_20181018.txt +0 -1441
  60. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  61. pvlib/data/msn19056.dat +0 -6
  62. pvlib/data/precise_iv_curves1.json +0 -10251
  63. pvlib/data/precise_iv_curves2.json +0 -10251
  64. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  65. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  66. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  67. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  68. pvlib/data/pvgis_tmy_meta.json +0 -32
  69. pvlib/data/pvgis_tmy_test.dat +0 -8761
  70. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  71. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  72. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  73. pvlib/data/spectrl2_example_spectra.csv +0 -123
  74. pvlib/data/surfrad-slv16001.dat +0 -1442
  75. pvlib/data/test_psm3_2017.csv +0 -17521
  76. pvlib/data/test_psm3_2019_5min.csv +0 -289
  77. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  78. pvlib/data/test_read_psm3.csv +0 -17523
  79. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  80. pvlib/data/tmy_45.000_8.000_2005_2020.csv +0 -8789
  81. pvlib/data/tmy_45.000_8.000_2005_2020.epw +0 -8768
  82. pvlib/data/tmy_45.000_8.000_2005_2020.json +0 -1
  83. pvlib/data/tmy_45.000_8.000_2005_2020.txt +0 -8761
  84. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  85. pvlib/data/variables_style_rules.csv +0 -56
  86. pvlib/spa_c_files/README.md +0 -81
  87. pvlib/spa_c_files/cspa_py.pxd +0 -43
  88. pvlib/spa_c_files/spa_py.pyx +0 -30
  89. pvlib/tests/__init__.py +0 -0
  90. pvlib/tests/bifacial/__init__.py +0 -0
  91. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  92. pvlib/tests/bifacial/test_losses_models.py +0 -54
  93. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  94. pvlib/tests/bifacial/test_utils.py +0 -192
  95. pvlib/tests/conftest.py +0 -476
  96. pvlib/tests/iotools/__init__.py +0 -0
  97. pvlib/tests/iotools/test_acis.py +0 -213
  98. pvlib/tests/iotools/test_bsrn.py +0 -131
  99. pvlib/tests/iotools/test_crn.py +0 -95
  100. pvlib/tests/iotools/test_epw.py +0 -23
  101. pvlib/tests/iotools/test_midc.py +0 -89
  102. pvlib/tests/iotools/test_panond.py +0 -32
  103. pvlib/tests/iotools/test_psm3.py +0 -198
  104. pvlib/tests/iotools/test_pvgis.py +0 -644
  105. pvlib/tests/iotools/test_sodapro.py +0 -298
  106. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  107. pvlib/tests/iotools/test_solargis.py +0 -68
  108. pvlib/tests/iotools/test_solcast.py +0 -324
  109. pvlib/tests/iotools/test_solrad.py +0 -152
  110. pvlib/tests/iotools/test_srml.py +0 -124
  111. pvlib/tests/iotools/test_surfrad.py +0 -75
  112. pvlib/tests/iotools/test_tmy.py +0 -133
  113. pvlib/tests/ivtools/__init__.py +0 -0
  114. pvlib/tests/ivtools/test_sde.py +0 -230
  115. pvlib/tests/ivtools/test_sdm.py +0 -407
  116. pvlib/tests/ivtools/test_utils.py +0 -173
  117. pvlib/tests/spectrum/__init__.py +0 -0
  118. pvlib/tests/spectrum/conftest.py +0 -40
  119. pvlib/tests/spectrum/test_irradiance.py +0 -138
  120. pvlib/tests/spectrum/test_mismatch.py +0 -304
  121. pvlib/tests/spectrum/test_response.py +0 -124
  122. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  123. pvlib/tests/test_albedo.py +0 -84
  124. pvlib/tests/test_atmosphere.py +0 -204
  125. pvlib/tests/test_clearsky.py +0 -878
  126. pvlib/tests/test_conftest.py +0 -81
  127. pvlib/tests/test_iam.py +0 -555
  128. pvlib/tests/test_inverter.py +0 -213
  129. pvlib/tests/test_irradiance.py +0 -1441
  130. pvlib/tests/test_location.py +0 -356
  131. pvlib/tests/test_modelchain.py +0 -2020
  132. pvlib/tests/test_numerical_precision.py +0 -124
  133. pvlib/tests/test_pvarray.py +0 -71
  134. pvlib/tests/test_pvsystem.py +0 -2495
  135. pvlib/tests/test_scaling.py +0 -207
  136. pvlib/tests/test_shading.py +0 -391
  137. pvlib/tests/test_singlediode.py +0 -608
  138. pvlib/tests/test_snow.py +0 -212
  139. pvlib/tests/test_soiling.py +0 -230
  140. pvlib/tests/test_solarposition.py +0 -933
  141. pvlib/tests/test_spa.py +0 -425
  142. pvlib/tests/test_temperature.py +0 -470
  143. pvlib/tests/test_tools.py +0 -146
  144. pvlib/tests/test_tracking.py +0 -474
  145. pvlib/tests/test_transformer.py +0 -60
  146. pvlib-0.11.1.dist-info/RECORD +0 -192
  147. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/AUTHORS.md +0 -0
  148. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info/licenses}/LICENSE +0 -0
  149. {pvlib-0.11.1.dist-info → pvlib-0.12.0.dist-info}/top_level.txt +0 -0
@@ -1,2495 +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
-
1874
- expected = pd.DataFrame(data=np.array(
1875
- [[883.65494055, 745.86141676, 137.79352379, 126.397131, 11.39639279],
1876
- [0., -0., 0., 0., 0.]]),
1877
- columns=['poa_global', 'poa_direct',
1878
- 'poa_diffuse', 'poa_sky_diffuse',
1879
- 'poa_ground_diffuse'],
1880
- index=solar_pos.index)
1881
- assert_frame_equal(irradiance, expected, check_less_precise=2)
1882
-
1883
-
1884
- def test_PVSystem_get_irradiance_albedo(solar_pos):
1885
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1886
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0],
1887
- 'albedo': [0.5, 0.5]},
1888
- index=solar_pos.index)
1889
- # albedo as a Series
1890
- irradiance = system.get_irradiance(solar_pos['apparent_zenith'],
1891
- solar_pos['azimuth'],
1892
- irrads['dni'],
1893
- irrads['ghi'],
1894
- irrads['dhi'],
1895
- albedo=irrads['albedo'])
1896
- expected = pd.DataFrame(data=np.array(
1897
- [[895.05134334, 745.86141676, 149.18992658, 126.397131, 22.79279558],
1898
- [0., -0., 0., 0., 0.]]),
1899
- columns=['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse',
1900
- 'poa_ground_diffuse'],
1901
- index=solar_pos.index)
1902
- assert_frame_equal(irradiance, expected, check_less_precise=2)
1903
-
1904
-
1905
- def test_PVSystem_get_irradiance_model(mocker, solar_pos):
1906
- spy_perez = mocker.spy(irradiance, 'perez')
1907
- spy_haydavies = mocker.spy(irradiance, 'haydavies')
1908
- system = pvsystem.PVSystem(surface_tilt=32, surface_azimuth=135)
1909
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1910
- index=solar_pos.index)
1911
- system.get_irradiance(solar_pos['apparent_zenith'],
1912
- solar_pos['azimuth'],
1913
- irrads['dni'],
1914
- irrads['ghi'],
1915
- irrads['dhi'])
1916
- spy_haydavies.assert_called_once()
1917
- system.get_irradiance(solar_pos['apparent_zenith'],
1918
- solar_pos['azimuth'],
1919
- irrads['dni'],
1920
- irrads['ghi'],
1921
- irrads['dhi'],
1922
- model='perez')
1923
- spy_perez.assert_called_once()
1924
-
1925
-
1926
- def test_PVSystem_multi_array_get_irradiance(solar_pos):
1927
- array_one = pvsystem.Array(pvsystem.FixedMount(surface_tilt=32,
1928
- surface_azimuth=135))
1929
- array_two = pvsystem.Array(pvsystem.FixedMount(surface_tilt=5,
1930
- surface_azimuth=150))
1931
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
1932
-
1933
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1934
- index=solar_pos.index)
1935
- array_one_expected = array_one.get_irradiance(
1936
- solar_pos['apparent_zenith'],
1937
- solar_pos['azimuth'],
1938
- irrads['dni'], irrads['ghi'], irrads['dhi']
1939
- )
1940
- array_two_expected = array_two.get_irradiance(
1941
- solar_pos['apparent_zenith'],
1942
- solar_pos['azimuth'],
1943
- irrads['dni'], irrads['ghi'], irrads['dhi']
1944
- )
1945
- array_one_irrad, array_two_irrad = system.get_irradiance(
1946
- solar_pos['apparent_zenith'],
1947
- solar_pos['azimuth'],
1948
- irrads['dni'], irrads['ghi'], irrads['dhi']
1949
- )
1950
- assert_frame_equal(
1951
- array_one_irrad, array_one_expected, check_less_precise=2
1952
- )
1953
- assert_frame_equal(
1954
- array_two_irrad, array_two_expected, check_less_precise=2
1955
- )
1956
-
1957
-
1958
- def test_PVSystem_multi_array_get_irradiance_multi_irrad(solar_pos):
1959
- """Test a system with two identical arrays but different irradiance.
1960
-
1961
- Because only the irradiance is different we expect the same output
1962
- when only one GHI/DHI/DNI input is given, but different output
1963
- for each array when different GHI/DHI/DNI input is given. For the later
1964
- case we verify that the correct irradiance data is passed to each array.
1965
- """
1966
- array_one = pvsystem.Array(pvsystem.FixedMount(0, 180))
1967
- array_two = pvsystem.Array(pvsystem.FixedMount(0, 180))
1968
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
1969
-
1970
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
1971
- index=solar_pos.index)
1972
- irrads_two = pd.DataFrame(
1973
- {'dni': [0, 900], 'ghi': [0, 600], 'dhi': [0, 100]},
1974
- index=solar_pos.index
1975
- )
1976
- array_irrad = system.get_irradiance(
1977
- solar_pos['apparent_zenith'],
1978
- solar_pos['azimuth'],
1979
- (irrads['dhi'], irrads['dhi']),
1980
- (irrads['ghi'], irrads['ghi']),
1981
- (irrads['dni'], irrads['dni'])
1982
- )
1983
- assert_frame_equal(array_irrad[0], array_irrad[1])
1984
- array_irrad = system.get_irradiance(
1985
- solar_pos['apparent_zenith'],
1986
- solar_pos['azimuth'],
1987
- (irrads['dhi'], irrads_two['dhi']),
1988
- (irrads['ghi'], irrads_two['ghi']),
1989
- (irrads['dni'], irrads_two['dni'])
1990
- )
1991
- array_one_expected = array_one.get_irradiance(
1992
- solar_pos['apparent_zenith'],
1993
- solar_pos['azimuth'],
1994
- irrads['dhi'], irrads['ghi'], irrads['dni']
1995
- )
1996
- array_two_expected = array_two.get_irradiance(
1997
- solar_pos['apparent_zenith'],
1998
- solar_pos['azimuth'],
1999
- irrads_two['dhi'], irrads_two['ghi'], irrads_two['dni']
2000
- )
2001
- assert not array_irrad[0].equals(array_irrad[1])
2002
- assert_frame_equal(array_irrad[0], array_one_expected)
2003
- assert_frame_equal(array_irrad[1], array_two_expected)
2004
- with pytest.raises(ValueError,
2005
- match="Length mismatch for per-array parameter"):
2006
- system.get_irradiance(
2007
- solar_pos['apparent_zenith'],
2008
- solar_pos['azimuth'],
2009
- (irrads['dhi'], irrads_two['dhi'], irrads['dhi']),
2010
- (irrads['ghi'], irrads_two['ghi']),
2011
- irrads['dni']
2012
- )
2013
- array_irrad = system.get_irradiance(
2014
- solar_pos['apparent_zenith'],
2015
- solar_pos['azimuth'],
2016
- (irrads['dhi'], irrads_two['dhi']),
2017
- irrads['ghi'],
2018
- irrads['dni']
2019
- )
2020
- assert_frame_equal(array_irrad[0], array_one_expected)
2021
- assert not array_irrad[0].equals(array_irrad[1])
2022
-
2023
-
2024
- def test_Array_get_irradiance(solar_pos):
2025
- array = pvsystem.Array(pvsystem.FixedMount(surface_tilt=32,
2026
- surface_azimuth=135))
2027
- irrads = pd.DataFrame({'dni': [900, 0], 'ghi': [600, 0], 'dhi': [100, 0]},
2028
- index=solar_pos.index)
2029
- # defaults for kwargs
2030
- modeled = array.get_irradiance(
2031
- solar_pos['apparent_zenith'],
2032
- solar_pos['azimuth'],
2033
- irrads['dni'], irrads['ghi'], irrads['dhi']
2034
- )
2035
- expected = pd.DataFrame(
2036
- data=np.array(
2037
- [[883.65494055, 745.86141676, 137.79352379, 126.397131,
2038
- 11.39639279],
2039
- [0., -0., 0., 0., 0.]]),
2040
- columns=['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse',
2041
- 'poa_ground_diffuse'],
2042
- index=solar_pos.index
2043
- )
2044
- assert_frame_equal(modeled, expected, check_less_precise=5)
2045
- # with specified kwargs, use isotropic sky diffuse because it's easier
2046
- modeled = array.get_irradiance(
2047
- solar_pos['apparent_zenith'],
2048
- solar_pos['azimuth'],
2049
- irrads['dni'], irrads['ghi'], irrads['dhi'],
2050
- albedo=0.5, model='isotropic'
2051
- )
2052
- sky_diffuse = irradiance.isotropic(array.mount.surface_tilt, irrads['dhi'])
2053
- ground_diff = irradiance.get_ground_diffuse(
2054
- array.mount.surface_tilt, irrads['ghi'], 0.5, surface_type=None)
2055
- aoi = irradiance.aoi(array.mount.surface_tilt, array.mount.surface_azimuth,
2056
- solar_pos['apparent_zenith'], solar_pos['azimuth'])
2057
- direct = irrads['dni'] * cosd(aoi)
2058
- expected = sky_diffuse + ground_diff + direct
2059
- assert_series_equal(expected, expected, check_less_precise=5)
2060
-
2061
-
2062
- def test_PVSystem___repr__():
2063
- system = pvsystem.PVSystem(
2064
- module='blah', inverter='blarg', name='pv ftw',
2065
- temperature_model_parameters={'a': -3.56})
2066
-
2067
- expected = """PVSystem:
2068
- name: pv ftw
2069
- Array:
2070
- name: None
2071
- mount: FixedMount(surface_tilt=0, surface_azimuth=180, racking_model=None, module_height=None)
2072
- module: blah
2073
- albedo: 0.25
2074
- module_type: None
2075
- temperature_model_parameters: {'a': -3.56}
2076
- strings: 1
2077
- modules_per_string: 1
2078
- inverter: blarg""" # noqa: E501
2079
- assert system.__repr__() == expected
2080
-
2081
-
2082
- def test_PVSystem_multi_array___repr__():
2083
- system = pvsystem.PVSystem(
2084
- arrays=[pvsystem.Array(pvsystem.FixedMount(surface_tilt=30,
2085
- surface_azimuth=100)),
2086
- pvsystem.Array(pvsystem.FixedMount(surface_tilt=20,
2087
- surface_azimuth=220),
2088
- name='foo')],
2089
- inverter='blarg',
2090
- )
2091
- expected = """PVSystem:
2092
- name: None
2093
- Array:
2094
- name: None
2095
- mount: FixedMount(surface_tilt=30, surface_azimuth=100, racking_model=None, module_height=None)
2096
- module: None
2097
- albedo: 0.25
2098
- module_type: None
2099
- temperature_model_parameters: {}
2100
- strings: 1
2101
- modules_per_string: 1
2102
- Array:
2103
- name: foo
2104
- mount: FixedMount(surface_tilt=20, surface_azimuth=220, racking_model=None, module_height=None)
2105
- module: None
2106
- albedo: 0.25
2107
- module_type: None
2108
- temperature_model_parameters: {}
2109
- strings: 1
2110
- modules_per_string: 1
2111
- inverter: blarg""" # noqa: E501
2112
- assert expected == system.__repr__()
2113
-
2114
-
2115
- def test_Array___repr__():
2116
- array = pvsystem.Array(
2117
- mount=pvsystem.FixedMount(surface_tilt=10, surface_azimuth=100,
2118
- racking_model='close_mount'),
2119
- albedo=0.15, module_type='glass_glass',
2120
- temperature_model_parameters={'a': -3.56},
2121
- module_parameters={'foo': 'bar'},
2122
- modules_per_string=100,
2123
- strings=10, module='baz',
2124
- name='biz'
2125
- )
2126
- expected = """Array:
2127
- name: biz
2128
- mount: FixedMount(surface_tilt=10, surface_azimuth=100, racking_model='close_mount', module_height=None)
2129
- module: baz
2130
- albedo: 0.15
2131
- module_type: glass_glass
2132
- temperature_model_parameters: {'a': -3.56}
2133
- strings: 10
2134
- modules_per_string: 100""" # noqa: E501
2135
- assert array.__repr__() == expected
2136
-
2137
-
2138
- def test_pvwatts_dc_scalars():
2139
- expected = 88.65
2140
- out = pvsystem.pvwatts_dc(900, 30, 100, -0.003)
2141
- assert_allclose(out, expected)
2142
-
2143
-
2144
- def test_pvwatts_dc_arrays():
2145
- irrad_trans = np.array([np.nan, 900, 900])
2146
- temp_cell = np.array([30, np.nan, 30])
2147
- irrad_trans, temp_cell = np.meshgrid(irrad_trans, temp_cell)
2148
- expected = np.array([[nan, 88.65, 88.65],
2149
- [nan, nan, nan],
2150
- [nan, 88.65, 88.65]])
2151
- out = pvsystem.pvwatts_dc(irrad_trans, temp_cell, 100, -0.003)
2152
- assert_allclose(out, expected, equal_nan=True)
2153
-
2154
-
2155
- def test_pvwatts_dc_series():
2156
- irrad_trans = pd.Series([np.nan, 900, 900])
2157
- temp_cell = pd.Series([30, np.nan, 30])
2158
- expected = pd.Series(np.array([ nan, nan, 88.65]))
2159
- out = pvsystem.pvwatts_dc(irrad_trans, temp_cell, 100, -0.003)
2160
- assert_series_equal(expected, out)
2161
-
2162
-
2163
- def test_pvwatts_losses_default():
2164
- expected = 14.075660688264469
2165
- out = pvsystem.pvwatts_losses()
2166
- assert_allclose(out, expected)
2167
-
2168
-
2169
- def test_pvwatts_losses_arrays():
2170
- expected = np.array([nan, 14.934904])
2171
- age = np.array([nan, 1])
2172
- out = pvsystem.pvwatts_losses(age=age)
2173
- assert_allclose(out, expected)
2174
-
2175
-
2176
- def test_pvwatts_losses_series():
2177
- expected = pd.Series([nan, 14.934904])
2178
- age = pd.Series([nan, 1])
2179
- out = pvsystem.pvwatts_losses(age=age)
2180
- assert_series_equal(expected, out)
2181
-
2182
-
2183
- @pytest.fixture
2184
- def pvwatts_system_defaults():
2185
- module_parameters = {'pdc0': 100, 'gamma_pdc': -0.003}
2186
- inverter_parameters = {'pdc0': 90}
2187
- system = pvsystem.PVSystem(module_parameters=module_parameters,
2188
- inverter_parameters=inverter_parameters)
2189
- return system
2190
-
2191
-
2192
- @pytest.fixture
2193
- def pvwatts_system_kwargs():
2194
- module_parameters = {'pdc0': 100, 'gamma_pdc': -0.003, 'temp_ref': 20}
2195
- inverter_parameters = {'pdc0': 90, 'eta_inv_nom': 0.95, 'eta_inv_ref': 1.0}
2196
- system = pvsystem.PVSystem(module_parameters=module_parameters,
2197
- inverter_parameters=inverter_parameters)
2198
- return system
2199
-
2200
-
2201
- def test_PVSystem_pvwatts_dc(pvwatts_system_defaults, mocker):
2202
- mocker.spy(pvsystem, 'pvwatts_dc')
2203
- irrad = 900
2204
- temp_cell = 30
2205
- expected = 90
2206
- out = pvwatts_system_defaults.pvwatts_dc(irrad, temp_cell)
2207
- pvsystem.pvwatts_dc.assert_called_once_with(
2208
- irrad, temp_cell,
2209
- **pvwatts_system_defaults.arrays[0].module_parameters)
2210
- assert_allclose(expected, out, atol=10)
2211
-
2212
-
2213
- def test_PVSystem_pvwatts_dc_kwargs(pvwatts_system_kwargs, mocker):
2214
- mocker.spy(pvsystem, 'pvwatts_dc')
2215
- irrad = 900
2216
- temp_cell = 30
2217
- expected = 90
2218
- out = pvwatts_system_kwargs.pvwatts_dc(irrad, temp_cell)
2219
- pvsystem.pvwatts_dc.assert_called_once_with(
2220
- irrad, temp_cell, **pvwatts_system_kwargs.arrays[0].module_parameters)
2221
- assert_allclose(expected, out, atol=10)
2222
-
2223
-
2224
- def test_PVSystem_multiple_array_pvwatts_dc():
2225
- array_one_module_parameters = {
2226
- 'pdc0': 100, 'gamma_pdc': -0.003, 'temp_ref': 20
2227
- }
2228
- array_one = pvsystem.Array(
2229
- pvsystem.FixedMount(0, 180),
2230
- module_parameters=array_one_module_parameters
2231
- )
2232
- array_two_module_parameters = {
2233
- 'pdc0': 150, 'gamma_pdc': -0.002, 'temp_ref': 25
2234
- }
2235
- array_two = pvsystem.Array(
2236
- pvsystem.FixedMount(0, 180),
2237
- module_parameters=array_two_module_parameters
2238
- )
2239
- system = pvsystem.PVSystem(arrays=[array_one, array_two])
2240
- irrad_one = 900
2241
- irrad_two = 500
2242
- temp_cell_one = 30
2243
- temp_cell_two = 20
2244
- expected_one = pvsystem.pvwatts_dc(irrad_one, temp_cell_one,
2245
- **array_one_module_parameters)
2246
- expected_two = pvsystem.pvwatts_dc(irrad_two, temp_cell_two,
2247
- **array_two_module_parameters)
2248
- dc_one, dc_two = system.pvwatts_dc((irrad_one, irrad_two),
2249
- (temp_cell_one, temp_cell_two))
2250
- assert dc_one == expected_one
2251
- assert dc_two == expected_two
2252
-
2253
-
2254
- def test_PVSystem_multiple_array_pvwatts_dc_value_error():
2255
- system = pvsystem.PVSystem(
2256
- arrays=[pvsystem.Array(pvsystem.FixedMount(0, 180)),
2257
- pvsystem.Array(pvsystem.FixedMount(0, 180)),
2258
- pvsystem.Array(pvsystem.FixedMount(0, 180))]
2259
- )
2260
- error_message = 'Length mismatch for per-array parameter'
2261
- with pytest.raises(ValueError, match=error_message):
2262
- system.pvwatts_dc(10, (1, 1, 1))
2263
- with pytest.raises(ValueError, match=error_message):
2264
- system.pvwatts_dc((10, 10), (1, 1, 1))
2265
- with pytest.raises(ValueError, match=error_message):
2266
- system.pvwatts_dc((10, 10, 10, 10), (1, 1, 1))
2267
- with pytest.raises(ValueError, match=error_message):
2268
- system.pvwatts_dc((1, 1, 1), 1)
2269
- with pytest.raises(ValueError, match=error_message):
2270
- system.pvwatts_dc((1, 1, 1), (1,))
2271
- with pytest.raises(ValueError, match=error_message):
2272
- system.pvwatts_dc((1,), 1)
2273
- with pytest.raises(ValueError, match=error_message):
2274
- system.pvwatts_dc((1, 1, 1, 1), (1, 1))
2275
- with pytest.raises(ValueError, match=error_message):
2276
- system.pvwatts_dc(2, 3)
2277
- with pytest.raises(ValueError, match=error_message):
2278
- # ValueError is raised for non-tuple iterable with correct length
2279
- system.pvwatts_dc((1, 1, 1), pd.Series([1, 2, 3]))
2280
-
2281
-
2282
- def test_PVSystem_pvwatts_losses(pvwatts_system_defaults, mocker):
2283
- mocker.spy(pvsystem, 'pvwatts_losses')
2284
- age = 1
2285
- pvwatts_system_defaults.losses_parameters = dict(age=age)
2286
- expected = 15
2287
- out = pvwatts_system_defaults.pvwatts_losses()
2288
- pvsystem.pvwatts_losses.assert_called_once_with(age=age)
2289
- assert out < expected
2290
-
2291
-
2292
- def test_PVSystem_num_arrays():
2293
- system_one = pvsystem.PVSystem()
2294
- system_two = pvsystem.PVSystem(arrays=[
2295
- pvsystem.Array(pvsystem.FixedMount(0, 180)),
2296
- pvsystem.Array(pvsystem.FixedMount(0, 180))])
2297
- assert system_one.num_arrays == 1
2298
- assert system_two.num_arrays == 2
2299
-
2300
-
2301
- def test_PVSystem_at_least_one_array():
2302
- with pytest.raises(ValueError,
2303
- match="PVSystem must have at least one Array"):
2304
- pvsystem.PVSystem(arrays=[])
2305
-
2306
-
2307
- def test_PVSystem_single_array():
2308
- # GH 1831
2309
- single_array = pvsystem.Array(pvsystem.FixedMount())
2310
- system = pvsystem.PVSystem(arrays=single_array)
2311
- assert isinstance(system.arrays, tuple)
2312
- assert system.arrays[0] is single_array
2313
-
2314
-
2315
- def test_combine_loss_factors():
2316
- test_index = pd.date_range(start='1990/01/01T12:00', periods=365, freq='d')
2317
- loss_1 = pd.Series(.10, index=test_index)
2318
- loss_2 = pd.Series(.05, index=pd.date_range(start='1990/01/01T12:00',
2319
- periods=365*2, freq='d'))
2320
- loss_3 = pd.Series(.02, index=pd.date_range(start='1990/01/01',
2321
- periods=12, freq='MS'))
2322
- expected = pd.Series(.1621, index=test_index)
2323
- out = pvsystem.combine_loss_factors(test_index, loss_1, loss_2, loss_3)
2324
- assert_series_equal(expected, out)
2325
-
2326
-
2327
- def test_no_extra_kwargs():
2328
- with pytest.raises(TypeError, match="arbitrary_kwarg"):
2329
- pvsystem.PVSystem(arbitrary_kwarg='value')
2330
-
2331
-
2332
- def test_AbstractMount_constructor():
2333
- match = "Can't instantiate abstract class AbstractMount"
2334
- with pytest.raises(TypeError, match=match):
2335
- _ = pvsystem.AbstractMount()
2336
-
2337
-
2338
- @pytest.fixture
2339
- def fixed_mount():
2340
- return pvsystem.FixedMount(20, 180)
2341
-
2342
-
2343
- @pytest.fixture
2344
- def single_axis_tracker_mount():
2345
- return pvsystem.SingleAxisTrackerMount(axis_tilt=10, axis_azimuth=170,
2346
- max_angle=45, backtrack=False,
2347
- gcr=0.4, cross_axis_tilt=-5)
2348
-
2349
-
2350
- def test_FixedMount_constructor(fixed_mount):
2351
- assert fixed_mount.surface_tilt == 20
2352
- assert fixed_mount.surface_azimuth == 180
2353
-
2354
-
2355
- def test_FixedMount_get_orientation(fixed_mount):
2356
- expected = {'surface_tilt': 20, 'surface_azimuth': 180}
2357
- assert fixed_mount.get_orientation(45, 130) == expected
2358
-
2359
-
2360
- def test_SingleAxisTrackerMount_constructor(single_axis_tracker_mount):
2361
- expected = dict(axis_tilt=10, axis_azimuth=170, max_angle=45,
2362
- backtrack=False, gcr=0.4, cross_axis_tilt=-5)
2363
- for attr_name, expected_value in expected.items():
2364
- assert getattr(single_axis_tracker_mount, attr_name) == expected_value
2365
-
2366
-
2367
- def test_SingleAxisTrackerMount_get_orientation(single_axis_tracker_mount):
2368
- expected = {'surface_tilt': 19.29835284, 'surface_azimuth': 229.7643755}
2369
- actual = single_axis_tracker_mount.get_orientation(45, 190)
2370
- for key, expected_value in expected.items():
2371
- err_msg = f"{key} value incorrect"
2372
- assert actual[key] == pytest.approx(expected_value), err_msg
2373
-
2374
-
2375
- def test_SingleAxisTrackerMount_get_orientation_asymmetric_max():
2376
- mount = pvsystem.SingleAxisTrackerMount(max_angle=(-30, 45))
2377
- expected = {'surface_tilt': [45, 30], 'surface_azimuth': [90, 270]}
2378
- actual = mount.get_orientation([60, 60], [90, 270])
2379
- for key, expected_value in expected.items():
2380
- err_msg = f"{key} value incorrect"
2381
- assert actual[key] == pytest.approx(expected_value), err_msg
2382
-
2383
-
2384
- def test_dc_ohms_from_percent():
2385
- expected = .1425
2386
- out = pvsystem.dc_ohms_from_percent(38, 8, 3, 1, 1)
2387
- assert_allclose(out, expected)
2388
-
2389
-
2390
- def test_PVSystem_dc_ohms_from_percent(mocker):
2391
- mocker.spy(pvsystem, 'dc_ohms_from_percent')
2392
-
2393
- expected = .1425
2394
- system = pvsystem.PVSystem(losses_parameters={'dc_ohmic_percent': 3},
2395
- module_parameters={'I_mp_ref': 8,
2396
- 'V_mp_ref': 38})
2397
- out = system.dc_ohms_from_percent()
2398
-
2399
- pvsystem.dc_ohms_from_percent.assert_called_once_with(
2400
- dc_ohmic_percent=3,
2401
- vmp_ref=38,
2402
- imp_ref=8,
2403
- modules_per_string=1,
2404
- strings=1
2405
- )
2406
-
2407
- assert_allclose(out, expected)
2408
-
2409
-
2410
- def test_dc_ohmic_losses():
2411
- expected = 9.12
2412
- out = pvsystem.dc_ohmic_losses(.1425, 8)
2413
- assert_allclose(out, expected)
2414
-
2415
-
2416
- def test_Array_dc_ohms_from_percent(mocker):
2417
- mocker.spy(pvsystem, 'dc_ohms_from_percent')
2418
-
2419
- expected = .1425
2420
-
2421
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2422
- array_losses_parameters={'dc_ohmic_percent': 3},
2423
- module_parameters={'I_mp_ref': 8,
2424
- 'V_mp_ref': 38})
2425
- out = array.dc_ohms_from_percent()
2426
- pvsystem.dc_ohms_from_percent.assert_called_with(
2427
- dc_ohmic_percent=3,
2428
- vmp_ref=38,
2429
- imp_ref=8,
2430
- modules_per_string=1,
2431
- strings=1
2432
- )
2433
- assert_allclose(out, expected)
2434
-
2435
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2436
- array_losses_parameters={'dc_ohmic_percent': 3},
2437
- module_parameters={'Impo': 8,
2438
- 'Vmpo': 38})
2439
- out = array.dc_ohms_from_percent()
2440
- pvsystem.dc_ohms_from_percent.assert_called_with(
2441
- dc_ohmic_percent=3,
2442
- vmp_ref=38,
2443
- imp_ref=8,
2444
- modules_per_string=1,
2445
- strings=1
2446
- )
2447
- assert_allclose(out, expected)
2448
-
2449
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2450
- array_losses_parameters={'dc_ohmic_percent': 3},
2451
- module_parameters={'Impp': 8,
2452
- 'Vmpp': 38})
2453
- out = array.dc_ohms_from_percent()
2454
-
2455
- pvsystem.dc_ohms_from_percent.assert_called_with(
2456
- dc_ohmic_percent=3,
2457
- vmp_ref=38,
2458
- imp_ref=8,
2459
- modules_per_string=1,
2460
- strings=1
2461
- )
2462
- assert_allclose(out, expected)
2463
-
2464
- with pytest.raises(ValueError,
2465
- match=('Parameters for Vmp and Imp could not be found '
2466
- 'in the array module parameters. Module '
2467
- 'parameters must include one set of '
2468
- '{"V_mp_ref", "I_mp_Ref"}, '
2469
- '{"Vmpo", "Impo"}, or '
2470
- '{"Vmpp", "Impp"}.')):
2471
- array = pvsystem.Array(pvsystem.FixedMount(0, 180),
2472
- array_losses_parameters={'dc_ohmic_percent': 3})
2473
- out = array.dc_ohms_from_percent()
2474
-
2475
-
2476
- @pytest.mark.parametrize('model,keys', [
2477
- ('sapm', ('a', 'b', 'deltaT')),
2478
- ('fuentes', ('noct_installed',)),
2479
- ('noct_sam', ('noct', 'module_efficiency'))
2480
- ])
2481
- def test_Array_temperature_missing_parameters(model, keys):
2482
- # test that a nice error is raised when required temp params are missing
2483
- array = pvsystem.Array(pvsystem.FixedMount(0, 180))
2484
- index = pd.date_range('2019-01-01', freq='h', periods=5)
2485
- temps = pd.Series(25, index)
2486
- irrads = pd.Series(1000, index)
2487
- winds = pd.Series(1, index)
2488
-
2489
- for key in keys:
2490
- match = f"Missing required parameter '{key}'"
2491
- params = {k: 1 for k in keys} # dummy values
2492
- params.pop(key) # remove each key in turn
2493
- array.temperature_model_parameters = params
2494
- with pytest.raises(KeyError, match=match):
2495
- array.get_cell_temperature(irrads, temps, winds, model)