Skip to content

fix: apply validity flag in vectorized_sig2noise_ratio#369

Open
fbanelli wants to merge 1 commit into
OpenPIV:masterfrom
fbanelli:fix/vectorized-sig2noise-flag
Open

fix: apply validity flag in vectorized_sig2noise_ratio#369
fbanelli wants to merge 1 commit into
OpenPIV:masterfrom
fbanelli:fix/vectorized-sig2noise-flag

Conversation

@fbanelli
Copy link
Copy Markdown

@fbanelli fbanelli commented Jun 3, 2026

Fixes #368.

What

vectorized_sig2noise_ratio builds a per-window validity flag (weak first peak, border first peak, and for peak2peak a weak/border second peak) but never applies it:

peak2peak[flag is True] = 0   # 'flag is True' is the constant False -> empty mask -> no-op

This PR indexes with the flag array itself (peak2peak[flag] = 0, peak2mean[flag] = 0), so invalid windows return 0 as intended and as the loop-based sig2noise_ratio already does.

Test changes

  • test_vectorized_sig2noise_ratio passed only because of the no-op: its 5×5 correlation maps are so small that the second peak always lands on the map border, so with the flag applied every peak2peak ratio in that test becomes 0 and the s2n[0] > s2n[2] assertion fails. Rebuilt on 16×16 maps with interior peaks (same assertions, plus > 0 checks that no window is flagged).
  • Added test_vectorized_sig2noise_ratio_flags_invalid_windows covering: healthy window stays positive, border first peak → 0, no-signal window → 0, border second peak → 0 for peak2peak (and correctly not zeroed for peak2mean).

Behavior change note

Downstream code thresholding on s2n (e.g. validation.sig2noise_val) will now correctly reject windows the function always meant to reject; previously those leaked raw ratios. Note the vectorized flag is stricter than the loop-based sig2noise_ratio (which rejects a border second peak only when corr_max2 > 0.5 * corr_max1); aligning those two semantics is left to a separate discussion, as noted in #368.

Verification

test_pyprocess.py (12), test_process.py + test_validation.py + test_lib.py (37) all pass locally against the patched source (numpy 1.x, CPU).

🤖 Generated with Claude Code

Summary by Sourcery

Ensure vectorized signal-to-noise ratio computation correctly zeroes out invalid windows and strengthen its regression test coverage.

Bug Fixes:

  • Apply the validity flag when computing vectorized peak2peak and peak2mean signal-to-noise ratios so invalid correlation windows return zero as intended.

Tests:

  • Rework vectorized_sig2noise_ratio tests to use larger correlation maps with interior peaks, ensuring ratios remain positive when no window is flagged.
  • Add regression tests verifying that windows with border or weak peaks and no-signal cases are flagged and produce zero signal-to-noise ratios for the appropriate methods.

'peak2peak[flag is True] = 0' indexes with the Python expression
'flag is True' (a constant False), which numpy treats as an empty
boolean mask, so the assignment was a silent no-op and invalid
windows (no signal, border peaks) leaked raw ratios instead of the
intended 0. Same for peak2mean. Index with the flag array itself.

The existing test only passed because of the no-op: on its 5x5
correlation maps the second peak always sits on the map border, so
applying the flag zeroes every peak2peak ratio. Rebuild it on 16x16
maps with interior peaks and add an explicit regression test for the
flag behaviour.

Fixes OpenPIV#368

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Jun 3, 2026

Reviewer's Guide

Fixes the application of the validity flag in vectorized_sig2noise_ratio so invalid correlation windows yield zero signal-to-noise ratios as intended, and expands/adjusts tests to cover and verify both valid and invalid window behavior for peak2peak and peak2mean methods.

File-Level Changes

Change Details Files
Correct application of the boolean validity mask in vectorized_sig2noise_ratio for both peak2peak and peak2mean methods so invalid windows return zero ratios.
  • Replace incorrect numpy indexing that used the Python identity expression flag is True with direct boolean mask indexing peak2peak[flag] = 0 to zero invalid peak2peak ratios.
  • Replace the analogous incorrect indexing for peak2mean with peak2mean[flag] = 0 so the same validity rules apply to the mean-based ratio.
openpiv/pyprocess.py
Rebuild and extend tests for vectorized_sig2noise_ratio to validate correct handling of interior peaks, method-dependent behavior, and invalid window flagging.
  • Redesign test_vectorized_sig2noise_ratio to use larger 16x16 correlation maps with interior peaks such that no validity flags are triggered, asserting shape, positivity of all ratios, and relative ordering of signal-to-noise values for peak2peak and peak2mean methods across different widths.
  • Add test_vectorized_sig2noise_ratio_flags_invalid_windows to explicitly cover windows with a border first peak, no-signal window, and border second peak, asserting that peak2peak zeros any invalid window while peak2mean only zeros windows with an invalid first peak and leaves a border second peak window positive.
openpiv/test/test_pyprocess.py

Assessment against linked issues

Issue Objective Addressed Explanation
#368 Correctly apply the validity flag in vectorized_sig2noise_ratio so that invalid windows (weak/border peaks, no signal) have their signal-to-noise ratios set to 0 instead of leaking raw ratios.
#368 Update and extend tests for vectorized_sig2noise_ratio to (a) no longer rely on the previous no-op behavior and (b) explicitly verify that invalid windows are zeroed while valid windows remain positive.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The new regression test test_vectorized_sig2noise_ratio_flags_invalid_windows bakes in the internal 1e-3 threshold for a valid peak; consider referencing the threshold symbolically (or centralizing it) so the test doesn’t become brittle if that value is adjusted in the implementation.
  • Since the vectorized implementation intentionally has stricter semantics than the loop-based sig2noise_ratio (e.g., border second peak handling), it may be helpful to add a brief comment in vectorized_sig2noise_ratio itself describing this difference so future maintainers don’t assume they are identical.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new regression test `test_vectorized_sig2noise_ratio_flags_invalid_windows` bakes in the internal `1e-3` threshold for a valid peak; consider referencing the threshold symbolically (or centralizing it) so the test doesn’t become brittle if that value is adjusted in the implementation.
- Since the vectorized implementation intentionally has stricter semantics than the loop-based `sig2noise_ratio` (e.g., border second peak handling), it may be helpful to add a brief comment in `vectorized_sig2noise_ratio` itself describing this difference so future maintainers don’t assume they are identical.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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.

vectorized_sig2noise_ratio never applies its validity flag (flag is True indexing is a no-op)

1 participant