NEDAS.models.qg.python.spectral module

Spectral grid setup and FFT transforms for the QG model.

Faithfully translates the Fortran transform_tools.f90 staggered-grid scheme.

Conventions

Spectral arrays: shape (…, nky, nkx) where nkx=2*kmax+1, nky=kmax+1 Physical arrays: shape (…, ny, nx) where nx=ny=2*(kmax+1)

kx index: kxv[j] = j - kmax in [-kmax, kmax] ky index: kyv[j] = j in [0, kmax]

Staggered-grid dealiasing

Following Vallis (c1991) / Smith (c1998), each spec->phys transform packs the straight physical field into Re(output) and the half-grid-shifted (staggered) field into Im(output). Products are computed separately on the two grids (ir_prod) to avoid aliasing, then transformed back.

FFT conventions (from fft_fftw3_1pe.f90)

Fortran fft(x, dirn=-1) -> FFTW_BACKWARD, scale=1 -> np.fft.ifft2(x)*N² Fortran fft(x, dirn=+1) -> FFTW_FORWARD, scale=1/N² -> np.fft.fft2(x)/N²

NEDAS.models.qg.python.spectral.setup_spectral_grid(kmax: int) dict[str, Any][source]

Return wavenumber grids and index arrays for spec<->phys transforms.

Returns a dict with keys:

kxv, kyv 1-D wavenumber vectors kx_, ky_, ksqd_ 2-D wavenumber grids (nky, nkx) nx, ny, nkx, nky kxup, kyup indices into the nx×ny physical array (positive side) kxdn, kydn indices for the conjugate (negative) side exx phase-shift for staggered grid, shape (nky, nkx) sgn (-1)^(m+n) sign matrix, shape (nx, ny) filter_mask base de-aliasing mask (1 inside, 0 outside), (nky, nkx) lin2kx, lin2ky packed index lists for the non-zero mask region nmask number of active (kx, ky) points

NEDAS.models.qg.python.spectral.make_filter(g, filter_type='hyperviscous', filter_exp=8.0, k_cut=None, dealiasing='isotropic', filt_tune=1.0)[source]

Build the full spectral filter (de-aliasing + small-scale damping).

Parameters match the Fortran Init_filter in qg_init_tools.f90. Returns real array of shape (nky, nkx).

NEDAS.models.qg.python.spectral.spec2grid_cc(wf, g)[source]

Spectral to physical transform with staggered-grid packing.

wf : complex array, shape (…, nky, nkx)

Returns complex array shape (…, nx, ny): real part = physical field on straight grid, imag part = physical field on staggered (half-shifted) grid.

Translates Fortran Spec2grid_cc2/3 from transform_tools.f90.

NEDAS.models.qg.python.spectral.grid2spec(pf, g)[source]

Physical (staggered-packed complex) to spectral transform.

pf : complex array, shape (…, nx, ny) Returns complex array shape (…, nky, nkx).

Translates Fortran Grid2spec_cc2/3 from transform_tools.f90.

NEDAS.models.qg.python.spectral.spec2grid(wf, g)[source]

Spectral to physical (real output), discards staggered grid.

wf : complex (…, nky, nkx) Returns real (…, nx, ny).

NEDAS.models.qg.python.spectral.ir_prod(f, g_field)[source]

Product of two staggered-packed physical fields.

f, g_field : complex (…, nx, ny) with Re=straight, Im=staggered Returns complex (…, nx, ny) with the same packing.

NEDAS.models.qg.python.spectral.ir_pwr(f, pwr)[source]

Raise staggered-packed field to power pwr (supports 2 and 0.5).

NEDAS.models.qg.python.spectral.jacob(fk, gk, g)[source]

Arakawa Jacobian J(f, g) in spectral space.

fk, gk : complex (…, nky, nkx) Returns complex (…, nky, nkx).

J(f,g) = df/dx * dg/dy - df/dy * dg/dx