Maps and Spherical Harmonics#
The litebird_sim.maps_and_harmonics module provides robust data containers for HEALPix maps and Spherical Harmonic coefficients ($a_{ell m}$).
While libraries like healpy provide low-level array manipulation, this module introduces an object-oriented layer designed to prevent common errors in cosmological simulation pipelines, such as mixing coordinate systems or misinterpreting array shapes.
Design Philosophy#
In standard pipelines, a map is often just a NumPy array. This leads to ambiguity:
is an array of shape (3, N) a T/Q/U map, or three T-only maps? Is the map in Galactic or Ecliptic coordinates?
The classes HealpixMap and SphericalHarmonics solve this by:
Strict Shape Enforcement: Data is always stored as
(nstokes, size)for single-frequency, or(nfreqs, nstokes, size)for multi-frequency. A temperature-only map is(1, npix), never(npix,).Metadata Propagation: Every object carries physical
unitsandcoordinates. Algebraic operations (likemap_a + map_b) automatically check that these match, raising aValueErrorif you try to add a Galactic map to an Ecliptic one.Multi-Frequency Support: Both classes support storing data for multiple frequencies simultaneously, with automatic validation that frequency arrays match during operations.
Backend Agnosticism: While the API feels like Healpy, the heavy lifting (SHTs) is performed by ducc0, offering significant performance improvements and correct handling of spin-weighted transforms.
Data Structures#
Healpix Maps#
The HealpixMap class wraps a dense HEALPix map.
Note
This class does not perform reordering (RING vs NESTED) internally.
It stores the ordering flag nest as metadata. Users must ensure they are using the correct geometry for their specific analysis tools.
Key features:
Geometry checks: The number of pixels is validated against the
nsideupon initialization.Algebra: Supports
+,-,*(scalar), and Stokes vector multiplication.Multi-frequency support: Can store maps for multiple frequencies with shape
(nfreqs, nstokes, npix). Thefrequencies_ghzattribute holds the frequency array, andnfreqsindicates the number of frequencies.Static Helpers: Access HEALPix geometry math without importing
healpy(e.g.,nside_to_resolution_rad()).
Spherical Harmonics#
The SphericalHarmonics class wraps $a_{ell m}$ coefficients.
It solves the “triangular array ambiguity” by explicitly storing lmax and mmax alongside the coefficients.
Storage: Standard HEALPix/ducc triangular layout.
Convolution: The
convolve()method allows easy application of beams or transfer functions in harmonic space. Supports flexible multi-frequency convolution with 1D (broadcast to all frequencies), 2D (TEB filters), or 3D (per-frequency-stokes) filter arrays.Resizing: The
resize_alm()method allows you to truncate or zero-pad coefficients to a new $ell_{max}$.Multi-frequency support: Can store coefficients for multiple frequencies with shape
(nfreqs, nstokes, nalms). Thefrequencies_ghzattribute holds the frequency array, andnfreqsindicates the number of frequencies.
Spherical Harmonics Ordering#
A frequent source of confusion in CMB analysis is the ordering of $a_{ell m}$ coefficients in the 1D array.
The SphericalHarmonics class strictly enforces the Standard Healpix Ordering (also known as m-major).
Memory Layout
The coefficients are stored sequentially by iterating over $m$ (outer loop) and then $ell$ (inner loop). This allows efficient recursion for Legendre polynomial calculations.
Block $m=0$: contains $ell = 0, 1, dots, ell_{max}$
Block $m=1$: contains $ell = 1, 2, dots, ell_{max}$
…
Block $m=m_{max}$: contains $ell = m_{max}, dots, ell_{max}$
Indexing Formula
To find the index of a specific mode $(ell, m)$, the class provides a static method SphericalHarmonics.get_index(). It implements the standard formula:
Example: Converting coordinates to indices
from litebird_sim import SphericalHarmonics
import numpy as np
lmax = 10
# Get index for a single mode (l=2, m=2)
# Note: Arguments are (lmax, l, m) to match healpy signature
idx = SphericalHarmonics.get_index(lmax, 2, 2)
# Vectorized usage
ls = np.array([2, 3, 4])
ms = np.array([2, 2, 2])
indices = SphericalHarmonics.get_index(lmax, ls, ms)
Transforms (SHT)#
We provide high-level wrappers around ducc0 for spherical harmonic transforms. These functions handle the complexity of spin-0 (Temperature) vs spin-2 (Polarization) transforms automatically.
estimate_alm(): Map $rightarrow$ $a_{ell m}$ (Analysis)pixelize_alm(): $a_{ell m}$ $rightarrow$ Map (Synthesis)interpolate_alm(): $a_{ell m}$ $rightarrow$ Values at arbitrary $(theta, phi)$compute_cl(): Compute auto- or cross-power spectra from $a_{ell m}$compute_dl(): Compute $D_{ell} = ell(ell+1)C_{ell}/(2pi)$ spectra
Tip
All transform functions accept a nthreads argument.
Setting nthreads=0 (default) uses all available hardware threads, which is optimal for standalone scripts but should be adjusted when running inside an MPI environment.
Note
All transform functions support multi-frequency data. When operating on multi-frequency objects, transforms are applied independently to each frequency, and the output maintains the multi-frequency structure.
Cookbook#
Basic I/O and Algebra#
from litebird_sim.maps_and_harmonics import HealpixMap, SphericalHarmonics
from litebird_sim.constants import Units
from litebird_sim.coordinates import CoordinateSystem
# Loading a map from disk (wrapper around hp.read_alm usually not needed for maps,
# but classes support direct instantiation)
# Here we create a dummy map for demonstration
import numpy as np
nside = 128
npix = HealpixMap.nside_to_npix(nside)
# Create a Temperature-only map in Galactic coordinates
m_gal = HealpixMap(
values=np.zeros((1, npix)),
nside=nside,
units=Units.K_CMB,
coordinates=CoordinateSystem.Galactic
)
# Create a mask (unitless)
mask = HealpixMap(
values=np.ones((1, npix)),
nside=nside,
units=Units.None,
coordinates=CoordinateSystem.Galactic
)
# Multiplication works (Units.K_CMB * Units.None = Units.K_CMB)
masked_map = m_gal * mask
Smoothing a Polarization Map#
This example demonstrates how to smooth a T, Q, U map using a Gaussian beam.
from litebird_sim.maps_and_harmonics import estimate_alm, pixelize_alm
from litebird_sim.beam_synthesis import gauss_bl
# 1. Start with a 3-component map (T, Q, U)
# shape must be (3, npix)
m_pol = HealpixMap(..., nside=64, units=Units.uK_CMB)
# 2. Analysis: Convert to alms
# This automatically handles spin-0 for T and spin-2 for Q,U
alms = estimate_alm(m_pol, lmax=128)
# 3. Create a beam window function B_ell
# gauss_bl returns an array of size lmax+1
fwhm_rad = np.radians(1.0)
b_ell = gauss_bl(fwhm_rad, lmax=128)
# 4. Convolve (apply beam)
# The 'convolve' method applies the filter to all Stokes components
# if a single array is passed.
alms_smoothed = alms.convolve(b_ell)
# 5. Synthesis: Convert back to map
m_smoothed = pixelize_alm(alms_smoothed, nside=64)
Interpolating Alms#
If you need to evaluate a set of alms at specific locations (e.g., catalog positions):
from litebird_sim.maps_and_harmonics import interpolate_alm
# Define locations: (theta, phi) in radians
# Shape must be (N, 2)
locations = np.array([
[1.57, 0.0], # Equator, phi=0
[0.0, 0.0] # North Pole
])
# Interpolate
# If alms.nstokes == 3, this returns tuple (T, Q, U)
# where each is an array of length N (single-freq) or (nfreqs, N) (multi-freq)
t_vals, q_vals, u_vals = interpolate_alm(alms, locations)
Multi-Frequency Operations#
Both HealpixMap and SphericalHarmonics support multi-frequency data:
from litebird_sim.maps_and_harmonics import SphericalHarmonics, compute_cl
import numpy as np
# Create multi-frequency alms
lmax = 128
nfreqs = 3
frequencies = np.array([100.0, 143.0, 217.0]) # GHz
# Shape: (nfreqs, nstokes, nalms)
nalms = SphericalHarmonics.alm_array_size(lmax, lmax, 3)[1]
values = np.random.randn(nfreqs, 3, nalms) + 1j * np.random.randn(nfreqs, 3, nalms)
alms = SphericalHarmonics(
values=values,
lmax=lmax,
frequencies_ghz=frequencies
)
# Multi-frequency smoothing: apply different FWHM to each frequency
fwhm_arcmin = np.array([30.0, 23.0, 14.0])
fwhm_rad = np.radians(fwhm_arcmin / 60.0)
alms_smooth = alms.apply_gaussian_smoothing(fwhm_rad=fwhm_rad)
# Compute power spectra: returns 2D arrays (nfreqs, lmax+1)
cls = compute_cl(alms_smooth, alms_smooth)
# cls["TT"] has shape (3, 129) for 3 frequencies
# cls["frequency_ghz"] contains the frequency array
# Arithmetic operations check frequency compatibility
alms2 = alms.copy()
alms_sum = alms + alms2 # Works: same frequencies
# This would raise ValueError:
# alms_bad = SphericalHarmonics(..., frequencies_ghz=np.array([95, 150, 220]))
# alms + alms_bad # ValueError: frequencies not compatible!
API Reference#
- class litebird_sim.maps_and_harmonics.SphericalHarmonics(values: ndarray, lmax: int, mmax: int | None = None, nfreqs: int | None = None, frequencies_ghz: ndarray | None = None, units: Units | None = None, coordinates: CoordinateSystem | None = None)#
Bases:
objectA class that wraps spherical harmonics coefficients
The convention used in libraries like HealPy is to keep the a_ℓm coefficients of a spherical harmonic expansion in a plain NumPy array. However, this is ambiguous because it is not possible to uniquely determine the value of ℓ_max and m_max from the size of the array (unless you assume that ℓ_max == m_max).
This small data class keeps the array and the values l_max and m_max together. The shape of values is
(nstokes, ncoeff)ifnfreqs == 1, even ifnstokes == 1. For multi-frequency data (nfreqs > 1), the shape is(nfreqs, nstokes, ncoeff).It also provides algebraic operations and I/O utilities compatible with Healpy.
Ordering Convention (Healpix Scheme): The coefficients are stored in m-major order. 1. The outer loop iterates over m from 0 to mmax. 2. The inner loop iterates over l from m to lmax.
Sequence of coefficients in the array: Index 0: (l=0, m=0) Index 1: (l=1, m=0) … Index lmax: (l=lmax, m=0) Index lmax+1: (l=1, m=1) <– Note: l starts at m Index lmax+2: (l=2, m=1) …
This specific ordering is required for operations involving healpy.alm2map or ducc0.sht.
- values#
The spherical harmonics coefficients, stored in a NumPy array of shape
(nstokes, ncoeff)ifnfreqs == 1, or(nfreqs, nstokes, ncoeff)ifnfreqs > 1.- Type:
np.ndarray
- lmax#
The maximum degree ℓ_max of the expansion.
- Type:
int
- mmax#
The maximum order m_max of the expansion. If None, it is set equal to lmax.
- Type:
int, optional
- frequencies_ghz#
Array of frequencies in GHz. Must be None if
nfreqs == 1, otherwise must be an array of lengthnfreqs.- Type:
np.ndarray or None
- units#
Physical units of the coefficients. If set to :data:
None, the object is treated as unitless / unspecified.- Type:
Units or None
- coordinates#
Sky coordinate system of these coefficients (e.g. Galactic or Ecliptic). If
None, coordinates are unspecified.- Type:
CoordinateSystem or None
- nstokes#
The number of Stokes parameters (1 for intensity-only, 3 for TEB).
- Type:
int
- nfreqs#
The number of frequency channels (1 for single frequency, > 1 for multi-frequency).
- Type:
int
- Arithmetic#
- ----------
- The following operations are supported
- - `+`, `-` between two SphericalHarmonics (same `lmax`, `mmax`, `nstokes`
and compatible units / coordinates)
- - `*` with scalar or Stokes-vector (array of shape `(nstokes,)`)
with optional units override:
sh * aorsh.__mul__(a, units=...)
- - `.convolve(f_ell)` applies a filter f_ell(ℓ) or f_ell^i(ℓ) per Stokes
(units are preserved)
- allclose(other: SphericalHarmonics, rtol: float = 1e-05, atol: float = 1e-08) bool#
Check if two SphericalHarmonics objects are equal within a tolerance.
Units must be compatible (same, or one/both None/Units.None). Coordinates must also be compatible (same, or one/both None).
- Returns:
True if the objects are structurally consistent and their values are close within the specified tolerance. If the objects are inconsistent (e.g., different lmax, units, etc.), a warning is logged with the specific reason, and False is returned.
- Return type:
bool
- static alm_array_size(lmax: int, mmax: int | None = None, nstokes: int = 3) tuple[int, int]#
Computes the expected shape of the a_ℓm array.
- Returns:
The expected shape (nstokes, ncoeff).
- Return type:
tuple[int, int]
- static alm_l_array(lmax: int, mmax: int | None = None) ndarray#
Return the ℓ values corresponding to each a_{ℓm} coefficient in Healpy’s flattened alm format.
- apply_gaussian_smoothing(fwhm_rad: float | ndarray | list, inplace: bool = True) SphericalHarmonics#
Apply Gaussian smoothing to the spherical harmonics coefficients.
- Parameters:
fwhm_rad (float, np.ndarray, or list) –
Full Width at Half Maximum (FWHM) of the Gaussian beam in radians. Can be:
A single float: Same FWHM applied to all frequencies.
An array or list of floats: Per-frequency FWHM. Must have length equal to nfreqs.
inplace (bool, optional) – If True, modifies the object in place. Default is True.
- Returns:
The smoothed object.
- Return type:
- apply_pixel_window(nside: int, inplace: bool = True) SphericalHarmonics#
Apply the HEALPix pixel window function.
- Parameters:
nside (int) – The HEALPix Nside resolution parameter.
inplace (bool, optional) – If True, modifies the object in place. Default is True.
- Returns:
The object with pixel window applied.
- Return type:
- convolve(f_ell: ndarray | list[ndarray], inplace: bool = True) SphericalHarmonics#
Apply a beam or filter to the SH coefficients.
- Parameters:
f_ell (np.ndarray or list[np.ndarray]) –
The ℓ-dependent filter(s). Can be:
A 1D array: Single filter applied to all alms regardless of nfreqs.
A list of 3 filters or 2D array with shape (3, >=lmax+1): TEB filters. If nfreqs==1, applied as-is. If nfreqs>1, looped over frequencies and applied to each frequency’s TEB alms.
A 3D array with shape (nfreqs, nstokes, >=lmax+1): Per-frequency windows. First two dimensions must match values shape.
inplace (bool, optional) – If True, modifies the coefficients of the current object. If False, returns a new SphericalHarmonics object. Default is True.
- Returns:
The object itself (if inplace=True) or a new object (if inplace=False).
- Return type:
- copy() SphericalHarmonics#
Returns a deep copy of this SphericalHarmonics object.
- static get_index(lmax: int, l_val: int | ndarray | list[int], m_val: int | ndarray | list[int]) int | ndarray#
Calculate the 1D linear index in the standard Healpix (m-major) layout for the given (l, m) pairs.
Formula: index = m * (2 * lmax + 1 - m) / 2 + l
- Parameters:
lmax (int) – Maximum degree of the expansion.
l_val (int or np.ndarray) – Degree l.
m_val (int or np.ndarray) – Order m.
- Returns:
The 1D index. Returns an integer if inputs are scalars, otherwise a numpy array.
- Return type:
int or np.ndarray
- get_lm_arrays() tuple[ndarray, ndarray]#
Generate arrays of l and m for every coefficient stored in this object.
This reconstructs the explicit (l, m) coordinates for the flattened data array, following the m-major ordering used internally.
- Returns:
l_arr (np.ndarray) – Array containing the l (degree) for each element.
m_arr (np.ndarray) – Array containing the m (order) for each element.
- is_consistent(other: SphericalHarmonics) bool#
Check if two SphericalHarmonics objects are compatible for algebraic operations.
- static lmax_from_num_of_alm(nalm: int, mmax: int | None = None) int#
Returns the lmax corresponding to a given array size.
- property mmax_int: int#
Returns the maximum order m_max of the expansion.
- static num_of_alm_from_lmax(lmax: int, mmax: int | None = None) int#
Computes the number of a_ℓm coefficients for given ℓ_max and m_max. If mmax is not provided, it is set equal to lmax.
- property num_of_alm_per_stokes: int#
Returns the number of a_ℓm coefficients per Stokes component.
- print_ordering_example()#
Prints the first few (l, m) pairs to demonstrate ordering.
- static read_fits(filename: str) SphericalHarmonics#
Load a SphericalHarmonics object from a FITS file. Compatible with both Explicit Index format and Standard Healpix format.
- resize_alm(lmax_out: int, mmax_out: int | None = None, inplace: bool = False)#
Resizes the spherical harmonics coefficients, either truncating or padding them with zeros.
Units, coordinates, and frequencies are preserved.
- write_fits(filename: str, overwrite: bool = True, idx_frequency: int | None = None)#
Save the SphericalHarmonics object to a FITS file using the Explicit Index scheme.
Format: - Separate HDUs for TEMPERATURE, E_MODE, B_MODE. - Each HDU has 3 columns: INDEX, REAL, IMAG. - INDEX = l^2 + l + m + 1 (FITS standard for sparse alm).
- Parameters:
filename (str) – The FITS file path.
overwrite (bool, optional) – If True, overwrite existing file. Default is True.
idx_frequency (int or None, optional) – The frequency index to write (for multi-frequency objects). - If nfreqs is None (single-frequency): ignored; raises warning if not None. - If nfreqs is not None (multi-frequency): must be specified and < nfreqs. Default is None.
- Raises:
ValueError – If nfreqs > 1 and idx_frequency is None. If idx_frequency is not in valid range [0, nfreqs).
UserWarning – If nfreqs is None and idx_frequency is not None.
- classmethod zeros(lmax: int, mmax: int | None = None, nstokes: int = 3, nfreqs: int | None = None, frequencies_ghz: float | Sequence[float] | ndarray | None = None, dtype: type[~typing.Any] | ~numpy.dtype[~typing.Any] | ~numpy._typing._dtype_like._HasDType[~numpy.dtype[~typing.Any]] | ~numpy._typing._dtype_like._HasNumPyDType[~numpy.dtype[~typing.Any]] | tuple[~typing.Any, ~typing.Any] | list[~typing.Any] | ~numpy._typing._dtype_like._DTypeDict | str=<class 'numpy.complex128'>, units: Units | None = None, coordinates: CoordinateSystem | None = None) SphericalHarmonics#
Create a SphericalHarmonics object filled with zeros.
- Parameters:
lmax (int) – Maximum degree.
mmax (int, optional) – Maximum order. Defaults to lmax.
nstokes (int, default=3) – Number of Stokes parameters (1 or 3).
nfreqs (int or None, default=None) – Number of frequency channels. If None (default), creates a single-frequency object. If int > 0, creates a multi-frequency object. If frequencies_ghz is provided, nfreqs is automatically computed and overrides this parameter.
frequencies_ghz (float, Sequence[float], np.ndarray, or None, optional) – Array of frequencies in GHz. Can be a single float or an array of floats. If provided, nfreqs is automatically set based on the size of frequencies_ghz. If not provided, nfreqs must be explicitly set or defaults to None (single-frequency mode).
dtype (type, default=np.complex128) – Data type for the array. Must be np.complex64 or np.complex128.
units (Units, optional) – Physical units.
coordinates (CoordinateSystem, optional) – Sky coordinate system.
- Returns:
Instance initialized with zeros.
- Return type:
- Raises:
ValueError – If dtype is not np.complex64 or np.complex128.
- class litebird_sim.maps_and_harmonics.HealpixMap(values: ndarray, nside: int | None = None, nfreqs: int | None = None, frequencies_ghz: ndarray | None = None, units: Units | None = None, coordinates: CoordinateSystem | None = None, nest: bool = False)#
Bases:
objectA small container class for HEALPix maps, with shape checks and algebra.
This class stores one- or three-component HEALPix maps and their NSIDE consistently. Maps are always stored as a 2D NumPy array of shape
(nstokes, npix), even ifnstokes == 1.If
nsideis not provided, it is inferred from the size ofvalues.- values#
Map values, stored as a NumPy array of shape
(nstokes, npix)ifnfreqs == 1, or(nfreqs, nstokes, npix)ifnfreqs > 1. If a 1D array is passed, it is promoted to shape(1, npix). If a tuple of arrays is passed (e.g. (I, Q, U)), it is stacked along the first axis.- Type:
np.ndarray
- nside#
HEALPix NSIDE resolution parameter. If
None, it is automatically inferred from the last dimension ofvalues. If provided, it is checked against the size ofvalues.- Type:
int | None
- frequencies_ghz#
Array of frequencies in GHz. Must be None if
nfreqs == 1, otherwise must be an array of lengthnfreqs.- Type:
np.ndarray or None
- units#
Physical units of the map. If set to
Units.NoneorNone, the map is treated as unitless / unspecified.- Type:
Units or None
- coordinates#
Sky coordinate system of the map (e.g. Galactic or Ecliptic). If
None, coordinates are unspecified.- Type:
CoordinateSystem or None
- nest#
If True, the map is in NESTED ordering; if False, in RING (default). This is just metadata here, no indexing operations are performed.
- Type:
bool, optional
- nstokes#
Number of Stokes parameters (1 for intensity-only, 3 for IQU).
- Type:
int
- nfreqs#
The number of frequency channels (1 for single frequency, > 1 for multi-frequency).
- Type:
int
- allclose(other: HealpixMap, rtol: float = 1e-05, atol: float = 1e-08) bool#
Check if two HealpixMap objects are equal within a tolerance.
Checks for consistency in geometry (nside, nest, nstokes), metadata (units, coordinates), and numerical values.
- Returns:
True if the objects are structurally consistent and their values are close within the specified tolerance. If the objects are inconsistent, a warning is logged with the specific reason, and False is returned.
- Return type:
bool
- copy() HealpixMap#
Return a deep copy of this HealpixMap object.
- is_consistent(other: HealpixMap) bool#
Check if two HealpixMap objects are compatible for algebraic operations.
Two maps are considered consistent if they share the same nside, nest, nstokes, and nfreqs.
- static is_npix_ok(num_of_pixels) bool#
Return True or False whenever num_of_pixels is a valid number.
The function checks if the number of pixels provided as an argument conforms to the Healpix standard, which means that the number must be in the form 12 * NSIDE^2, where NSIDE is a power of 2.
>>> from litebird_sim import HealpixMap >>> HealpixMap.is_npix_ok(48) True >>> HealpixMap.is_npix_ok(108) # 12 * 3^2, but 3 not power of 2 False
- property npix: int#
Return the number of pixels in the map.
- static npix_to_nside(num_of_pixels: int) int#
Return NSIDE for a Healpix map containing num_of_pixels pixels.
If the number of pixels does not conform to the Healpix standard, an AssertionError exception is raised.
>>> from litebird_sim import HealpixMap >>> HealpixMap.npix_to_nside(48) 2
- static nside_to_npix(nside: int) int#
Return the number of pixels in a Healpix map with the specified NSIDE.
If the value of nside is not valid (power of two), an AssertionError exception is raised.
>>> from litebird_sim import HealpixMap >>> HealpixMap.nside_to_npix(1) 12
- static nside_to_pixel_solid_angle_sterad(nside: int) float#
Return the value of the solid angle of a pixel.
The result is exact, as all pixels in a Healpix map have the same area.
The result is in steradians.
- static nside_to_resolution_rad(nside: int) float#
Return an approximated resolution of a Healpix map, given its NSIDE.
The value is the square root of the pixel area (which is measured in steradians); see
HealpixMap.nside_to_pixel_solid_angle_sterad().The result is an angle in radians.
- classmethod zeros(nside: int, nstokes: int = 3, nfreqs: int | None = None, frequencies_ghz: float | Sequence[float] | ndarray | None = None, dtype: type = <class 'numpy.float64'>, units: Units | None = None, coordinates: CoordinateSystem | None = None, nest: bool = False) HealpixMap#
Create a HealpixMap object filled with zeros.
- Parameters:
nside (int) – HEALPix resolution.
nstokes (int, default=3) – Number of Stokes parameters.
nfreqs (int | None, default=None) – Number of frequency channels. If None, creates single-frequency map (2D); if int > 0, creates multi-frequency map (3D). If frequencies_ghz is provided, nfreqs is automatically computed and overrides this parameter.
frequencies_ghz (float, Sequence[float], np.ndarray, or None, optional) – Array of frequencies in GHz. Can be a single float or an array of floats. If provided, nfreqs is automatically set based on the size of frequencies_ghz. If not provided, nfreqs must be explicitly set or defaults to None (single-frequency mode).
dtype (type, default=np.float64) – Data type of the map.
units (Units, optional) – Physical units.
coordinates (CoordinateSystem, optional) – Sky coordinate system.
nest (bool, default=False) – Ordering (Ring vs Nested).
- Returns:
Instance initialized with zeros.
- Return type:
- Raises:
ValueError – If both nfreqs and frequencies_ghz are inconsistent.
- litebird_sim.maps_and_harmonics.estimate_alm(map: HealpixMap, *, lmax: int | None = None, mmax: int | None = None, maxiter: int | None = None, epsilon: float | None = None, nthreads: int = 0) SphericalHarmonics#
Estimate spherical harmonic coefficients ($a_{ell m}$) from a HEALPix map.
This function performs a spherical harmonic analysis to transform the input map into harmonic space. Two backends are available depending on
maxiter:Default (``maxiter=None``) – uses
ducc0.sht.adjoint_synthesis()to compute the pixel summation and scales the result by the pixel area, approximating the integral over the sphere:\[a_{\ell m} \approx \Omega_{pix} \sum_{p} f(p) Y_{\ell m}^*(p)\]where
ducc0.sht.adjoint_synthesis()computes $sum f Y^*$ and the result is multiplied by $Omega_{pix}$ (base.pix_area()).Iterative (``maxiter`` a positive integer) – uses
ducc0.sht.pseudo_analysis(), an iterative least-squares solver that converges to more accurate coefficients at the cost of additional computation.
Both backends support scalar and polarized fields:
map.nstokes == 1→ spin-0 transform, returns a 1-component almmap.nstokes == 3→ spin-0 for T and spin-2 for (Q, U), returns a 3-component alm (T, Q, U interpreted as spin-2)
Geometry is obtained from
ducc0.healpix.Healpix_Basevia itssht_info()method, which provides the arraystheta,nphi,phi0and (optionally)ringstartneeded by ducc’s SHT routines.The units and coordinates metadata are propagated from
mapto the returnedSphericalHarmonics.- Parameters:
map (HealpixMap) –
Input HEALPix map. Must satisfy:
map.values.shape == (nstokes, npix)map.nstokes in (1, 3)map.nsideis a power of two.
lmax (int, optional) –
Maximum multipoles to compute. Defaults are chosen in a Healpy-like way:
if
lmaxis None →lmax_eff = 3 * nside - 1if
mmaxis None →mmax_eff = lmax_eff
mmax_effmust be ≤lmax_eff.mmax (int, optional) –
Maximum multipoles to compute. Defaults are chosen in a Healpy-like way:
if
lmaxis None →lmax_eff = 3 * nside - 1if
mmaxis None →mmax_eff = lmax_eff
mmax_effmust be ≤lmax_eff.maxiter (int or None, optional) – If
None(default), uses the non-iterativeducc0.sht.adjoint_synthesis()backend followed by pixel-area scaling. If a positive integer, usesducc0.sht.pseudo_analysis()instead and performs at mostmaxiteriterations.epsilon (float or None, optional) –
Desired accuracy for
ducc0.sht.pseudo_analysis(). This parameter is used only whenmaxiteris a positive integer. IfNone, a dtype-dependent default is chosen:complex64output ->1e-6complex128output ->1e-13
nthreads (int, optional) – Number of threads passed to ducc. If zero (default), ducc chooses the number of threads.
- Returns:
A spherical harmonics object with
valuesof shape(nstokes, nalm)lmax = lmax_effmmax = mmax_effunits = map.unitscoordinates = map.coordinates
- Return type:
- Raises:
TypeError – If
maxiteris not an integer orNone.ValueError – If
maxiteris an integer but not positive (i.e. ≤ 0). If the HealpixMap object has unsupportednstokes, or if requestedlmax/mmaxare inconsistent.
- litebird_sim.maps_and_harmonics.pixelize_alm(alms: SphericalHarmonics, nside: int, *, nest: bool = False, lmax: int | None = None, mmax: int | None = None, nthreads: int = 0) HealpixMap#
Convert spherical harmonics coefficients to a HEALPix map using
ducc0.sht.synthesis()on the HEALPix geometry.This is essentially an
pixelize_almimplemented on top of ducc0, with support for both scalar and polarized fields:alms.nstokes == 1→ spin-0 synthesis, returns a 1-component mapalms.nstokes == 3→ spin-0 for T and spin-2 for (Q, U), returns a 3-component map
Geometry is obtained from
ducc0.healpix.Healpix_Basevia itssht_info()method, which provides the arraystheta,nphi,phi0and (optionally)ringstartneeded by ducc’s SHT routines.The units and coordinates metadata are propagated from
almsto the returnedHealpixMap.- Parameters:
alms (SphericalHarmonics) –
Harmonic coefficients. Must satisfy:
alms.values.shape == (nstokes, nalm)alms.nstokes in (1, 3)triangular Healpy/ducc layout in the last dimension (i.e. increasing m, l ≥ m).
nside (int) – Target HEALPix resolution (power of two). The output map will have
npix = 12 * nside**2pixels.nest (bool, optional) – If
False(default), the map is in RING ordering. IfTrue, the map is in NESTED ordering. The underlying SHT is always performed in RING geometry; for NESTED, the geometry is built from a NESTEDHealpix_Basebut pixel ordering in the returnedHealpixMapis marked accordingly.lmax (int, optional) –
Maximum multipoles to use in the synthesis. If omitted, the values from
almsare used:lmax_eff = alms.lmaxiflmaxisNonemmax_eff = alms.mmaxifmmaxisNone
Both must be ≤ the corresponding values in
alms. If a smallerlmax/mmaxis requested than what is stored inalms, the coefficient array is truncated accordingly.mmax (int, optional) –
Maximum multipoles to use in the synthesis. If omitted, the values from
almsare used:lmax_eff = alms.lmaxiflmaxisNonemmax_eff = alms.mmaxifmmaxisNone
Both must be ≤ the corresponding values in
alms. If a smallerlmax/mmaxis requested than what is stored inalms, the coefficient array is truncated accordingly.nthreads (int, optional) – Number of threads passed to ducc. If zero (default), ducc chooses the number of threads.
- Returns:
A HEALPix map with shape
(nstokes, npix)and metadatansideas specifiednestas specifiedunits = alms.unitscoordinates = alms.coordinates
- Return type:
- Raises:
ValueError – If the SphericalHarmonics object has unsupported
nstokes, or if requestedlmax/mmaxare inconsistent with the available coefficients.
- litebird_sim.maps_and_harmonics.interpolate_alm(alms: SphericalHarmonics, locations: ndarray, *, epsilon: float | None = None, nthreads: int = 0) ndarray | tuple[ndarray, ndarray, ndarray]#
Interpolate spherical-harmonic coefficients at arbitrary positions using
ducc0.sht.synthesis_general().This wrapper supports both scalar and polarized fields:
If
alms.nstokes == 1: a single spin-0 field is synthesized and the function returns a 1D arrayTof lengthN.If
alms.nstokes == 3: the first component is interpreted as a spin-0 field (T), and the remaining two as a spin-2 field, returningT, Q, U.
- Parameters:
alms (SphericalHarmonics) –
Object exposing at least the attributes:
values: ndarray, shape(nstokes, nalm), complex64/complex128lmax: intmmax: intnstokes: int (1 or 3)
The last dimension of
valuesmust follow the standard triangular (healpy/ducc) ordering.locations (ndarray, shape (N, 2)) – Target positions on the sphere, in radians.
locations[:, 0]= colatitudetheta(0 .. π),locations[:, 1]= longitudephi(0 .. 2π).epsilon (float, optional) –
Desired accuracy passed to
synthesis_general(). IfNone, a safe default is chosen depending on the dtype:complex64 →
1e-6complex128 →
1e-13
nthreads (int, optional) – Number of threads for ducc. If 0 (default), ducc uses the number of hardware threads.
- Returns:
T (ndarray) – If
alms.nstokes == 1, a 1D array of lengthNwith the interpolated scalar field.T, Q, U (ndarray) – If
alms.nstokes == 3, three 1D arrays of lengthNwith the interpolated Stokes parameters.
- Raises:
ValueError – If the input shapes are inconsistent or
nstokesis not 1 or 3.