From b8f2634643cefa2ebec2e44274ed08e1b01a437c Mon Sep 17 00:00:00 2001 From: Omesh37 Date: Fri, 8 May 2026 13:10:52 +0530 Subject: [PATCH 1/4] BUG: fix dirint KeyError with scalar inputs on pandas >= 2.0 --- pvlib/irradiance.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 5a4a76df25..abdd565779 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -2109,6 +2109,14 @@ def _dirint_bins(times, kt_prime, zenith, w, delta_kt_prime): ------- tuple of kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin """ + # Ensure scalar inputs are converted to Series so that boolean masks + # produce a boolean Series rather than a scalar bool. + # Scalar bools cause KeyError in pandas >= 2.0. GH #XXXX + kt_prime = pd.Series(kt_prime, index=times, dtype=float) + zenith = pd.Series(zenith, index=times, dtype=float) + w = pd.Series(w, index=times, dtype=float) + delta_kt_prime = pd.Series(delta_kt_prime, index=times, dtype=float) + # @wholmgren: the following bin assignments use MATLAB's 1-indexing. # Later, we'll subtract 1 to conform to Python's 0-indexing. From 33f8c49bd868cdd2a47aed9d809410be295455f2 Mon Sep 17 00:00:00 2001 From: Omesh37 Date: Fri, 8 May 2026 13:24:40 +0530 Subject: [PATCH 2/4] TST,CHANGELOG: add test and whatsnew entry for dirint scalar fix GH#2751 --- docs/sphinx/source/whatsnew/v0.15.2.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.15.2.rst b/docs/sphinx/source/whatsnew/v0.15.2.rst index 37f8692280..5d7b456d24 100644 --- a/docs/sphinx/source/whatsnew/v0.15.2.rst +++ b/docs/sphinx/source/whatsnew/v0.15.2.rst @@ -14,6 +14,9 @@ Deprecations Bug fixes ~~~~~~~~~ +* Fixed :py:func:`pvlib.irradiance.dirint` raising ``KeyError`` with + scalar inputs on pandas >= 2.0. (:pull:`XXXX`, :issue:`2751`) + By :ghuser:`Omesh37`. * Corrects a bug in :py:func:`pvlib.temperature.fuentes`. If inputs were data type integer, users can expect modeled cell temperature values to increase slightly. From 343fbe903b7716452a1f7eca10024dd811d44b8f Mon Sep 17 00:00:00 2001 From: Omesh37 Date: Sat, 9 May 2026 20:34:19 +0530 Subject: [PATCH 3/4] BUG: fix dirint KeyError for scalar inputs on pandas >= 2.0 --- docs/sphinx/source/whatsnew/v0.15.2.rst | 2 +- pvlib/irradiance.py | 17 +++++++++------ tests/test_irradiance.py | 28 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.15.2.rst b/docs/sphinx/source/whatsnew/v0.15.2.rst index 5d7b456d24..f1bc3742f0 100644 --- a/docs/sphinx/source/whatsnew/v0.15.2.rst +++ b/docs/sphinx/source/whatsnew/v0.15.2.rst @@ -15,7 +15,7 @@ Deprecations Bug fixes ~~~~~~~~~ * Fixed :py:func:`pvlib.irradiance.dirint` raising ``KeyError`` with - scalar inputs on pandas >= 2.0. (:pull:`XXXX`, :issue:`2751`) + scalar inputs on pandas >= 2.0. (:pull:`2752`, :issue:`2751`) By :ghuser:`Omesh37`. * Corrects a bug in :py:func:`pvlib.temperature.fuentes`. If inputs were data type integer, users can expect modeled cell temperature values to diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index abdd565779..7937b6f443 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -1927,10 +1927,10 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, Parameters ---------- - ghi : array-like + ghi : numeric Global horizontal irradiance. See :term:`ghi`. [Wm⁻²] - solar_zenith : array-like + solar_zenith : numeric True (not refraction-corrected) solar zenith angles. See :term:`solar_zenith`. [°] @@ -1964,9 +1964,9 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, Returns ------- - dni : array-like - The modeled direct normal irradiance, as provided by the - DIRINT model. [Wm⁻²] + dni : numeric or pd.Series + Estimated direct normal irradiance. Returns float if all inputs + are scalar, pd.Series otherwise. [Wm⁻²] Notes ----- @@ -1983,7 +1983,8 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, Global Horizontal to Direct Normal Insolation", Technical Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research Institute, 1987. """ - + scalar_input = np.isscalar(solar_zenith) + disc_out = disc(ghi, solar_zenith, times, pressure=pressure, min_cos_zenith=min_cos_zenith, max_zenith=max_zenith) airmass = disc_out['airmass'] @@ -1998,9 +1999,12 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w, delta_kt_prime) + # Perez eqn 5 dni = disc_out['dni'] * dirint_coeffs + if scalar_input: + return float(dni.iloc[0]) return dni @@ -2160,6 +2164,7 @@ def _dirint_bins(times, kt_prime, zenith, w, delta_kt_prime): return kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin + def dirindex(ghi, ghi_clear, dni_clear, zenith, times, pressure=101325., use_delta_kt_prime=True, temp_dew=None, min_cos_zenith=0.065, max_zenith=87): diff --git a/tests/test_irradiance.py b/tests/test_irradiance.py index a416636ae9..ea5a410d7f 100644 --- a/tests/test_irradiance.py +++ b/tests/test_irradiance.py @@ -1139,6 +1139,34 @@ def test_dirindex_min_cos_zenith_max_zenith(): expected = pd.Series([nan, 5.], index=times) assert_series_equal(out, expected) +def test_dirint_scalar_inputs(): + """Scalar numeric inputs return scalar float output. GH #2751""" + times = pd.DatetimeIndex(['2023-06-21 12:00'], tz='UTC') + + # scalar int input → should return float (not Series) + result = irradiance.dirint( + ghi=500, solar_zenith=45, times=times + ) + assert np.isscalar(result), "scalar input should return scalar output" + assert isinstance(result, float) + + # scalar float with delta_kt_prime disabled → non-NaN value check + result = irradiance.dirint( + ghi=500.0, solar_zenith=45.0, times=times, + use_delta_kt_prime=False + ) + assert np.isscalar(result) + assert isinstance(result, float) + assert result > 0 # should be positive DNI + + # Series input → should still return Series (regression check) + times2 = pd.date_range('2023-06-21 10:00', periods=3, freq='h', tz='UTC') + result_series = irradiance.dirint( + ghi=pd.Series([400, 500, 300], index=times2), + solar_zenith=pd.Series([50, 40, 60], index=times2), + times=times2 + ) + assert isinstance(result_series, pd.Series) def test_dni(): ghi = pd.Series([90, 100, 100, 100, 100]) From fe8055c223e17e66645bbd58e90e723bf138c3b9 Mon Sep 17 00:00:00 2001 From: Omesh37 Date: Sat, 9 May 2026 20:59:40 +0530 Subject: [PATCH 4/4] STY: fix flake8 whitespace and blank line errors --- pvlib/irradiance.py | 4 +--- tests/test_irradiance.py | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 7937b6f443..bb737560bc 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -1984,7 +1984,7 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, SERI/TR-215-3087, Golden, CO: Solar Energy Research Institute, 1987. """ scalar_input = np.isscalar(solar_zenith) - + disc_out = disc(ghi, solar_zenith, times, pressure=pressure, min_cos_zenith=min_cos_zenith, max_zenith=max_zenith) airmass = disc_out['airmass'] @@ -1999,7 +1999,6 @@ def dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True, dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w, delta_kt_prime) - # Perez eqn 5 dni = disc_out['dni'] * dirint_coeffs @@ -2164,7 +2163,6 @@ def _dirint_bins(times, kt_prime, zenith, w, delta_kt_prime): return kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin - def dirindex(ghi, ghi_clear, dni_clear, zenith, times, pressure=101325., use_delta_kt_prime=True, temp_dew=None, min_cos_zenith=0.065, max_zenith=87): diff --git a/tests/test_irradiance.py b/tests/test_irradiance.py index ea5a410d7f..10f7ee9697 100644 --- a/tests/test_irradiance.py +++ b/tests/test_irradiance.py @@ -1139,6 +1139,7 @@ def test_dirindex_min_cos_zenith_max_zenith(): expected = pd.Series([nan, 5.], index=times) assert_series_equal(out, expected) + def test_dirint_scalar_inputs(): """Scalar numeric inputs return scalar float output. GH #2751""" times = pd.DatetimeIndex(['2023-06-21 12:00'], tz='UTC') @@ -1168,6 +1169,7 @@ def test_dirint_scalar_inputs(): ) assert isinstance(result_series, pd.Series) + def test_dni(): ghi = pd.Series([90, 100, 100, 100, 100]) dhi = pd.Series([100, 90, 50, 50, 50])