Galaxy distribution

This example simulates a matter-only light cone up to redshift 1 and samples galaxies from a uniform distribution in redshift. The results are shown in a pseudo-3D plot.

Setup

Set up a galaxy-positions-only GLASS simulation. The setup for angular matter power spectra matches the definition from the Matter shell definition example.

[ ]:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LogNorm

# use the CAMB cosmology that generated the matter power spectra
import camb
from cosmology import Cosmology

# almost all GLASS functionality is available from the `glass` namespace
import glass
import glass.ext.camb

# creating a numpy random number generator for sampling
rng = np.random.default_rng(seed=42)

# cosmology for the simulation
h = 0.7
Oc = 0.25
Ob = 0.05

# basic parameters of the simulation
nside = lmax = 128

# set up CAMB parameters for matter angular power spectrum
pars = camb.set_params(
    H0=100 * h,
    omch2=Oc * h**2,
    ombh2=Ob * h**2,
    NonLinear=camb.model.NonLinear_both,
)

# get the cosmology from CAMB
cosmo = Cosmology.from_camb(pars)

# shells of 200 Mpc in comoving distance spacing
zb = glass.distance_grid(cosmo, 0.0, 1.0, dx=200.0)

# linear radial window functions
ws = glass.linear_windows(zb)

# compute the angular matter power spectra of the shells with CAMB
cls = glass.ext.camb.matter_cls(pars, lmax, ws)

Matter

[ ]:
# apply discretisation to the full set of spectra:
# - HEALPix pixel window function (`nside=nside`)
# - maximum angular mode number (`lmax=lmax`)
# - number of correlated shells (`ncorr=3`)
cls = glass.discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

# compute Gaussian spectra for lognormal fields from discretised spectra
gls = glass.lognormal_gls(cls)

# generator for lognormal matter fields
matter = glass.generate_lognormal(gls, nside, ncorr=3, rng=rng)

Galaxies

[ ]:
# constant galaxy density distribution
z = np.linspace(0.0, 1.0, 100)
dndz = np.full_like(z, 0.01)

# distribute the dN/dz over the linear window functions
ngal = glass.partition(z, dndz, ws)

Simulation

The goal of this example is to make a 3D cube of the sampled galaxy numbers. A redshift cube is initialised with zero counts, and the simulation is run. For every shell in the light cone, the galaxies are counted in the cube.

[ ]:
# make a cube for galaxy number in redshift
zcub = np.linspace(-zb[-1], zb[-1], 21)
cube = np.zeros((zcub.size - 1,) * 3)

# simulate and add galaxies in each matter shell to cube
for i, delta_i in enumerate(matter):
    # simulate positions from matter density
    for gal_lon, gal_lat, gal_count in glass.positions_from_delta(
        ngal[i],
        delta_i,
        rng=rng,
    ):
        # sample redshifts uniformly in shell
        gal_z = glass.redshifts(gal_count, ws[i], rng=rng)

        # add counts to cube
        z1 = gal_z * np.cos(np.deg2rad(gal_lon)) * np.cos(np.deg2rad(gal_lat))
        z2 = gal_z * np.sin(np.deg2rad(gal_lon)) * np.cos(np.deg2rad(gal_lat))
        z3 = gal_z * np.sin(np.deg2rad(gal_lat))
        indices, count = np.unique(
            np.searchsorted(zcub[1:], [z1, z2, z3]),
            axis=1,
            return_counts=True,
        )
        cube[*indices] += count

Visualisation

Lastly, make a pseudo-3D plot by stacking a number of density slices on top of each other.

[ ]:
# positions of grid cells of the cube
z = (zcub[:-1] + zcub[1:]) / 2
z1, z2, z3 = np.meshgrid(z, z, z)

# plot the galaxy distribution in pseudo-3D
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d", proj_type="ortho")
norm = LogNorm(vmin=np.min(cube[cube > 0]), vmax=np.max(cube), clip=True)
for i in range(len(zcub) - 1):
    v = norm(cube[..., i])
    c = plt.cm.inferno(v)
    c[..., -1] = 0.2 * v
    ax.plot_surface(
        z1[..., i],
        z2[..., i],
        z3[..., i],
        rstride=1,
        cstride=1,
        facecolors=c,
        linewidth=0,
        shade=False,
        antialiased=False,
    )
fig.tight_layout()
plt.show()
../../_images/examples_1-basic_density_10_0.png