Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

DOC: update examples for multiple related fields #12

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
version: 2

build:
os: ubuntu-22.04
tools:
python: "3.11"

python:
install:
- requirements: requirements.txt
13 changes: 8 additions & 5 deletions examples/advanced/plot_s4_galaxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
Stage IV Galaxy Survey
======================

This example simulates a galaxy catalogue from a Stage IV Space Satellite Galaxy
Survey such as *Euclid* and *Roman* combining the :doc:`/basic/plot_density` and
:doc:`/basic/plot_lensing` examples with galaxy ellipticities and galaxy shears,
This example simulates a galaxy catalogue from a Stage IV Space Satellite
Galaxy Survey such as *Euclid* and *Roman* combining the :doc:`/basic/galaxies`
and :doc:`/basic/lensing` examples with galaxy ellipticities and galaxy shears,
as well as using some auxiliary functions.

The focus in this example is mock catalogue generation using auxiliary functions
Expand Down Expand Up @@ -71,9 +71,12 @@
# compute the angular matter power spectra of the shells with CAMB
cls = glass.ext.camb.matter_cls(pars, lmax, ws)

# compute Gaussian cls for lognormal fields for 3 correlated shells
# angular discretisation with 3 correlated shells
# putting nside here means that the HEALPix pixel window function is applied
gls = glass.fields.lognormal_gls(cls, nside=nside, lmax=lmax, ncorr=3)
cls = glass.fields.discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

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

# generator for lognormal matter fields
matter = glass.fields.generate_lognormal(gls, nside, ncorr=3)
Expand Down
18 changes: 11 additions & 7 deletions examples/advanced/plot_shears.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
============

This example simulates a galaxy catalogue with shears affected by weak lensing,
combining the :doc:`/basic/plot_density` and :doc:`/basic/plot_lensing` examples
with generators for the intrinsic galaxy ellipticity and the resulting shear.
combining the :doc:`/basic/galaxies` and :doc:`/basic/lensing` examples with
generators for the intrinsic galaxy ellipticity and the resulting shear.

'''

Expand All @@ -31,6 +31,7 @@
import glass.shapes
import glass.lensing
import glass.galaxies
import glass.user
from glass.core.constants import ARCMIN2_SPHERE


Expand All @@ -56,15 +57,18 @@
ws = glass.shells.tophat_windows(zb)

# load the angular matter power spectra previously computed with CAMB
cls = np.load('../basic/cls.npy')
cls = glass.user.load_cls('../basic/cls.npz')

# angular discretisation with 3 correlated shells
# putting nside here means that the HEALPix pixel window function is applied
cls = glass.fields.discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

# %%
# Matter
# ------

# compute Gaussian cls for lognormal fields for 3 correlated shells
# putting nside here means that the HEALPix pixel window function is applied
gls = glass.fields.lognormal_gls(cls, nside=nside, lmax=lmax, ncorr=3)
# compute Gaussian cls for lognormal fields
gls = glass.fields.lognormal_gls(cls)

# generator for lognormal matter fields
matter = glass.fields.generate_lognormal(gls, nside, ncorr=3)
Expand Down Expand Up @@ -136,7 +140,7 @@

# apply the shear fields to the ellipticities
gal_she = glass.galaxies.galaxy_shear(gal_lon, gal_lat, gal_eps,
kappa_i, gamm1_i, gamm2_i)
kappa_i, gamm1_i, gamm2_i)

# map the galaxy shears to a HEALPix map; this is opaque but works
gal_pix = hp.ang2pix(nside, gal_lon, gal_lat, lonlat=True)
Expand Down
184 changes: 184 additions & 0 deletions examples/basic/biased_lognormal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
"""
Biased lognormal fields
=======================

This example shows how to compute a biased lognormal field by rescaling the
*alms* of the matter field with a biased angular power spectrum.

**WARNING**: This model has a major caveat. See below.

"""

# %%
# Setup
# -----
#
# This example simulates a lognormal matter field and a biased tracer field.
#
# The precomputed angular matter power spectra from the :doc:`/basic/shells`
# example are used, so the simulation is set up in the same way.

import numpy as np
import healpy as hp
import matplotlib.pyplot as plt

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

# GLASS imports
from glass.shells import distance_grid, partition, tophat_windows
from glass.fields import (discretized_cls, lognormal_gls, generate_alms,
biased_cls, rescaled_alm, alm_to_lognormal, getcl)
from glass.user import load_cls


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

# basic parameters of the simulation
nside = lmax = 256

# 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
zgrid = distance_grid(cosmo, 0., 1., dx=200.)

# uniform matter weight function
shells = tophat_windows(zgrid)

# load the previously-computed angular matter power spectra
cls = load_cls("cls.npz")

# apply angular discretisation to cls
cls = discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

# %%
# Matter
# ------
#
# The matter fields in this example are lognormal. To simulate both matter and
# the biased tracer field, we require the Gaussian *alm* array for each shell.
# We therefore use the :func:`~glass.fields.generate_alms` generator, instead
# of generating the lognormal matter fields directly.

# compute Gaussian angular power spectra for lognormal matter fields
gls = lognormal_gls(cls)

# generator for Gaussian random field alms
alms = generate_alms(gls, ncorr=3)

# %%
# Biased tracer
# -------------
#
# The biased tracer fields in this example have a single bias factor *bias*,
# but this could be an array with a different value for each shell. The
# biasing works by first applying the bias factors to the original *cls* array
# using the :func:`~glass.fields.biased_cls` function. We then compute the
# Gaussian angular power spectra for biased lognormal fields.
#
# This is just one example of how to obtained biased tracer fields. The
# Gaussian angular power spectra could be obtained in any number of ways.

# this is the bias we want to implement
bias = 1.8

# apply linear bias factor to the cls
cls_b = biased_cls(cls, bias)

# compute Gaussian cls for the biased lognormal galaxy fields
gls_b = lognormal_gls(cls_b)

# %%
# This example will produce an integrated density for the unbiased and biased
# fields. Here, we are making an example *dndz* distribution, and computing
# its contribution to each matter shell.

# localised redshift distribution
# the actual density per arcmin2 does not matter here, it is never used
z = np.linspace(0, 1, 101)
dndz = np.exp(-(z - 0.5)**2/(0.1)**2)

# partition the dndz function into a ngal value for each shell
ngal = partition(z, dndz, shells)

# %%
# Simulation
# ----------
# The simulation generates the Gaussian *alm* for each matter shell and
# computes its lognormal matter field. The *alm* array is rescaled with the
# biased *gls* to compute the biased lognormal tracer field. Both are then
# added to an integrated number density field, using the shell's contribution
# *ngal* to the total redshift distribution.

# initialise maps for biased and unbiased total number densities
ntot = np.zeros(12 * nside**2)
ntot_b = np.zeros(12 * nside**2)

# main loop to simulate the matter fields iteratively
for i, alm in enumerate(alms):

# first, compute the lognormal matter field
delta = alm_to_lognormal(alm, nside)

# now rescale the alm to the biased lognormal field for galaxies
alm_b = rescaled_alm(alm, getcl(gls_b, i), getcl(gls, i))

# compute the biased lognormal galaxies field
delta_b = alm_to_lognormal(alm_b, nside)

# add both fields to number density
ntot += ngal[i] * (1 + delta)
ntot_b += ngal[i] * (1 + delta_b)

# %%
# Analysis
# --------
# To make sure the biased tracer field works as expected, we compute the
# density contrast of the unbiased and biased integrated fields, then compare
# their bias to the linear bias factor we used above.

# this is the mean number density over the entire distribution
nbar = np.trapz(dndz, z)

# compute the integrated density contrasts
delta_tot = (ntot - nbar)/nbar
delta_tot_b = (ntot_b - nbar)/nbar

# get the angular power spectra of the number density maps
sim_cls = hp.anafast([delta_tot, delta_tot_b],
pol=False, lmax=lmax, use_pixel_weights=True)

# plot the unbiased and biased cls
l = np.arange(lmax+1)
fig, ax = plt.subplots(2, 1, sharex=True, sharey=True, layout="constrained")
ax[0].plot(l, (sim_cls[1]/sim_cls[0])**0.5, "-k", lw=2, label="simulated bias (biased $\\times$ biased)")
ax[0].axhline(bias, c="r", ls="-", lw=1, label="bias factor")
ax[0].legend(frameon=False)
ax[0].set_ylabel(r"bias factor")
ax[1].plot(l, sim_cls[2]/sim_cls[0], "-k", lw=2, label="simulated bias (biased $\\times$ unbiased)")
ax[1].axhline(bias, c="r", ls="-", lw=1, label="bias factor")
ax[1].legend(frameon=False)
ax[1].set_ylabel(r"bias factor")
ax[1].set_xscale("log")
ax[1].set_xlabel(r"angular mode number $l$")
ax[1].set_ylim(bias - 0.25, bias + 0.25)
plt.show()

# %%
# The results show that the biased lognormal tracer is able to capture the
# linear bias in the auto-correlation of the biased tracer reasonably well.
# **However, there is a significant deviation from the linear model in the
# cross-correlation between biased tracer and unbiased field.** The "defect"
# in the model is roughly a function of the amplitude of the spectrum, and
# hence tendentially worse for lower redshifts, higher :math:`sigma_8` values,
# and higher bias values. The biased lognormal tracer model should therefore
# only be used where this defect is acceptable.
Binary file removed examples/basic/cls.npy
Binary file not shown.
Binary file added examples/basic/cls.npz
Binary file not shown.
10 changes: 7 additions & 3 deletions examples/basic/plot_density.py → examples/basic/galaxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import glass.fields
import glass.points
import glass.galaxies
import glass.user


# cosmology for the simulation
Expand All @@ -52,14 +53,17 @@
ws = glass.shells.tophat_windows(zb)

# load the angular matter power spectra previously computed with CAMB
cls = np.load('cls.npy')
cls = glass.user.load_cls('cls.npz')

# angular discretisation with 3 correlated shells
cls = glass.fields.discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

# %%
# Matter
# ------

# compute Gaussian cls for lognormal fields for 3 correlated shells
gls = glass.fields.lognormal_gls(cls, nside=nside, lmax=lmax, ncorr=3)
# compute Gaussian cls for lognormal fields
gls = glass.fields.lognormal_gls(cls)

# generator for lognormal matter fields
matter = glass.fields.generate_lognormal(gls, nside, ncorr=3)
Expand Down
12 changes: 8 additions & 4 deletions examples/basic/plot_lensing.py → examples/basic/lensing.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import glass.fields
import glass.lensing
import glass.galaxies
import glass.user


# cosmology for the simulation
Expand All @@ -60,15 +61,18 @@
ws = glass.shells.tophat_windows(zb)

# load the angular matter power spectra previously computed with CAMB
cls = np.load('cls.npy')
cls = glass.user.load_cls('cls.npz')

# angular discretisation with 3 correlated shells
# putting nside here means that the HEALPix pixel window function is applied
cls = glass.fields.discretized_cls(cls, nside=nside, lmax=lmax, ncorr=3)

# %%
# Matter
# ------

# compute Gaussian cls for lognormal fields for 3 correlated shells
# putting nside here means that the HEALPix pixel window function is applied
gls = glass.fields.lognormal_gls(cls, nside=nside, lmax=lmax, ncorr=3)
# compute Gaussian cls for lognormal fields
gls = glass.fields.lognormal_gls(cls)

# generator for lognormal matter fields
matter = glass.fields.generate_lognormal(gls, nside, ncorr=3)
Expand Down
10 changes: 7 additions & 3 deletions examples/basic/matter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
# these are the GLASS imports: matter and random fields
import glass.shells
import glass.fields
import glass.user


# cosmology for the simulation
Expand All @@ -48,10 +49,13 @@
zb = glass.shells.distance_grid(cosmo, 0., 1., dx=200.)

# load precomputed angular matter power spectra
cls = np.load('cls.npy')
cls = glass.user.load_cls('cls.npz')

# compute Gaussian cls for lognormal fields with 3 correlated shells
gls = glass.fields.lognormal_gls(cls, ncorr=3, nside=nside)
# angular discretisation with 3 correlated shells
cls = glass.fields.discretized_cls(cls, nside=nside, ncorr=3)

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

# this generator will yield the matter fields in each shell
matter = glass.fields.generate_lognormal(gls, nside, ncorr=3)
Expand Down
20 changes: 8 additions & 12 deletions examples/basic/shells.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
# Here we define the shells for these examples, and use CAMB to compute the
# angular matter power spectra for the shell definitions.

import numpy as np
import camb
from cosmology import Cosmology

import glass.shells
import glass.ext.camb
from glass.shells import distance_grid, tophat_windows
from glass.ext.camb import matter_cls, camb_tophat_weight
from glass.user import save_cls


# cosmology for the simulation
Expand All @@ -41,18 +41,14 @@
cosmo = Cosmology.from_camb(pars)

# shells of 200 Mpc in comoving distance spacing
zb = glass.shells.distance_grid(cosmo, 0., 1., dx=200.)
zgrid = distance_grid(cosmo, 0., 1., dx=200.)

# uniform matter weight function
# CAMB requires linear ramp for low redshifts
ws = glass.shells.tophat_windows(zb, weight=glass.ext.camb.camb_tophat_weight)
shells = tophat_windows(zgrid, weight=camb_tophat_weight)

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


# %%
# Save
# ----
# We save the shell definitions to file, for use in other examples.
np.save('cls.npy', cls)
# save the angular power spectra to file, to use in other examples
save_cls("cls.npz", cls)