Skip to content

Strict 2/3 de-aliasing mask (3|k| < N) with one active Fourier subspace - #55

Open
rogeriojorge wants to merge 4 commits into
mainfrom
fix/strict-two-thirds-mask
Open

rogeriojorge wants to merge 4 commits into
mainfrom
fix/strict-two-thirds-mask

Conversation

@rogeriojorge

@rogeriojorge rogeriojorge commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Problem

_twothirds_mask keeps |k| <= N//3. When N = 3K, two retained +K modes multiply to 2K, which aliases onto the retained -K. For u = cos(2*pi*K*x/N) the masked square should contain only its mean; on main it keeps a spurious amplitude 1/4 at |k| = K. Reproduced against main (ab87385) for N = 6, 12, 33, 129 on both the rFFT (x) axis and the full-FFT (y) axis. This is a Fourier-product issue, not an rFFT issue. It says nothing yet about how much existing runs were affected; that depends on their spectrum at the cutoff.

Change

  • _twothirds_mask: integer mode indices, keep 3*|k| < N (i.e. |k| <= (N-1)//3) on every axis.
  • simulation: project Ck_0, Fk_0 onto the same active set so distribution, current and fields share one Fourier subspace; the removed norm is reported as output["initial_projection_residual"].
  • With the strict bound N=3 keeps only k=0, so the three example inputs with Nx=3 now use Nx=4 (still kx=1, same physics).

Tests (tests/test_dealiasing.py, 78 cases)

Exact kept set for N in {3..9,12,33,34,129} on y/x/z; exhaustive triad no-alias check; boundary-cosine square on rFFT and full axes; 2D mixed triads (even/odd, divisible by 3); initial projection + residual reporting. 39 of them fail on main's mask.

Evidence (tested SHA 4f8939f, local, Python 3.12.9, JAX 0.11.2, diffrax 0.7.2)

python -m pytest -n 2 -q tests -> main: 8 passed; this branch: 86 passed.
Landau example IC, t in [0,20]: main at Nx=4 and this branch at Nx=4 give bitwise-identical EM_energy. Main at Nx=3 gives exactly half of it: the kx=1 mode is counted as Nyquist with weight 1 at odd Nx (the weight bug fixed by #9), the dynamics agree.

No dependencies. Conflicts with #13 in simulation (initial state + output dict); resolution = project, then reshape to the structured tuple (see branch integration/dark-baseline-a1, all six PRs combined: 115 passed locally). GitHub CI on 4f8939f: 3.11 and 3.12 passed.

…state onto it

The inclusive bound |k| <= N//3 keeps k = K when N = 3K; the product of two
retained +K modes then aliases onto the retained -K mode (amplitude 1/4 for a
cosine). Build the mask from integer mode indices with 3|k| < N on every axis,
project the initial state onto the same active set, and report the removed norm
as initial_projection_residual. The Nx=3 example inputs, which would now retain
only k=0, use Nx=4 so they keep their kx=1 mode.
@codecov

codecov Bot commented Oct 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
spectrax/_simulation.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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