From 2ed87aa28e5314965a289d0e1f1ffbe71971a087 Mon Sep 17 00:00:00 2001 From: bfs2021 <101915083+bfs2021@users.noreply.github.com> Date: Sat, 10 Oct 2026 16:28:34 +0800 Subject: [PATCH 1/2] scaling.wvm: return unchanged signal for a single site With one position, pdist returns an empty distance array and the effective-size optimizer converges to n_dist=0, so _compute_vr divided by zero and scaling.wvm returned an all-NaN signal. A single site has no variability reduction, so _compute_vr now returns a reduction factor of 1 for every timescale and wvm passes the input through unchanged. Fixes #2895 Signed-off-by: bfs2021 <101915083+bfs2021@users.noreply.github.com> --- pvlib/scaling.py | 5 +++++ tests/test_scaling.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/pvlib/scaling.py b/pvlib/scaling.py index 693d9f6bff..683cb26877 100644 --- a/pvlib/scaling.py +++ b/pvlib/scaling.py @@ -127,6 +127,11 @@ def _compute_vr(positions, cloud_speed, tmscales): # Added by Joe Ranalli (@jranalli), Penn State Hazleton, 2021 pos = np.array(positions) + if len(pos) <= 1: + # A single site has no pairwise distances, so the variability + # reduction is 1; the effective-size optimizer below would converge + # to n_dist=0 and divide by zero. See GH #2895. + return np.ones(tmscales.shape) dist = pdist(pos, 'euclidean') # Find effective length of position vector, 'dist' is full pairwise diff --git a/tests/test_scaling.py b/tests/test_scaling.py index f8638f580a..f778f0e65b 100644 --- a/tests/test_scaling.py +++ b/tests/test_scaling.py @@ -207,3 +207,17 @@ def test_wvm_series_xyaslist(clear_sky_index, time, positions, def test_wvm_invalid(clear_sky_index, positions): with pytest.raises(ValueError): scaling.wvm(clear_sky_index, positions, cloud_speed) + + +def test_compute_vr_single_site(expect_tmscale): + vr = scaling._compute_vr(np.array([(0., 0.)]), cloud_speed, + np.array(expect_tmscale)) + assert_almost_equal(vr, np.ones(len(expect_tmscale))) + + +def test_wvm_single_site(clear_sky_index): + # A single site has no variability reduction: the smoothed signal is the + # input unchanged. Previously returned all NaNs. See GH #2895. + single_site = np.array([(0., 0.)]) + cs_sm, _, _ = scaling.wvm(clear_sky_index, single_site, cloud_speed, dt=dt) + assert_almost_equal(cs_sm[5000:5005], clear_sky_index[5000:5005]) From 15078372d1a3d78884fcc78062757d6a9b7a847e Mon Sep 17 00:00:00 2001 From: bfs2021 <101915083+bfs2021@users.noreply.github.com> Date: Sat, 10 Oct 2026 16:33:36 +0800 Subject: [PATCH 2/2] add whatsnew entry for the wvm single-site fix Signed-off-by: bfs2021 <101915083+bfs2021@users.noreply.github.com> --- docs/sphinx/source/whatsnew/v0.16.2.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.16.2.rst b/docs/sphinx/source/whatsnew/v0.16.2.rst index f0b52494dc..410c7a4bc1 100644 --- a/docs/sphinx/source/whatsnew/v0.16.2.rst +++ b/docs/sphinx/source/whatsnew/v0.16.2.rst @@ -16,6 +16,8 @@ Bug fixes ~~~~~~~~~ * :py:func:`pvlib.tracking.calc_surface_orientation` returns scalar when input is scalar (:issue:`2881`, :pull:`2882`) +* :py:func:`pvlib.scaling.wvm` no longer returns all NaNs when ``positions`` + contains a single site (:issue:`2895`, :pull:`2896`) by :ghuser:`bfs2021` Enhancements ~~~~~~~~~~~~