alm_latlon — Part 3: API reference#
Module
healpix_analyse.alm_latlon
Parts 1 · Quickstart · 2 · Mathematics · 3 · API reference
Overview#
Function |
Purpose |
|---|---|
Sort a flat pixel list into iso-latitude rings |
|
Compute per-pixel quadrature weights |
|
Map → spherical harmonic coefficients |
|
Spherical harmonic coefficients → map |
|
Map → angular power spectrum |
|
Print a diagnostic summary of the grid |
build_rings_from_latlon#
ring_theta, ring_phi_list, ring_counts, sort_idx = build_rings_from_latlon(
lat, lon,
atol=1e-10,
convention="colatitude_rad"
)
Group a flat list of \(N\) pixels into iso-latitude rings, sorted by colatitude.
This is the mandatory first step before any transform call. The function
sorts pixels by colatitude (then longitude) and identifies contiguous groups
whose colatitude values agree within atol.
Parameters#
Name |
Type |
Default |
Description |
|---|---|---|---|
|
array-like |
— |
Latitude or colatitude of each pixel. Unit and sign depend on |
|
array-like |
— |
Longitude of each pixel. Unit depends on |
|
|
|
Angular tolerance in radians (after conversion) to merge two pixels into the same ring. Increase to |
|
|
|
Coordinate convention (see table below). |
Coordinate conventions#
|
|
|
|---|---|---|
|
colatitude \(\theta\), radians, \(0 \to \pi\) |
longitude \(\phi\), radians, \(0 \to 2\pi\) |
|
colatitude \(\theta\), degrees, \(0° \to 180°\) |
longitude \(\phi\), degrees, \(0° \to 360°\) |
|
geographic latitude, radians, \(-\pi/2 \to +\pi/2\) |
longitude, radians, \(-\pi \to +\pi\) or \(0 \to 2\pi\) |
|
geographic latitude, degrees, \(-90° \to +90°\) |
longitude, degrees, \(-180° \to +180°\) or \(0° \to 360°\) |
All conventions convert internally to colatitude + longitude in radians before any further processing.
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Colatitude \(\theta_r\) in radians of each ring, sorted in ascending order (North pole first). |
|
|
Longitudes \(\phi_j\) in radians for each ring. |
|
|
Number of pixels \(N_r\) in each ring. |
|
|
Permutation index. Apply as |
Raises#
ValueError — if convention is not one of the four accepted strings.
Notes#
Pixels within the same ring do not need to be pre-sorted in longitude;
build_rings_from_latlonsorts them internally.Pixels at different colatitudes that differ by less than
atolare merged into the same ring. If two rings are spuriously merged, decreaseatolor ensure the input coordinates are infloat64.
compute_weights#
weights = compute_weights(
ring_theta,
ring_phi_list,
ring_counts,
quadrature="trapeze"
)
Compute per-pixel quadrature weights in steradians such that:
The weights are the product of a colatitude weight \(w_r^\theta\) (ring-level) and a longitude weight \(w_j^\phi\) (pixel-level within the ring).
Parameters#
Name |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Colatitudes in radians (output of |
|
|
— |
Longitudes in radians per ring. |
|
|
— |
Number of pixels per ring. |
|
|
|
Quadrature rule for the colatitude integral. See table below. |
Quadrature rules#
|
Colatitude weight \(w_r^\theta\) |
Accuracy |
Best for |
|---|---|---|---|
|
\(\sin(\theta_r) \cdot \Delta\theta_r\) (trapezoidal) |
\(O(\Delta\theta^2)\) |
Regular grids, HEALPix |
|
Gauss-Legendre weight \(w_r^{\text{GL}}\) |
Exact for \(\ell \leq 2R-1\) |
ERA5, ECMWF, IFS, ARPEGE |
|
\(4\pi / N_{\text{total}}\) (uniform) |
Exact for equal-area grids |
HEALPix |
For the longitude direction, the weights are:
Uniform ring: \(w_j^\phi = 2\pi / N_r\) (exact rectangle rule).
Irregular ring: wrapped trapezoidal rule on the sorted longitudes.
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Per-pixel weights in steradians, in ring order (same order as a map reindexed by |
Raises#
ValueError— ifquadratureis not one of the three accepted strings.UserWarning— whenquadrature="gauss_legendre"and the provided colatitudes deviate from the expected Gauss-Legendre nodes by more than \(10^{-6}\) radians.
map2alm_latlon#
alm = map2alm_latlon(
im,
ring_theta,
ring_phi_list,
ring_counts,
lmax=24,
weights=None,
quadrature="trapeze",
limit_range=1e10,
)
Compute spherical harmonic coefficients \(a_{\ell m}\) from a map.
The transform follows the orthonormal convention (same as healpy.map2alm):
The algorithm performs two sequential steps:
Longitude DFT (per ring): FFT + phase shift for uniform rings, direct DFT for irregular rings.
Legendre projection (over rings): for each \(m\), projects the ring Fourier coefficients onto normalised associated Legendre polynomials.
Parameters#
Name |
Type |
Default |
Description |
|---|---|---|---|
|
array-like or |
— |
Map values in ring order. Apply |
|
|
— |
Colatitudes in radians. |
|
|
— |
Longitudes in radians per ring. |
|
|
— |
Number of pixels per ring. |
|
|
|
Maximum multipole \(\ell_{\max}\). |
|
|
|
Per-pixel quadrature weights. |
|
|
|
Quadrature rule passed to |
|
|
|
Overflow guard in the Legendre recurrence. |
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Spherical harmonic coefficients. \(n_{\text{alm}} = ({\ell_{\max}+1})(\ell_{\max}+2)/2\). |
Memory layout#
Coefficients are stored in order of increasing \(m\), then increasing \(\ell\) within each \(m\)-block:
Index: 0 1 ... lmax lmax+1 lmax+2 ...
Coeff: a_{0,0} a_{1,0} ... a_{L,0} a_{1,1} a_{2,1} ...
m=0 block (L+1 entries) m=1 block (L entries)
This layout matches healpy.map2alm exactly.
To extract \(a_{\ell m}\):
def alm_index(ell, m, lmax):
offset = sum(lmax - mp + 1 for mp in range(m))
return offset + (ell - m)
a_32 = alm[alm_index(3, 2, lmax)] # a_{3,2}
Notes#
The output is
complex128regardless of the input dtype.A 1-D input
imis treated as an unbatched map; the batch dimension is removed from the output automatically.lmaxshould not exceed \(3 \times n_{\text{side}} - 1\) for HEALPix grids.
alm2map_latlon#
im_out = alm2map_latlon(
alm,
ring_theta,
ring_phi_list,
ring_counts,
lmax=24,
limit_range=1e10,
)
Reconstruct a map from spherical harmonic coefficients (synthesis / inverse transform).
Parameters#
Name |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Coefficients in the layout produced by |
|
|
— |
Colatitudes in radians of the target grid. |
|
|
— |
Longitudes in radians of the target grid. |
|
|
— |
Number of pixels per ring of the target grid. |
|
|
|
Maximum multipole used when computing the alm. |
|
|
|
Overflow guard in the Legendre recurrence. |
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Reconstructed map values in ring order. |
Notes#
The target grid (defined by
ring_theta,ring_phi_list,ring_counts) can differ from the analysis grid. This allows, for example, analysing on an ERA5 grid and synthesising on a finer regular grid.The synthesis uses a direct DFT in longitude (\(O(N_r \cdot \ell_{\max})\) per ring). There is no FFT optimisation for the synthesis step in the current version.
The output is a real tensor (imaginary parts from numerical noise are discarded).
anafast_latlon#
cl = anafast_latlon(
im,
ring_theta,
ring_phi_list,
ring_counts,
lmax=24,
weights=None,
quadrature="trapeze",
limit_range=1e10,
)
Estimate the angular power spectrum \(C_\ell\) from a map.
Internally calls map2alm_latlon, then accumulates:
Parameters#
All parameters are identical to map2alm_latlon.
Name |
Type |
Default |
Description |
|---|---|---|---|
|
array-like or |
— |
Map in ring order (apply |
|
|
— |
Colatitudes in radians. |
|
|
— |
Longitudes in radians per ring. |
|
|
— |
Number of pixels per ring. |
|
|
|
Maximum multipole. |
|
|
|
Quadrature weights (same semantics as |
|
|
|
Quadrature rule (same semantics as |
|
|
|
Overflow guard in the Legendre recurrence. |
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Angular power spectrum. |
Notes#
cl[0](\(C_0\)) is the square of the map mean, divided by 1.cl[1](\(C_1\)) is the dipole power.For a Gaussian random field with theoretical spectrum \(C_\ell^{\text{th}}\), the expected value of
cl[ell]is \(C_\ell^{\text{th}}\) (unbiased estimator, up to quadrature accuracy).Batch dimensions are preserved:
cl_batch.shape == im_batch.shape[:-1] + (lmax+1,).
grid_summary#
info = grid_summary(ring_theta, ring_phi_list, ring_counts, lmax=24)
Print a human-readable diagnostic summary of the grid geometry and estimated computational cost.
Parameters#
Name |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Colatitudes in radians. |
|
|
— |
Longitudes in radians per ring. |
|
|
— |
Number of pixels per ring. |
|
|
|
Maximum multipole for the cost estimate. |
Returns#
Name |
Type |
Description |
|---|---|---|
|
|
Dictionary with the same fields printed to stdout. |
info keys#
Key |
Type |
Description |
|---|---|---|
|
|
Total number of pixels. |
|
|
Number of iso-latitude rings \(R\). |
|
|
Number of rings whose longitudes are uniformly spaced (FFT path). |
|
|
Number of alm coefficients for the given |
|
|
Colatitude of the northernmost ring, in degrees. |
|
|
Colatitude of the southernmost ring, in degrees. |
Example output#
=== Grid summary (lmax=192) ===
Total pixels : 786432
Latitude rings : 511
Uniform rings : 511/511 (FFT acceleration)
θ range : [0.110°, 179.890°]
Pixels/ring : min=4, max=512, mean=1538.0
n_alm : 18721
Cost estimate : 5.94e+06 ops (FFT: 5.94e+06, DFT: 0.00e+00)
Internal functions (not public API)#
These functions are implementation details. Their signatures may change between versions.
Function |
Description |
|---|---|
|
Evaluate normalised associated Legendre polynomials \(\tilde{P}_{\ell m}(\cos\theta)\) for \(\ell = m \ldots \ell_{\max}\) via three-term recurrence in log-space. Returns shape |
|
Return \(\log(n!!)\). Used to seed the Legendre recurrence. |
|
Reconstruct the full \(N\)-point complex spectrum from |
|
Return |
|
Accept |
|
Per-ring weighted longitude DFT. Dispatches to FFT+phase-shift (uniform rings) or direct DFT (irregular rings). Returns shape |
Error handling#
Situation |
Behaviour |
|---|---|
Unknown |
|
Unknown |
|
Colatitudes do not match GL nodes with |
|
|
Treated as |
|
Same: batch dim added then removed |
Type reference#
# Input maps accept any of:
ArrayLike = Union[np.ndarray, torch.Tensor, List[float]]
# ring_phi_list accepts either:
List[np.ndarray] # one array per ring (output of build_rings_from_latlon)
np.ndarray # flat [N_total] array (split internally by ring_counts)
# All returns:
ring_theta : np.ndarray float64 [R]
ring_counts : np.ndarray int64 [R]
sort_idx : np.ndarray int64 [N]
weights : np.ndarray float64 [N_total]
alm : torch.Tensor complex128 [..., n_alm]
cl : torch.Tensor float64 [..., lmax+1]
im_out : torch.Tensor float64 [..., N_total]