Skip to content

Commit 5df830e

Browse files
cwhansekandersolar
andauthored
Add error check to detect_clearsky (#2281)
* add ValueError when window is too short * clean up error msg * test catches up * add to Raises docstring section * whatsnew * clarify error message * Update pvlib/clearsky.py Co-authored-by: Kevin Anderson <[email protected]> * revise error, add POA to docstring * docstring edits --------- Co-authored-by: Kevin Anderson <[email protected]>
1 parent 891778c commit 5df830e

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Documentation
3131
page. (:issue:`2202`, :pull:`2226`)
3232
* Updated :py:func:`~pvlib.irradiance.reindl` to include definitions of terms
3333
and a new "notes" section (:issue:`2183`, :pull:`2193`)
34+
* Clarified the error message in :py:func:`~pvlib.clearsky.detect_clearsky` when
35+
windows contain fewer than three data points (:issue:`2005`, :pull:`2281`)
3436
* Added a new :ref:`nomenclature` page, in place of the Variables and Symbols
3537
page, using the sphinx glossary directive. (:issue:`1421`, :pull:`2234`)
3638
* Explained how to write docstrings for new functions in :ref:`example-docstring`

pvlib/clearsky.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -683,22 +683,26 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
683683
var_diff=0.005, slope_dev=8, max_iterations=20,
684684
return_components=False):
685685
"""
686-
Detects clear sky times according to the algorithm developed by Reno
687-
and Hansen for GHI measurements. The algorithm [1]_ was designed and
688-
validated for analyzing GHI time series only. Users may attempt to
689-
apply it to other types of time series data using different filter
690-
settings, but should be skeptical of the results.
686+
Detects clear sky times using the algorithm developed by Reno
687+
and Hansen.
691688
692-
The algorithm detects clear sky times by comparing statistics for a
689+
The algorithm [1]_ was designed and
690+
validated for analyzing GHI time series. Jordan and Hansen [2]_ extended
691+
the algorithm to plane-of-array (POA) irradiance measurements.
692+
693+
The algorithm [1]_ detects clear sky times by comparing statistics for a
693694
measured time series and an expected clearsky time series.
694695
Statistics are calculated using a sliding time window (e.g., 10
695696
minutes). An iterative algorithm identifies clear periods, uses the
696697
identified periods to estimate bias in the clearsky data, scales the
697698
clearsky data and repeats.
698699
699-
Clear times are identified by meeting 5 criteria. Default values for
700+
Clear times are identified by meeting five criteria. Default values for
700701
these thresholds are appropriate for 10 minute windows of 1 minute
701-
GHI data.
702+
GHI data. For data at longer intervals, it is recommended
703+
to set ``infer_limits=True`` to use the thresholds from [2]_.
704+
705+
For POA data, ``clearsky`` must be on the same plane as ``measured``.
702706
703707
Parameters
704708
----------
@@ -713,8 +717,8 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
713717
If True, does not use passed in kwargs (or defaults), but instead
714718
interpolates these values from Table 1 in [2]_.
715719
window_length : int, default 10
716-
Length of sliding time window in minutes. Must be greater than 2
717-
periods.
720+
Length of sliding time window in minutes. Each window must contain at
721+
least three data points.
718722
mean_diff : float, default 75
719723
Threshold value for agreement between mean values of measured
720724
and clearsky in each interval, see Eq. 6 in [1]. [W/m2]
@@ -723,8 +727,6 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
723727
clearsky values in each interval, see Eq. 7 in [1]. [W/m2]
724728
lower_line_length : float, default -5
725729
Lower limit of line length criterion from Eq. 8 in [1].
726-
Criterion satisfied when lower_line_length < line length difference
727-
< upper_line_length.
728730
upper_line_length : float, default 10
729731
Upper limit of line length criterion from Eq. 8 in [1].
730732
var_diff : float, default 0.005
@@ -736,7 +738,7 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
736738
change in successive values, see Eqs. 12 through 14 in [1].
737739
max_iterations : int, default 20
738740
Maximum number of times to apply a different scaling factor to
739-
the clearsky and redetermine clear_samples. Must be 1 or larger.
741+
the clearsky and redetermine ``clear_samples``. Must be 1 or larger.
740742
return_components : bool, default False
741743
Controls if additional output should be returned. See below.
742744
@@ -748,19 +750,23 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
748750
749751
components : OrderedDict, optional
750752
Dict of arrays of whether or not the given time window is clear
751-
for each condition. Only provided if return_components is True.
753+
for each condition. Only provided if ``return_components`` is True.
752754
753755
alpha : scalar, optional
754-
Scaling factor applied to the clearsky_ghi to obtain the
755-
detected clear_samples. Only provided if return_components is
756+
Scaling factor applied to ``clearsky`` to obtain the
757+
detected ``clear_samples``. Only provided if ``return_components`` is
756758
True.
757759
758760
Raises
759761
------
760762
ValueError
761-
If measured is not a Series and times is not provided
763+
If ``measured`` is not a Series and times is not provided.
764+
ValueError
765+
If a window contains less than three data points.
766+
ValueError
767+
If the measured data is not sufficient to fill a window.
762768
NotImplementedError
763-
If timestamps are not equally spaced
769+
If timestamps are not equally spaced.
764770
765771
References
766772
----------
@@ -812,6 +818,13 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
812818
sample_interval, samples_per_window = \
813819
tools._get_sample_intervals(times, window_length)
814820

821+
if samples_per_window < 3:
822+
raise ValueError(f"Samples per window of {samples_per_window}"
823+
" found. Each window must contain at least 3 data"
824+
" points."
825+
f" Window length of {window_length} found; increase"
826+
f" window length to {3*sample_interval} or longer.")
827+
815828
# if infer_limits, find threshold values using the sample interval
816829
if infer_limits:
817830
window_length, mean_diff, max_diff, lower_line_length, \

pvlib/tests/test_clearsky.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,10 +674,16 @@ def test_detect_clearsky_missing_index(detect_clearsky_data):
674674

675675
def test_detect_clearsky_not_enough_data(detect_clearsky_data):
676676
expected, cs = detect_clearsky_data
677-
with pytest.raises(ValueError, match='have at least'):
677+
with pytest.raises(ValueError, match='times has only'):
678678
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=60)
679679

680680

681+
def test_detect_clearsky_window_too_short(detect_clearsky_data):
682+
expected, cs = detect_clearsky_data
683+
with pytest.raises(ValueError, match="Samples per window of "):
684+
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=2)
685+
686+
681687
@pytest.mark.parametrize("window_length", [5, 10, 15, 20, 25])
682688
def test_detect_clearsky_optimizer_not_failed(
683689
detect_clearsky_data, window_length

0 commit comments

Comments
 (0)