def lensing_correlations(clpp, xvals, lmax=None): """ Get the sigma^2(x) and C_{gl,2}(x) functions from the lensing power spectrum :param clpp: array of [l(l+1)]^2 C_phi_phi/2/pi lensing potential power spectrum :param xvals: array of cos(theta) values at which to calculate correlation function. :param lmax: optional maximum L to use from the cls arrays :return: sigmasq, Cg2 """ if lmax is None: lmax = clpp.shape[0] - 1 ls = np.arange(1, lmax + 1, dtype=np.float64) cldd = clpp[1:] / (ls * (ls + 1)) cphil3 = (2 * ls + 1) * cldd / 2 # (2*l+1)l(l+1)/4pi C_phi_phi sigmasq = np.zeros(xvals.shape) Cg2 = np.zeros(xvals.shape) llp1 = ls * (ls + 1) for i, x in enumerate(xvals): P, dP = legendreP(lmax, x) fac1 = 1 - x fac2 = 1 + x d_11 = fac1 * dP[1:] / llp1 + P[1:] d_m11 = fac2 * dP[1:] / llp1 - P[1:] sigmasq[i] = np.dot(1 - d_11, cphil3) Cg2[i] = np.dot(d_m11, cphil3) return sigmasq, Cg2
def legendre_funcs(lmax, x, m=(0, 2), lfacs=None, lfacs2=None, lrootfacs=None): r""" Utility function to return array of Legendre and :math:`d_{mn}` functions for all :math:`\ell` up to lmax. Note that :math:`d_{mn}` arrays start at :math:`\ell_{\rm min} = \max(m,n)`, so returned arrays are different sizes :param lmax: maximum :math:`\ell` :param x: scalar value of :math:`\cos(\theta)` at which to evaluate :param m: m values to calculate :math:`d_{m,n}`, etc as relevant :param lfacs: optional pre-computed :math:`\ell(\ell+1)` float array :param lfacs2: optional pre-computed :math:`(\ell+2)*(\ell-1)` float array :param lrootfacs: optional pre-computed sqrt(lfacs*lfacs2) array :return: :math:`(P,P'),(d_{11},d_{-1,1}), (d_{20}, d_{22}, d_{2,-2})` as requested, where P starts at :math:`\ell=0`, but spin functions start at :math:`\ell=\ell_{\rm min}` """ allP, alldP = legendreP(lmax, x) # Polarization functions all start at L=2 fac1 = 1 - x fac2 = 1 + x res = [] if 0 in m: res.append((allP, alldP)) if 1 in m: lfacs1 = np.arange(1, lmax + 1, dtype=np.float64) lfacs1 *= (1 + lfacs1) d11 = fac1 * alldP[1:] / lfacs1 + allP[1:] dm11 = fac2 * alldP[1:] / lfacs1 - allP[1:] res.append((d11, dm11)) if 2 in m: if lfacs is None: ls = np.arange(2, lmax + 1, dtype=np.float64) lfacs = ls * (ls + 1) lfacs2 = (ls + 2) * (ls - 1) lrootfacs = np.sqrt(lfacs * lfacs2) P = allP[2:] dP = alldP[2:] fac = fac1 / fac2 d22 = (((4 * x - 8) / fac2 + lfacs) * P + 4 * fac * (fac2 + (x - 2) / lfacs) * dP) / lfacs2 if x > 0.998: # for stability use series at small angles (thanks Pavel Motloch) d2m2 = np.empty(lmax - 1) indser = int(np.sqrt((400.0 + 3 / (1 - x**2)) / 150)) - 1 d2m2[indser:] = ( (lfacs[indser:] - (4 * x + 8) / fac1) * P[indser:] + 4 / fac * (-fac1 + (x + 2) / lfacs[indser:]) * dP[indser:]) / lfacs2[indser:] sin2 = 1 - x**2 d2m2[: indser] = lfacs[:indser] * lfacs2[:indser] * sin2**2 / 7680 * ( 20 + sin2 * (16 - lfacs[:indser])) else: d2m2 = ((lfacs - (4 * x + 8) / fac1) * P + 4 / fac * (-fac1 + (x + 2) / lfacs) * dP) / lfacs2 d20 = (2 * x * dP - lfacs * P) / lrootfacs res.append((d20, d22, d2m2)) return res
def lensing_correlations(clpp, xvals, lmax=None): r""" Get the :math:`\sigma^2(x)` and :math:`C_{{\rm gl},2}(x)` functions from the lensing power spectrum :param clpp: array of :math:`[L(L+1)]^2 C_L^{\phi\phi}/2\pi` lensing potential power spectrum (zero based) :param xvals: array of :math:`\cos(\theta)` values at which to calculate correlation function. :param lmax: optional maximum L to use from the clpp array :return: array of :math:`\sigma^2(x)`, array of :math:`C_{{\rm gl},2}(x)` """ if lmax is None: lmax = clpp.shape[0] - 1 ls = np.arange(1, lmax + 1, dtype=np.float64) cldd = clpp[1:] / (ls * (ls + 1)) cphil3 = (2 * ls + 1) * cldd / 2 # (2*L+1)L(L+1)/4pi C_phi_phi sigmasq = np.zeros(xvals.shape) Cg2 = np.zeros(xvals.shape) llp1 = ls * (ls + 1) for i, x in enumerate(xvals): P, dP = legendreP(lmax, x) fac1 = 1 - x fac2 = 1 + x d_11 = fac1 * dP[1:] / llp1 + P[1:] d_m11 = fac2 * dP[1:] / llp1 - P[1:] sigmasq[i] = np.dot(1 - d_11, cphil3) Cg2[i] = np.dot(d_m11, cphil3) return sigmasq, Cg2
def lensing_correlations(clpp, xvals, lmax=None): r""" Get the :math:`\sigma^2(x)` and :math:`C_{{\rm gl},2}(x)` functions from the lensing power spectrum :param clpp: array of :math:`[L(L+1)]^2 C_L^{\phi\phi}/2\pi` lensing potential power spectrum (zero based) :param xvals: array of :math:`\cos(\theta)` values at which to calculate correlation function. :param lmax: optional maximum L to use from the clpp array :return: array of :math:`\sigma^2(x)`, array of :math:`C_{{\rm gl},2}(x)` """ if lmax is None: lmax = clpp.shape[0] - 1 ls = np.arange(1, lmax + 1, dtype=np.float64) cldd = clpp[1:] / (ls * (ls + 1)) cphil3 = (2 * ls + 1) * cldd / 2 # (2*l+1)l(l+1)/4pi C_phi_phi sigmasq = np.zeros(xvals.shape) Cg2 = np.zeros(xvals.shape) llp1 = ls * (ls + 1) for i, x in enumerate(xvals): P, dP = legendreP(lmax, x) fac1 = 1 - x fac2 = 1 + x d_11 = fac1 * dP[1:] / llp1 + P[1:] d_m11 = fac2 * dP[1:] / llp1 - P[1:] sigmasq[i] = np.dot(1 - d_11, cphil3) Cg2[i] = np.dot(d_m11, cphil3) return sigmasq, Cg2
def legendre_funcs(lmax, x, m=[0, 2], lfacs=None, lfacs2=None, lrootfacs=None): """ Utility function to return array of Legendre and d_{mn} functions for all L up to lmax. Note that d_{mn} arrays start at L_min = max(m,n), so returned arrays are different sizes :param lmax: maximum L :param x: scalar value of cos(theta) at which to evaluate :param m: m values to calculate d_{m,n}, etc as relevant :param lfacs: optional pre-computed L(L+1) float array :param lfacs2: optional pre-computed (L+2)*(L-1) float array :param lrootfacs: optional pre-computed sqrt(lfacs*lfacs2) array :return: (P,dP),(d11,dm11), (d20, d22, d2m2) as requested, where P starts at L=0, but spin functions start at L=Lmin """ allP, alldP = legendreP(lmax, x) # Polarization functions all start at L=2 fac1 = 1 - x fac2 = 1 + x res = [] if 0 in m: res.append((allP, alldP)) if 1 in m: lfacs1 = np.arange(1, lmax + 1, dtype=np.float64) lfacs1 *= (1 + lfacs1) d11 = fac1 * alldP[1:] / lfacs1 + allP[1:] dm11 = fac2 * alldP[1:] / lfacs1 - allP[1:] res.append((d11, dm11)) if 2 in m: if lfacs is None: ls = np.arange(2, lmax + 1, dtype=np.float64) lfacs = ls * (ls + 1) lfacs2 = (ls + 2) * (ls - 1) lrootfacs = np.sqrt(lfacs * lfacs2) P = allP[2:] dP = alldP[2:] fac = fac1 / fac2 d22 = (((4 * x - 8) / fac2 + lfacs) * P + 4 * fac * (fac2 + (x - 2) / lfacs) * dP) / lfacs2 if x > 0.998: # for stability use series at small angles (thanks Pavel Motloch) d2m2 = np.empty(lmax - 1) indser = int(np.sqrt((400.0 + 3 / (1 - x ** 2)) / 150)) - 1 d2m2[indser:] = ((lfacs[indser:] - (4 * x + 8) / fac1) * P[indser:] + 4 / fac * (-fac1 + (x + 2) / lfacs[indser:]) * dP[indser:]) / lfacs2[indser:] sin2 = 1 - x ** 2 d2m2[:indser] = lfacs[:indser] * lfacs2[:indser] * sin2 ** 2 / 7680 * (20 + sin2 * (16 - lfacs[:indser])) else: d2m2 = ((lfacs - (4 * x + 8) / fac1) * P + 4 / fac * (-fac1 + (x + 2) / lfacs) * dP) / lfacs2 d20 = (2 * x * dP - lfacs * P) / lrootfacs res.append((d20, d22, d2m2)) return res