Skip to content

[WIP] Attempt refactor soiling pr#479

Draft
martin-springer wants to merge 75 commits intodevelopmentfrom
attempt_refactor_soiling_pr
Draft

[WIP] Attempt refactor soiling pr#479
martin-springer wants to merge 75 commits intodevelopmentfrom
attempt_refactor_soiling_pr

Conversation

@martin-springer
Copy link
Collaborator

  • Code changes are covered by tests
  • Code changes have been evaluated for compatibility/integration with TrendAnalysis
  • New functions added to __init__.py
  • API.rst is up to date, along with other sphinx docs pages
  • Example notebooks are rerun and differences in results scrutinized
  • Updated changelog

nmoyer and others added 30 commits June 24, 2024 11:57
…tio and fit multiple soiling rates per soiling interval (piecewise)) as well as CODS algorithm being added
Signed-off-by: nmoyer <noah.moyer@nrel.gov>
Move SRR and CODS development branch from noromo01 to rdtools repo
@codecov-commenter
Copy link

codecov-commenter commented Feb 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.09%. Comparing base (acc357c) to head (2fa047c).

Additional details and impacted files
@@               Coverage Diff               @@
##           development     #479      +/-   ##
===============================================
- Coverage        96.18%   96.09%   -0.09%     
===============================================
  Files               12       12              
  Lines             2280     2458     +178     
===============================================
+ Hits              2193     2362     +169     
- Misses              87       96       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This is a work-in-progress pull request that refactors and enhances the soiling module in rdtools, specifically the SRR (Stochastic Rate and Recovery) and CODS (Combined Degradation and Soiling) algorithms. The PR removes the experimental warning label and introduces several new features for detecting negative shifts and piecewise linear fitting in soiling analysis.

Changes:

  • Renamed parameters for clarity: min_interval_lengthmin_interval_days, max_negative_stepmax_neg_step
  • Added negative shift detection (detect_neg_shifts) and piecewise linear fitting (piecewise_fit) capabilities
  • Added inferred_clean method for handling detected cleaning events with inferred recovery values
  • Fixed pandas Copy-on-Write compatibility issue and variable shadowing bug
  • Added comprehensive test coverage for new features with new fixtures for negative shifts and piecewise slopes
  • Removed experimental warnings from soiling module functions

Reviewed changes

Copilot reviewed 11 out of 16 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
rdtools/soiling.py Major refactor: parameter renames, new features (detect_neg_shifts, piecewise_fit, inferred_clean method), bug fixes (CoW, variable shadowing), added segmented_soiling_period function
rdtools/test/soiling_test.py Updated tests for parameter renames, added tests for new features (negative shifts, piecewise fitting), fixed typos, reformatted to double quotes
rdtools/test/soiling_cods_test.py Added new tests for CODS edge cases (NaN prefix handling, non-daily frequency, invalid order, prescient_cleaning_events mismatch)
rdtools/test/conftest.py Added two new fixtures: soiling_normalized_daily_with_neg_shifts and soiling_normalized_daily_with_piecewise_slope
rdtools/plotting.py Removed experimental warnings from soiling plotting functions, removed unused warnings import
docs/sphinx/source/changelog/pending.rst Comprehensive changelog documenting all breaking changes, API changes, enhancements, bug fixes, and testing updates
docs/sphinx/source/changelog.rst Added include for pending.rst
docs/sphinx/source/examples.rst Added reference to new soiling_options_guide notebook
docs/sphinx/source/examples/soiling_options_guide.nblink New notebook link file for soiling options guide
docs/degradation_and_soiling_example.ipynb Updated outputs to show new columns (inferred_recovery, inferred_begin_shift) in soiling interval summary
docs/TrendAnalysis_example_NSRDB.ipynb Minor formatting fix (removed semicolon)
.github/workflows/nbval.yaml Added new notebook to test matrix, fixed pytest command syntax

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

martin-springer and others added 5 commits February 12, 2026 18:17
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 17 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

run: |
# --sanitize-with: pre-process text to remove irrelevant differences (e.g. warning filepaths)
pytest --nbval docs/${{ matrix.notebook-file }} --sanitize-with docs/nbval_sanitization_rules.cfg
pytest --nbval --nbval-sanitize-with docs/nbval_sanitization_rules.cfg docs/${{ matrix.notebook-file }}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow command uses --nbval-sanitize-with, but the repository docs (and the comment immediately above) reference nbval’s --sanitize-with option. With nbval>=0.10.0 in test dependencies, --nbval-sanitize-with is likely not a valid flag and would break the notebook CI job. Consider switching back to --sanitize-with docs/nbval_sanitization_rules.cfg (or updating the docs/comment and nbval requirement if this flag is intentional).

Suggested change
pytest --nbval --nbval-sanitize-with docs/nbval_sanitization_rules.cfg docs/${{ matrix.notebook-file }}
pytest --nbval --sanitize-with docs/nbval_sanitization_rules.cfg docs/${{ matrix.notebook-file }}

Copilot uses AI. Check for mistakes.
def _build_monthly_summary(top_rows):
'''
"""
Convienience function to build a full monthly soiling summary
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in docstring: "Convienience" should be "Convenience".

Suggested change
Convienience function to build a full monthly soiling summary
Convenience function to build a full monthly soiling summary

Copilot uses AI. Check for mistakes.
Comment on lines +434 to +435
if not detect_neg_shifts:
results.loc[filt, "valid"] = False
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When detect_neg_shifts=True, intervals that fail the slope validity criteria (run_slope > 0 or slope_err too large) have their slopes zeroed, but valid is never set to False. This means downstream logic (e.g., selecting results[results.valid] and reporting soiling_ratio_perfect_clean) will treat these excluded intervals as valid. Consider setting results.loc[filt, "valid"] = False (and any other validity-related fields) regardless of detect_neg_shifts, while still skipping the max_neg_step criterion when detect_neg_shifts=True.

Suggested change
if not detect_neg_shifts:
results.loc[filt, "valid"] = False
results.loc[filt, "valid"] = False

Copilot uses AI. Check for mistakes.
Comment on lines +3010 to +3018
# Initialize default for initial_guesses to avoid mutable default argument
if initial_guesses is None:
initial_guesses = [13, 1, 0, 0]

# Define bounds if not provided
if bounds is None:
# bounds are neg in first 4 and pos in second 4
# ordered as x0,b,k1,k2 where x0 is the breakpoint k1 and k2 are slopes
bounds = [(13, -5, -np.inf, -np.inf), ((len(pr) - 13), 5, +np.inf, +np.inf)]
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

segmented_soiling_period takes days_clean_vs_cp as a parameter, but the default bounds hard-code the change-point search window to start/end at 13 days (lower bound x0=13, upper bound len(pr)-13). If a caller passes a different days_clean_vs_cp, the bounds will not reflect that and can incorrectly prevent valid change points from being found. Consider deriving the default x0 bounds from days_clean_vs_cp (and validating that len(pr) is large enough).

Suggested change
# Initialize default for initial_guesses to avoid mutable default argument
if initial_guesses is None:
initial_guesses = [13, 1, 0, 0]
# Define bounds if not provided
if bounds is None:
# bounds are neg in first 4 and pos in second 4
# ordered as x0,b,k1,k2 where x0 is the breakpoint k1 and k2 are slopes
bounds = [(13, -5, -np.inf, -np.inf), ((len(pr) - 13), 5, +np.inf, +np.inf)]
n_points = len(pr)
# Initialize default for initial_guesses to avoid mutable default argument
if initial_guesses is None:
initial_guesses = [13, 1, 0, 0]
# Derive minimum distance from series ends using days_clean_vs_cp
min_distance = int(days_clean_vs_cp)
if min_distance < 1:
raise ValueError("days_clean_vs_cp must be at least 1")
# If the series is too short for the requested clean-vs-change-point window,
# return a NaN series and no change point (consistent with other failure modes).
if n_points <= 2 * min_distance:
z = [np.nan] * n_points
cp_index = None
sr = pd.Series(z, index=pr.index)
return sr, cp_index
# Define bounds if not provided
if bounds is None:
# bounds are neg in first 4 and pos in second 4
# ordered as x0,b,k1,k2 where x0 is the breakpoint k1 and k2 are slopes
bounds = [(min_distance, -5, -np.inf, -np.inf),
(n_points - min_distance, 5, +np.inf, +np.inf)]

Copilot uses AI. Check for mistakes.
if ce-index+HW not in index_dummy]
if np.abs(u[0]) > np.sqrt(f.R) / 2:
index_dummy = [n + 3 for n in range(window_size - HW - 1) if n + 3 != HW]
cleaning_events = [
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable cleaning_events is not used.

Suggested change
cleaning_events = [
cleaning_events[:] = [

Copilot uses AI. Check for mistakes.
if changepoint is False:
prev_shift = start_shift # assigned at new soil period

elif new_soil > 0: # within soiling period
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test is always true, because of this condition.

Suggested change
elif new_soil > 0: # within soiling period
else: # within soiling period

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants