Integrated Effects

CosmoWAP can also compute integrated contributions to the galaxy 3D power spectrum. See 2511.09466 for full details. These involve computing line-of-sight integrals between the observer and source, including lensing convergence, the integrated Sachs-Wolfe (ISW) effect, and time delay.

Integration Methods

Analytic \(\mu\) Pipeline

CosmoWAP provides underlying integration routines (in lib.integrated.BaseInt) for evaluating 1D and 2D (for IxI contributions) line-of-sight integrals using Gauss-Legendre quadrature:

BaseInt.single_int(func, \*args, n=128, remove_div=True, source_func=None)

Gauss-Legendre quadrature over a single line-of-sight integral \(\int_0^{1} f(y)\, dy\), where \(y = \chi/d\) is the normalised radial distance. Used for RSD x Integrated terms.

Parameters:
  • n (int) – Number of quadrature nodes

  • remove_div (bool) – Excise numerical divergence near the source (default: True)

  • source_func – Optional function returning the integrand value at the source, used for interpolation near the divergence

BaseInt.double_int(func, \*args, n=128, n2=None, fast=True)

Gauss-Legendre quadrature over a double line-of-sight integral \(\int_0^{1}\!\int_0^{1} f(y_1, y_2)\, dy_1\, dy_2\), where \(y_i = \chi_i/d\). Used for Integrated x Integrated terms. Exploits symmetry \(f(y_1, y_2) = f(y_2, y_1)\) when fast=True to reduce memory and computation.

Parameters:
  • n (int) – Number of quadrature nodes for first integral

  • n2 (int) – Nodes for second integral (default: same as n)

  • fast (bool) – Sum directly rather than building the full 2D grid (default: True)

Numerical \(\mu\) Pipeline

numeric_mu.pk.get_multipole provides an alternative numerical approach for computing power spectrum multipoles. Rather than using the analytically-derived multipole expressions (e.g. pk.NPP.l0), it constructs the full \(P(k,\mu)\) from given kernels (defined in numeric_mu/kernels.py) and numerically projects onto Legendre multipoles. This handles any combination of standard and integrated kernels with a single interface. This is actually advantageous in this case as we can rewrite these now (up to) 3D integrals for an endpoint LOS to greatly speed up their computation (see Appendix G.1 of 2511.09466). The actual integration methods vary but we use general filon-type quadratue for integrals over these exponential functions.

numeric_mu.pk.get_multipole(kernel1, kernel2, l, cosmo_funcs, kk, zz, sigma=None, n=32, n_mu=256, nr=2000, deg=8, delta=0.1, GL=False)

Compute the l-th multipole of the power spectrum for a given pair of kernels.

Parameters:
  • kernel1 (list) – Kernel(s) for field 1 (e.g. ['N'], ['N', 'LP'], ['I'])

  • kernel2 (list) – Kernel(s) for field 2

  • l (int) – Multipole order

  • cosmo_funcsClassWAP instance

  • kk (array) – Wavevectors [h/Mpc]

  • zz (float) – Redshift

  • sigma (float) – FoG damping

  • n (int) – Number of Gauss-Legendre nodes for the line-of-sight integral

  • n_mu (int) – Number of \(\mu\) integration points

  • nr (int) – Number of radial points for the kernel integration

  • deg (int) – Polynomial degree for Filon integration

  • delta (float) – Width of the central region for non-uniform \(\mu\) grid

  • GL (bool) – Use Gauss-Legendre for \(\mu\) integration (default: non-uniform grid)

Returns:

Power spectrum multipole [(Mpc/h)^3]

Available Kernels

The kernels are defined in numeric_mu/kernels.py (class K1). Each kernel represents a first-order field contribution to the observed galaxy overdensity.

Standard (evaluated at source):

  • 'N' – Newtonian (Kaiser RSD): \(D(z)[b_1 + f\mu^2]\)

  • 'LP' – Local projection effects (relativistic): \(D(z)[i\mu\,\beta_1/k + \beta_2/k^2]\)

Integrated (line-of-sight):

  • 'I' – All integrated effects combined (L + TD + ISW)

  • 'L' – Lensing convergence

  • 'TD' – Time delay

  • 'ISW' – Integrated Sachs-Wolfe

The power spectrum for any pair of kernels is \(P_\ell(k) = \frac{2\ell+1}{2}\int_{-1}^{1} K_1 K_2^* P(k)\, \mathcal{L}_\ell(\mu)\, d\mu\), where the line-of-sight integrals for integrated kernels are handled internally.

Usage

import numpy as np
import cosmo_wap as cw
from cosmo_wap.numeric_mu import pk as pk_int
from cosmo_wap.lib import utils

cosmo = utils.get_cosmo()
survey = cw.SurveyParams.Euclid(cosmo)
cosmo_funcs = cw.ClassWAP(cosmo, survey)

k = np.linspace(0.01, 0.3, 100)
z = 1.0

# Standard Newtonian (Kaiser x Kaiser) -- equivalent to pk.NPP
P0_NPP = pk_int.get_multipole(['N'], ['N'], 0, cosmo_funcs, k, z)

# Integrated x NPP (lensing + ISW + TD crossed with Kaiser)
P0_IntNPP = pk_int.get_multipole(['I'], ['N'], 0, cosmo_funcs, k, z) + pk_int.get_multipole(['N'], ['I'], 0, cosmo_funcs, k, z)
P2_IntNPP = pk_int.get_multipole(['I'], ['N'], 2, cosmo_funcs, k, z) + pk_int.get_multipole(['N'], ['I'], 2, cosmo_funcs, k, z)

# Integrated x Integrated
P0_IntInt = pk_int.get_multipole(['I'], ['I'], 0, cosmo_funcs, k, z)

# Individual components (e.g. Lensing x NPP only)
P0_LxNPP = pk_int.get_multipole(['L'], ['N'], 0, cosmo_funcs, k, z)

Analytic Multipole Classes

Analytically-derived multipole expressions are also available in pk.int and pk.int_components. These are computed in Mathematica and exported, with the line-of-sight integrals evaluated via Gauss-Legendre quadrature.

class pk.int.IntNPP

RSD x Integrated (single line-of-sight integral).

l0(cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)
l1(cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)
l2(cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)
l3(cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)
l4(cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)
l(l, cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128, n_mu=16)

Generic l-th multipole via numeric \(\mu\) integration.

mu(mu, cosmo_funcs, k1, zz=0, t=0, sigma=None, n=128)

Full \(P(k, \mu)\).

class pk.int.IntInt

Integrated x Integrated (double line-of-sight integral).

l0(cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, fast=True)
l1(cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, fast=True)
l2(cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, fast=True)
l3(cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, fast=True)
l4(cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, fast=True)
l(l, cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128, n_mu=16)

Generic l-th multipole via numeric \(\mu\) integration.

mu(mu, cosmo_funcs, k1, zz=0, t=0.5, sigma=None, n=128)

Full \(P(k, \mu)\).

Individual integrated component classes are also available in pk.int_components:

  • LxL, LxTD, LxISW, TDxTD, ISWxISW, TDxISW

Each provides l0 through l4 multipoles with the same interface as IntInt.