Power Spectrum Computation

Power Spectrum Computation#

Introduction#

The main entry point to the power spectrum module is the calc_power() function, which takes a set of points, deposits them onto a mesh (optionally with interlacing), computes the mode powers through an FFT, and then computes bandpowers and multipoles. This notebook is a quick demonstration of that function, with a similarly quick sanity check against nbodykit.

Example#

import numpy as np
import matplotlib.pyplot as plt

from abacusnbody.analysis.power_spectrum import calc_power

Load the data:

power_test_data = dict(**np.load("../../../tests/data_power/test_pos.npz"))
Lbox = 1000.
pos = power_test_data['pos']

Specifications of the power spectrum computation. The only required args are pos and Lbox.

interlaced = True
compensated = True
paste = 'TSC'
nmesh = 72
nbins_mu = 4
logk = False
k_hMpc_max = np.pi*nmesh/Lbox + 1.e-6
nbins_k = nmesh//2
poles = [0, 2, 4]

Compute the power spectrum, including bandpowers and multipoles:

power = calc_power(pos, Lbox, nbins_k, nbins_mu, k_hMpc_max, logk, \
                    paste, nmesh, compensated, interlaced, poles=poles)

The result is an Astropy Table. The shape of the k_avg, power, etc, columns is (nbins_k,nbins_mu). The poles column is shape (nbins_k,len(poles)).

power
Table length=36
k_mink_maxk_midk_avgpowerN_modepolesN_mode_polesmu_minmu_maxmu_mid
float64float64float64float32[4]float32[4]int64[4]float32[3]int64float64[4]float64[4]float64[4]
0.00.0062832130849573640.0031416065424786820.005026548 .. 0.00628318547568.9023 .. 6049.02545 .. 27134.6523 .. 33801.09870.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0062832130849573640.0125664261699147280.0094248196274360470.010726068 .. 0.0125663712942.2803 .. 49420.0748 .. 212721.525 .. 8581.41260.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0125664261699147280.0188496392548720940.0157080327123934120.016180087 .. 0.015178949128.091 .. 26119.80516 .. 1817876.928 .. -4302.0957900.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0188496392548720940.0251328523398294570.0219912457973507750.022035956 .. 0.0222218549138.691 .. 20882.1420 .. 4216421.23 .. -2728.31471340.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0251328523398294570.0314160654247868240.028274458882308140.0278653 .. 0.028731079497.041 .. 21889.50880 .. 5814460.294 .. 1471.57342580.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0314160654247868240.037699278509744190.03455767196726550.03427213 .. 0.03448248653.626 .. 17725.803112 .. 9013018.891 .. -5607.49764100.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.037699278509744190.043982491594701550.040840885052222870.04038116 .. 0.040898978631.141 .. 15932.965108 .. 13811582.084 .. 430.214024940.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.043982491594701550.0502657046796589140.047124098137180230.046560723 .. 0.047365518191.2383 .. 14180.858144 .. 17810757.994 .. -2565.64876900.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.0502657046796589140.056548917764616280.05340731122213760.053127706 .. 0.0535847478125.8447 .. 13207.899280 .. 2269751.573 .. -19.1544349620.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.056548917764616280.062832130849573650.059690524307094960.05940248 .. 0.059612997919.7124 .. 12426.76280 .. 2749381.509 .. 696.677610980.0 .. 0.750.25 .. 1.00.125 .. 0.875
.................................
0.163363540208891460.169646753293848850.166505146751370150.16650459 .. 0.166508783508.4248 .. 4512.5692208 .. 22343929.0388 .. -230.0423689940.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.169646753293848850.17592996637880620.17278835983632750.17277633 .. 0.172908683562.9634 .. 4224.7242212 .. 24183855.428 .. 27.3119594460.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.17592996637880620.182213179463763560.17907157292128490.17895347 .. 0.179099193525.7412 .. 4377.74562600 .. 24583806.5596 .. 139.7558799780.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.182213179463763560.188496392548720910.185354786006242220.185251 .. 0.18528613623.513 .. 4494.1072864 .. 27623875.3442 .. 257.82697111380.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.188496392548720910.19477960563367830.19163799909119960.19156447 .. 0.191528663384.806 .. 4229.8432836 .. 28903696.4075 .. 195.4255114060.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.19477960563367830.201062818718635660.1979212121761570.19781813 .. 0.197858663382.7285 .. 4218.51862960 .. 31863763.8347 .. -332.63657125780.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.201062818718635660.2073460318035930.204204425261114320.20413305 .. 0.204237853378.4102 .. 4038.11183584 .. 33463576.4487 .. 61.47841134900.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.2073460318035930.21362924488855040.21048763834607170.21046124 .. 0.210466743222.9612 .. 3837.1593504 .. 34663501.6152 .. -58.982677139620.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.21362924488855040.219912457973507750.21677085143102910.21672955 .. 0.216717473282.833 .. 3728.51863748 .. 37703434.2856 .. 90.5686150620.0 .. 0.750.25 .. 1.00.125 .. 0.875
0.219912457973507750.22619567105846510.223054064515986420.22298157 .. 0.223080563189.86 .. 3806.17583702 .. 40023485.2192 .. 1.8451325156880.0 .. 0.750.25 .. 1.00.125 .. 0.875

The meta field saves some information about how the power spectrum was calculated:

power.meta
{'Lbox': 1000.0,
 'logk': False,
 'paste': 'TSC',
 'nmesh': 72,
 'compensated': True,
 'interlaced': True,
 'poles': [0, 2, 4],
 'nthread': 24,
 'N_pos': 421791,
 'is_weighted': False,
 'field_dtype': numpy.float32,
 'squeeze_mu_axis': True}

Compare with nbodykit#

Load presaved nbodykit computation:

comp_str = "_compensated" if compensated else ""
int_str = "_interlaced" if interlaced else ""
fn = f"../../../tests/data_power/nbody_{paste}{comp_str}{int_str}.npz"
data = np.load(fn)
k_nbody = data['k']
Pkmu_nbody = data['power'].real
Pell_nbody = data['power_ell'].real

Plot and compare:

colors = ['k', 'c', 'm', 'y']
plt.figure(figsize=(9, 7))
for i in range(nbins_mu):
    if i == 0:
        label1 = 'nbodykit'
        label2 = 'abacus_power'
    else:
        label1 = label2 = None
    plt.plot(k_nbody, Pkmu_nbody[:, i] * k_nbody, c=colors[i], label=label1)
    plt.plot(power['k_mid'], power['power'][:, i] * power['k_mid'], c=colors[i], ls='--', label=label2)
plt.ylabel(r"$k P(k)$")
plt.xlabel(r"$k \ [h/{\rm Mpc}]$")
plt.legend();
../../_images/fd642348af5130fa6fc73c50575193810e234bf50f7e9c070ef80c1cb1346419.png
# plot and compare
plt.figure(figsize=(9, 7))
for i in range(len(poles)):
    if i == 0:
        label1 = 'nbodykit'
        label2 = 'abacus_power'
    else:
        label1 = label2 = None
    plt.plot(k_nbody, Pell_nbody[i, :] * k_nbody, c=colors[i], label=label1)
    plt.plot(power['k_mid'], power['poles'][:,i] * power['k_mid'], c=colors[i], ls='--', label=label2)
plt.ylabel(r"$k P_\ell(k)$")
plt.xlabel(r"$k \ [h/{\rm Mpc}]$")
plt.legend();
../../_images/f044e6a3fe128f48eacd73dd379dc38b1e8b5d1d60d51b52b91e7efbcc921b77.png