Power Spectrum Estimation
The Spectra class implements Quadratic Maximum Likelihood (QML) estimation for power spectrum recovery from partial-sky observations of spin-0 and spin-2 fields. This method provides unbiased, minimum-variance power spectrum estimates while properly accounting for noise, masking, and correlations. It applies to any Gaussian field on the sphere, such as CMB temperature and polarization, galaxy density, or 21 cm intensity.
Mathematical Background
QML Theory
QML power spectrum estimation maximizes the likelihood function for Gaussian random fields. For each multipole \(\ell\), the QML estimator is:
where: - \(\mathbf{x}\) is the observed data vector - \(\mathbf{E}_\ell = \mathbf{C}^{-1} \frac{\partial \mathbf{C}}{\partial C_\ell} \mathbf{C}^{-1}\) is the estimator matrix - \(\mathbf{S}\) is the total covariance matrix - \(\mathbf{C} = \mathbf{S} + \mathbf{N}\) includes signal and noise
This estimator is unbiased: \(\langle \hat{C}_\ell \rangle = C_\ell\) and achieves the minimum variance bound given by the Fisher information.
Bias Correction
The normalized QML estimator includes bias correction for finite-size effects:
where \(\mathbf{M}\) is the appropriate normalization matrix that accounts for the specific covariance structure.
Class Documentation
- class qube.spectra.Spectra(params_file=None, fisher=None, compression=None, **kwargs)[source]
Bases:
Core,MPISharedMemoryMixinQuadratic Maximum Likelihood (QML) power spectrum estimator.
This class implements the QML method for optimal power spectrum estimation from observations of spin-0 and spin-2 fields on the sphere (e.g. CMB temperature and polarization, cosmic shear). The QML estimator provides unbiased, minimum-variance estimates of angular power spectra C_l while properly accounting for instrumental noise, sky cuts, and pixel correlations.
The QML estimator computes power spectrum amplitudes as:
q̂_l = (1/2) * x^T * E_l * x
where E_l = C^(-1) * ∂C/∂q_l * C^(-1) is the quadratic estimator matrix, x is the data vector, and C is the total covariance matrix.
- Parameters:
params_file (str, optional) – Path to YAML parameter file containing analysis configuration.
fisher (Fisher, optional) – Pre-computed Fisher matrix instance. If provided, reuses computed components (covariance matrices, geometry, etc.) for efficiency.
**kwargs (dict) – Additional keyword arguments passed to the Core parent class.
- comm
MPI communicator for parallel computation.
- Type:
MPI.Comm
- rank
MPI process rank (0 for master process).
- Type:
- size
Total number of MPI processes.
- Type:
- fisher_instance
Fisher matrix computation instance, either provided or computed.
- Type:
Fisher
- maps1, maps2
Input map data for primary and secondary fields (cross-correlation).
- Type:
- qml_results
QML power spectrum estimates for all simulations and multipoles.
- Type:
- qml_noise_bias
Noise bias estimates for auto-correlation spectra.
- Type:
- invfisher
Inverse of the beam-smoothed Fisher matrix.
- Type:
- inv_cov1, inv_cov2
Inverted covariance matrices for primary and secondary datasets.
- Type:
Examples
Basic QML power spectrum estimation:
>>> from cosmoforge.qube import Spectra >>> spectra = Spectra("config/qml_analysis.yaml") >>> spectra.run() >>> power_spectra = spectra.get_power_spectra() >>> noise_bias = spectra.get_noise_bias()
Using pre-computed Fisher matrix:
>>> from cosmoforge.qube import Fisher, Spectra >>> fisher = Fisher("config/fisher_config.yaml") >>> fisher.run() >>> spectra = Spectra("config/qml_config.yaml", fisher=fisher) >>> spectra.run() # Reuses Fisher components for efficiency
MPI parallel execution:
>>> # Run with: mpirun -n 8 python qml_analysis.py >>> spectra = Spectra("config/high_res_config.yaml") >>> spectra.run() # Distributes computation across processes
Notes
The QML method offers several advantages over pseudo-C_l estimators: 1. Optimal statistical properties (minimum variance, unbiased) 2. Exact treatment of sky cuts and inhomogeneous noise 3. Proper error propagation through Fisher matrix 4. Natural handling of mode coupling
However, it is computationally expensive, scaling as O(N_pix^3) due to matrix inversions and O(N_ell * N_pix^2) for quadratic form evaluations.
For auto-correlation analyses, noise bias is computed and can be subtracted: noise_bias_l = (1/2) * Tr[N * E_l] where N is the noise covariance matrix.
Cross-correlation analyses are naturally noise-bias free when using independent realizations of noise between maps.
The implementation supports both temperature-only and polarization analyses with proper treatment of spin-2 fields and E/B mode decomposition.
See also
FisherFisher information matrix computation
cosmocore.CoreBase class providing fundamental analysis infrastructure
- __init__(params_file=None, fisher=None, compression=None, **kwargs)[source]
Initialize QML power spectrum estimation class.
- Parameters:
params_file (str, optional) – Path to YAML configuration file.
fisher (Fisher, optional) – Pre-computed Fisher instance. If provided, reuses computed components (covariance matrices, geometry, field collections) for efficiency.
compression (dict, optional) – Computation basis configuration (method, epsilon, basis, mode_fraction).
**kwargs (dict) – Additional arguments passed to Core.
- Raises:
TypeError – If fisher is not a Fisher instance.
ValueError – If fisher doesn’t contain a valid Fisher matrix.
- property lmax_signal: int
Maximum multipole for signal/derivative matrix computation.
This defaults to 4*nside to match the Fortran reference implementation. The derivative matrices are computed up to this lmax, while the output power spectra use params.lmax.
- Returns:
Maximum multipole for signal covariance and derivative computation.
- Return type:
- setup_maps()[source]
Read observational map data from FITS files.
Loads maps with proper pixel selection, field extraction, and calibration. For cross-correlation (do_cross=True), loads both primary and secondary maps. Output shape: (n_active_pixels, n_simulations).
- Raises:
ValueError – If pixel information not available (setup_geometry not called).
FileNotFoundError – If input map files not found.
- setup_fisher_inversion()[source]
Prepare inverted Fisher matrix for QML estimation.
The Fisher matrix is already beam-smoothed (beam window functions absorbed into derivatives). This method computes F⁻¹, F⁻¹/², and writes results to output files.
- Raises:
ValueError – If Fisher matrix is not available or singular.
LinAlgError – If Fisher matrix inversion fails.
- setup_qml_computation()[source]
Initialize arrays and variables for QML power spectrum computation.
This method allocates memory for QML estimation results and prepares the computational infrastructure for the main QML calculation phase. Arrays are sized based on the number of multipoles, spectra, and Monte Carlo simulations.
Notes
Initializes the following arrays:
qml_results: Storage for QML power spectrum estimates with shape (n_simulations, n_total_parameters) where n_total_parameters = n_spectra * (lmax - 1)
qml_noise_bias: Storage for noise bias estimates (auto-correlation only) with shape (n_total_parameters,)
The qml_results array stores the raw quadratic estimates: q̂_l^(sim) = (1/2) * x^(sim)T * E_l * x^(sim)
for each simulation and multipole. These raw estimates will be combined using the inverse Fisher matrix to produce the final optimally-weighted power spectrum estimates.
For auto-correlation analyses, noise bias terms are computed as: bias_l = (1/2) * Tr[N * E_l] where N is the noise covariance matrix and E_l is the quadratic estimator matrix for multipole l.
Memory allocation scales as O(n_sims * n_ell * n_spec) for results and O(n_ell * n_spec) for bias terms, which is typically much smaller than the O(n_pix^2) covariance matrix storage.
Examples
This method is called automatically during computation:
>>> spectra = Spectra("config.yaml") >>> spectra.setup_qml_computation() >>> print(f"QML results shape: {spectra.qml_results.shape}") >>> print(f"Total parameters: {spectra.qml_results.shape[1]}")
- compute_qml_spectra()[source]
Execute parallel QML power spectrum computation.
Distributes multipole computations across MPI processes (round-robin). For each multipole: computes signal derivative, E-operator, and quadratic estimates for all simulations. Selects compressed or traditional method based on basis_manager availability.
- compute()[source]
Execute QML power spectrum computation.
Calls setup_qml_computation() to initialize arrays, then compute_qml_spectra() for the main parallel computation.
- run()[source]
Execute the complete QML power spectrum analysis pipeline.
Pipeline phases: 1. Master setup: fields, geometry, covariance, spectra, beams
(reuses Fisher components if provided)
QML setup: maps, Fisher inversion
MPI broadcast of shared data to workers
Parallel QML computation
MPI synchronization
- Raises:
ValueError – If required setup components are missing.
FileNotFoundError – If input files not accessible.
- get_power_spectra(mode='deconvolved', *, as_dict=False)[source]
Retrieve power spectrum estimates in specified normalization mode.
This method returns power spectrum estimates with three different normalization prescriptions, allowing users to choose the output format best suited to their analysis needs.
- Parameters:
mode (str, optional) –
Normalization mode for output (default: “deconvolved”):
”deconvolved”: F⁻¹y - estimates of true C_ℓ with correlated errors. This is the standard QML output that attempts to recover the true underlying spectrum by inverting the window function.
”decorrelated”: F⁻¹/²y - uncorrelated bandpower estimates with identity covariance matrix. Useful when independent error bars are needed.
”convolved”: Raw y estimates with window matrix W for theory comparison. Instead of deconvolving the window, compare with window-convolved theory: <y> = W @ C_true.
as_dict (bool, optional) – If
False(default, back-compat), return the flat numpy array described below. IfTrue, return a dict keyed by physical labels ("TT","EE","TE", …) whose values have shape(n_simulations, n_bins). In"convolved"mode, the dict applies to the raw estimatesyonly; the window matrixWandconvolve_theorycallable are unchanged (useFisher.get_bandpower_slices()onself.fisher_instanceto navigateW).
- Return type:
- Returns:
numpy.ndarray or tuple or dict or None – For “deconvolved” or “decorrelated” modes with
as_dict=False:Array of shape
(n_simulations, n_parameters)wheren_parameters = n_spectra * n_bins.- For “convolved” mode with
as_dict=False: Tuple of
(y, W, convolve_theory_func)where:y: Raw estimates of shape(n_simulations, n_parameters)W: Window matrix of shape(n_parameters, n_parameters)convolve_theory_func: Callable that appliesW @ theory
With
as_dict=True: a dict for the per-spectrum arrays (and, in convolved mode, a 3-tuple(y_dict, W, convolve)).Returns
Nonefor worker processes (rank != 0) or if computation has not completed.- For “convolved” mode with
**Layout (flat-array shape)**
The columns of the returned array are organised as
n_spectracontiguous blocks of
n_binscolumns each. Spectrum orderfollows
Fisher.spectra_listonself.fisher_instance— auto-spectra first (per component,in the order each component emits them), then cross-spectra in
(i, j)order withi < j. For TQU (spins=[0, 2],labels=["T", "E", "B"]) underSymmetryMode.SYMMETRICwith
nbins=10,n_parameters = 60and the columns are:: – cols 0..9 : TT cols 10..19 : EE cols 20..29 : BB cols 30..39 : EB cols 40..49 : TE cols 50..59 : TBUse
Fisher.get_bandpower_slices()(onself.fisher_instance) or passas_dict=Trueto look upper-spectrum slices without computing these offsets by hand.
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
Mode Comparison:
Mode | Formula | Covariance | Use Case ||------|———|------------|———-| | deconvolved | F⁻¹y | F⁻¹ (correlated) | Standard analysis | | decorrelated | F⁻¹/²y | I (identity) | Independent errors | | convolved | y | F | Theory comparison |
Deconvolved Mode (default): The standard QML output that inverts the window function to recover estimates of the true C_ℓ. Errors are correlated between multipoles.
Decorrelated Mode: Produces bandpower estimates with uncorrelated errors (unit variance). Useful for plotting error bars or when independent measurements are required. Note that information content is preserved but redistributed.
Convolved Mode: Returns raw QML estimates without deconvolution, along with the window matrix for comparing with convolved theoretical spectra. This avoids numerical issues from inverting poorly-conditioned window matrices.
Output Convention: When
output_conventionis set to"Dl"in the configuration, all returned spectra are converted from C_ℓ to D_ℓ = ℓ(ℓ+1)/(2π) C_ℓ. In convolved mode, the window matrix is also transformed so that the returnedconvolve_theory_funcexpects D_ℓ input.Examples
Default (flat array) — back-compat:
>>> spectra = Spectra("config.yaml") >>> spectra.run() >>> cl_deconv = spectra.get_power_spectra() # shape (n_sims, 60) >>> ee_slice = cl_deconv[:, 10:20] # bins 0..9 of EE
Label-keyed dict (recommended for human-readable code):
>>> cl = spectra.get_power_spectra(as_dict=True) >>> cl["EE"].shape # (n_sims, n_bins) >>> cl["TE"] # cross-spectrum
Decorrelated bandpowers:
>>> cl_decorr = spectra.get_power_spectra(mode="decorrelated") >>> # Errors are all 1.0 by construction
Convolved mode for theory comparison:
>>> y, W, convolve = spectra.get_power_spectra(mode="convolved") >>> cl_theory_convolved = convolve(cl_theory) >>> # Compare: y should match cl_theory_convolved >>> # With as_dict=True, the y component becomes a dict; W and >>> # the convolve callable are unchanged. >>> y_dict, W, convolve = spectra.get_power_spectra( ... mode="convolved", as_dict=True ... )
See also
get_covarianceGet covariance matrix for specified mode
get_error_barsGet 1-sigma error bars for specified mode
convolve_theoryApply window matrix to theoretical spectrum
Fisher.get_bandpower_slicesSlice mapping for navigating the flat layout.
- get_effective_ells()[source]
Return effective multipole for each bin.
For unbinned (delta_ell=1), returns integer ells from 2 to lmax. For binned, returns bin midpoints.
- Returns:
Effective multipoles, shape (nbins,). None for workers.
- Return type:
np.ndarray or None
- get_noise_bias()[source]
Retrieve noise bias estimates for auto-correlation spectra.
- Returns:
Shape (n_params,). Returns None for workers, cross-correlation analyses (do_cross=True), or if computation incomplete.
- Return type:
np.ndarray or None
Notes
Noise bias: (1/2) * Tr[N * E_l]. Cross-correlations are bias-free.
- convolve_theory_for_inference(cl_theory)[source]
Apply the QML bandpower window to a per-ℓ theory spectrum.
Returns the expected binned bandpower for the given theory, in the same convention as
get_power_spectra(mode="deconvolved"). Use this in a Gaussian likelihood for parameter inference:mu_b(θ) = convolve_theory_for_inference(C_ℓ(θ)) -2 ln L = (d - mu)ᵀ F_b (d - mu)
- Parameters:
cl_theory (np.ndarray) –
Per-ℓ theory C_ℓ. Two formats accepted: - shape
(n_ell,)for ℓ=lmin..lmax (length lmax-lmin+1) - shape(lmax+1,)starting at ℓ=0 (entries belowlminare ignored)
Must be unbeamed physical C_ℓ — beam² is already absorbed into the window.
- Returns:
cl_binned – Expected binned bandpower for the given theory. If the output convention is “Dl”, the result is converted to D_ℓ using the bin effective ells. Returns None on worker processes (rank != 0).
- Return type:
np.ndarray of shape (n_bins,), or None
Notes
This delegates to
Fisher.get_bandpower_window_function()on the underlying Fisher instance. The first call triggers a per-ℓ Fisher computation (cached for subsequent calls).Scope: single-spectrum only. For multi-spectrum likelihoods, use
get_power_spectra()(mode="convolved") — the returnedconvolve_theory_funcaccepts a label-keyed dict and handles the fulln_spectra * n_binswindow matrix.See
Fisher.get_bandpower_window_function()for details on the buffer approach and the multi-spectrum limitation.Examples
>>> spectra = Spectra("config.yaml", fisher=fisher, ... compression={"method": "harmonic"}) >>> spectra.set_binning(bins) >>> spectra.run() >>> cl_th = compute_camb_cl(theta) # ell=0..lmax >>> mu_b = spectra.convolve_theory_for_inference(cl_th) >>> data = spectra.get_power_spectra(mode="deconvolved").mean(0) >>> F_b = spectra.fisher_instance.get_fisher_matrix() >>> neg2lnL = (data - mu_b) @ F_b @ (data - mu_b)
See also
Fisher.get_bandpower_window_functionUnderlying window matrix.
get_power_spectraGet the data bandpower (deconvolved mode).
get_covarianceGet the covariance matrix (= F_b⁻¹).
- get_covariance(mode='deconvolved')[source]
Get covariance matrix for power spectrum estimates in specified mode.
Returns the covariance matrix appropriate for the normalization mode, which quantifies the statistical uncertainties and correlations between different multipole estimates.
- Parameters:
mode (str, optional) –
Normalization mode (default: “deconvolved”):
”deconvolved”: Returns F⁻¹, the inverse Fisher matrix with correlated errors between multipoles.
”decorrelated”: Returns identity matrix I, as decorrelated estimates have unit variance by construction.
”convolved”: Returns F, the normalized Fisher matrix, which is the covariance of raw y estimates.
- Returns:
Covariance matrix of shape (n_params, n_params). Returns None for worker processes (rank != 0) or if matrices are not available.
- Return type:
numpy.ndarray or None
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
Mode-specific covariances:
Mode | Covariance | Interpretation ||------|————|----------------| | deconvolved | F⁻¹ | Correlated errors on C_ℓ estimates | | decorrelated | I | Unit variance (uncorrelated) | | convolved | F | Covariance of raw y estimates |
The covariance matrix is essential for: - Computing chi-square statistics - Parameter estimation from power spectra - Constructing likelihood functions - Understanding multipole correlations
Examples
Get covariance for chi-square computation:
>>> cov = spectra.get_covariance(mode="deconvolved") >>> cl_data = spectra.get_power_spectra(mode="deconvolved") >>> residuals = np.mean(cl_data, axis=0) - cl_theory >>> chi2 = residuals @ np.linalg.inv(cov) @ residuals
Decorrelated mode has identity covariance:
>>> cov_decorr = spectra.get_covariance(mode="decorrelated") >>> # cov_decorr is identity matrix
See also
get_power_spectraGet power spectrum estimates
get_error_barsGet 1-sigma error bars (sqrt of diagonal)
- get_error_bars(mode='deconvolved')[source]
Get 1-sigma error bars for power spectrum estimates.
Returns the marginal standard deviations for each multipole estimate, computed from the diagonal of the covariance matrix.
- Parameters:
mode (str, optional) –
Normalization mode (default: “deconvolved”):
”deconvolved”: sqrt(diag(F⁻¹)) - standard QML errors
”decorrelated”: all ones (unit variance by construction)
”convolved”: sqrt(diag(F)) - errors on raw y estimates
- Returns:
1D array of error bars with shape (n_params,). Returns None for worker processes (rank != 0) or if covariance not available.
- Return type:
numpy.ndarray or None
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
The error bars are computed as: σ_i = sqrt(Cov_ii)
where Cov is the mode-appropriate covariance matrix. These represent marginal uncertainties on individual estimates, marginalized over all other multipoles.
Important: For deconvolved and convolved modes, errors are correlated between multipoles. The full covariance matrix (from get_covariance) should be used for proper statistical analysis.
For decorrelated mode, error bars are all 1.0 by construction, making them suitable for simple error bar plots.
Examples
Get error bars for plotting:
>>> errors = spectra.get_error_bars(mode="deconvolved") >>> cl = np.mean(spectra.get_power_spectra(), axis=0) >>> plt.errorbar(ell, cl, yerr=errors)
Decorrelated mode has unit errors:
>>> errors_decorr = spectra.get_error_bars(mode="decorrelated") >>> # All elements are 1.0
See also
get_covarianceGet full covariance matrix
get_power_spectraGet power spectrum estimates
- convolve_theory(cl_theory)[source]
Apply window matrix to theoretical power spectrum.
Convolves a theoretical power spectrum with the QML window matrix, producing the expected value of the raw QML estimates y for that theory: <y> = W @ C_theory.
- Parameters:
cl_theory (numpy.ndarray) – Theoretical power spectrum values. Should be a 1D array with shape (n_params,) matching the QML output dimensions. When
output_convention="Dl", this should be D_ℓ values.- Returns:
Window-convolved theoretical spectrum with shape (n_params,), in the same convention as the input. Returns None if window matrix is not available.
- Return type:
numpy.ndarray or None
Notes
This method is useful for comparing QML estimates with theoretical predictions when using the “convolved” normalization mode. Instead of deconvolving the window function from the data (which can be numerically unstable), the window is applied to the theory.
The relationship is: <y> = W @ C_true
where y are the raw QML estimates and W is the window matrix. When
output_convention="Dl", the window matrix is internally transformed so the input and output are both in D_ℓ convention.Examples
Compare convolved estimates with theory:
>>> y, W, _ = spectra.get_power_spectra(mode="convolved") >>> cl_theory_convolved = spectra.convolve_theory(cl_theory) >>> residuals = np.mean(y, axis=0) - cl_theory_convolved
See also
get_power_spectraGet power spectra (convolved mode returns window)
- write_power_spectra(mode='deconvolved', filename=None, include_errors=True)[source]
Write power spectra to file in specified normalization mode.
Outputs power spectrum estimates and optionally error bars to text files. For convolved mode, also writes the window matrix.
- Parameters:
mode (str, optional) – Normalization mode (default: “deconvolved”): “deconvolved”, “decorrelated”, or “convolved”.
filename (str or None, optional) – Output filename. If None, auto-generates based on mode: “{outclfile_base}_{mode}.{ext}”
include_errors (bool, optional) – If True, writes error bars to a separate file (default: True). For convolved mode, this parameter is ignored.
- Return type:
Notes
File outputs by mode:
deconvolved/decorrelated: Writes mean spectrum across simulations and optionally error bars from diagonal of covariance.
convolved: Writes mean raw y estimates and the window matrix W to separate files (filename and filename_window).
Files are only written on the master process (rank 0).
Examples
Write all modes:
>>> spectra.write_power_spectra(mode="deconvolved") >>> spectra.write_power_spectra(mode="decorrelated") >>> spectra.write_power_spectra(mode="convolved")
Custom filename:
>>> spectra.write_power_spectra( ... mode="deconvolved", ... filename="my_results.dat" ... )
See also
get_power_spectraGet power spectrum estimates
get_error_barsGet 1-sigma error bars
Key Methods
Initialization
- Spectra.__init__(params_file=None, fisher=None, compression=None, **kwargs)[source]
Initialize QML power spectrum estimation class.
- Parameters:
params_file (str, optional) – Path to YAML configuration file.
fisher (Fisher, optional) – Pre-computed Fisher instance. If provided, reuses computed components (covariance matrices, geometry, field collections) for efficiency.
compression (dict, optional) – Computation basis configuration (method, epsilon, basis, mode_fraction).
**kwargs (dict) – Additional arguments passed to Core.
- Raises:
TypeError – If fisher is not a Fisher instance.
ValueError – If fisher doesn’t contain a valid Fisher matrix.
- Spectra.setup_geometry()
Set up geometry including active pixels and pointing vectors.
- Returns:
Tuple containing (active_pixels, pointing_vectors) where: - active_pixels: Object array of active pixel indices per field component - pointing_vectors: Tuple of unit vector arrays for each component
- Return type:
- Raises:
ValueError – If fields have not been set up before calling this method.
Notes
This method: 1. Extracts active pixel counts from each field 2. Computes 3D pointing vectors for each active pixel 3. Computes theta (colatitude) and phi (longitude) for computation basis 4. Sets pointing vectors in the field collection 5. Optionally outputs geometry data to file
The pointing vectors are unit vectors in 3D space pointing to pixel centers, used for spherical harmonic transforms and coordinate operations.
Core Computation
- Spectra.setup_maps()[source]
Read observational map data from FITS files.
Loads maps with proper pixel selection, field extraction, and calibration. For cross-correlation (do_cross=True), loads both primary and secondary maps. Output shape: (n_active_pixels, n_simulations).
- Raises:
ValueError – If pixel information not available (setup_geometry not called).
FileNotFoundError – If input map files not found.
- Spectra.setup_fisher_inversion()[source]
Prepare inverted Fisher matrix for QML estimation.
The Fisher matrix is already beam-smoothed (beam window functions absorbed into derivatives). This method computes F⁻¹, F⁻¹/², and writes results to output files.
- Raises:
ValueError – If Fisher matrix is not available or singular.
LinAlgError – If Fisher matrix inversion fails.
- Spectra.setup_qml_computation()[source]
Initialize arrays and variables for QML power spectrum computation.
This method allocates memory for QML estimation results and prepares the computational infrastructure for the main QML calculation phase. Arrays are sized based on the number of multipoles, spectra, and Monte Carlo simulations.
Notes
Initializes the following arrays:
qml_results: Storage for QML power spectrum estimates with shape (n_simulations, n_total_parameters) where n_total_parameters = n_spectra * (lmax - 1)
qml_noise_bias: Storage for noise bias estimates (auto-correlation only) with shape (n_total_parameters,)
The qml_results array stores the raw quadratic estimates: q̂_l^(sim) = (1/2) * x^(sim)T * E_l * x^(sim)
for each simulation and multipole. These raw estimates will be combined using the inverse Fisher matrix to produce the final optimally-weighted power spectrum estimates.
For auto-correlation analyses, noise bias terms are computed as: bias_l = (1/2) * Tr[N * E_l] where N is the noise covariance matrix and E_l is the quadratic estimator matrix for multipole l.
Memory allocation scales as O(n_sims * n_ell * n_spec) for results and O(n_ell * n_spec) for bias terms, which is typically much smaller than the O(n_pix^2) covariance matrix storage.
Examples
This method is called automatically during computation:
>>> spectra = Spectra("config.yaml") >>> spectra.setup_qml_computation() >>> print(f"QML results shape: {spectra.qml_results.shape}") >>> print(f"Total parameters: {spectra.qml_results.shape[1]}")
- Spectra.compute_qml_spectra()[source]
Execute parallel QML power spectrum computation.
Distributes multipole computations across MPI processes (round-robin). For each multipole: computes signal derivative, E-operator, and quadratic estimates for all simulations. Selects compressed or traditional method based on basis_manager availability.
- Spectra.compute()[source]
Execute QML power spectrum computation.
Calls setup_qml_computation() to initialize arrays, then compute_qml_spectra() for the main parallel computation.
- Spectra.run()[source]
Execute the complete QML power spectrum analysis pipeline.
Pipeline phases: 1. Master setup: fields, geometry, covariance, spectra, beams
(reuses Fisher components if provided)
QML setup: maps, Fisher inversion
MPI broadcast of shared data to workers
Parallel QML computation
MPI synchronization
- Raises:
ValueError – If required setup components are missing.
FileNotFoundError – If input files not accessible.
Results Processing
- Spectra.get_power_spectra(mode='deconvolved', *, as_dict=False)[source]
Retrieve power spectrum estimates in specified normalization mode.
This method returns power spectrum estimates with three different normalization prescriptions, allowing users to choose the output format best suited to their analysis needs.
- Parameters:
mode (str, optional) –
Normalization mode for output (default: “deconvolved”):
”deconvolved”: F⁻¹y - estimates of true C_ℓ with correlated errors. This is the standard QML output that attempts to recover the true underlying spectrum by inverting the window function.
”decorrelated”: F⁻¹/²y - uncorrelated bandpower estimates with identity covariance matrix. Useful when independent error bars are needed.
”convolved”: Raw y estimates with window matrix W for theory comparison. Instead of deconvolving the window, compare with window-convolved theory: <y> = W @ C_true.
as_dict (bool, optional) – If
False(default, back-compat), return the flat numpy array described below. IfTrue, return a dict keyed by physical labels ("TT","EE","TE", …) whose values have shape(n_simulations, n_bins). In"convolved"mode, the dict applies to the raw estimatesyonly; the window matrixWandconvolve_theorycallable are unchanged (useFisher.get_bandpower_slices()onself.fisher_instanceto navigateW).
- Return type:
- Returns:
numpy.ndarray or tuple or dict or None – For “deconvolved” or “decorrelated” modes with
as_dict=False:Array of shape
(n_simulations, n_parameters)wheren_parameters = n_spectra * n_bins.- For “convolved” mode with
as_dict=False: Tuple of
(y, W, convolve_theory_func)where:y: Raw estimates of shape(n_simulations, n_parameters)W: Window matrix of shape(n_parameters, n_parameters)convolve_theory_func: Callable that appliesW @ theory
With
as_dict=True: a dict for the per-spectrum arrays (and, in convolved mode, a 3-tuple(y_dict, W, convolve)).Returns
Nonefor worker processes (rank != 0) or if computation has not completed.- For “convolved” mode with
**Layout (flat-array shape)**
The columns of the returned array are organised as
n_spectracontiguous blocks of
n_binscolumns each. Spectrum orderfollows
Fisher.spectra_listonself.fisher_instance— auto-spectra first (per component,in the order each component emits them), then cross-spectra in
(i, j)order withi < j. For TQU (spins=[0, 2],labels=["T", "E", "B"]) underSymmetryMode.SYMMETRICwith
nbins=10,n_parameters = 60and the columns are:: – cols 0..9 : TT cols 10..19 : EE cols 20..29 : BB cols 30..39 : EB cols 40..49 : TE cols 50..59 : TBUse
Fisher.get_bandpower_slices()(onself.fisher_instance) or passas_dict=Trueto look upper-spectrum slices without computing these offsets by hand.
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
Mode Comparison:
Mode | Formula | Covariance | Use Case ||------|———|------------|———-| | deconvolved | F⁻¹y | F⁻¹ (correlated) | Standard analysis | | decorrelated | F⁻¹/²y | I (identity) | Independent errors | | convolved | y | F | Theory comparison |
Deconvolved Mode (default): The standard QML output that inverts the window function to recover estimates of the true C_ℓ. Errors are correlated between multipoles.
Decorrelated Mode: Produces bandpower estimates with uncorrelated errors (unit variance). Useful for plotting error bars or when independent measurements are required. Note that information content is preserved but redistributed.
Convolved Mode: Returns raw QML estimates without deconvolution, along with the window matrix for comparing with convolved theoretical spectra. This avoids numerical issues from inverting poorly-conditioned window matrices.
Output Convention: When
output_conventionis set to"Dl"in the configuration, all returned spectra are converted from C_ℓ to D_ℓ = ℓ(ℓ+1)/(2π) C_ℓ. In convolved mode, the window matrix is also transformed so that the returnedconvolve_theory_funcexpects D_ℓ input.Examples
Default (flat array) — back-compat:
>>> spectra = Spectra("config.yaml") >>> spectra.run() >>> cl_deconv = spectra.get_power_spectra() # shape (n_sims, 60) >>> ee_slice = cl_deconv[:, 10:20] # bins 0..9 of EE
Label-keyed dict (recommended for human-readable code):
>>> cl = spectra.get_power_spectra(as_dict=True) >>> cl["EE"].shape # (n_sims, n_bins) >>> cl["TE"] # cross-spectrum
Decorrelated bandpowers:
>>> cl_decorr = spectra.get_power_spectra(mode="decorrelated") >>> # Errors are all 1.0 by construction
Convolved mode for theory comparison:
>>> y, W, convolve = spectra.get_power_spectra(mode="convolved") >>> cl_theory_convolved = convolve(cl_theory) >>> # Compare: y should match cl_theory_convolved >>> # With as_dict=True, the y component becomes a dict; W and >>> # the convolve callable are unchanged. >>> y_dict, W, convolve = spectra.get_power_spectra( ... mode="convolved", as_dict=True ... )
See also
get_covarianceGet covariance matrix for specified mode
get_error_barsGet 1-sigma error bars for specified mode
convolve_theoryApply window matrix to theoretical spectrum
Fisher.get_bandpower_slicesSlice mapping for navigating the flat layout.
- Spectra.get_noise_bias()[source]
Retrieve noise bias estimates for auto-correlation spectra.
- Returns:
Shape (n_params,). Returns None for workers, cross-correlation analyses (do_cross=True), or if computation incomplete.
- Return type:
np.ndarray or None
Notes
Noise bias: (1/2) * Tr[N * E_l]. Cross-correlations are bias-free.
- Spectra.get_covariance(mode='deconvolved')[source]
Get covariance matrix for power spectrum estimates in specified mode.
Returns the covariance matrix appropriate for the normalization mode, which quantifies the statistical uncertainties and correlations between different multipole estimates.
- Parameters:
mode (str, optional) –
Normalization mode (default: “deconvolved”):
”deconvolved”: Returns F⁻¹, the inverse Fisher matrix with correlated errors between multipoles.
”decorrelated”: Returns identity matrix I, as decorrelated estimates have unit variance by construction.
”convolved”: Returns F, the normalized Fisher matrix, which is the covariance of raw y estimates.
- Returns:
Covariance matrix of shape (n_params, n_params). Returns None for worker processes (rank != 0) or if matrices are not available.
- Return type:
numpy.ndarray or None
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
Mode-specific covariances:
Mode | Covariance | Interpretation ||------|————|----------------| | deconvolved | F⁻¹ | Correlated errors on C_ℓ estimates | | decorrelated | I | Unit variance (uncorrelated) | | convolved | F | Covariance of raw y estimates |
The covariance matrix is essential for: - Computing chi-square statistics - Parameter estimation from power spectra - Constructing likelihood functions - Understanding multipole correlations
Examples
Get covariance for chi-square computation:
>>> cov = spectra.get_covariance(mode="deconvolved") >>> cl_data = spectra.get_power_spectra(mode="deconvolved") >>> residuals = np.mean(cl_data, axis=0) - cl_theory >>> chi2 = residuals @ np.linalg.inv(cov) @ residuals
Decorrelated mode has identity covariance:
>>> cov_decorr = spectra.get_covariance(mode="decorrelated") >>> # cov_decorr is identity matrix
See also
get_power_spectraGet power spectrum estimates
get_error_barsGet 1-sigma error bars (sqrt of diagonal)
- Spectra.get_error_bars(mode='deconvolved')[source]
Get 1-sigma error bars for power spectrum estimates.
Returns the marginal standard deviations for each multipole estimate, computed from the diagonal of the covariance matrix.
- Parameters:
mode (str, optional) –
Normalization mode (default: “deconvolved”):
”deconvolved”: sqrt(diag(F⁻¹)) - standard QML errors
”decorrelated”: all ones (unit variance by construction)
”convolved”: sqrt(diag(F)) - errors on raw y estimates
- Returns:
1D array of error bars with shape (n_params,). Returns None for worker processes (rank != 0) or if covariance not available.
- Return type:
numpy.ndarray or None
- Raises:
ValueError – If mode is not one of “deconvolved”, “decorrelated”, “convolved”.
Notes
The error bars are computed as: σ_i = sqrt(Cov_ii)
where Cov is the mode-appropriate covariance matrix. These represent marginal uncertainties on individual estimates, marginalized over all other multipoles.
Important: For deconvolved and convolved modes, errors are correlated between multipoles. The full covariance matrix (from get_covariance) should be used for proper statistical analysis.
For decorrelated mode, error bars are all 1.0 by construction, making them suitable for simple error bar plots.
Examples
Get error bars for plotting:
>>> errors = spectra.get_error_bars(mode="deconvolved") >>> cl = np.mean(spectra.get_power_spectra(), axis=0) >>> plt.errorbar(ell, cl, yerr=errors)
Decorrelated mode has unit errors:
>>> errors_decorr = spectra.get_error_bars(mode="decorrelated") >>> # All elements are 1.0
See also
get_covarianceGet full covariance matrix
get_power_spectraGet power spectrum estimates
- Spectra.convolve_theory(cl_theory)[source]
Apply window matrix to theoretical power spectrum.
Convolves a theoretical power spectrum with the QML window matrix, producing the expected value of the raw QML estimates y for that theory: <y> = W @ C_theory.
- Parameters:
cl_theory (numpy.ndarray) – Theoretical power spectrum values. Should be a 1D array with shape (n_params,) matching the QML output dimensions. When
output_convention="Dl", this should be D_ℓ values.- Returns:
Window-convolved theoretical spectrum with shape (n_params,), in the same convention as the input. Returns None if window matrix is not available.
- Return type:
numpy.ndarray or None
Notes
This method is useful for comparing QML estimates with theoretical predictions when using the “convolved” normalization mode. Instead of deconvolving the window function from the data (which can be numerically unstable), the window is applied to the theory.
The relationship is: <y> = W @ C_true
where y are the raw QML estimates and W is the window matrix. When
output_convention="Dl", the window matrix is internally transformed so the input and output are both in D_ℓ convention.Examples
Compare convolved estimates with theory:
>>> y, W, _ = spectra.get_power_spectra(mode="convolved") >>> cl_theory_convolved = spectra.convolve_theory(cl_theory) >>> residuals = np.mean(y, axis=0) - cl_theory_convolved
See also
get_power_spectraGet power spectra (convolved mode returns window)
Normalization Modes
Power spectrum estimates can be retrieved in three normalization modes, each suited to different analysis needs. The raw QML estimates \(\mathbf{y}\) are related to the true power spectrum \(C_\ell\) through the Fisher matrix \(\mathbf{F}\):
The three modes differ in how \(\mathbf{y}\) is post-processed before being returned to the user.
Mode |
Formula |
Covariance |
Use case |
|---|---|---|---|
|
\(\mathbf{F}^{-1} \mathbf{y}\) |
\(\mathbf{F}^{-1}\) (correlated) |
Standard analysis: estimates of the true \(C_\ell\) |
|
\(\mathbf{F}^{-1/2} \mathbf{y}\) |
\(\mathbf{I}\) (identity) |
Independent error bars for visualization |
|
\(\mathbf{y}\) |
\(\mathbf{F}\) |
Theory comparison via \(\langle \mathbf{y} \rangle = \mathbf{W} C_\ell^{\rm th}\) |
Deconvolved (default)
The standard QML output. The window function is inverted so the returned estimates
are direct estimates of the true \(C_\ell\). Errors are correlated between
multipoles; use get_covariance() for the full covariance matrix.
cl = spectra.get_power_spectra() # or mode="deconvolved"
cov = spectra.get_covariance()
errors = spectra.get_error_bars()
Convolved
Returns the raw estimates together with the window matrix \(\mathbf{W}\) and a convenience function to convolve a theoretical spectrum. This avoids inverting a potentially ill-conditioned Fisher matrix.
y, W, convolve = spectra.get_power_spectra(mode="convolved")
cl_theory_convolved = convolve(cl_theory)
# Compare: y ≈ cl_theory_convolved
Chi-squared equivalence
All three modes yield the same chi-squared value for any given data realization:
Usage Examples
Basic QML Estimation
from cosmoforge.qube import Spectra
# Initialize QML analysis
spectra = Spectra("config/qml_config.yaml")
# Run complete estimation pipeline
spectra.run()
# Get power spectrum estimates (master process)
if spectra.rank == 0:
cl = spectra.get_power_spectra()
errors = spectra.get_error_bars()
Cross-Correlation Analysis
# Configure for cross-correlation between two datasets
config = {
'do_cross': True,
'covmatfile1': 'dataset1_noise.bin',
'covmatfile2': 'dataset2_noise.bin',
'mapfiles1': ['map1_T.fits', 'map1_Q.fits', 'map1_U.fits'],
'mapfiles2': ['map2_T.fits', 'map2_Q.fits', 'map2_U.fits'],
}
spectra = Spectra(config)
spectra.run()
MPI Parallel Execution
# Run QML estimation with 16 processes
mpirun -n 16 python -c "
from cosmoforge.qube import Spectra
spectra = Spectra('qml_config.yaml')
spectra.run()
"
Error Analysis
# Compute error estimates from Fisher matrix
from cosmoforge.qube import Fisher, Spectra
# First run Fisher analysis for error forecasting
fisher = Fisher("fisher_config.yaml")
fisher.run()
# Then run QML estimation
spectra = Spectra("qml_config.yaml")
spectra.run()
if spectra.rank == 0:
# Compare with Fisher forecasts
fisher_errors = fisher.get_error_bars()
qml_estimates = spectra.get_power_spectra()
Computational Performance
Algorithm Complexity
The QML algorithm scales as:
Matrix inversion: \(O(N_{pix}^3)\) one-time cost
Estimator matrices: \(O(N_{ell} \times N_{pix}^2)\)
Quadratic forms: \(O(N_{ell} \times N_{pix}^2)\) per data realization
where \(N_{pix}\) is the number of active pixels and \(N_{ell}\) is the number of multipole bins.
Memory Requirements
Peak memory usage is dominated by:
Covariance matrix: \(N_{pix}^2 \times 8\) bytes
Estimator matrices: \(N_{ell} \times N_{pix}^2 \times 8\) bytes
Working arrays: Additional \(\sim 2 \times N_{pix}^2 \times 8\) bytes
Optimization Strategies
For large-scale analyses:
Hierarchical approach: Start with low resolution for initial estimates
Block processing: Process multipole blocks separately to reduce memory
Iterative methods: Use conjugate gradient for matrix operations
Preconditioning: Improve convergence with appropriate preconditioners
Resource Scaling
Typical requirements for full-mission analyses:
Resolution |
Active Pixels |
Memory (GB) |
Compute Time |
Cores |
|---|---|---|---|---|
nside=128 |
~50k |
~2 |
~30 min |
4-8 |
nside=256 |
~200k |
~8 |
~3 hours |
8-16 |
nside=512 |
~800k |
~128 |
~1 day |
16-32 |
nside=1024 |
~3.2M |
~2000 |
~1 week |
32-64 |
Configuration Options
Essential QML configuration parameters:
# Analysis type
do_cross: false # Auto-correlation (true for cross-correlation)
# Input data
mapfiles1: ["map_T.fits", "map_Q.fits", "map_U.fits"]
covmatfile1: "noise_covariance.bin"
maskfile: "analysis_mask.fits"
input_convention: Dl # "Cl" (default) or "Dl" for input spectra
output_convention: Dl # "Cl" (default) or "Dl" for output spectra
# Multipole range
lmin: 2
lmax: 2000
nbands: 50 # Number of bandpowers
# Output files
outfile: "qml_power_spectra.dat"
outfilelhood: "likelihood_data.dat"
# Computation options
compute_fisher: true # Include Fisher matrix computation
save_estimators: false # Save estimator matrices (large files)
Advanced Features
Likelihood Analysis
The QML estimates come with full likelihood information for parameter fitting:
# Access likelihood data for cosmological parameter fitting
spectra = Spectra("config.yaml")
spectra.run()
if spectra.rank == 0:
# Get bandpowers and covariance for likelihood
bandpowers = spectra.get_power_spectra()
covariance = spectra.get_covariance()
# Use in cosmological parameter fitting pipeline
Systematic Error Studies
# Test robustness to different analysis choices
systematics = {
'lmax_values': [1500, 2000, 2500, 3000],
'mask_apodization': [0.0, 1.0, 2.0, 5.0],
'multipole_binning': ['linear', 'logarithmic', 'hybrid']
}
for test_case in systematic_combinations:
config = base_config.copy()
config.update(test_case)
spectra = Spectra(config)
spectra.run()
# Analyze systematic differences...
See Also
qube.fisher.Fisher: Fisher information matrix computationcosmocore.harmonic: Spherical harmonic transformationsQML Power Spectrum Estimation Pipeline : Main execution script for QML analysis
Mock Data Generation : Mock data generation for testing