Skip to content

Diagnostics: operating-curve filter figures for every reference turbine - #153

Merged
aclerc merged 1 commit into
v1from
ops-curves-per-reference
Oct 23, 2026
Merged

aclerc merged 1 commit into
v1from
ops-curves-per-reference

Conversation

@aclerc

@aclerc aclerc commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Summary

The three filter-stage operating-curve figures (ops_curves.png, ops_curves_kept_only.png, ops_curves_excluded.png) were drawn for the test turbine only. They are now also written for every reference turbine in the run, from that reference's own power, wind speed, pitch and generator rpm, as {ref}_ops_curves.png, {ref}_ops_curves_kept_only.png and {ref}_ops_curves_excluded.png in the same plots/2_filter/ folder (the per-turbine prefix convention {wtg}_coverage_timeseries.png / {wtg}_pairing_gap.png already use). The test turbine's filenames are unchanged. Each figure's suptitle names the turbine it shows.

Why

In a toggle run a reference with bad data (a stuck anemometer, a mis-scaled power signal, a special operating mode nobody flagged) corrupts the estimate as surely as a bad test turbine, but the test turbine's figures cannot show it. With one set of figures per reference the whole reference group can be eyeballed in the filter stage before the estimate is trusted.

  • Kept is the method's used timestamps for every turbine (a timestamp is used only when the test turbine and every reference passed), so a reference's kept-only figure shows exactly which of its rows fed the estimate.
  • The excluded figure colours each reference by its own ColumnSchema.exclude_row flag (new DiagnosticContext.turbine_excluded_mask), not the run-wide excluded_ts mask, which is the union over turbines and would hide which turbine carried the flag. A reference with nothing excluded gets no excluded figure.
  • A reference with too little wind speed (or no power column) gets no figures, as the test-turbine code already did.
  • Plots in common._PLOTS may now return Path | list[Path] | None; write_common_diagnostics flattens the list form.

Test plan

  • New TestReferenceOpsCurves in tests/benchmarking/diagnostics/test_diagnostics.py (written first, watched fail, then made green): the three files are written per reference into 2_filter; the test turbine's filenames are unchanged and never prefixed; a reference's excluded figure follows its own flag (a flagged reference gets one, an unflagged one does not, while the run-wide mask is set); turbine_excluded_mask reads the per-turbine column; no reference excluded figures without an exclusion concept; a reference with no wind speed draws nothing for itself.
  • uv run python -m pytest tests/benchmarking/diagnostics -q : 30 passed
  • uv run python -m pytest tests/benchmarking/baselines/test_toggle_specialist.py -k "Exclu or exclu or plot or diagnostic" : 28 passed
  • uv run poe lint (ruff format, ruff check, mypy) : clean

🤖 Generated with Claude Code

…nce turbine too

The kept-vs-removed, kept-only and kept-vs-excluded operating-curve figures were drawn for the
test turbine alone, so a reference with bad data (a stuck anemometer, a mis-scaled power signal,
a special operating mode nobody flagged) was invisible in the run's plots even though it corrupts
a toggle estimate as surely as a bad test turbine. The same three figures are now written for
each reference, from that reference's own power, wind speed, pitch and rpm, as
{ref}_ops_curves.png, {ref}_ops_curves_kept_only.png and {ref}_ops_curves_excluded.png alongside
the test turbine's unchanged files in plots/2_filter.

"Kept" is the method's used timestamps for every turbine (a timestamp is used only when the test
turbine and every reference passed), so a reference's kept-only figure shows exactly which of its
rows fed the estimate. The excluded figure colours each reference by its own exclude_row flag
(new DiagnosticContext.turbine_excluded_mask) rather than the run-wide excluded_ts mask, which is
the union over turbines and would hide which turbine carried the flag. A reference with nothing
excluded, or too little wind speed to draw a curve against, gets no figure.

Shared plots may now return a list of paths for a figure drawn per turbine;
write_common_diagnostics flattens them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Diagnostics should use the method’s effective reference set rather than every non-test turbine in the input data.

No open issues 🎉

What changed in this PR

This pull request extends filter-stage operating-curve diagnostics from the test turbine to reference turbines, using each turbine’s own signals and exclusion flags while preserving existing test-turbine filenames.

Changes:

  • Generates standard, kept-only, and excluded operating-curve figures for reference turbines.
  • Adds per-turbine exclusion-mask handling.
  • Supports diagnostic plots returning multiple output paths.
  • Adds regression coverage for reference figures, filenames, exclusions, and missing signals.
  • The effective reference set used by the estimate is not currently propagated into diagnostics, so figures may be generated for turbines outside the actual reference group.
File Description
tests/​benchmarking/​diagnostics/​test_diagnostics.py Tests reference figures, filenames, exclusion behavior, and missing-signal handling.
benchmarking/​diagnostics/​curves.py Generalizes operating-curve plotting across the test turbine and references.
benchmarking/​diagnostics/​context.py Adds per-turbine exclusion-mask extraction aligned to the diagnostic index.
benchmarking/​diagnostics/​common.py Supports diagnostic functions returning lists of output paths.

Review effort: Lite

@aclerc
aclerc merged commit 66a2fd1 into v1 Oct 23, 2026
5 checks passed
@aclerc
aclerc deleted the ops-curves-per-reference branch October 23, 2026 11:58
aclerc added a commit that referenced this pull request Nov 3, 2026
…s without operating-state labels

#153 drew the kept-vs-removed and kept-only operating-curve figures for every reference turbine;
the C3 merge dropped both, since a labelled run draws its used and unused records as the
uplift-validity scatters instead. A toggle run carries no operating-state labels, so it was left
with neither view of which rows, its references' included, fed the estimate. Both figures are back,
per turbine and in the valid-records stage, and stay off for a labelled run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aclerc added a commit that referenced this pull request Nov 3, 2026
…s without operating-state labels (#155)

#153 drew the kept-vs-removed and kept-only operating-curve figures for every reference turbine;
the C3 merge dropped both, since a labelled run draws its used and unused records as the
uplift-validity scatters instead. A toggle run carries no operating-state labels, so it was left
with neither view of which rows, its references' included, fed the estimate. Both figures are back,
per turbine and in the valid-records stage, and stay off for a labelled run.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants