pvlib 0.9.4a1__py3-none-any.whl → 0.10.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 (86) hide show
  1. pvlib/__init__.py +3 -2
  2. pvlib/atmosphere.py +23 -173
  3. pvlib/bifacial/infinite_sheds.py +88 -277
  4. pvlib/bifacial/utils.py +270 -28
  5. pvlib/data/adr-library-cec-inverters-2019-03-05.csv +5009 -0
  6. pvlib/data/precise_iv_curves1.json +10251 -0
  7. pvlib/data/precise_iv_curves2.json +10251 -0
  8. pvlib/data/precise_iv_curves_parameter_sets1.csv +33 -0
  9. pvlib/data/precise_iv_curves_parameter_sets2.csv +33 -0
  10. pvlib/data/test_psm3_2017.csv +17521 -17521
  11. pvlib/data/test_psm3_2019_5min.csv +288 -288
  12. pvlib/data/test_read_psm3.csv +17522 -17522
  13. pvlib/data/test_read_pvgis_horizon.csv +49 -0
  14. pvlib/data/variables_style_rules.csv +3 -0
  15. pvlib/iam.py +207 -51
  16. pvlib/inverter.py +6 -1
  17. pvlib/iotools/__init__.py +7 -2
  18. pvlib/iotools/acis.py +516 -0
  19. pvlib/iotools/midc.py +4 -4
  20. pvlib/iotools/psm3.py +59 -42
  21. pvlib/iotools/pvgis.py +84 -28
  22. pvlib/iotools/sodapro.py +8 -6
  23. pvlib/iotools/srml.py +121 -18
  24. pvlib/iotools/surfrad.py +2 -2
  25. pvlib/iotools/tmy.py +146 -102
  26. pvlib/irradiance.py +270 -15
  27. pvlib/ivtools/sde.py +14 -20
  28. pvlib/ivtools/sdm.py +31 -20
  29. pvlib/ivtools/utils.py +127 -6
  30. pvlib/location.py +3 -2
  31. pvlib/modelchain.py +67 -70
  32. pvlib/pvarray.py +225 -0
  33. pvlib/pvsystem.py +169 -539
  34. pvlib/shading.py +43 -2
  35. pvlib/singlediode.py +216 -66
  36. pvlib/snow.py +36 -15
  37. pvlib/soiling.py +3 -3
  38. pvlib/spa.py +327 -368
  39. pvlib/spectrum/__init__.py +8 -2
  40. pvlib/spectrum/mismatch.py +335 -0
  41. pvlib/temperature.py +124 -13
  42. pvlib/tests/bifacial/test_infinite_sheds.py +44 -106
  43. pvlib/tests/bifacial/test_utils.py +102 -5
  44. pvlib/tests/conftest.py +0 -31
  45. pvlib/tests/iotools/test_acis.py +213 -0
  46. pvlib/tests/iotools/test_midc.py +6 -6
  47. pvlib/tests/iotools/test_psm3.py +7 -5
  48. pvlib/tests/iotools/test_pvgis.py +21 -14
  49. pvlib/tests/iotools/test_sodapro.py +1 -1
  50. pvlib/tests/iotools/test_srml.py +71 -6
  51. pvlib/tests/iotools/test_tmy.py +43 -8
  52. pvlib/tests/ivtools/test_sde.py +19 -17
  53. pvlib/tests/ivtools/test_sdm.py +9 -4
  54. pvlib/tests/ivtools/test_utils.py +96 -1
  55. pvlib/tests/test_atmosphere.py +8 -64
  56. pvlib/tests/test_clearsky.py +0 -1
  57. pvlib/tests/test_iam.py +74 -1
  58. pvlib/tests/test_irradiance.py +56 -2
  59. pvlib/tests/test_location.py +1 -1
  60. pvlib/tests/test_modelchain.py +33 -76
  61. pvlib/tests/test_pvarray.py +46 -0
  62. pvlib/tests/test_pvsystem.py +366 -201
  63. pvlib/tests/test_shading.py +35 -0
  64. pvlib/tests/test_singlediode.py +306 -29
  65. pvlib/tests/test_snow.py +84 -1
  66. pvlib/tests/test_soiling.py +8 -7
  67. pvlib/tests/test_solarposition.py +7 -7
  68. pvlib/tests/test_spa.py +6 -7
  69. pvlib/tests/test_spectrum.py +145 -1
  70. pvlib/tests/test_temperature.py +29 -11
  71. pvlib/tests/test_tools.py +41 -0
  72. pvlib/tests/test_tracking.py +0 -149
  73. pvlib/tools.py +49 -25
  74. pvlib/tracking.py +1 -269
  75. pvlib-0.10.0.dist-info/AUTHORS.md +35 -0
  76. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/LICENSE +5 -2
  77. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/METADATA +3 -13
  78. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/RECORD +80 -75
  79. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/WHEEL +1 -1
  80. pvlib/data/adr-library-2013-10-01.csv +0 -1762
  81. pvlib/forecast.py +0 -1211
  82. pvlib/iotools/ecmwf_macc.py +0 -312
  83. pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
  84. pvlib/tests/test_forecast.py +0 -228
  85. pvlib-0.9.4a1.dist-info/AUTHORS.md +0 -32
  86. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
@@ -9,8 +9,9 @@ import pytest
9
9
  import requests
10
10
  from pvlib.iotools import get_pvgis_tmy, read_pvgis_tmy
11
11
  from pvlib.iotools import get_pvgis_hourly, read_pvgis_hourly
12
+ from pvlib.iotools import get_pvgis_horizon
12
13
  from ..conftest import (DATA_DIR, RERUNS, RERUNS_DELAY, assert_frame_equal,
13
- fail_on_pvlib_version)
14
+ fail_on_pvlib_version, assert_series_equal)
14
15
  from pvlib._deprecation import pvlibDeprecationWarning
15
16
 
16
17
 
@@ -206,14 +207,14 @@ def test_read_pvgis_hourly_bad_extension():
206
207
 
207
208
 
208
209
  args_radiation_csv = {
209
- 'surface_tilt': 30, 'surface_azimuth': 0, 'outputformat': 'csv',
210
+ 'surface_tilt': 30, 'surface_azimuth': 180, 'outputformat': 'csv',
210
211
  'usehorizon': False, 'userhorizon': None, 'raddatabase': 'PVGIS-SARAH',
211
212
  'start': 2016, 'end': 2016, 'pvcalculation': False, 'components': True}
212
213
 
213
214
  url_hourly_radiation_csv = 'https://re.jrc.ec.europa.eu/api/seriescalc?lat=45&lon=8&outputformat=csv&angle=30&aspect=0&usehorizon=0&pvtechchoice=crystSi&mountingplace=free&trackingtype=0&components=1&raddatabase=PVGIS-SARAH&startyear=2016&endyear=2016' # noqa: E501
214
215
 
215
216
  args_pv_json = {
216
- 'surface_tilt': 30, 'surface_azimuth': 0, 'outputformat': 'json',
217
+ 'surface_tilt': 30, 'surface_azimuth': 180, 'outputformat': 'json',
217
218
  'usehorizon': True, 'userhorizon': None, 'raddatabase': 'PVGIS-SARAH2',
218
219
  'start': pd.Timestamp(2013, 1, 1), 'end': pd.Timestamp(2014, 5, 1),
219
220
  'pvcalculation': True, 'peakpower': 10, 'pvtechchoice': 'CIS', 'loss': 5,
@@ -364,17 +365,6 @@ def pvgis_tmy_mapped_columns():
364
365
  'wind_speed', 'wind_direction', 'pressure']
365
366
 
366
367
 
367
- @fail_on_pvlib_version('0.10')
368
- @pytest.mark.remote_data
369
- @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
370
- def test_pvgis_tmy_variable_map_deprecating_warning_0_10():
371
- with pytest.warns(pvlibDeprecationWarning, match='names will be renamed'):
372
- _ = get_pvgis_tmy(45, 8)
373
- with pytest.warns(pvlibDeprecationWarning, match='names will be renamed'):
374
- fn = DATA_DIR / 'tmy_45.000_8.000_2005_2016.epw'
375
- _ = read_pvgis_tmy(fn)
376
-
377
-
378
368
  @pytest.mark.remote_data
379
369
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
380
370
  def test_get_pvgis_tmy(expected, month_year_expected, inputs_expected,
@@ -509,6 +499,23 @@ def test_get_pvgis_map_variables(pvgis_tmy_mapped_columns):
509
499
  assert all([c in pvgis_tmy_mapped_columns for c in actual.columns])
510
500
 
511
501
 
502
+ @pytest.mark.remote_data
503
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
504
+ def test_read_pvgis_horizon():
505
+ pvgis_data, _ = get_pvgis_horizon(35.171051, -106.465158)
506
+ horizon_data = pd.read_csv(DATA_DIR / 'test_read_pvgis_horizon.csv',
507
+ index_col=0)
508
+ horizon_data = horizon_data['horizon_elevation']
509
+ assert_series_equal(pvgis_data, horizon_data)
510
+
511
+
512
+ @pytest.mark.remote_data
513
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
514
+ def test_read_pvgis_horizon_invalid_coords():
515
+ with pytest.raises(requests.HTTPError, match='lat: Incorrect value'):
516
+ _, _ = get_pvgis_horizon(100, 50) # unfeasible latitude
517
+
518
+
512
519
  def test_read_pvgis_tmy_map_variables(pvgis_tmy_mapped_columns):
513
520
  fn = DATA_DIR / 'tmy_45.000_8.000_2005_2016.json'
514
521
  actual, _, _, _ = read_pvgis_tmy(fn, map_variables=True)
@@ -209,7 +209,7 @@ def test_get_cams(requests_mock, testfile, index, columns, values, dtypes,
209
209
  mock_response = test_file.read()
210
210
  # Specify the full URI of a specific example, this ensures that all of the
211
211
  # inputs are passing on correctly
212
- url_test_cams = f'https://www.soda-is.com/service/wps?DataInputs=latitude=55.7906;longitude=12.5251;altitude=80;date_begin=2020-01-01;date_end=2020-05-04;time_ref=UT;summarization=P01M;username=pvlib-admin%2540googlegroups.com;verbose=false&Service=WPS&Request=Execute&Identifier=get_{identifier}&version=1.0.0&RawDataOutput=irradiation' # noqa: E501
212
+ url_test_cams = f'https://api.soda-solardata.com/service/wps?DataInputs=latitude=55.7906;longitude=12.5251;altitude=80;date_begin=2020-01-01;date_end=2020-05-04;time_ref=UT;summarization=P01M;username=pvlib-admin%2540googlegroups.com;verbose=false&Service=WPS&Request=Execute&Identifier=get_{identifier}&version=1.0.0&RawDataOutput=irradiation' # noqa: E501
213
213
 
214
214
  requests_mock.get(url_test_cams, text=mock_response,
215
215
  headers={'Content-Type': 'application/csv'})
@@ -3,7 +3,9 @@ import pandas as pd
3
3
  import pytest
4
4
 
5
5
  from pvlib.iotools import srml
6
- from ..conftest import DATA_DIR, RERUNS, RERUNS_DELAY
6
+ from ..conftest import (DATA_DIR, RERUNS, RERUNS_DELAY, assert_index_equal,
7
+ assert_frame_equal, fail_on_pvlib_version)
8
+ from pvlib._deprecation import pvlibDeprecationWarning
7
9
 
8
10
  srml_testfile = DATA_DIR / 'SRML-day-EUPO1801.txt'
9
11
 
@@ -28,6 +30,16 @@ def test_read_srml_columns_exist():
28
30
  assert '7008_flag' in data.columns
29
31
 
30
32
 
33
+ def test_read_srml_map_variables_false():
34
+ data = srml.read_srml(srml_testfile, map_variables=False)
35
+ assert '1000' in data.columns
36
+ assert '1000_flag' in data.columns
37
+ assert '2010' in data.columns
38
+ assert '2010_flag' in data.columns
39
+ assert '7008' in data.columns
40
+ assert '7008_flag' in data.columns
41
+
42
+
31
43
  def test_read_srml_nans_exist():
32
44
  data = srml.read_srml(srml_testfile)
33
45
  assert isnan(data['dni_0'][1119])
@@ -60,23 +72,37 @@ def test_read_srml_dt_index(url, year, month):
60
72
  ('2001', '2001'),
61
73
  ('2017', 'dni_7')
62
74
  ])
63
- def test_map_columns(column, expected):
64
- assert srml.map_columns(column) == expected
75
+ def test__map_columns(column, expected):
76
+ assert srml._map_columns(column) == expected
65
77
 
66
78
 
79
+ @pytest.mark.remote_data
80
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
81
+ def test_get_srml():
82
+ url = 'http://solardat.uoregon.edu/download/Archive/EUPO1801.txt'
83
+ file_data = srml.read_srml(url)
84
+ requested, _ = srml.get_srml(station='EU', start='2018-01-01',
85
+ end='2018-01-31')
86
+ assert_frame_equal(file_data, requested)
87
+
88
+
89
+ @fail_on_pvlib_version('0.11')
67
90
  @pytest.mark.remote_data
68
91
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
69
92
  def test_read_srml_month_from_solardat():
70
93
  url = 'http://solardat.uoregon.edu/download/Archive/EUPO1801.txt'
71
94
  file_data = srml.read_srml(url)
72
- requested = srml.read_srml_month_from_solardat('EU', 2018, 1)
95
+ with pytest.warns(pvlibDeprecationWarning, match='get_srml instead'):
96
+ requested = srml.read_srml_month_from_solardat('EU', 2018, 1)
73
97
  assert file_data.equals(requested)
74
98
 
75
99
 
100
+ @fail_on_pvlib_version('0.11')
76
101
  @pytest.mark.remote_data
77
102
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
78
103
  def test_15_minute_dt_index():
79
- data = srml.read_srml_month_from_solardat('TW', 2019, 4, 'RQ')
104
+ with pytest.warns(pvlibDeprecationWarning, match='get_srml instead'):
105
+ data = srml.read_srml_month_from_solardat('TW', 2019, 4, 'RQ')
80
106
  start = pd.Timestamp('20190401 00:00')
81
107
  start = start.tz_localize('Etc/GMT+8')
82
108
  end = pd.Timestamp('20190430 23:45')
@@ -86,10 +112,12 @@ def test_15_minute_dt_index():
86
112
  assert (data.index[3::4].minute == 45).all()
87
113
 
88
114
 
115
+ @fail_on_pvlib_version('0.11')
89
116
  @pytest.mark.remote_data
90
117
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
91
118
  def test_hourly_dt_index():
92
- data = srml.read_srml_month_from_solardat('CD', 1986, 4, 'PH')
119
+ with pytest.warns(pvlibDeprecationWarning, match='get_srml instead'):
120
+ data = srml.read_srml_month_from_solardat('CD', 1986, 4, 'PH')
93
121
  start = pd.Timestamp('19860401 00:00')
94
122
  start = start.tz_localize('Etc/GMT+8')
95
123
  end = pd.Timestamp('19860430 23:00')
@@ -97,3 +125,40 @@ def test_hourly_dt_index():
97
125
  assert data.index[0] == start
98
126
  assert data.index[-1] == end
99
127
  assert (data.index.minute == 0).all()
128
+
129
+
130
+ @pytest.mark.remote_data
131
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
132
+ def test_get_srml_hourly():
133
+ data, meta = data, meta = srml.get_srml(station='CD', start='1986-04-01',
134
+ end='1986-05-31', filetype='PH')
135
+ expected_index = pd.date_range(start='1986-04-01', end='1986-05-31 23:59',
136
+ freq='1h', tz='Etc/GMT+8')
137
+ assert_index_equal(data.index, expected_index)
138
+
139
+
140
+ @pytest.mark.remote_data
141
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
142
+ def test_get_srml_minute():
143
+ data_read = srml.read_srml(srml_testfile)
144
+ data_get, meta = srml.get_srml(station='EU', start='2018-01-01',
145
+ end='2018-01-31', filetype='PO')
146
+ expected_index = pd.date_range(start='2018-01-01', end='2018-01-31 23:59',
147
+ freq='1min', tz='Etc/GMT+8')
148
+ assert_index_equal(data_get.index, expected_index)
149
+ assert all([c in data_get.columns for c in data_read.columns])
150
+ # Check that all indices in example file are present in remote file
151
+ assert data_read.index.isin(data_get.index).all()
152
+ assert meta['station'] == 'EU'
153
+ assert meta['filetype'] == 'PO'
154
+ assert meta['filenames'] == ['EUPO1801.txt']
155
+
156
+
157
+ @pytest.mark.remote_data
158
+ @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
159
+ def test_get_srml_nonexisting_month_warning():
160
+ with pytest.warns(UserWarning, match='file was not found: EUPO0912.txt'):
161
+ # Request data for a period where not all files exist
162
+ # Eugene (EU) station started reporting 1-minute data in January 2010
163
+ data, meta = data, meta = srml.get_srml(
164
+ station='EU', start='2009-12-01', end='2010-01-31', filetype='PO')
@@ -1,8 +1,10 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
3
  from pvlib.iotools import tmy
4
+ from pvlib._deprecation import pvlibDeprecationWarning
4
5
  from ..conftest import DATA_DIR
5
6
  import pytest
7
+ import warnings
6
8
 
7
9
  # test the API works
8
10
  from pvlib.iotools import read_tmy3
@@ -16,29 +18,60 @@ TMY3_SOLARANYWHERE = DATA_DIR / 'Burlington, United States SolarAnywhere Time Se
16
18
 
17
19
 
18
20
  def test_read_tmy3():
19
- tmy.read_tmy3(TMY3_TESTFILE)
21
+ tmy.read_tmy3(TMY3_TESTFILE, map_variables=False)
20
22
 
21
23
 
22
24
  def test_read_tmy3_recolumn():
23
- data, meta = tmy.read_tmy3(TMY3_TESTFILE)
25
+ with warnings.catch_warnings():
26
+ warnings.simplefilter("ignore")
27
+ data, meta = tmy.read_tmy3(TMY3_TESTFILE, recolumn=True)
24
28
  assert 'GHISource' in data.columns
25
29
 
26
30
 
27
31
  def test_read_tmy3_norecolumn():
28
- data, _ = tmy.read_tmy3(TMY3_TESTFILE, recolumn=False)
32
+ data, _ = tmy.read_tmy3(TMY3_TESTFILE, map_variables=False)
29
33
  assert 'GHI source' in data.columns
30
34
 
31
35
 
36
+ def test_read_tmy3_raise_valueerror():
37
+ with pytest.raises(ValueError, match='`map_variables` and `recolumn`'):
38
+ _ = tmy.read_tmy3(TMY3_TESTFILE, recolumn=True, map_variables=True)
39
+
40
+
41
+ def test_read_tmy3_map_variables():
42
+ data, meta = tmy.read_tmy3(TMY3_TESTFILE, map_variables=True)
43
+ assert 'ghi' in data.columns
44
+ assert 'dni' in data.columns
45
+ assert 'dhi' in data.columns
46
+ assert 'pressure' in data.columns
47
+ assert 'wind_direction' in data.columns
48
+ assert 'wind_speed' in data.columns
49
+ assert 'temp_air' in data.columns
50
+ assert 'temp_dew' in data.columns
51
+ assert 'relative_humidity' in data.columns
52
+ assert 'albedo' in data.columns
53
+ assert 'ghi_extra' in data.columns
54
+ assert 'dni_extra' in data.columns
55
+ assert 'precipitable_water' in data.columns
56
+
57
+
58
+ def test_read_tmy3_map_variables_deprecating_warning():
59
+ with pytest.warns(pvlibDeprecationWarning, match='names will be renamed'):
60
+ data, meta = tmy.read_tmy3(TMY3_TESTFILE)
61
+
62
+
32
63
  def test_read_tmy3_coerce_year():
33
64
  coerce_year = 1987
34
- data, _ = tmy.read_tmy3(TMY3_TESTFILE, coerce_year=coerce_year)
65
+ data, _ = tmy.read_tmy3(TMY3_TESTFILE, coerce_year=coerce_year,
66
+ map_variables=False)
35
67
  assert (data.index[:-1].year == 1987).all()
36
68
  assert data.index[-1].year == 1988
37
69
 
38
70
 
39
71
  def test_read_tmy3_no_coerce_year():
40
72
  coerce_year = None
41
- data, _ = tmy.read_tmy3(TMY3_TESTFILE, coerce_year=coerce_year)
73
+ data, _ = tmy.read_tmy3(TMY3_TESTFILE, coerce_year=coerce_year,
74
+ map_variables=False)
42
75
  assert 1997 and 1999 in data.index.year
43
76
  assert data.index[-2] == pd.Timestamp('1998-12-31 23:00:00-09:00')
44
77
  assert data.index[-1] == pd.Timestamp('1999-01-01 00:00:00-09:00')
@@ -50,7 +83,7 @@ def test_read_tmy2():
50
83
 
51
84
  def test_gh865_read_tmy3_feb_leapyear_hr24():
52
85
  """correctly parse the 24th hour if the tmy3 file has a leap year in feb"""
53
- data, meta = read_tmy3(TMY3_FEB_LEAPYEAR)
86
+ data, meta = read_tmy3(TMY3_FEB_LEAPYEAR, map_variables=False)
54
87
  # just to be safe, make sure this _IS_ the Greensboro file
55
88
  greensboro = {
56
89
  'USAF': 723170,
@@ -66,7 +99,8 @@ def test_gh865_read_tmy3_feb_leapyear_hr24():
66
99
  assert data.index[1414] == pd.Timestamp('1996-02-28 23:00:00-0500')
67
100
  assert data.index[1415] == pd.Timestamp('1996-03-01 00:00:00-0500')
68
101
  # now check if it parses correctly when we try to coerce the year
69
- data, _ = read_tmy3(TMY3_FEB_LEAPYEAR, coerce_year=1990)
102
+ data, _ = read_tmy3(TMY3_FEB_LEAPYEAR, coerce_year=1990,
103
+ map_variables=False)
70
104
  # if get's here w/o an error, then gh865 is fixed, but let's check anyway
71
105
  assert all(data.index[:-1].year == 1990)
72
106
  assert data.index[-1].year == 1991
@@ -87,7 +121,8 @@ def test_solaranywhere_tmy3(solaranywhere_index):
87
121
  # The SolarAnywhere TMY3 format specifies midnight as 00:00 whereas the
88
122
  # NREL TMY3 format utilizes 24:00. The SolarAnywhere file is therefore
89
123
  # included to test files with 00:00 timestamps are parsed correctly
90
- data, meta = tmy.read_tmy3(TMY3_SOLARANYWHERE)
124
+ data, meta = tmy.read_tmy3(TMY3_SOLARANYWHERE, encoding='iso-8859-1',
125
+ map_variables=False)
91
126
  pd.testing.assert_index_equal(data.index, solaranywhere_index)
92
127
  assert meta['USAF'] == 0
93
128
  assert meta['Name'] == 'Burlington United States'
@@ -2,6 +2,7 @@ import numpy as np
2
2
  import pytest
3
3
  from pvlib import pvsystem
4
4
  from pvlib.ivtools import sde
5
+ from pvlib._deprecation import pvlibDeprecationWarning
5
6
 
6
7
 
7
8
  @pytest.fixture
@@ -11,31 +12,32 @@ def get_test_iv_params():
11
12
 
12
13
  def test_fit_sandia_simple(get_test_iv_params, get_bad_iv_curves):
13
14
  test_params = get_test_iv_params
14
- testcurve = pvsystem.singlediode(photocurrent=test_params['IL'],
15
- saturation_current=test_params['I0'],
16
- resistance_shunt=test_params['Rsh'],
17
- resistance_series=test_params['Rs'],
18
- nNsVth=test_params['nNsVth'],
19
- ivcurve_pnts=300)
20
- expected = tuple(test_params[k] for k in ['IL', 'I0', 'Rs', 'Rsh',
21
- 'nNsVth'])
22
- result = sde.fit_sandia_simple(voltage=testcurve['v'],
23
- current=testcurve['i'])
15
+ test_params = dict(photocurrent=test_params['IL'],
16
+ saturation_current=test_params['I0'],
17
+ resistance_series=test_params['Rs'],
18
+ resistance_shunt=test_params['Rsh'],
19
+ nNsVth=test_params['nNsVth'])
20
+ testcurve = pvsystem.singlediode(**test_params)
21
+ v = np.linspace(0., testcurve['v_oc'], 300)
22
+ i = pvsystem.i_from_v(voltage=v, **test_params)
23
+ expected = tuple(test_params.values())
24
+
25
+ result = sde.fit_sandia_simple(voltage=v, current=i)
24
26
  assert np.allclose(result, expected, rtol=5e-5)
25
- result = sde.fit_sandia_simple(voltage=testcurve['v'],
26
- current=testcurve['i'],
27
+
28
+ result = sde.fit_sandia_simple(voltage=v, current=i,
27
29
  v_oc=testcurve['v_oc'],
28
30
  i_sc=testcurve['i_sc'])
29
31
  assert np.allclose(result, expected, rtol=5e-5)
30
- result = sde.fit_sandia_simple(voltage=testcurve['v'],
31
- current=testcurve['i'],
32
+
33
+ result = sde.fit_sandia_simple(voltage=v, current=i,
32
34
  v_oc=testcurve['v_oc'],
33
35
  i_sc=testcurve['i_sc'],
34
36
  v_mp_i_mp=(testcurve['v_mp'],
35
- testcurve['i_mp']))
37
+ testcurve['i_mp']))
36
38
  assert np.allclose(result, expected, rtol=5e-5)
37
- result = sde.fit_sandia_simple(voltage=testcurve['v'],
38
- current=testcurve['i'], vlim=0.1)
39
+
40
+ result = sde.fit_sandia_simple(voltage=v, current=i, vlim=0.1)
39
41
  assert np.allclose(result, expected, rtol=5e-5)
40
42
 
41
43
 
@@ -6,6 +6,7 @@ from numpy.testing import assert_allclose
6
6
 
7
7
  from pvlib.ivtools import sdm
8
8
  from pvlib import pvsystem
9
+ from pvlib._deprecation import pvlibDeprecationWarning
9
10
 
10
11
  from pvlib.tests.conftest import requires_pysam, requires_statsmodels
11
12
 
@@ -100,11 +101,15 @@ def test_fit_desoto_sandia(cec_params_cansol_cs5p_220p):
100
101
  temp_cell = np.array([15., 25., 35., 45.])
101
102
  ee = np.tile(effective_irradiance, len(temp_cell))
102
103
  tc = np.repeat(temp_cell, len(effective_irradiance))
103
- iph, io, rs, rsh, nnsvth = pvsystem.calcparams_desoto(
104
+ IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
104
105
  ee, tc, alpha_sc=specs['alpha_sc'], **params)
105
- sim_ivcurves = pvsystem.singlediode(iph, io, rs, rsh, nnsvth, 300)
106
- sim_ivcurves['ee'] = ee
107
- sim_ivcurves['tc'] = tc
106
+ ivcurve_params = dict(photocurrent=IL, saturation_current=I0,
107
+ resistance_series=Rs, resistance_shunt=Rsh,
108
+ nNsVth=nNsVth)
109
+ sim_ivcurves = pvsystem.singlediode(**ivcurve_params).to_dict('series')
110
+ v = np.linspace(0., sim_ivcurves['v_oc'], 300)
111
+ i = pvsystem.i_from_v(voltage=v, **ivcurve_params)
112
+ sim_ivcurves.update(v=v.T, i=i.T, ee=ee, tc=tc)
108
113
 
109
114
  result = sdm.fit_desoto_sandia(sim_ivcurves, specs)
110
115
  modeled = pd.Series(index=params.keys(), data=np.nan)
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
3
  import pytest
4
- from pvlib.ivtools.utils import _numdiff, rectify_iv_curve
4
+ from pvlib.ivtools.utils import _numdiff, rectify_iv_curve, astm_e1036
5
5
  from pvlib.ivtools.utils import _schumaker_qspline
6
6
 
7
7
  from ..conftest import DATA_DIR
@@ -76,3 +76,98 @@ def test__schmumaker_qspline(x, y, expected):
76
76
  np.testing.assert_allclose(t, expected[1], atol=0.0001)
77
77
  np.testing.assert_allclose(yhat, expected[2], atol=0.0001)
78
78
  np.testing.assert_allclose(kflag, expected[3], atol=0.0001)
79
+
80
+
81
+ @pytest.fixture
82
+ def i_array():
83
+ i = np.array([8.09403993, 8.09382549, 8.09361103, 8.09339656, 8.09318205,
84
+ 8.09296748, 8.09275275, 8.09253771, 8.09232204, 8.09210506,
85
+ 8.09188538, 8.09166014, 8.09142342, 8.09116305, 8.09085392,
86
+ 8.09044425, 8.08982734, 8.08878333, 8.08685945, 8.08312463,
87
+ 8.07566926, 8.06059856, 8.03005836, 7.96856869, 7.8469714,
88
+ 7.61489584, 7.19789314, 6.51138396, 5.49373476, 4.13267172,
89
+ 2.46021487, 0.52838624, -1.61055289])
90
+ return i
91
+
92
+
93
+ @pytest.fixture
94
+ def v_array():
95
+ v = np.array([-0.005, 0.015, 0.035, 0.055, 0.075, 0.095, 0.115, 0.135,
96
+ 0.155, 0.175, 0.195, 0.215, 0.235, 0.255, 0.275, 0.295,
97
+ 0.315, 0.335, 0.355, 0.375, 0.395, 0.415, 0.435, 0.455,
98
+ 0.475, 0.495, 0.515, 0.535, 0.555, 0.575, 0.595, 0.615,
99
+ 0.635])
100
+ return v
101
+
102
+
103
+ # astm_e1036 tests
104
+ def test_astm_e1036(v_array, i_array):
105
+ result = astm_e1036(v_array, i_array)
106
+ expected = {'voc': 0.6195097477985162,
107
+ 'isc': 8.093986320386227,
108
+ 'vmp': 0.494283417170082,
109
+ 'imp': 7.626088301548568,
110
+ 'pmp': 3.7694489853302127,
111
+ 'ff': 0.7517393078504361}
112
+ fit = result.pop('mp_fit')
113
+ expected_fit = np.array(
114
+ [3.6260726, 0.49124176, -0.24644747, -0.26442383, -0.1223237])
115
+ assert fit.coef == pytest.approx(expected_fit)
116
+ assert result == pytest.approx(expected)
117
+
118
+
119
+ def test_astm_e1036_fit_order(v_array, i_array):
120
+ result = astm_e1036(v_array, i_array, mp_fit_order=3)
121
+ fit = result.pop('mp_fit')
122
+ expected_fit = np.array(
123
+ [3.64081697, 0.49124176, -0.3720477, -0.26442383])
124
+ assert fit.coef == pytest.approx(expected_fit)
125
+
126
+
127
+ def test_astm_e1036_est_isc_voc(v_array, i_array):
128
+ '''
129
+ Test the case in which Isc and Voc estimates are
130
+ valid without a linear fit
131
+ '''
132
+ v = v_array
133
+ i = i_array
134
+ v = np.append(v, [0.001, 0.6201])
135
+ i = np.append(i, [8.09397560e+00, 7.10653445e-04])
136
+ result = astm_e1036(v, i)
137
+ expected = {'voc': 0.6201,
138
+ 'isc': 8.093975598317805,
139
+ 'vmp': 0.494283417170082,
140
+ 'imp': 7.626088301548568,
141
+ 'pmp': 3.7694489853302127,
142
+ 'ff': 0.751024747526615}
143
+ result.pop('mp_fit')
144
+ assert result == pytest.approx(expected)
145
+
146
+
147
+ def test_astm_e1036_mpfit_limits(v_array, i_array):
148
+ result = astm_e1036(v_array,
149
+ i_array,
150
+ imax_limits=(0.85, 1.1),
151
+ vmax_limits=(0.85, 1.1))
152
+ expected = {'voc': 0.6195097477985162,
153
+ 'isc': 8.093986320386227,
154
+ 'vmp': 0.49464214190725303,
155
+ 'imp': 7.620032530519718,
156
+ 'pmp': 3.769189212299219,
157
+ 'ff': 0.7516875014460312}
158
+ result.pop('mp_fit')
159
+ assert result == pytest.approx(expected)
160
+
161
+
162
+ def test_astm_e1036_fit_points(v_array, i_array):
163
+ i = i_array
164
+ i[3] = 8.1 # ensure an interesting change happens
165
+ result = astm_e1036(v_array, i, voc_points=4, isc_points=4)
166
+ expected = {'voc': 0.619337073271274,
167
+ 'isc': 8.093160893325297,
168
+ 'vmp': 0.494283417170082,
169
+ 'imp': 7.626088301548568,
170
+ 'pmp': 3.7694489853302127,
171
+ 'ff': 0.7520255886236707}
172
+ result.pop('mp_fit')
173
+ assert result == pytest.approx(expected)
@@ -9,6 +9,8 @@ import pytest
9
9
 
10
10
  from pvlib import atmosphere
11
11
 
12
+ from pvlib._deprecation import pvlibDeprecationWarning
13
+
12
14
 
13
15
  def test_pres2alt():
14
16
  out = atmosphere.pres2alt(np.array([10000, 90000, 101325]))
@@ -35,7 +37,8 @@ def zeniths():
35
37
  ['kastenyoung1989', [nan, 36.467, 5.586, 1.000]],
36
38
  ['gueymard1993', [nan, 36.431, 5.581, 1.000]],
37
39
  ['young1994', [nan, 30.733, 5.541, 1.000]],
38
- ['pickering2002', [nan, 37.064, 5.581, 1.000]]])
40
+ ['pickering2002', [nan, 37.064, 5.581, 1.000]],
41
+ ['gueymard2003', [nan, 36.676, 5.590, 1.000]]])
39
42
  def test_airmass(model, expected, zeniths):
40
43
  out = atmosphere.get_relative_airmass(zeniths, model)
41
44
  expected = np.array(expected)
@@ -85,68 +88,10 @@ def test_gueymard94_pw():
85
88
  assert_allclose(pws, expected, atol=0.01)
86
89
 
87
90
 
88
- @pytest.mark.parametrize("module_type,expect", [
89
- ('cdte', np.array(
90
- [[ 0.9905102 , 0.9764032 , 0.93975028],
91
- [ 1.02928735, 1.01881074, 0.98578821],
92
- [ 1.04750335, 1.03814456, 1.00623986]])),
93
- ('monosi', np.array(
94
- [[ 0.9776977 , 1.02043409, 1.03574032],
95
- [ 0.98630905, 1.03055092, 1.04736262],
96
- [ 0.98828494, 1.03299036, 1.05026561]])),
97
- ('polysi', np.array(
98
- [[ 0.9770408 , 1.01705849, 1.02613202],
99
- [ 0.98992828, 1.03173953, 1.04260662],
100
- [ 0.99352435, 1.03588785, 1.04730718]])),
101
- ('cigs', np.array(
102
- [[ 0.9745919 , 1.02821696, 1.05067895],
103
- [ 0.97529378, 1.02967497, 1.05289307],
104
- [ 0.97269159, 1.02730558, 1.05075651]])),
105
- ('asi', np.array(
106
- [[ 1.0555275 , 0.87707583, 0.72243772],
107
- [ 1.11225204, 0.93665901, 0.78487953],
108
- [ 1.14555295, 0.97084011, 0.81994083]]))
109
- ])
110
- def test_first_solar_spectral_correction(module_type, expect):
111
- ams = np.array([1, 3, 5])
112
- pws = np.array([1, 3, 5])
113
- ams, pws = np.meshgrid(ams, pws)
114
- out = atmosphere.first_solar_spectral_correction(pws, ams, module_type)
115
- assert_allclose(out, expect, atol=0.001)
116
-
117
-
118
- def test_first_solar_spectral_correction_supplied():
119
- # use the cdte coeffs
120
- coeffs = (0.87102, -0.040543, -0.00929202, 0.10052, 0.073062, -0.0034187)
121
- out = atmosphere.first_solar_spectral_correction(1, 1, coefficients=coeffs)
122
- expected = 0.99134828
123
- assert_allclose(out, expected, atol=1e-3)
124
-
125
-
126
- def test_first_solar_spectral_correction_ambiguous():
127
- with pytest.raises(TypeError):
128
- atmosphere.first_solar_spectral_correction(1, 1)
129
-
130
-
131
- def test_first_solar_spectral_correction_range():
132
- with pytest.warns(UserWarning, match='Exceptionally high pw values'):
133
- out = atmosphere.first_solar_spectral_correction(np.array([.1, 3, 10]),
134
- np.array([1, 3, 5]),
135
- module_type='monosi')
136
- expected = np.array([0.96080878, 1.03055092, nan])
137
- assert_allclose(out, expected, atol=1e-3)
138
- with pytest.warns(UserWarning, match='Exceptionally high pw values'):
139
- out = atmosphere.first_solar_spectral_correction(6, 1.5, max_pw=5,
140
- module_type='monosi')
141
- with pytest.warns(UserWarning, match='Exceptionally low pw values'):
142
- out = atmosphere.first_solar_spectral_correction(np.array([0, 3, 8]),
143
- np.array([1, 3, 5]),
144
- module_type='monosi')
145
- expected = np.array([0.96080878, 1.03055092, 1.04932727])
146
- assert_allclose(out, expected, atol=1e-3)
147
- with pytest.warns(UserWarning, match='Exceptionally low pw values'):
148
- out = atmosphere.first_solar_spectral_correction(0.2, 1.5, min_pw=1,
149
- module_type='monosi')
91
+ def test_first_solar_spectral_correction_deprecated():
92
+ with pytest.warns(pvlibDeprecationWarning,
93
+ match='Use pvlib.spectrum.spectral_factor_firstsolar'):
94
+ atmosphere.first_solar_spectral_correction(1, 1, 'cdte')
150
95
 
151
96
 
152
97
  def test_kasten96_lt():
@@ -169,7 +114,6 @@ def test_kasten96_lt():
169
114
  )
170
115
  lt = atmosphere.kasten96_lt(*np.meshgrid(amp, pwat, aod_bb))
171
116
  assert np.allclose(lt, lt_expected, 1e-3)
172
- return lt
173
117
 
174
118
 
175
119
  def test_angstrom_aod():
@@ -808,4 +808,3 @@ def test_bird():
808
808
  [Eb3, Ebh3, Gh3, Dh3],
809
809
  testdata2[['Direct Beam', 'Direct Hz', 'Global Hz', 'Dif Hz']].iloc[11],
810
810
  rtol=1e-3)
811
- return pd.DataFrame({'Eb': Eb, 'Ebh': Ebh, 'Gh': Gh, 'Dh': Dh}, index=times)