Skip to content

Preserve explicit odd FFT depths in 3D correlation - #380

Open
antonsoo wants to merge 1 commit into
OpenPIV:masterfrom
antonsoo:fix/3d-inverse-fft-shape
Open

antonsoo wants to merge 1 commit into
OpenPIV:masterfrom
antonsoo:fix/3d-inverse-fft-shape

Conversation

@antonsoo

@antonsoo antonsoo commented Oct 20, 2026 •

Copy link
Copy Markdown

correlate_windows passes nfftz to the forward FFT but omits the original shape when calling irfftn. For an odd depth, the inverse assumes an even output length, corrupting the correlation and sometimes losing its final plane. Pass the same FFT lengths to the inverse, as required by SciPy's shape convention.

For example, identical synthetic frames currently produce false motion:

import numpy as np
from openpiv.pyprocess3D import extended_search_area_piv3D

frame = np.random.default_rng(0).integers(0, 256, size=(16, 16, 16))
u, v, w = extended_search_area_piv3D(
    frame, frame, window_size=(8, 8, 8), search_area_size=(8, 8, 8), nfftz=17,
)
print(float(np.max(np.abs(w))))
# Before: about 0.808; after: 0.0.

Regression tests compare complete correlations with direct spatial correlation for float32, float64 and integer inputs, unequal windows and odd/even padding. They also check stationary PIV and unchanged inputs. Eighteen cases fail before the change; six controls already pass. Separate particle-volume/tracking runs repair 72 odd-depth configurations while preserving all 72 default/even configurations exactly on Python 3.10/3.12. Recorded-image workflows and the original tutorial retain identical results.

The new test module passes Ruff; the full run retains the same existing findings as master. This is separate from #379; both fixes retain their complete workload results together. Local Linux test suites:

Environment Standalone With #379
Python 3.12, Rust installed 278 passed 296 passed
Python 3.10, no Rust 243 passed, 4 optional skips 261 passed, 4 optional skips

Summary by Sourcery

Preserve FFT dimensions during inverse 3D correlation to prevent incorrect motion results for odd-depth transforms.

Bug Fixes:

  • Preserve explicitly requested odd FFT depths during 3D correlation so inverse transforms retain the correct output shape and correlation results.

Tests:

  • Add regression coverage comparing 3D FFT correlations with direct spatial correlations across numeric types, window shapes, and odd/even padding.
  • Verify stationary 3D PIV produces zero motion for odd FFT depths without modifying input frames.

An odd nfftz cannot be inferred from the packed real spectrum. Pass the original FFT lengths to irfftn so stationary volumes do not acquire a false displacement and full correlation tails are retained.
@sourcery-ai

sourcery-ai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes 3D FFT-based correlation by supplying irfftn with the explicit (nfftx, nffty, nfftz) shape used for the forward transform, preventing odd-depth outputs from being inferred as even. New regression tests validate correlation values, shape behavior, stationary PIV results, dtype coverage, padding variants, and input immutability.

Sequence diagram for explicit-shape 3D FFT correlation

sequenceDiagram
    participant Correlate as correlate_windows
    participant FFT as scipy.fft
    Correlate->>FFT: rfftn(normalize_intensity(window_a), s=(nfftx,nffty,nfftz))
    FFT-->>Correlate: f2a
    Correlate->>FFT: rfftn(normalize_intensity(window_b), s=(nfftx,nffty,nfftz))
    FFT-->>Correlate: f2b
    Correlate->>FFT: irfftn(f2a * f2b, s=(nfftx,nffty,nfftz))
    FFT-->>Correlate: corr with explicit odd-depth shape
    Correlate->>Correlate: crop correlation to window dimensions
Loading

Flow diagram for preserving odd FFT depth

flowchart LR
    A["Two normalized 3D windows"] --> B["rfftn with nfftx, nffty, nfftz"]
    B --> C["Multiply frequency-domain arrays"]
    C --> D["irfftn with the same FFT shape"]
    D --> E["Crop complete correlation"]
Loading

File-Level Changes

Change Details Files
Preserve the requested real-FFT output depth during inverse transforms.
  • Pass the same three-dimensional FFT lengths to irfftn that are used by rfftn.
  • Retain the existing correlation cropping and real-valued output handling.
openpiv/pyprocess3D.py
Add regression coverage for odd-depth FFT correlation and stationary 3D PIV.
  • Compare correlations across numeric dtypes, unequal shapes, and varied odd/even padding against direct spatial correlation.
  • Verify odd-depth stationary volumes produce zero motion and that inputs remain unchanged.
openpiv/test/test_pyprocess3d_fft.py

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

This branch has not been deployed

No deployments
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.

1 participant