Skip to content

Commit 483cd51

Browse files
committed
Merge branch 'main' into fix_some_examples_not_run_by_sphinx
2 parents 1a67ca1 + 35c9e61 commit 483cd51

6 files changed

Lines changed: 96 additions & 115 deletions

File tree

docs/sphinx/source/whatsnew/v0.15.3.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,14 @@ Requirements
4343
Maintenance
4444
~~~~~~~~~~~
4545
* Fix some gallery examples not being run. Only gallery examples whose filename begins with ``noplot_`` will be excluded. (:issue:`2790`, :pull:`2792`)
46+
* Removed unused internal function ``clearsky._is_leap_year`` (:issue:`2768`, :pull:`2813`)
4647
* Fix documentation builds on runner images lacking link-type timezones. (:issue:`2795`, :pull:`2809`)
4748

4849

4950
Contributors
5051
~~~~~~~~~~~~
5152
* Eesh Saxena (:ghuser:`eeshsaxena`)
5253
* Karl Hill (:ghuser:`karlhillx`)
54+
* Mathias Aschwanden (:ghuser:`maschwanden`)
5355
* Yonry Zhu (:ghuser:`yonryzhu`)
56+
* Darshan Gowda (:ghuser:`dgowdaan-cmyk`)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
.. _whatsnew_0_16_0:
2+
3+
4+
v0.16.0
5+
Breaking Changes
6+
~~~~~~~~~~~~~~~~
7+
* Change output type of :py:func:`pvlib.irradiance.perez` and
8+
:py:func:`pvlib.irradiance.perez_driesse` from ``OrderedDict`` to ``dict`` when
9+
``return_components=True`` to be consistent with other models.
10+
(:pull:`2789`)
11+
* Remove empty ``poa_horizon`` key from the ``diffuse_components`` output of
12+
:py:func:`pvlib.irradiance.haydavies`.
13+
(:pull:`2788`)
14+
15+
16+
Deprecations
17+
~~~~~~~~~~~~
18+
19+
20+
Bug fixes
21+
~~~~~~~~~
22+
23+
24+
Enhancements
25+
~~~~~~~~~~~~
26+
27+
28+
Documentation
29+
~~~~~~~~~~~~~
30+
31+
32+
Testing
33+
~~~~~~~
34+
35+
36+
Benchmarking
37+
~~~~~~~~~~~~
38+
39+
40+
Requirements
41+
~~~~~~~~~~~~
42+
43+
44+
Maintenance
45+
~~~~~~~~~~~
46+
47+
48+
Contributors
49+
~~~~~~~~~~~~
50+
* Carolina Crespo (:ghuser:`cbcrespo`)

pvlib/clearsky.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -220,22 +220,6 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
220220
return linke_turbidity
221221

222222

223-
def _is_leap_year(year):
224-
"""Determine if a year is leap year.
225-
226-
Parameters
227-
----------
228-
year : numeric
229-
230-
Returns
231-
-------
232-
isleap : array of bools
233-
"""
234-
isleap = ((np.mod(year, 4) == 0) &
235-
((np.mod(year, 100) != 0) | (np.mod(year, 400) == 0)))
236-
return isleap
237-
238-
239223
def _interpolate_turbidity(lts, time):
240224
"""
241225
Interpolated monthly Linke turbidity onto daily values.

pvlib/irradiance.py

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
787787
788788
Returns
789789
--------
790-
numeric, OrderedDict, or DataFrame
790+
numeric, dict, or DataFrame
791791
Return type controlled by ``return_components`` argument.
792792
If `False`, ``sky_diffuse`` is returned.
793793
If `True`, ``diffuse_components`` is returned.
@@ -796,13 +796,11 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
796796
The sky diffuse component of the solar radiation on a tilted
797797
surface. [Wm⁻²]
798798
799-
diffuse_components : OrderedDict (array input) or DataFrame (Series input)
799+
diffuse_components : dict (array input) or DataFrame (Series input)
800800
Keys/columns are:
801801
* poa_sky_diffuse: Total sky diffuse
802802
* poa_isotropic
803803
* poa_circumsolar
804-
* poa_horizon (always zero, not accounted for by the
805-
Hay-Davies model)
806804
807805
Notes
808806
------
@@ -860,14 +858,11 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
860858
sky_diffuse = poa_isotropic + poa_circumsolar
861859

862860
if return_components:
863-
diffuse_components = OrderedDict()
864-
diffuse_components['poa_sky_diffuse'] = sky_diffuse
865-
866-
# Calculate the individual components
867-
diffuse_components['poa_isotropic'] = poa_isotropic
868-
diffuse_components['poa_circumsolar'] = poa_circumsolar
869-
diffuse_components['poa_horizon'] = np.where(
870-
np.isnan(diffuse_components['poa_isotropic']), np.nan, 0.)
861+
diffuse_components = {
862+
'poa_sky_diffuse': sky_diffuse,
863+
'poa_isotropic': poa_isotropic,
864+
'poa_circumsolar': poa_circumsolar
865+
}
871866

872867
if isinstance(sky_diffuse, pd.Series):
873868
diffuse_components = pd.DataFrame(diffuse_components)
@@ -1109,7 +1104,7 @@ def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
11091104
11101105
Returns
11111106
--------
1112-
numeric, OrderedDict, or DataFrame
1107+
numeric, dict, or DataFrame
11131108
Return type controlled by `return_components` argument.
11141109
If ``return_components=False``, `sky_diffuse` is returned.
11151110
If ``return_components=True``, `diffuse_components` is returned.
@@ -1118,7 +1113,7 @@ def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
11181113
The sky diffuse component of the solar radiation on a tilted
11191114
surface.
11201115
1121-
diffuse_components : OrderedDict (array input) or DataFrame (Series input)
1116+
diffuse_components : dict (array input) or DataFrame (Series input)
11221117
Keys/columns are:
11231118
* poa_sky_diffuse: Total sky diffuse
11241119
* poa_isotropic
@@ -1205,13 +1200,12 @@ def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
12051200
sky_diffuse = np.where(np.isnan(airmass), 0, sky_diffuse)
12061201

12071202
if return_components:
1208-
diffuse_components = OrderedDict()
1209-
diffuse_components['poa_sky_diffuse'] = sky_diffuse
1210-
1211-
# Calculate the different components
1212-
diffuse_components['poa_isotropic'] = dhi * term1
1213-
diffuse_components['poa_circumsolar'] = dhi * term2
1214-
diffuse_components['poa_horizon'] = dhi * term3
1203+
diffuse_components = {
1204+
'poa_sky_diffuse': sky_diffuse,
1205+
'poa_isotropic': dhi * term1,
1206+
'poa_circumsolar': dhi * term2,
1207+
'poa_horizon': dhi * term3
1208+
}
12151209

12161210
# Set values of components to 0 when sky_diffuse is 0
12171211
mask = sky_diffuse == 0
@@ -1351,7 +1345,7 @@ def perez_driesse(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
13511345
13521346
Returns
13531347
--------
1354-
numeric, OrderedDict, or DataFrame
1348+
numeric, dict, or DataFrame
13551349
Return type controlled by `return_components` argument.
13561350
If ``return_components=False``, `sky_diffuse` is returned.
13571351
If ``return_components=True``, `diffuse_components` is returned.
@@ -1360,7 +1354,7 @@ def perez_driesse(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
13601354
The sky diffuse component of the solar radiation on a tilted
13611355
surface.
13621356
1363-
diffuse_components : OrderedDict (array input) or DataFrame (Series input)
1357+
diffuse_components : dict (array input) or DataFrame (Series input)
13641358
Keys/columns are:
13651359
* poa_sky_diffuse: Total sky diffuse
13661360
* poa_isotropic
@@ -1425,13 +1419,12 @@ def perez_driesse(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
14251419
sky_diffuse = np.maximum(dhi * (term1 + term2 + term3), 0)
14261420

14271421
if return_components:
1428-
diffuse_components = OrderedDict()
1429-
diffuse_components['poa_sky_diffuse'] = sky_diffuse
1430-
1431-
# Calculate the different components
1432-
diffuse_components['poa_isotropic'] = dhi * term1
1433-
diffuse_components['poa_circumsolar'] = dhi * term2
1434-
diffuse_components['poa_horizon'] = dhi * term3
1422+
diffuse_components = {
1423+
'poa_sky_diffuse': sky_diffuse,
1424+
'poa_isotropic': dhi * term1,
1425+
'poa_circumsolar': dhi * term2,
1426+
'poa_horizon': dhi * term3
1427+
}
14351428

14361429
if isinstance(sky_diffuse, pd.Series):
14371430
diffuse_components = pd.DataFrame(diffuse_components)

tests/iotools/test_meteonorm.py

Lines changed: 18 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,6 @@ def expected_meteonorm_index():
6161
return expected_meteonorm_index
6262

6363

64-
@pytest.fixture
65-
def expected_meteonorm_data():
66-
# The first 12 rows of data
67-
columns = ['ghi', 'global_horizontal_irradiance_with_shading']
68-
expected = [
69-
[0.0, 0.0],
70-
[0.0, 0.0],
71-
[0.0, 0.0],
72-
[0.0, 0.0],
73-
[0.0, 0.0],
74-
[0.0, 0.0],
75-
[0.0, 0.0],
76-
[3.75, 3.74],
77-
[57.25, 57.20],
78-
[149.0, 148.96],
79-
[242.25, 242.24],
80-
[228.0, 227.98],
81-
]
82-
index = pd.date_range('2025-01-01 00:30', periods=12, freq='1h', tz='UTC')
83-
index.freq = None
84-
expected = pd.DataFrame(expected, index=index, columns=columns)
85-
return expected
86-
87-
8864
@pytest.fixture
8965
def expected_columns_all():
9066
columns = [
@@ -114,8 +90,7 @@ def expected_columns_all():
11490
@pytest.mark.remote_data
11591
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
11692
def test_get_meteonorm_training(
117-
demo_api_key, demo_url, expected_meta, expected_meteonorm_index,
118-
expected_meteonorm_data):
93+
demo_api_key, demo_url, expected_meta, expected_meteonorm_index):
11994
data, meta = pvlib.iotools.get_meteonorm_observation_training(
12095
latitude=50, longitude=10,
12196
start='2025-01-01', end='2026-01-01',
@@ -128,10 +103,12 @@ def test_get_meteonorm_training(
128103
for key in ['version', 'commit']:
129104
assert key in meta # value changes, so only check presence
130105
pd.testing.assert_index_equal(data.index, expected_meteonorm_index)
131-
# meteonorm API only guarantees similar, not identical, results between
132-
# calls. so we allow a small amount of variation with atol.
133-
pd.testing.assert_frame_equal(data.iloc[:12], expected_meteonorm_data,
134-
check_exact=False, atol=1)
106+
# don't pin values: meteonorm may update the dataset without it being a
107+
# breaking change. check parsing instead.
108+
assert list(data.columns) == \
109+
['ghi', 'global_horizontal_irradiance_with_shading']
110+
assert data.dtypes.map(pd.api.types.is_numeric_dtype).all()
111+
assert (data.isna().mean() <= 0.2).all() # meteonorm guarantees <=20% NaN
135112

136113

137114
@pytest.mark.remote_data
@@ -156,8 +133,11 @@ def test_get_meteonorm_realtime(demo_api_key, demo_url, expected_columns_all):
156133
assert meta['surface_tilt'] == 20
157134
assert meta['surface_azimuth'] == 10
158135

159-
assert list(data.columns) == expected_columns_all
160-
assert data.shape == (241, 19)
136+
# meteonorm may add parameters to 'all' at any time, so only check that
137+
# the columns we know about are present, not that the set matches exactly.
138+
assert set(expected_columns_all).issubset(data.columns)
139+
assert data.shape[0] == 241 # row count is determined by the time range
140+
assert data.shape[1] >= len(expected_columns_all)
161141
# can't test the specific index as it varies due to the
162142
# use of pd.Timestamp.now
163143
assert type(data.index) is pd.core.indexes.interval.IntervalIndex
@@ -259,38 +239,10 @@ def expected_meteonorm_tmy_meta():
259239
return meta
260240

261241

262-
@pytest.fixture
263-
def expected_meteonorm_tmy_data():
264-
# The first 12 rows of data
265-
columns = ['diffuse_horizontal_irradiance']
266-
expected = [
267-
[0.],
268-
[0.],
269-
[0.],
270-
[0.],
271-
[0.],
272-
[0.],
273-
[0.],
274-
[0.],
275-
[9.07],
276-
[8.44],
277-
[86.64],
278-
[110.44],
279-
]
280-
index = pd.date_range(
281-
'2030-01-01', periods=12, freq='1h', tz=3600)
282-
index.freq = None
283-
interval_index = pd.IntervalIndex.from_arrays(
284-
index, index + pd.Timedelta(hours=1), closed='left')
285-
expected = pd.DataFrame(expected, index=interval_index, columns=columns)
286-
return expected
287-
288-
289242
@pytest.mark.remote_data
290243
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
291244
def test_get_meteonorm_tmy(
292-
demo_api_key, demo_url, expected_meteonorm_tmy_meta,
293-
expected_meteonorm_tmy_data):
245+
demo_api_key, demo_url, expected_meteonorm_tmy_meta):
294246
data, meta = pvlib.iotools.get_meteonorm_tmy(
295247
latitude=50, longitude=10,
296248
api_key=demo_api_key,
@@ -312,10 +264,11 @@ def test_get_meteonorm_tmy(
312264
assert meta.items() >= expected_meteonorm_tmy_meta.items()
313265
for key in ['version', 'commit']:
314266
assert key in meta # value changes, so only check presence
315-
# meteonorm API only guarantees similar, not identical, results between
316-
# calls. so we allow a small amount of variation with atol.
317-
pd.testing.assert_frame_equal(data.iloc[:12], expected_meteonorm_tmy_data,
318-
check_exact=False, atol=1)
267+
# don't pin values: meteonorm may update the dataset without it being a
268+
# breaking change. check parsing instead.
269+
assert list(data.columns) == ['diffuse_horizontal_irradiance']
270+
assert data.dtypes.map(pd.api.types.is_numeric_dtype).all()
271+
assert (data.isna().mean() <= 0.2).all() # meteonorm guarantees <=20% NaN
319272

320273

321274
@fail_on_pvlib_version('0.16.0')

tests/test_irradiance.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,11 @@ def test_haydavies(irrad_data, ephem_data, dni_et):
209209

210210

211211
def test_haydavies_components(irrad_data, ephem_data, dni_et):
212-
keys = ['poa_sky_diffuse', 'poa_isotropic', 'poa_circumsolar',
213-
'poa_horizon']
212+
keys = ['poa_sky_diffuse', 'poa_isotropic', 'poa_circumsolar']
214213
expected = pd.DataFrame(np.array(
215214
[[0, 27.1775, 102.9949, 33.1909],
216215
[0, 27.1775, 30.1818, 27.9837],
217-
[0, 0, 72.8130, 5.2071],
218-
[0, 0, 0, 0]]).T,
216+
[0, 0, 72.8130, 5.2071]]).T,
219217
columns=keys,
220218
index=irrad_data.index
221219
)

0 commit comments

Comments
 (0)