Skip to content

BUG: scaling.wvm returns all NaNs for a single-site layout #2895

Open

Description

@ByungwoongYoo

Describe the bug

pvlib.scaling.wvm returns an entirely NaN output for a layout with one coordinate pair. The WVM correlation-sum equation gives a variability reduction of 1 for one site, so the expected result is the unchanged input signal. The public API does not appear to document a minimum of two sites.

This reproduces in pvlib 0.16.1 and with scaling.py from current main at 88fb562455a43da38329dfc3fe6d5039659a5225. Those two versions of scaling.py are byte-identical.

To reproduce

import numpy as np
import pvlib
from pvlib.scaling import wvm

x = np.array([1., .2, 1., .2, 1., .2, 1., .2])
print(pvlib.__version__)

single, _, _ = wvm(x, [[0., 0.]], cloud_speed=10., dt=60.)
coincident, _, _ = wvm(x, [[0., 0.], [0., 0.]], cloud_speed=10., dt=60.)

print("one site:", single)
print("two coincident sites:", coincident)

Observed:

0.16.1
RuntimeWarning: invalid value encountered in scalar divide
one site: [nan nan nan nan nan nan nan nan]
two coincident sites: [1.  0.2 1.  0.2 1.  0.2 1.  0.2]

Expected behavior

The single-site output should also equal x, within floating-point precision.

The primary reference is Lave, Kleissl and Stein (2013), DOI: 10.1109/TSTE.2012.2205716, university-hosted author version. Equation 6 on page 3 of the author-version PDF gives:

VR = N**2 / sum_m sum_n rho(d_mn, timescale).

For one site, the only correlation is the diagonal self-correlation, equal to 1. Therefore VR=1 at every timescale. Equations 7-8 preserve the wavelet coefficients and reconstruct the input. This is an algebraic limiting-case check; it does not challenge the published model.

Likely cause and possible fix

_compute_vr infers the site count from the number of entries in pdist(positions) by minimizing abs((N**2-N)/2-n_pairs).

For one site, n_pairs=0; both N=0 and N=1 solve the equation. The minimizer starts at zero and returns N=0, making the later VR calculation 0/0.

Since the original positions are already available, a possible fix is to replace the count-inference block with:

n_dist = pos.shape[0]

An empty layout is a separate validation question.

Local checks

With that candidate change:

  • All 16 existing test_scaling.py tests from the pinned main commit pass.
  • Eleven added regression cases pass, including one-site ndarray/Series inputs at 0.5, 1, 60 and 300-second intervals, plus coincident-site VR checks.
  • Original code: 9 failures and 18 passes across those 27 selected tests. Candidate: 27 passes.
  • A separate full-matrix correlation-sum calculation agrees within 1.8e-15 for deterministic layouts of 1, 2, 3, 4, 10 and 100 sites. The candidate exactly preserves the original VR output for the tested layouts with more than one site.

This is a targeted regression check, not a full pvlib suite run or validation on real-plant data. The report and calculations were prepared in an AI-assisted local audit.

Versions

  • pvlib: 0.16.1
  • Python: 3.12.14
  • NumPy: 2.5.3
  • pandas: 3.0.6
  • SciPy: 1.18.1

Additional context

On 2026-10-10, bounded searches of this repository's issues and PRs for wvm, _compute_vr, "single point" wvm, and "scaling" "NaN" found no matching report. Related historical issues #1206 and #1257 concern different, already-corrected problems; #2660 concerns output bounding. This search is not a claim of first discovery.

The original Sandia MATLAB source has the same count-inference pattern. MATLAB was not executed in this audit.

Reported by Byungwoong Yoo (@ByungwoongYoo). If this report leads to a fix, I would appreciate acknowledgment in the release notes or other appropriate project credits.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions