ClimaCoreSpectra.jl

ClimaCoreSpectra.jl provides functionality for calculating kinetic energy spectra using spherical harmonics.

Interface

ClimaCoreSpectra.SpectralSphericalMeshType
SpectralSphericalMesh{FT}(nθ, nd)
SpectralSphericalMesh(nθ, nd, ArrType, ComplexType, IntArrType)

Spherical mesh data structure for computing spectra on a regular latitude-longitude grid with latitudes, nλ = 2nθ longitudes, and nd vertical levels. The triangular truncation is num_fourier = floor((2nθ - 1) / 3) (e.g. nθ = 32 gives T21).

ArrType, ComplexType, and IntArrType are the array types used for the real, complex, and integer work arrays; the first form uses Arrays of FT.

Fields

  • num_fourier: number of truncated zonal wavenumbers m.
  • num_spherical: number of total wavenumbers n (num_fourier + 1).
  • , , nd: numbers of longitudes, latitudes, and vertical levels.
  • Δλ: longitude spacing [rad].
  • qwg: Gaussian-weighted associated Legendre polynomials, indexed [m, n, θ].
  • qnm: normalized associated Legendre polynomials, indexed [m, n, θ].
  • wave_numbers: total wavenumber n for each [m, n] entry.
  • var_grid, var_fourier, var_spherical, var_spectrum: work arrays for the variable on the grid, after the Fourier transform, in spherical-harmonic space, and its power spectrum.
source
ClimaCoreSpectra.power_spectrum_1dFunction
power_spectrum_1d(FT, var_grid, z, lat, lon, weight)

Compute the zonal (1D) power spectrum of the variable var_grid on a (lon, lat, z) grid with a Fourier transform along each latitude circle, weighting each level by weight. The input field must first be interpolated to a regular latitude-longitude grid.

Arguments

  • FT: float type.
  • var_grid: variable on the (lon, lat, z) grid to be transformed.
  • z: array of vertical levels.
  • lat: array of latitudes [degrees].
  • lon: array of uniformly spaced longitudes [degrees].
  • weight: array with one weight per level, e.g. for mass weighting.

Returns

The tuple (zon_spectrum, freqs) of arrays of shape (num_pfourier, nlat, nlev), where num_pfourier is the number of non-negative Fourier frequencies: the power at each frequency (with the negative-frequency contribution folded in) and the corresponding angular wavenumbers.

source
ClimaCoreSpectra.power_spectrum_2dFunction
power_spectrum_2d(FT, var_grid, mass_weight)

Transform the variable var_grid on a regular latitude-longitude grid into spherical-harmonic space, using an FFT along latitude circles (as for the 1D spectrum) and a Legendre transform along meridians, and compute its 2D power spectrum.

Arguments

  • FT: float type.
  • var_grid: variable on the (lon, lat, z) grid to be transformed, with nlon = 2 nlat.
  • mass_weight: array with one weight per level, e.g. for mass weighting.

Returns

The tuple (var_spectrum, wave_numbers, var_spherical, mesh): the power spectrum indexed [m, n, k], the total wavenumber of each [m, n] entry, the spherical-harmonic coefficients indexed [m, n, k, θ], and the SpectralSphericalMesh used.

See [55].

source
ClimaCoreSpectra.compute_gaussian!Function
compute_gaussian!(FT, n)

Compute sin(latitude) at the n Gaussian latitudes and the corresponding weights for Gaussian integration, returned as the tuple (sinθ, wts) of arrays with element type FT. n must be even. The function allocates its results and mutates none of its arguments.

Notes

The roots of the Legendre polynomial $P_n$ are found by Newton iteration from the initial guess $x_i = \cos(π(i - 1/4)/(n + 1/2))$, using the recurrences $n P_n(x) = (2n-1) x P_{n-1}(x) - (n-1) P_{n-2}(x)$ and $P'_n(x) = \frac{n}{x^2 - 1}(x P_n(x) - P_{n-1}(x))$; since $P_n$ is odd, only half of the roots are computed. The weights are $w_i = 2 / ((1 - x_i^2) P'_n(x_i)^2)$. An error is logged if the iteration does not converge. See Ehrendorfer, M. (2011), Spectral Numerical Weather Prediction Models, Appendix B, SIAM.

source
ClimaCoreSpectra.compute_legendre!Function
compute_legendre!(FT, num_fourier, num_spherical, sinθ, nθ)

Compute the normalized associated Legendre polynomials $P_{l,m}$ at the Gaussian latitudes and return them as an array qnm of shape (num_fourier + 1, num_spherical + 1, nθ), with qnm[m + 1, l + 1, :] holding $P_{l,m}$. The function allocates its result and mutates none of its arguments.

Arguments

  • FT: float type.
  • num_fourier: number of truncated zonal wavenumbers m.
  • num_spherical: number of total wavenumbers n.
  • sinθ: array of sin(latitude) at the Gaussian latitudes.
  • : number of Gaussian latitudes.

Notes

Following the notation and equation numbers of Ehrendorfer (2011), Appendix B, with l = 0, 1, … and m = -l, …, l:

P_{0,0} = 1
P_{m,m} = sqrt((2m+1)/2m) cosθ P_{m-1,m-1}
P_{m+1,m} = sqrt(2m+3) sinθ P_{m,m}
sqrt((l²-m²)/(4l²-1)) P_{l,m} = sinθ P_{l-1,m} - sqrt(((l-1)²-m²)/(4(l-1)²-1)) P_{l-2,m}

The normalization gives $\frac{1}{2} \int_{-1}^1 P_{l,m}(x) P_{n,m}(x)\, dx = δ_{n,l}$ with $x = \sin θ$.

References: Ehrendorfer, M. (2011), Spectral Numerical Weather Prediction Models, Appendix B, SIAM; Winch, D. (2007), Spherical harmonics, in Encyclopedia of Geomagnetism and Paleomagnetism, Springer.

source
ClimaCoreSpectra.trans_grid_to_spherical!Function
trans_grid_to_spherical!(mesh::SpectralSphericalMesh, pfield::AbstractArray)

Transform the variable pfield of shape (nλ, nθ) on a Gaussian grid into spherical-harmonic space and return the complex coefficient array of shape (num_fourier + 1, num_spherical + 1, nθ ÷ 2), split by latitude hemisphere pairs.

The transform is a Fourier transform along each latitude circle followed by a Legendre transform using the weighted polynomials mesh.qwg. mesh is read but not mutated; must be even.

Arguments

  • mesh: mesh information and weighted Legendre polynomials.
  • pfield: variable on the Gaussian grid to be transformed.

Notes

With λ the longitude, θ the latitude, η = sin θ, m the zonal wavenumber, and n the total wavenumber:

var_spherical2d = F_{m,n}    # output in spectral space
qwg = P_{m,n}(η) w(η)        # weighted Legendre polynomials
var_fourier2d = g_{m,θ}      # untruncated Fourier transform
pfield = F(λ, η)             # input on the Gaussian grid

See Ehrendorfer, M. (2011), Spectral Numerical Weather Prediction Models, Appendix B, SIAM, and [56].

source
ClimaCoreSpectra.compute_wave_numbers!Function
compute_wave_numbers!(wave_numbers, num_fourier::Int, num_spherical::Int)

Store the total wavenumber n for each (m, n) entry of the triangular truncation in the matrix wave_numbers, which is mutated in place. Entries with n < m are left unchanged. Returns nothing.

Arguments

  • wave_numbers: integer matrix of shape (num_fourier + 1, num_spherical + 1).
  • num_fourier: number of truncated zonal wavenumbers m.
  • num_spherical: number of total wavenumbers n.
source

Examples

lib/ClimaCoreSpectra/test/gcm_visual_test.jl computes the one- and two-dimensional spectra of test fields on a latitude–longitude grid, transforms them back, and plots the input, the spectra, and the reconstruction error. Run it from the repository root with BUILD_DOCS=true set to write the figures:

import ClimaCore
fn = joinpath(pkgdir(ClimaCore), "lib", "ClimaCoreSpectra", "test", "gcm_visual_test.jl")
ENV["BUILD_DOCS"] = true
include(fn)