Пример #1
0
    def get_bamc(self):
        """Binned additive MC correction, with crude error bars.

            This compares the reconstruction on the simulations to the FFP10 input lensing spectrum.

            Note:
                the approximate error corrections to the additive MC correction variance follows Appendix C of
                https://arxiv.org/abs/1807.06210, check this for more details on its validity.

        """
        assert self.k1[0] == 'p' and self.k2[
            0] == 'p' and self.ksource == 'p', (self.k1, self.k2, self.ksource)
        ss2 = 2 * self.parfile.qcls_ss.get_sim_stats_qcl(
            self.k1, self.parfile.mc_sims_var, k2=self.k2).mean()
        cl_pred = utils.camb_clfile(
            os.path.join(
                self.cls_path,
                'FFP10_wdipole_lenspotentialCls.dat'))['pp'][:len(ss2)]
        qc_norm = utils.cli(
            self.parfile.qresp_dd.get_response(self.k1, self.ksource) *
            self.parfile.qresp_dd.get_response(self.k2, self.ksource))
        bp_stats = utils.stats(self.nbins)
        bp_n1 = self.get_n1()
        for i, idx in utils.enumerate_progress(self.parfile.mc_sims_var,
                                               label='collecting BP stats'):
            dd = self.parfile.qcls_dd.get_sim_qcl(self.k1, idx, k2=self.k2)
            bp_stats.add(
                self._get_binnedcl(qc_norm * (dd - ss2) - cl_pred) - bp_n1)
        NMF = len(self.parfile.qcls_dd.mc_sims_mf)
        NB = len(self.parfile.mc_sims_var)
        return bp_stats.mean(), bp_stats.sigmas_on_mean() * np.sqrt(
            (1. + 1. + 2. / NMF + 2 * NB / (float(NMF * NMF))))
Пример #2
0
    def get_bmmc(self, mc_sims_dd=None, mc_sims_ss=None):
        """Binned multiplicative MC correction.

            This compares the reconstruction on the simulations to the FFP10 input lensing spectrum.

        """
        assert self.k1[0] == 'p' and self.k2[
            0] == 'p' and self.ksource == 'p', (self.k1, self.k2, self.ksource)
        if mc_sims_dd is None: mc_sims_dd = self.parfile.mc_sims_var
        if mc_sims_ss is None: mc_sims_ss = self.parfile.mc_sims_var
        dd = self.parfile.qcls_dd.get_sim_stats_qcl(self.k1,
                                                    mc_sims_dd,
                                                    k2=self.k2).mean()
        ss = self.parfile.qcls_ss.get_sim_stats_qcl(self.k1,
                                                    mc_sims_ss,
                                                    k2=self.k2).mean()
        cl_pred = utils.camb_clfile(
            os.path.join(self.cls_path,
                         'FFP10_wdipole_lenspotentialCls.dat'))['pp']
        qc_resp = self.parfile.qresp_dd.get_response(
            self.k1, self.ksource) * self.parfile.qresp_dd.get_response(
                self.k2, self.ksource)
        bps = self._get_binnedcl(
            utils.cli(qc_resp) *
            (dd - 2 * ss) - cl_pred[:len(dd)]) - self.get_n1()
        return 1. / (1 + bps / self.fid_bandpowers)
Пример #3
0
    def get_n1(self, k1=None, k2=None, unnormed=False):
        """Returns analytical N1 lensing bias.

            This uses the analyical approximation to the QE pair filtering as input.

        """
        k1 = self.k1 if k1 is None else k1
        k2 = self.k2 if k2 is None else k2
        assert k1 == k2, 'check signs for qe' 's of different spins'
        assert self.ksource[0] == 'p', 'check aniso source spectrum'
        # This implementation accepts 2 different qes but pairwise identical filtering on each qe leg.
        assert np.all(self.parfile.qcls_dd.qeA.f2map1.ivfs.get_ftl() ==
                      self.parfile.qcls_dd.qeA.f2map2.ivfs.get_ftl())
        assert np.all(self.parfile.qcls_dd.qeA.f2map1.ivfs.get_fel() ==
                      self.parfile.qcls_dd.qeA.f2map2.ivfs.get_fel())
        assert np.all(self.parfile.qcls_dd.qeA.f2map1.ivfs.get_fbl() ==
                      self.parfile.qcls_dd.qeA.f2map2.ivfs.get_fbl())
        assert np.all(self.parfile.qcls_dd.qeB.f2map1.ivfs.get_ftl() ==
                      self.parfile.qcls_dd.qeB.f2map2.ivfs.get_ftl())
        assert np.all(self.parfile.qcls_dd.qeB.f2map1.ivfs.get_fel() ==
                      self.parfile.qcls_dd.qeB.f2map2.ivfs.get_fel())
        assert np.all(self.parfile.qcls_dd.qeB.f2map1.ivfs.get_fbl() ==
                      self.parfile.qcls_dd.qeB.f2map2.ivfs.get_fbl())

        ivfsA = self.parfile.qcls_dd.qeA.f2map1.ivfs
        ivfsB = self.parfile.qcls_dd.qeB.f2map1.ivfs
        ftlA = ivfsA.get_ftl()
        felA = ivfsA.get_fel()
        fblA = ivfsA.get_fbl()
        ftlB = ivfsB.get_ftl()
        felB = ivfsB.get_fel()
        fblB = ivfsB.get_fbl()
        clpp_fid = utils.camb_clfile(
            os.path.join(self.cls_path,
                         'FFP10_wdipole_lenspotentialCls.dat'))['pp']
        qc_resp = self.parfile.qresp_dd.get_response(
            k1, self.ksource) * self.parfile.qresp_dd.get_response(
                k2, self.ksource)
        n1pp = self.parfile.n1_dd.get_n1(k1,
                                         self.ksource,
                                         clpp_fid,
                                         ftlA,
                                         felA,
                                         fblA,
                                         len(qc_resp) - 1,
                                         kB=k2,
                                         ftlB=ftlB,
                                         felB=felB,
                                         fblB=fblB)
        return self._get_binnedcl(utils.cli(qc_resp) *
                                  n1pp) if not unnormed else n1pp
Пример #4
0
                        'data', 'cls')

#--- definition of simulation and inverse-variance filtered simulation libraries:
lmax_ivf = 2048
lmin_ivf = 100  # We will use in the QE only CMB modes between lmin_ivf and lmax_ivf
lmax_qlm = 4096  # We will calculate lensing estimates until multipole lmax_qlm.
nside = 2048  # Healpix resolution of the data and sims.
nlev_t = 35.  # Filtering noise level in temperature (here also used for the noise simulations generation).
nlev_p = 55.  # Filtering noise level in polarization (here also used for the noise simulations generation).
nsims = 300  # Total number of simulations to consider.

transf = hp.gauss_beam(5. / 60. / 180. * np.pi,
                       lmax=lmax_ivf) * hp.pixwin(nside)[:lmax_ivf + 1]
#: CMB transfer function. Here a 5' Gaussian beam and healpix pixel window function.

cl_unl = utils.camb_clfile(
    os.path.join(cls_path, 'FFP10_wdipole_lenspotentialCls.dat'))
cl_len = utils.camb_clfile(
    os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))
#: Fiducial unlensed and lensed power spectra used for the analysis.

cl_weight = utils.camb_clfile(
    os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))
cl_weight['bb'] *= 0.
#: CMB spectra entering the QE weights (the spectra multplying the inverse-variance filtered maps in the QE legs)

libdir_pixphas = os.path.join(TEMP, 'pix_phas_nside%s' % nside)
pix_phas = phas.pix_lib_phas(libdir_pixphas, 3, (hp.nside2npix(nside), ))
#: Noise simulation T, Q, U random phases instance.

sims = maps_utils.sim_lib_shuffle(
    maps.cmb_maps_nlev(planck2018_sims.cmb_len_ffp10(),
Пример #5
0
lmin_ivf = 100
lmax_qlm = 4096  # We will calculate lensing estimates until multipole lmax_qlm.
nside = 2048  # Healpix resolution of the data and sims.
fwhm = 7.1  # Pixel size of the survey, in arc-miniutes.
int_survey = 6.  # (delta T)/T intensity of the survey, in microkelvin.
nlev_t = fwhm * int_survey  # Set by the above two parameters and determines
# Gaussian noise standard deviation. Also used for noise processing.

nlev_p = 55.  # Setting in case polarization data is provided. In this script no calculation
# with polarization is done, so this is just a place holder.

transf = hp.gauss_beam(fwhm / 60. / 180. * np.pi,
                       lmax=lmax_ivf) * hp.pixwin(nside)[:lmax_ivf + 1]
# CMB transfer function. Here a Gaussian beam and healpix pixel window function. Used in smoothing.

cl_unl = utils.camb_clfile(os.path.join(cls_path, 'CAMB_lenspotentialCls.dat'))
cl_len = utils.camb_clfile(os.path.join(cls_path, 'CAMB_lensedCls.dat'))
# Fiducial unlensed and lensed power spectra used for the analysis.

cl_weight = cl_len
cl_weight['bb'] *= 0
# CMB spectra entering the QE weights (the spectra multplying the inverse-variance filtered maps in the QE legs)

libdir_pixphas = os.path.join(TEMP, 'pix_phas_nside%s' % nside)
pix_phas = phas.pix_lib_phas(libdir_pixphas, 3, (hp.nside2npix(nside), ))
# Noise simulation T, Q, U random phases instance.

lib = maps.cmb_maps_nlev(datamaps.websky_lensed(),
                         transf,
                         nlev_t,
                         nlev_p,
Пример #6
0
    def __init__(self, k1, k2, parfile, btype, ksource='p'):

        lmaxphi = 2048
        cls_path = os.path.join(
            os.path.dirname(os.path.abspath(plancklens.__file__)), 'data',
            'cls')

        if ksource == 'p':
            kswitch = (np.arange(0, lmaxphi + 1, dtype=float) *
                       (np.arange(1, lmaxphi + 2)))**2 / (2. * np.pi) * 1e7
            if k1[0] == 'p' and k2[0] == 'p':
                clpp_fid = utils.camb_clfile(
                    os.path.join(
                        cls_path,
                        'FFP10_wdipole_lenspotentialCls.dat'))['pp'][:lmaxphi +
                                                                     1]
            elif k1[0] == 'x' and k2[0] == 'x':
                clpp_fid = np.ones(lmaxphi + 1, dtype=float)
            else:
                assert 0, 'not implemented'
        else:
            kswitch = np.ones(lmaxphi + 1, dtype=float)
            clpp_fid = np.ones(lmaxphi + 1, dtype=float)

        clkk_fid = clpp_fid * kswitch
        qc_resp = parfile.qresp_dd.get_response(
            k1, ksource)[:lmaxphi + 1] * parfile.qresp_dd.get_response(
                k2, ksource)[:lmaxphi + 1]
        bin_lmins, bin_lmaxs, bin_centers = get_blbubc(btype)
        vlpp_inv = qc_resp * (2 * np.arange(lmaxphi + 1) +
                              1) * (0.5 * parfile.qcls_dd.fsky1234)
        vlpp_inv *= utils.cli(kswitch)**2
        vlpp_den = [
            np.sum(clkk_fid[slice(lmin, lmax + 1)]**2 *
                   vlpp_inv[slice(lmin, lmax + 1)])
            for lmin, lmax in zip(bin_lmins, bin_lmaxs)
        ]

        fid_bandpowers = np.ones(
            len(bin_centers
                ))  # We will renormalize that as soon as l_av is calculated.

        def _get_bil(
            i, L
        ):  # Bin i window function to be applied to cLpp-like arrays as just described
            ret = (fid_bandpowers[i] /
                   vlpp_den[i]) * vlpp_inv[L] * clkk_fid[L] * kswitch[L]
            ret *= (L >= bin_lmins[i]) * (L <= bin_lmaxs[i])
            return ret

        lav = np.zeros(len(bin_centers))
        for i, (lmin, lmax) in enumerate(zip(bin_lmins, bin_lmaxs)):
            w_lav = 1. / np.arange(lmin, lmax + 1)**2 / np.arange(
                lmin + 1, lmax + 2)**2
            lav[i] = np.sum(
                np.arange(lmin, lmax + 1) * w_lav *
                _get_bil(i, np.arange(lmin, lmax + 1))) / np.sum(
                    w_lav * _get_bil(i, np.arange(lmin, lmax + 1)))

        self.k1 = k1
        self.k2 = k2
        self.ksource = ksource
        self.parfile = parfile

        self.fid_bandpowers = np.interp(lav, np.arange(lmaxphi + 1,
                                                       dtype=float), clkk_fid)
        self.bin_lmins = bin_lmins
        self.bin_lmaxs = bin_lmaxs
        self.bin_lavs = lav
        self.nbins = len(bin_centers)

        self.vlpp_den = vlpp_den
        self.vlpp_inv = vlpp_inv
        self.clkk_fid = clkk_fid
        self.kswitch = kswitch

        self.cls_path = cls_path
Пример #7
0
    def get_ps_data(self,
                    lmin_ss_s4=100,
                    lmax_ss_s4=2048,
                    mc_sims_ss=None,
                    mc_sims_ds=None):
        ks4 = 'stt'
        twolpo = 2 * np.arange(lmax_ss_s4 + 1) + 1.
        filt = np.ones(lmax_ss_s4 + 1, dtype=float)
        filt[:lmax_ss_s4] *= 0.

        dd_ptsrc = self.parfile.qcls_dd.get_sim_stats_qcl(
            ks4, self.parfile.mc_sims_var).mean()[:lmax_ss_s4 + 1]
        ds_ptsrc = self.parfile.qcls_ds.get_sim_stats_qcl(
            ks4, self.parfile.mc_sims_bias
            if mc_sims_ds is None else mc_sims_ds).mean()[:lmax_ss_s4 + 1]
        ss_ptsrc = self.parfile.qcls_ss.get_sim_stats_qcl(
            ks4, self.parfile.mc_sims_bias
            if mc_sims_ss is None else mc_sims_ss).mean()[:lmax_ss_s4 + 1]
        dat_ptsrc = self.parfile.qcls_dd.get_sim_qcl(ks4, -1)[:lmax_ss_s4 + 1]

        # This simple PS implementation accepts only identical filtering on each four legs.
        assert np.all(self.parfile.qcls_dd.qeA.f2map1.ivfs.get_ftl() ==
                      self.parfile.qcls_dd.qeA.f2map2.ivfs.get_ftl())
        assert np.all(self.parfile.qcls_dd.qeB.f2map1.ivfs.get_ftl() ==
                      self.parfile.qcls_dd.qeB.f2map2.ivfs.get_ftl())
        assert np.all(self.parfile.qcls_dd.qeA.f2map1.ivfs.get_ftl() ==
                      self.parfile.qcls_dd.qeB.f2map1.ivfs.get_ftl())
        ftl = self.parfile.qcls_dd.qeA.f2map1.ivfs.get_ftl()
        qc_resp_ptsrc = nhl.get_nhl(ks4,
                                    ks4, {}, {'tt': ftl},
                                    len(ftl) - 1,
                                    len(ftl) - 1,
                                    lmax_out=lmax_ss_s4)[0]**2

        s4_band_norm = 4.0 / np.sum(4.0 *
                                    (twolpo[lmin_ss_s4:lmax_ss_s4 + 1] *
                                     qc_resp_ptsrc[lmin_ss_s4:lmax_ss_s4 + 1]))
        s4_cl_dat = s4_band_norm * twolpo * (dat_ptsrc - 4. * ds_ptsrc +
                                             2. * ss_ptsrc)
        s4_cl_check = s4_band_norm * twolpo * (dd_ptsrc - 2. * ss_ptsrc)
        s4_cl_systs = s4_band_norm * twolpo * (4. * ds_ptsrc - 4. * ss_ptsrc)
        # phi-induced PS estimator N1
        clpp_fid = utils.camb_clfile(
            os.path.join(self.cls_path,
                         'FFP10_wdipole_lenspotentialCls.dat'))['pp']
        s4_cl_clpp_n1 = s4_band_norm * twolpo * self.get_n1(
            k1=ks4, k2=ks4, unnormed=True)[:lmax_ss_s4 + 1]

        s4_cl_clpp_prim = s4_band_norm * twolpo * self.parfile.qresp_dd.get_response(
            ks4, self.ksource)[:lmax_ss_s4 + 1]**2 * clpp_fid[:lmax_ss_s4 + 1]

        s4_band_dat = np.sum((s4_cl_dat - s4_cl_clpp_prim -
                              s4_cl_clpp_n1)[lmin_ss_s4:lmax_ss_s4 + 1])
        s4_band_check = np.sum((s4_cl_check - s4_cl_clpp_prim -
                                s4_cl_clpp_n1)[lmin_ss_s4:lmax_ss_s4 + 1])
        s4_band_syst = np.abs(np.sum(s4_cl_systs[lmin_ss_s4:lmax_ss_s4 + 1]))

        Cs2s2 = (s4_cl_dat - s4_cl_clpp_prim -
                 s4_cl_clpp_n1) * utils.cli(twolpo) / s4_band_norm
        Cs2s2 *= utils.cli(qc_resp_ptsrc[:lmax_ss_s4 + 1])
        # reconstucted PS power (with correct normalization)
        s4_band_sim_stats = []

        for i, idx in utils.enumerate_progress(self.parfile.mc_sims_var):
            ts4_cl = s4_band_norm * twolpo[: lmax_ss_s4 + 1] * \
                     (self.parfile.qcls_dd.get_sim_qcl(ks4, idx)[:lmax_ss_s4 + 1] - 2. * ss_ptsrc)
            s4_band_sim_stats.append(
                np.sum((ts4_cl - s4_cl_clpp_prim -
                        s4_cl_clpp_n1)[lmin_ss_s4:lmax_ss_s4 + 1]))

        print("ptsrc stats:")
        print('   fit range = [' + str(lmin_ss_s4) + ', ' + str(lmax_ss_s4) +
              ']')
        print('   sim avg has amplitude of ' +
              ('%.3g +- %0.3g (stat), discrepant from zero at %.3f sigma.' %
               (s4_band_check, np.std(s4_band_sim_stats) /
                np.sqrt(len(self.parfile.mc_sims_var)),
                s4_band_check / np.std(s4_band_sim_stats) *
                np.sqrt(len(self.parfile.mc_sims_var)))))
        print('   dat has amplitude of ' +
              ('%.3g +- %0.3g (stat), signif of %.3f sigma.' %
               (s4_band_dat, np.std(s4_band_sim_stats),
                s4_band_dat / np.sqrt(np.var(s4_band_sim_stats)))))
        qc_resp =   self.parfile.qresp_dd.get_response(self.k1, self.ksource) \
                  * self.parfile.qresp_dd.get_response(self.k2, self.ksource)
        # PS spectrum response to ks4, using qe.key- source key symmetry of response functions.
        qlss = self.parfile.qresp_dd.get_response(
            ks4, self.k1[0]) * self.parfile.qresp_dd.get_response(
                ks4, self.k2[0])
        # Correction to apply to estimated spectrum :
        pp_cl_ps = s4_band_dat * utils.cli(qc_resp) * qlss
        return s4_band_dat, s4_band_check, s4_band_syst, s4_band_sim_stats, Cs2s2, pp_cl_ps
Пример #8
0
beam_fwhm = 6.
lmax_qlm = lmax_ivf


if ksource in ['p', 'f']:
    qe_keys = [ksource + 'tt', ksource+'_p', ksource]
    qe_keys_lab = [ (r'$\hat\phi^{%s}$' if ksource == 'p' else 'f')%l for l in ['TT', 'P.', 'MV']]
elif ksource in ['a', 'a_p', 'stt']:
    qe_keys = [ksource]
    qe_keys_lab = [ksource]
else:
    assert 0

transf = hp.gauss_beam(beam_fwhm / 60. / 180. * np.pi, lmax=lmax_ivf)

cls_len = utils.camb_clfile(os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))
cls_weight = utils.camb_clfile(os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))

fal_sepTP =  {'tt': utils.cli(cls_len['tt'][:lmax_ivf + 1] + (nlev_t / 60. / 180. * np.pi) ** 2 / transf ** 2),
              'ee': utils.cli(cls_len['ee'][:lmax_ivf + 1] + (nlev_p / 60. / 180. * np.pi) ** 2 / transf ** 2),
              'bb': utils.cli(cls_len['bb'][:lmax_ivf + 1] + (nlev_p / 60. / 180. * np.pi) ** 2 / transf ** 2)}


cls_ivfs_sepTP = {'tt':fal_sepTP['tt'].copy(),
                  'ee':fal_sepTP['ee'].copy(),
                  'bb':fal_sepTP['bb'].copy(),
                  'te':cls_len['te'][:lmax_ivf + 1] * fal_sepTP['tt'] * fal_sepTP['ee']}
cls_dat = {
    'tt': (cls_len['tt'][:lmax_ivf + 1] + (nlev_t / 60. /180. * np.pi) ** 2 / transf ** 2),
    'ee': (cls_len['ee'][:lmax_ivf + 1] + (nlev_p / 60. /180. * np.pi) ** 2 / transf ** 2),
    'bb': (cls_len['bb'][:lmax_ivf + 1] + (nlev_p / 60. /180. * np.pi) ** 2 / transf ** 2),
Пример #9
0
def test_w():
    cls_path = os.path.join(
        os.path.dirname(os.path.abspath(plancklens.__file__)), 'data', 'cls')

    lmax_ivf = 500
    lmin_ivf = 100
    nlev_t = 35.
    nlev_p = 35. * np.sqrt(2.)
    beam_fwhm = 6.
    lmax_qlm = lmax_ivf

    for ksource in ['p', 'f']:
        if ksource in ['p', 'f']:
            qe_keys = [ksource + 'tt', ksource + '_p', ksource]
        elif ksource in ['a', 'a_p', 'stt']:
            qe_keys = [ksource]
        else:
            assert 0

        transf = hp.gauss_beam(beam_fwhm / 60. / 180. * np.pi, lmax=lmax_ivf)

        cls_len = utils.camb_clfile(
            os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))
        cls_weight = utils.camb_clfile(
            os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))

        fal_sepTP = {
            'tt':
            utils.cli(cls_len['tt'][:lmax_ivf + 1] +
                      (nlev_t / 60. / 180. * np.pi)**2 / transf**2),
            'ee':
            utils.cli(cls_len['ee'][:lmax_ivf + 1] +
                      (nlev_p / 60. / 180. * np.pi)**2 / transf**2),
            'bb':
            utils.cli(cls_len['bb'][:lmax_ivf + 1] +
                      (nlev_p / 60. / 180. * np.pi)**2 / transf**2)
        }

        cls_ivfs_sepTP = {
            'tt': fal_sepTP['tt'].copy(),
            'ee': fal_sepTP['ee'].copy(),
            'bb': fal_sepTP['bb'].copy(),
            'te':
            cls_len['te'][:lmax_ivf + 1] * fal_sepTP['tt'] * fal_sepTP['ee']
        }
        cls_dat = {
            'tt': (cls_len['tt'][:lmax_ivf + 1] +
                   (nlev_t / 60. / 180. * np.pi)**2 / transf**2),
            'ee': (cls_len['ee'][:lmax_ivf + 1] +
                   (nlev_p / 60. / 180. * np.pi)**2 / transf**2),
            'bb': (cls_len['bb'][:lmax_ivf + 1] +
                   (nlev_p / 60. / 180. * np.pi)**2 / transf**2),
            'te':
            np.copy(cls_len['te'][:lmax_ivf + 1])
        }

        fal_jtTP = utils.cl_inverse(cls_dat)
        cls_ivfs_jtTP = utils.cl_inverse(cls_dat)

        for cls in [fal_sepTP, fal_jtTP, cls_ivfs_sepTP, cls_ivfs_jtTP]:
            for cl in cls.values():
                cl[:max(1, lmin_ivf)] *= 0.

        for qe_key in qe_keys:
            NG, NC, NGC, NCG = nhl.get_nhl(qe_key,
                                           qe_key,
                                           cls_weight,
                                           cls_ivfs_sepTP,
                                           lmax_ivf,
                                           lmax_ivf,
                                           lmax_out=lmax_qlm)
            RG, RC, RGC, RCG = qresp.get_response(qe_key,
                                                  lmax_ivf,
                                                  ksource,
                                                  cls_weight,
                                                  cls_len,
                                                  fal_sepTP,
                                                  lmax_qlm=lmax_qlm)
            if qe_key[1:] in ['tt', '_p']:
                assert np.allclose(NG[1:], RG[1:], rtol=1e-6), qe_key
                assert np.allclose(NC[2:], RC[2:], rtol=1e-6), qe_key
            assert np.all(NCG == 0.) and np.all(NGC == 0.)  # for these keys
            assert np.all(RCG == 0.) and np.all(RGC == 0.)

        NG, NC, NGC, NCG = nhl.get_nhl(ksource,
                                       ksource,
                                       cls_weight,
                                       cls_ivfs_jtTP,
                                       lmax_ivf,
                                       lmax_ivf,
                                       lmax_out=lmax_qlm)
        RG, RC, RGC, RCG = qresp.get_response(ksource,
                                              lmax_ivf,
                                              ksource,
                                              cls_weight,
                                              cls_len,
                                              fal_jtTP,
                                              lmax_qlm=lmax_qlm)
        assert np.allclose(NG[1:], RG[1:], rtol=1e-6), ksource
        assert np.allclose(NC[2:], RC[2:], rtol=1e-6), ksource
        assert np.all(NCG == 0.) and np.all(NGC == 0.)  # for these keys
        assert np.all(RCG == 0.) and np.all(RGC == 0.)
Пример #10
0
def get_N0(beam_fwhm=1.4,
           nlev_t: float or np.ndarray = 5.,
           nlev_p=None,
           lmax_CMB: dict or int = 3000,
           lmin_CMB=100,
           lmax_out=None,
           cls_len: dict or None = None,
           cls_weight: dict or None = None,
           joint_TP=True,
           ksource='p'):
    r"""Example function to calculates reconstruction noise levels for a bunch of quadratic estimators

        Args:
            beam_fwhm: beam fwhm in arcmin
            nlev_t: T white noise level in uK-arcmin (an array of size lmax_CMB can be passed for scale-dependent noise level)
            nlev_p: P white noise level in uK-arcmin (defaults to root(2) nlevt) (can also be an array)
            lmax_CMB: max. CMB multipole used in the QE (use a dict with 't' 'e' 'b' keys instead of int to set different CMB lmaxes)
            lmin_CMB: min. CMB multipole used in the QE
            lmax_out: max lensing 'L' multipole calculated
            cls_len: CMB spectra entering the sky response to the anisotropy (defaults to FFP10 lensed CMB spectra)
            cls_weight: CMB spectra entering the QE weights (defaults to FFP10 lensed CMB spectra)
            joint_TP: if True include calculation of the N0s for the GMV estimator (incl. joint T and P filtering)
            ksource: anisotropy source to consider (defaults to 'p', lensing)

        Returns:
            N0s array for the lensing gradient and curl modes for  the T-only, P-onl and (G)MV estimators

        Prompted by AL
    """
    if nlev_p is None:
        nlev_p = nlev_t * np.sqrt(2)
    if not isinstance(lmax_CMB, dict):
        lmaxs_CMB = {s: lmax_CMB for s in ['t', 'e', 'b']}
    else:
        lmaxs_CMB = lmax_CMB
        print("Seeing lmax's:")
        for s in lmaxs_CMB.keys():
            print(s + ': ' + str(lmaxs_CMB[s]))

    lmax_ivf = np.max(list(lmaxs_CMB.values()))
    lmin_ivf = lmin_CMB
    lmax_qlm = lmax_out or lmax_ivf
    cls_path = os.path.join(
        os.path.dirname(os.path.abspath(plancklens.__file__)), 'data', 'cls')
    cls_len = cls_len or utils.camb_clfile(
        os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))
    cls_weight = cls_weight or utils.camb_clfile(
        os.path.join(cls_path, 'FFP10_wdipole_lensedCls.dat'))

    # We consider here TT, Pol-only and the GMV comb if joint_TP is set
    qe_keys = [ksource + 'tt', ksource + '_p']
    if not joint_TP:
        qe_keys.append(ksource)

    # Simple white noise model. Can feed here something more fancy if desired
    transf = hp.gauss_beam(beam_fwhm / 60. / 180. * np.pi, lmax=lmax_ivf)
    Noise_L_T = (nlev_t / 60. / 180. * np.pi)**2 / transf**2
    Noise_L_P = (nlev_p / 60. / 180. * np.pi)**2 / transf**2

    # Data power spectra
    cls_dat = {
        'tt': (cls_len['tt'][:lmax_ivf + 1] + Noise_L_T),
        'ee': (cls_len['ee'][:lmax_ivf + 1] + Noise_L_P),
        'bb': (cls_len['bb'][:lmax_ivf + 1] + Noise_L_P),
        'te': np.copy(cls_len['te'][:lmax_ivf + 1])
    }

    for s in cls_dat.keys():
        cls_dat[s][min(lmaxs_CMB[s[0]], lmaxs_CMB[s[1]]) + 1:] *= 0.

    # (C+N)^{-1} filter spectra
    # For independent T and P filtering, this is really just 1/ (C+ N), diagonal in T, E, B space
    fal_sepTP = {spec: utils.cli(cls_dat[spec]) for spec in ['tt', 'ee', 'bb']}
    # Spectra of the inverse-variance filtered maps
    # In general cls_ivfs = fal * dat_cls * fal^t, with a matrix product in T, E, B space
    cls_ivfs_sepTP = utils.cls_dot([fal_sepTP, cls_dat, fal_sepTP],
                                   ret_dict=True)

    # For joint TP filtering, fals is matrix inverse
    fal_jtTP = utils.cl_inverse(cls_dat)
    # since cls_dat = fals, cls_ivfs = fals. If the data spectra do not match the filter, this must be changed:
    cls_ivfs_jtTP = utils.cls_dot([fal_jtTP, cls_dat, fal_jtTP], ret_dict=True)
    for cls in [fal_sepTP, fal_jtTP, cls_ivfs_sepTP, cls_ivfs_jtTP]:
        for cl in cls.values():
            cl[:max(1, lmin_ivf)] *= 0.

    N0s = {}
    N0_curls = {}
    for qe_key in qe_keys:
        # This calculates the unormalized QE gradient (G), curl (C) variances and covariances:
        # (GC and CG is zero for most estimators)
        NG, NC, NGC, NCG = nhl.get_nhl(qe_key,
                                       qe_key,
                                       cls_weight,
                                       cls_ivfs_sepTP,
                                       lmax_ivf,
                                       lmax_ivf,
                                       lmax_out=lmax_qlm)
        # Calculation of the G to G, C to C, G to C and C to G QE responses (again, cross-terms are typically zero)
        RG, RC, RGC, RCG = qresp.get_response(qe_key,
                                              lmax_ivf,
                                              ksource,
                                              cls_weight,
                                              cls_len,
                                              fal_sepTP,
                                              lmax_qlm=lmax_qlm)

        # Gradient and curl noise terms
        N0s[qe_key] = utils.cli(RG**2) * NG
        N0_curls[qe_key] = utils.cli(RC**2) * NC

    if joint_TP:
        NG, NC, NGC, NCG = nhl.get_nhl(ksource,
                                       ksource,
                                       cls_weight,
                                       cls_ivfs_jtTP,
                                       lmax_ivf,
                                       lmax_ivf,
                                       lmax_out=lmax_qlm)
        RG, RC, RGC, RCG = qresp.get_response(ksource,
                                              lmax_ivf,
                                              ksource,
                                              cls_weight,
                                              cls_len,
                                              fal_jtTP,
                                              lmax_qlm=lmax_qlm)
        N0s[ksource] = utils.cli(RG**2) * NG
        N0_curls[ksource] = utils.cli(RC**2) * NC

    return N0s, N0_curls