def GeneratePowerSpectrum(lightcone_fg,redshift_lc,frequency_lc,lc_slice_sel,Ngrid,inputdatadir,outputdatadir,lcgridfilename,lcdesiredfields): print("Generating the power spectrum") start = time.time() #Read the lightcone from the meraxes grid data gridata = ReadGridData(inputdatadir,lcgridfilename,lcdesiredfields) #Keep only parts that are within the given frequency range lightcone_eor = gridata["LightconeBox"][:,:,lc_slice_sel] #The number of frequencies nfreq = len(frequency_lc) # the lightcone cube that we fill out fg_lightcone = np.zeros([Ngrid, Ngrid,nfreq]) # convert foreground to brightness temperature and fill up a cube with its evolution at each frequency ii = 0 for jj in range(nfreq): fg_lightcone[:,:,ii] = lightcone_fg[:,:,jj] / (mpctoRadian(500, redshift_lc[jj]) / Ngrid)**2 / mKtoJy_per_sr(frequency_lc[jj]) ii+=1 # sort out the coords of box in Mpc Lz_Mpc = cosmo.comoving_transverse_distance(redshift_lc[-1]).value-cosmo.comoving_transverse_distance(redshift_lc[0]).value + np.diff(cosmo.comoving_transverse_distance(redshift_lc).value)[0] coords_xy = np.linspace(0, 500, Ngrid+1) coords_xy = coords_xy[1:] - np.diff(coords_xy)[0]/2 coords_z = cosmo.comoving_transverse_distance(redshift_lc).value new_coords_z = np.linspace(coords_z.min(), coords_z.max(), 150) xx, yy, zz = np.meshgrid(coords_xy, coords_xy, new_coords_z, indexing='ij') # interpolate the foreground across frequency to smoothen its evolution f_lc_fg = scipy.interpolate.RegularGridInterpolator([coords_xy, coords_xy, coords_z], fg_lightcone) highres_lightcone_fg = f_lc_fg(np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T).reshape(Ngrid,Ngrid,len(new_coords_z)) # interpolate the eor across frequency to make sure we have the same dimension as foregrounds f_lc_eor = scipy.interpolate.RegularGridInterpolator([coords_xy, coords_xy, coords_z], lightcone_eor) highres_lightcone_eor = f_lc_eor(np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T).reshape(Ngrid,Ngrid,len(new_coords_z)) # Find the PS of foregrounds plus eor P_both, kperp, kparal = get_power((highres_lightcone_fg + highres_lightcone_eor) * signal.blackmanharris(len(new_coords_z)), [500/cosmo.h, 500/cosmo.h, Lz_Mpc/cosmo.h], bins = 50, res_ndim =2, bin_ave=False, get_variance=False) # Find the PS of foregrounds only P_fg = get_power(highres_lightcone_fg * signal.blackmanharris(len(new_coords_z)), [500/cosmo.h, 500/cosmo.h, Lz_Mpc/cosmo.h], bins = 50, res_ndim =2, bin_ave=False, get_variance=False)[0] # Find the PS of eor only P_eor = get_power(highres_lightcone_eor * signal.blackmanharris(len(new_coords_z)), [500/cosmo.h, 500/cosmo.h, Lz_Mpc/cosmo.h], bins = 50, res_ndim =2, bin_ave=False, get_variance=False)[0] #Save the power spectrum np.savez_compressed(outputdatadir + "power_spectrum.npz", power_spectrum_both = P_both, power_spectrum_eor = P_eor, power_spectrum_fg = P_fg, kperp = kperp, kparal = kparal) print("Done generating the power spectrum in",time.time()-start)
def test_k_zero_ignore(): pb = PowerBox(50, dim=2, pk=lambda k: 1.0 * k**-2., boxlength=1.0, b=1) dx = pb.delta_x() p1, k1 = get_power(dx, pb.boxlength, bin_ave=False) p0, k0 = get_power(dx, pb.boxlength, ignore_zero_mode=True, bin_ave=False) assert np.all(k1 == k0) assert np.all(p1[1:] == p0[1:]) assert p1[0] != p0[0]
def test_k_weights(): pb = PowerBox(50, dim=2, pk=lambda k: 1.0 * k**-2., boxlength=1.0, b=1) dx = pb.delta_x() k_weights = np.ones_like(dx) k_weights[:, 25] = 0 p1, k1 = get_power(dx, pb.boxlength, bin_ave=False) p0, k0 = get_power(dx, pb.boxlength, bin_ave=False, k_weights=k_weights) assert np.all(k1 == k0) assert not np.allclose(p1, p0)
def test_ln_vs_straight_standard_freq(): # Set up two boxes with exactly the same parameters pb = PowerBox(128,lambda u : 12.*u**-2., dim=3,seed=1234,boxlength=1200.,a=0,b=2*np.pi) ln_pb = LogNormalPowerBox(128,lambda u : 12.*u**-2., dim=3,seed=1234,boxlength=1200.,a=0,b=2*np.pi) pk = get_power(pb.delta_x(),pb.boxlength,a=0,b=2*np.pi)[0] ln_pk = get_power(ln_pb.delta_x(), pb.boxlength,a=0,b=2*np.pi)[0] pk = pk[1:-1] ln_pk = ln_pk[1:-1] print(np.mean(np.abs((pk-ln_pk)/pk)), np.abs((pk-ln_pk)/pk)) assert np.mean(np.abs((pk-ln_pk)/pk)) < 2e-1 # 10% agreement
def compute_power_spectra(vols, cubedim=64, inverse_loglike_a=None, unsqueeze=False): pks, power_kbins = [], [] if inverse_loglike_a is not None: # for generated data \ vols = inverse_loglike_transform(vols, a=inverse_loglike_a) if unsqueeze: vols = vols[:, 0, :, :, :] # gets rid of single channel \ for i in xrange(vols.shape[0]): pk, bins = get_power(vols[i] - np.mean(vols[i]), cubedim, log_bins=True, bins=16) if np.isnan(pk).all(): print('NaN for power spectrum') continue pks.append(pk) return np.array(pks), np.array(bins)
def produce_perturb_field_data(redshift, **kwargs): options = get_all_options(redshift, **kwargs) options_ics = get_all_options_ics(**kwargs) out = { key: kwargs[key] for key in kwargs if key.upper() in (k.upper() for k in global_params.keys()) } velocity_normalisation = 1e16 with config.use(regenerate=True, write=False): init_box = initial_conditions(**options_ics) pt_box = perturb_field(redshift=redshift, init_boxes=init_box, **out) p_dens, k_dens = get_power( pt_box.density, boxlength=options["user_params"]["BOX_LEN"], ) p_vel, k_vel = get_power( pt_box.velocity * velocity_normalisation, boxlength=options["user_params"]["BOX_LEN"], ) def hist(kind, xmin, xmax, nbins): data = getattr(pt_box, kind) if kind == "velocity": data = velocity_normalisation * data bins, edges = np.histogram( data, bins=np.linspace(xmin, xmax, nbins), range=[xmin, xmax], density=True, ) left, right = edges[:-1], edges[1:] X = np.array([left, right]).T.flatten() Y = np.array([bins, bins]).T.flatten() return X, Y X_dens, Y_dens = hist("density", -0.8, 2.0, 50) X_vel, Y_vel = hist("velocity", -2, 2, 50) return k_dens, p_dens, k_vel, p_vel, X_dens, Y_dens, X_vel, Y_vel, init_box
def produce_lc_power_spectra(redshift, **kwargs): options = get_all_options(redshift, **kwargs) lightcone = run_lightcone(max_redshift=options["redshift"] + 2, **options) p, k = get_power(lightcone.brightness_temp, boxlength=lightcone.lightcone_dimensions) return k, p, lightcone
def compute_average_cross_correlation(npairs=100, gen_samples=None, cubedim=64., real_samples=None): xcorrs = [] for i in xrange(npairs): if gen_samples is None: idxs = np.random.choice(real_samples.shape[0], 2, replace=False) reali = real_samples[idxs[0]] - np.mean(real_samples[idxs[0]]) realj = real_samples[idxs[1]] - np.mean(real_samples[idxs[1]]) xc, ks = get_power(deltax=reali, boxlength=cubedim, deltax2=realj, log_bins=True, bins=16) elif real_samples is None: idxs = np.random.choice(gen_samples.shape[0], 2, replace=False) geni = gen_samples[idxs[0]] - np.mean(gen_samples[idxs[0]]) genj = gen_samples[idxs[1]] - np.mean(gen_samples[idxs[1]]) xc, ks = get_power(geni[0], cubedim, deltax2=genj[0], log_bins=True, bins=16) else: idxreal = np.random.choice(real_samples.shape[0], 1, replace=False)[0] idxgen = np.random.choice(gen_samples.shape[0], 1, replace=False)[0] real = real_samples[idxreal] - np.mean(real_samples[idxreal]) gen = (gen_samples[idxgen] - np.mean(gen_samples[idxgen]))[0] xc, ks = get_power(np.array(real), cubedim, deltax2=np.array(gen), log_bins=True, bins=16) xcorrs.append(xc) return np.array(xcorrs), ks
def test_power1d_ordinary_freq(): p = [0] * 40 for i in range(40): pb = PowerBox(8001, dim=1, pk=lambda k: 1.0 * k**-3., boxlength=1.0) p[i], k = get_power(pb.delta_x(), pb.boxlength) assert np.allclose(np.mean(np.array(p), axis=0)[2000:], 1.0 * k[2000:]**-3., rtol=2)
def produce_coeval_power_spectra(redshift, **kwargs): options = get_all_options(redshift, **kwargs) coeval = run_coeval(**options) p, k = get_power( coeval.brightness_temp, boxlength=coeval.user_params.BOX_LEN, ) return k, p, coeval
def produce_coeval_power_spectra(redshift, **kwargs): options = get_all_options(redshift, **kwargs) coeval = run_coeval(write=write_ics_only_hook, **options) p = {} for field in COEVAL_FIELDS: if hasattr(coeval, field): p[field], k = get_power(getattr(coeval, field), boxlength=coeval.user_params.BOX_LEN) return k, p, coeval
def test_power2d(): p = [0] * 5 for i in range(5): pb = PowerBox(200, dim=2, pk=lambda k: 1.0 * k**-2., boxlength=1.0, b=1) p[i], k = get_power(pb.delta_x(), pb.boxlength, b=1) assert np.allclose(np.mean(np.array(p), axis=0)[100:], 1.0 * k[100:]**-2., rtol=2)
def test_power1d_halfN(): p = [0] * 40 for i in range(40): pb = PowerBox(4001, dim=1, pk=lambda k: 1.0 * k**-3., boxlength=1.0, b=1) p[i], k = get_power(pb.delta_x(), pb.boxlength, b=1) assert np.allclose(np.mean(np.array(p), axis=0)[1000:], 1.0 * k[1000:]**-3., rtol=2)
def ps(fname, boxsize, opt="mean"): with open(fname, 'rb') as f: dens_gas = np.fromfile(f, dtype='f', count=-1) data = lu.slice_2d(dens_gas, 512, 10, operation=opt) data_mean = np.mean(data) d2p = data * data_mean + data_mean p_k_m, bins_m = get_power(d2p, boxsize) return p_k_m, bins_m
def test_discrete_power_lognormal(): pb = LogNormalPowerBox(N=512, dim=2, boxlength=100., pk=lambda u: 0.1 * u**-1.5, ensure_physical=True) sample = pb.create_discrete_sample(nbar=1000.) power, bins = get_power(sample, pb.boxlength, N=pb.N) res = np.mean(np.abs(power[50:-50] / (0.1 * bins[50:-50]**-1.5) - 1)) print(res) assert res < 1e-1
def produce_lc_power_spectra(redshift, **kwargs): options = get_all_options(redshift, **kwargs) lightcone = run_lightcone( max_redshift=options["redshift"] + 2, lightcone_quantities=[ k for k in LIGHTCONE_FIELDS if (options["flag_options"].get("USE_TS_FLUCT", False) or k not in ("Ts_box", "x_e_box", "Tk_box", "J_21_LW_box")) ], write=write_ics_only_hook, **options, ) p = {} for field in LIGHTCONE_FIELDS: if hasattr(lightcone, field): p[field], k = get_power(getattr(lightcone, field), boxlength=lightcone.lightcone_dimensions) return k, p, lightcone
def powerspectra(x_grid, boxlength, ngrid, project_length, y_grid=None): cellsize = boxlength / ngrid nproj = project_length / cellsize if project_length is not None: if x_grid: g_xi, gx_j, x_ij = lu.slice(x_grid, ngrid, nproj, option='C') if y_grid is not None: g_yi, g_yj, y_ij = lu.slice(y_grid, ngrid, nproj, option='C') if y_grid is None: g_yi, g_yj, y_ij = g_xi, gx_j, x_ij X, Y = np.meshgrid(g_xi, g_xi) p_k_samples, bins_samples = get_power(samples, pb.boxlength, N=pb.N) return 0
def pr_feature( param, value, struct, vtype, lightcone, redshift, max_redshift, random_seed, verbose, regenerate, ): """ Create standard plots comparing a default simulation against a simulation with a new feature. The new feature is switched on by setting PARAM to VALUE. Plots are saved in the current directory, with the prefix "pr_feature". Parameters ---------- param : str Name of the parameter to modify to "switch on" the feature. value : float Value to which to set it. struct : str The input parameter struct to which `param` belongs. vtype : str Type of the new parameter. lightcone : bool Whether the comparison should be done on a lightcone. redshift : float Redshift of comparison. max_redshift : float If using a lightcone, the maximum redshift in the lightcone to compare. random_seed : int Random seed at which to compare. verbose : int How verbose the output should be. regenerate : bool Whether to regenerate all data, even if it is in cache. """ import powerbox lvl = [logging.WARNING, logging.INFO, logging.DEBUG][verbose] logger = logging.getLogger("21cmFAST") logger.setLevel(lvl) value = getattr(builtins, vtype)(value) structs = { "user_params": { "HII_DIM": 128, "BOX_LEN": 250 }, "flag_options": { "USE_TS_FLUCT": True }, "cosmo_params": {}, "astro_params": {}, } if lightcone: print("Running default lightcone...") lc_default = lib.run_lightcone( redshift=redshift, max_redshift=max_redshift, random_seed=random_seed, regenerate=regenerate, **structs, ) structs[struct][param] = value print("Running lightcone with new feature...") lc_new = lib.run_lightcone( redshift=redshift, max_redshift=max_redshift, random_seed=random_seed, regenerate=regenerate, **structs, ) print("Plotting lightcone slices...") for field in ["brightness_temp"]: fig, ax = plt.subplots(3, 1, sharex=True, sharey=True) vmin = -150 vmax = 30 plotting.lightcone_sliceplot(lc_default, ax=ax[0], fig=fig, vmin=vmin, vmax=vmax) ax[0].set_title("Default") plotting.lightcone_sliceplot(lc_new, ax=ax[1], fig=fig, cbar=False, vmin=vmin, vmax=vmax) ax[1].set_title("New") plotting.lightcone_sliceplot(lc_default, lightcone2=lc_new, cmap="bwr", ax=ax[2], fig=fig) ax[2].set_title("Difference") plt.savefig(f"pr_feature_lighcone_2d_{field}.pdf") def rms(x, axis=None): return np.sqrt(np.mean(x**2, axis=axis)) print("Plotting lightcone history...") fig, ax = plt.subplots(4, 1, sharex=True, gridspec_kw={"hspace": 0.05}) ax[0].plot(lc_default.node_redshifts, lc_default.global_xHI, label="Default") ax[0].plot(lc_new.node_redshifts, lc_new.global_xHI, label="New") ax[0].set_ylabel(r"$x_{\rm HI}$") ax[0].legend() ax[1].plot( lc_default.node_redshifts, lc_default.global_brightness_temp, label="Default", ) ax[1].plot(lc_new.node_redshifts, lc_new.global_brightness_temp, label="New") ax[1].set_ylabel("$T_b$ [K]") ax[3].set_xlabel("z") rms_diff = rms(lc_default.brightness_temp, axis=(0, 1)) - rms( lc_new.brightness_temp, axis=(0, 1)) ax[2].plot(lc_default.lightcone_redshifts, rms_diff, label="RMS") ax[2].plot( lc_new.node_redshifts, lc_default.global_xHI - lc_new.global_xHI, label="$x_{HI}$", ) ax[2].plot( lc_new.node_redshifts, lc_default.global_brightness_temp - lc_new.global_brightness_temp, label="$T_b$", ) ax[2].legend() ax[2].set_ylabel("Differences") diff_rms = rms(lc_default.brightness_temp - lc_new.brightness_temp, axis=(0, 1)) ax[3].plot(lc_default.lightcone_redshifts, diff_rms) ax[3].set_ylabel("RMS of Diff.") plt.savefig("pr_feature_history.pdf") print("Plotting power spectra history...") p_default = [] p_new = [] z = [] thickness = 200 # Mpc ncells = int(thickness / lc_new.cell_size) chunk_size = lc_new.cell_size * ncells start = 0 print(ncells) while start + ncells <= lc_new.shape[-1]: pd, k = powerbox.get_power( lc_default.brightness_temp[:, :, start:start + ncells], lc_default.lightcone_dimensions[:2] + (chunk_size, ), ) p_default.append(pd) pn, k = powerbox.get_power( lc_new.brightness_temp[:, :, start:start + ncells], lc_new.lightcone_dimensions[:2] + (chunk_size, ), ) p_new.append(pn) z.append(lc_new.lightcone_redshifts[start]) start += ncells p_default = np.array(p_default).T p_new = np.array(p_new).T fig, ax = plt.subplots(2, 1, sharex=True) ax[0].set_yscale("log") inds = [ np.where(np.abs(k - 0.1) == np.abs(k - 0.1).min())[0][0], np.where(np.abs(k - 0.2) == np.abs(k - 0.2).min())[0][0], np.where(np.abs(k - 0.5) == np.abs(k - 0.5).min())[0][0], np.where(np.abs(k - 1) == np.abs(k - 1).min())[0][0], ] for i, (pdef, pnew, kk) in enumerate(zip(p_default[inds], p_new[inds], k[inds])): ax[0].plot(z, pdef, ls="--", label=f"k={kk:.2f}", color=f"C{i}") ax[0].plot(z, pnew, ls="-", color=f"C{i}") ax[1].plot(z, np.log10(pdef / pnew), ls="-", color=f"C{i}") ax[1].set_xlabel("z") ax[0].set_ylabel(r"$\Delta^2 [{\rm mK}^2]$") ax[1].set_ylabel(r"log ratio of $\Delta^2 [{\rm mK}^2]$") ax[0].legend() plt.savefig("pr_feature_power_history.pdf") else: raise NotImplementedError()
def test_power3d(): pb = PowerBox(50, dim=2, pk=lambda k: 1.0 * k**-2., boxlength=1.0, b=1) p, k = get_power(pb.delta_x(), pb.boxlength, b=1) print(p / (1.0 * k**-2.)) assert np.allclose(p, 1.0 * k**-2., rtol=2)
def get_power_single_z(fname, get_delta=True, maxN=None, bins=50, forcerun=False): """ Calculate the spherically-averaged power spectrum for a single-redshift box. Parameters ---------- fname : str Filename of 21cmFAST simulation box. Should *not* be a lighttravel box. get_delta : bool, optional If True, return the dimensionless power spectrum, Delta^2, otherwise, return the volume-normalised power. maxN : int, optional The maximum number of cells per side to use in the estimation. Use to fit within memory. bins : int, optional Number of k-bins to use (linearly spaced) forcerun : bool, optional Forces the function to run even if it thinks it will use too much memory. Returns ------- pk : array The power spectrum as a function of k. Has units mK^2 if `get_delta` is True, otherwise has units mK^2 Mpc^3. kbins : array The k values corresponding to pk. Has units 1/Mpc. """ if fname.endswith("lighttravel"): raise ValueError( "This function is intended for obtaining power spectra from boxes at a single redshift" ) box = readbox(fname) N = box.dim L = box.param_dict['BoxSize'] box = box.box_data if maxN is None or maxN > N: maxN = N if maxN**3 * 8 * 3 > psutil.virtual_memory().available: msg = """ Required memory (%s GB) would be more than that available (%s GB), aborting. If you really want to run it, use forcerun. """ % (maxN**3 * 8 * 3 / 1.0e9, psutil.virtual_memory().available / 1.0e9) if not forcerun: raise ValueError(msg) else: print "Warning: required memory (%s GB) may be more than that available (%s GB)." % ( maxN**3 * 8 * 3 / 1.0e9, psutil.virtual_memory().available / 1.0e9) # Restrict the box for memory box = box[:maxN, :maxN, :maxN] L *= float(maxN) / N pk, kbins = get_power(box, L, bins=bins) if get_delta: pk *= kbins**3 / (2 * np.pi**2) return pk, kbins
def get_power_lightcone(fname, numin=150., numax=161.15, get_delta=True, bins=50, res_ndim=None, taper=None): """ Calculate the spherically-averaged power spectrum in a segment of a lightcone. Parameters ---------- fname : str Filename of 21cmFAST simulation box. Should *not* be a lighttravel box. numin, numax : float Min/Max frequencies of the "observation", in MHz. Used to cut the box before PS estimation. get_delta : bool, optional If True, return the dimensionless power spectrum, Delta^2, otherwise, return the volume-normalised power. bins : int, optional Number of k-bins to use (linearly spaced) res_ndim : int, optional Only perform angular averaging over first `res_ndim` dimensions. By default, uses all dimensions. Returns ------- pk : array The power spectrum as a function of k. Has units mK^2 if `get_delta` is True, otherwise has units mK^2 Mpc^3. kbins : array The k values corresponding to pk. Has units 1/Mpc. """ if res_ndim is not None and res_ndim != 3 and get_delta: raise NotImplementedError( "Currently can't get Delta^2 for not fully-averaged data") box, N, L, d, nu, z = get_cut_box(fname, numin, numax) if taper is not None: box = box * taper(len(nu)) res = get_power(box, [L, L, np.abs(d[-1] - d[0])], bins=bins, res_ndim=res_ndim) if get_delta: return res[0] * res[1]**3 / (2 * np.pi**2), res[1] else: P = res[0] kav = res[1] k_other = res[2][0] P = P[np.logical_not(np.isnan(kav))] P = P[:, k_other > 0] kav = kav[np.logical_not(np.isnan(kav))] k_other = k_other[k_other > 0] return P, kav, k_other, {"N": N, "L": L, "d": d, "nu": nu, "z": z}
def get_power_lightcone_beam(fname, numin=150., numax=161.15, get_delta=True, bins=50, beam_model=CircularGaussian): """ Calculate the spherically-averaged power spectrum in a segment of a lightcone, after attenuation by a given beam. Parameters ---------- fname : str Filename of 21cmFAST simulation box. Should *not* be a lighttravel box. numin, numax : float Min/Max frequencies of the "observation", in MHz. Used to cut the box before PS estimation. get_delta : bool, optional If True, return the dimensionless power spectrum, Delta^2, otherwise, return the volume-normalised power. bins : int, optional Number of k-bins to use (linearly spaced) beam_model : `spore.model.beam.CircularBeam` subclass Defines the beam model Returns ------- pk : array The power spectrum as a function of k. Has units mK^2 if `get_delta` is True, otherwise has units mK^2 Mpc^3. kbins : array The k values corresponding to pk. Has units 1/Mpc. """ box, N, L, d, nu, z = get_cut_box(fname, numin, numax) # INITIALISE A BEAM MODEL beam = beam_model(nu.min(), np.linspace(1, nu.max() / nu.min(), len(nu))) # ATTENUATE BOX BY THE BEAM width = L / Planck15.angular_diameter_distance(z).value vol = np.ones_like(box) for i in range(len(nu)): dl = width[i] / N l = np.sin( np.linspace(-width[i] / 2 + dl / 2, width[i] / 2 - dl / 2, N)) X, M = np.meshgrid(l, l) vol[:, :, i] = np.exp(-(X**2 + M**2) / (2 * beam.sigma[i]**2)) box[:, :, i] = box[:, :, i] * vol[:, :, i] volfrac = np.sum(vol) / np.product(vol.shape) pk, kbins = get_power(box, [L, L, np.abs(d[-1] - d[0])], bins=bins) if get_delta: pk *= kbins**3 / (2 * np.pi**2) return pk, kbins, volfrac
highres_lightcone_fg = f_lc( np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T).reshape(Ngrid, Ngrid, len(new_coords_z)) # interpolate the eor across frequency to make sure we have the same dimension as foregrounds f_lc_fg = scipy.interpolate.RegularGridInterpolator( [coords_xy, coords_xy, coords_z], lightcone_eor) highres_lightcone_eor = f_lc( np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T).reshape(Ngrid, Ngrid, len(new_coords_z)) # Find the PS of foregrounds plus eor P_both, kperp, kparal = get_power( (highres_lightcone_fg + highres_lightcone_eor) * signal.blackmanharris(len(new_coords_z)), [500, 500, Lz_Mpc], bins=50, res_ndim=2, bin_ave=False, get_variance=False) # Find the PS of foregrounds only P_fg = get_power(highres_lightcone_fg * signal.blackmanharris(len(new_coords_z)), [500, 500, Lz_Mpc], bins=50, res_ndim=2, bin_ave=False, get_variance=False)[0] # Find the PS of eor only P_eor = get_power(highres_lightcone_eor * signal.blackmanharris(len(new_coords_z)), [500, 500, Lz_Mpc],