Skip to content

Fix zero frequency index along the width in metrics.general.power_spectrum - #2008

Open
Nicholas022400701 wants to merge 2 commits into
NVIDIA:mainfrom
Nicholas022400701:fix-power-spectrum-odd-width-center
Open

Nicholas022400701 wants to merge 2 commits into
NVIDIA:mainfrom
Nicholas022400701:fix-power-spectrum-odd-width-center

Conversation

@Nicholas022400701

Copy link
Copy Markdown

PhysicsNeMo Pull Request

Description

closes #2007

power_spectrum builds the radial wavenumber grid after fftshift with h // 2 for the height and w / 2 for the width. After fftshift the zero frequency of an axis of length n sits at index n // 2 for even and odd n alike, so for an odd width the whole grid was skewed by half a cell along the width. A cosine along the height and the same cosine along the width gave different spectra, the spectrum of a field did not match the spectrum of its transpose and a single mode along the width filled two bins instead of one. Even widths were not affected, which is why the existing test_power_spectrum on a 32 by 32 grid never caught it.

Changes:

  • Build the meshgrid coordinates in float32 and use w // 2 for the width, so both axes are centered the same way. torch.hypot has no integer kernel, so the plain // change alone would raise. The trailing .to(torch.float32) is gone because the result already is float32.
  • Reword the comment above the azimuthal average to say where the zero frequency sits.
  • Add test/metrics/test_power_spectrum_center.py with three checks on 32 and 33 sized grids. The same cosine along either axis gives the same spectrum, the spectrum is invariant under transpose for 32 by 32, 33 by 33 and 32 by 33 fields, and a single cosine along the width of a 33 by 33 grid fills exactly one bin centered within half a bin width of the true wavenumber.

Nothing else in the file changed.

Verification on a CPU GitHub Actions runner with torch CPU wheels and Python 3.12:

I did not touch CHANGELOG.md in this PR. I can add a line under Fixed in the 2.3.0 section if you want it here.

AI disclosure: I used an AI coding agent to help write this patch, the tests and this description. I have read the change and the tests myself and I will answer review comments personally.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes. No public API or docstring changes.
  • The CHANGELOG.md is up to date with these changes.
  • An issue is linked to this pull request.
  • If I am implementing a new model or modifying any existing model, I have followed the Models Implementation Coding Standards. Not applicable, no model is touched.

Dependencies

None.

Review Process

All PRs are reviewed by the PhysicsNeMo team before merging.
Depending on which files are changed, GitHub may automatically assign a maintainer for review.

We are also testing AI-based code review tools (e.g., Greptile), which may add automated comments with a confidence score.
This score reflects the AI’s assessment of merge readiness and is not a qualitative judgment of your work, nor is
it an indication that the PR will be accepted / rejected.
AI-generated feedback should be reviewed critically for usefulness.
You are not required to respond to every AI comment, but they are intended to help both authors and reviewers.
Please react to Greptile comments with 👍 or 👎 to provide feedback on their accuracy.

…ctrum

After fftshift the zero frequency of an axis of length n sits at index
n // 2 for even and odd n alike. The radial wavenumber grid used h // 2
for the height but w / 2 for the width, so for an odd width every
wavenumber along the width was off by half a cell. A cosine along the
width then landed in different bins than the same cosine along the
height and the spectrum of a field differed from the spectrum of its
transpose. Build the grid in float32 and use w // 2 for the width.

Signed-off-by: 区梓灏 <116372750+Nicholas022400701@users.noreply.github.com>
The same cosine along the height and along the width has to give the
same azimuthally averaged spectrum, the spectrum of a field has to match
the spectrum of its transpose and a single cosine along the width has
to fill exactly one wavenumber bin. All three held for even sizes and
failed for odd widths before the fix.

Signed-off-by: 区梓灏 <116372750+Nicholas022400701@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 18, 2026 14:46
@copy-pr-bot

copy-pr-bot Bot commented Sep 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

CODEOWNERS review map

Current for commit 740760872306. An approval covers every file listed for that owner; one owner is sufficient for shared files.

⏳ @dallasfoster — 1 file(s)
  • physicsnemo/metrics/general/power_spectrum.py
⏳ @NickGeneva — 1 file(s)
  • physicsnemo/metrics/general/power_spectrum.py

No CODEOWNER

  • test/metrics/test_power_spectrum_center.py

Comment /codeowners-info to refresh.

@greptile-apps

greptile-apps Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Retrigger

The PR appears safe to merge, with the numerical correction matching post-FFT-shift indexing and targeted tests covering the regression.

Summary

Corrects the radial wavenumber grid so the width axis uses the actual post-fftshift zero-frequency index for odd dimensions.

  • Constructs mesh coordinates directly in float32 for torch.hypot.
  • Uses w // 2 consistently with the height-axis centering.
  • Adds regression coverage for axis symmetry, transpose invariance, rectangular grids, and odd-width single modes.

Reviews (1) · Last reviewed commit: "Test power_spectrum on odd sized grids"

@Unjuno

Unjuno commented Sep 30, 2026

Copy link
Copy Markdown

Update (2026-09-30): I reran the focused CPU reproducer against current main at eb8f95897eed9887295cb8110ba1017d2d670b58 (Torch 2.11.0). The 33×33 single-mode case still reproduces the odd-width asymmetry: height-axis peak power is 10.083, width-axis power is split across 6.188 and 5.042, and the transpose-control maximum difference is 0.109448 (fails tolerance). The 32×32 control passes at 2.38e-7. The current-main source file SHA256 is 13e7847c62b9285daafdf88307bd548e0f18e1f5d4fa0bf33f3552303deb8552.

I also reran the same control against this PR's head 7407608723062dc11ba5332e9ff3774f42bb02d9; the 33×33 transpose difference is 3.58e-7 and both even/odd controls pass. The current-main and PR-head JSON outputs plus the rerunnable script are in our benchmark evidence.

This is a focused reproducer only; I did not run the full PhysicsNeMo suite. The benchmark currently uses even grid sizes, so these results do not alter its measured spectra. This update confirms the tracked defect remains in main and that the existing PR addresses this reproducer; it is not a duplicate issue or a broader validation claim.

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.

🐛[BUG]: power_spectrum in metrics.general puts the zero frequency half a cell off along an odd width

3 participants