Covariance Estimation
The covariance between two spectra $\textrm{Cov}(\hat{C}_{\ell}^{XY,i,j}, \hat{C}_{\ell}^{WZ,p,q})$ for channels $X,Y,W,Z \in \{T, E\}$ obtained from masked maps can be expressed using
- spherical harmonic coefficients of the masks of the four maps $i, j, p, q$ involved in the covariance
- assumed signal spectrum $C_{\ell,\mathrm{tot}}^{XY}$, for example $C_{\ell}^{\mathrm{th}} + C_{\ell}^{\mathrm{fg},i,j}$
- pixel variance maps $\sigma_p^{XX}$ for $XX \in \{II, QQ, UU\}$ for the four maps involved in the covariance
However, these are only sufficient for a description of a homogeneous survey with white noise and sufficient mask apodization. Two additional corrections are required for $\sim1\%$ covariance determinations.
- noise power spectra $\hat{N}_{\ell}^{XY,i,j}$ for the involved channels
- corrections to the diagonals of the covariance matrices from insufficient apodization around point sources
The basic calculation is essentially a mode-coupling calculation, and mode-coupling matrices are themselves used to correct the covariance matrix at the end. The methods in this package were written to match the analysis of the Planck satellite, and we provide a more detailed description of these methods in Li et al. 2020 (in prep). The derivation of these covariance matrices, in the limit of uniform noise, are available in Thibaut Louis's excellent notes.
The expressions for the covariance matrix tend to reuse the same expressions many times, and one tends also to compute several different related covariance matrices (i.e. TTTT, TETE, TTTE) on the same maps. The covariance calculation in PowerSpectra.jl is centered around the CovarianceWorkspace
, which caches the various quantities that are re-used during covariance estimation.
Computing the Covariance
First, let's set up the required data – masks and variances. The variance is a Healpix.PolarizedHealpixMap
containing the fields i
, q
, u
. In this example, we read the masks from disk, but set the variances for everything to 1.
using Healpix, PowerSpectra
mask1_T = readMapFromFITS("test/data/mask1_T.fits", 1, Float64)
mask2_T = readMapFromFITS("test/data/mask2_T.fits", 1, Float64)
mask1_P = readMapFromFITS("test/data/mask1_T.fits", 1, Float64)
mask2_P = readMapFromFITS("test/data/mask2_T.fits", 1, Float64)
# for this example, pixel variance = 1
nside = mask1_T.resolution.nside
unit_var = PolarizedHealpixMap{Float64, RingOrder}(nside)
unit_var.i .= 1.0
unit_var.q .= 1.0
unit_var.u .= 1.0
Once you have the masks and variances, you can create a CovField
for each field involved. This structure also has an associated name, which is used for the signal spectra.
# set up CovField, we're computing the variance of a spectrum on (f1 × f2)
f1 = CovField("143_hm1", mask1_T, mask1_P, unit_var)
f2 = CovField("143_hm2", mask2_T, mask2_P, unit_var)
f3 = f1
f4 = f2
# compute covariance between the (f1 × f2) spectrum and (f3 × f4) spectrum
workspace = CovarianceWorkspace(f1, f2, f3, f4)
A covariance matrix calculation needs an assumed signal spectrum for each channel you want. You need to generate a dictionary that maps the names of various cross-spectra to SpectralVector
.
cl_th = SpectralVector(ones(nside2lmax(nside)+1))
spectra = Dict{SpectrumName, SpectralVector{Float64, Vector{Float64}}}(
(:TT, "143_hm1", "143_hm1") => cl_th, (:TT, "143_hm1", "143_hm2") => cl_th,
(:TT, "143_hm2", "143_hm1") => cl_th, (:TT, "143_hm2", "143_hm2") => cl_th,
(:EE, "143_hm1", "143_hm1") => cl_th, (:EE, "143_hm1", "143_hm2") => cl_th,
(:EE, "143_hm2", "143_hm1") => cl_th, (:EE, "143_hm2", "143_hm2") => cl_th ,
(:TE, "143_hm1", "143_hm1") => cl_th, (:TE, "143_hm1", "143_hm2") => cl_th,
(:TE, "143_hm2", "143_hm1") => cl_th, (:TE, "143_hm2", "143_hm2") => cl_th)
Now all that remains is to compute the coupled covmat.
C = coupledcov(:TT, :TT, workspace, spectra)
API
PowerSpectra.CovField
— TypeCovField(name, maskT, maskP,
σ²II::HealpixMap{T, O, AA}, σ²QQ::HealpixMap{T, O, AA}, σ²UU::HealpixMap{T, O, AA},
beamT::SpectralVector{T}, beamP::SpectralVector{T})
Create a structure for describing the information needed for a covariance involving this field.
Arguments:
name::String
: name of this fieldmaskT::HealpixMap{T}
: temperature maskmaskP::HealpixMap{T}
: polarization maskσ²::PolarizedHealpixMap{T}
: pixel variancesbeamT::SpectralVector{T}
: temperature beambeamP::SpectralVector{T}
: polarization beam
PowerSpectra.CovarianceWorkspace
— TypeCovarianceWorkspace(m_i, m_j, m_p, m_q; lmax::Int=0)
Inputs and cache for covariance calculations. A covariance matrix relates the masks of four fields and spins. This structure caches various cross-spectra between masks and noise-weighted masks. By default, operates at Float64 precision.
Arguments:
m_i::CovField{T}
: map im_j::CovField{T}
: map jm_p::CovField{T}
: map pm_q::CovField{T}
: map q
Keywords
lmax::Int=0
: maximum multipole to compute covariance matrix
PowerSpectra.coupledcov
— Functioncoupledcov(ch1, ch2, workspace, spectra;
noiseratios=Dict(), lmax=0) where T
Arguments:
ch1::Symbol
: spectrum type of first spectrum (i.e. :TT, :TE, :EE)ch2::Symbol
: spectrum type of second spectrum (i.e. :TT, :TE, :EE)workspace
: cache for working with covariancesspectra
: signal spectra
Keywords
noiseratios::AbstractDict
: ratio of noise spectra to white noiselmax=0
: maximum multipole moment for covariance matrix
Returns:
SpectralArray{T,2}
: covariance matrix (0-indexed)