DES SN 5YR Tutorial Part 6: Demonstrate cosmology analysis using Des SN 5 year

85632ed57bd84cff9b2e51c2663e011e Dark Energy Survey Supernova Program

Tutorial Cosmology analysis using DES SN 5 year Contact author: Paul Shah

Sheet to demonstrate cosmology analysis using Des SN 5 year

Results will not exactly match Key Paper due to settings, use of Astropy (instead of CAMB) etc.

To run this sheet you will need :

[1]:
import warnings
warnings.filterwarnings("ignore")
[2]:
import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from astropy.cosmology import FlatwCDM, FlatLambdaCDM
import pandas as pd

import pypolychord
from pypolychord.settings import PolyChordSettings
from pypolychord.priors import UniformPrior
[3]:
# setup MPI env for Polychord (you will need to have installed Polychord using MPI compilation option)
%env OMP_NUM_THREADS=8
%env OPENBLAS_NUM_THREADS=8
%env MKL_NUM_THREADS=8
%env VECLIB_MAXIMUM_THREADS=8
%env NUMEXPR_NUM_THREADS=8

mpl.rcParams['figure.figsize'] = (10, 10)
env: OMP_NUM_THREADS=8
env: OPENBLAS_NUM_THREADS=8
env: MKL_NUM_THREADS=8
env: VECLIB_MAXIMUM_THREADS=8
env: NUMEXPR_NUM_THREADS=8
[4]:
import os
from dessndr import data, utils

You will need to download the Hubble diagram and covariance matrix from the GitHub repo, and unzip the cov. mat. Then set the path to your downloaded data location.

[5]:
path = os.path.join(data.DES5YRDR_DATA, "4_DISTANCES_COVMAT/")

snfile = path + "DES-SN5YR_HD.csv"
covfile = path + "STAT+SYS.txt"

Note : zHD is the appropriate redshift to use in cosmological formulae, as it has been corrected for host peculiar velocities (eg see https://arxiv.org/pdf/1012.2912, Eqn 15)

[6]:
(_, _, _, zhd, zhel, mu, muerr)  = np.genfromtxt(snfile, delimiter=',', dtype=np.float32, unpack=True, skip_header=1)
nsn = len(zhd)

cov = np.genfromtxt(covfile)
cov = cov[1:]
cov = cov.reshape((nsn, nsn))

The covariance matrix is systematics only so add statistical error to the diagonal

note : the statistical errors incorporate the probability of SN mis-classification (see https://arxiv.org/pdf/2401.02929.pdf) this down-weights likely contaminants (which mostly lie above the Hubble diagram) in the cosmology fit
[7]:
np.fill_diagonal(cov, cov.diagonal() + muerr**2)
invcov = np.linalg.inv(cov)
invvars = 1/cov.diagonal()

print('Loaded ',nsn, ' sn')
Loaded  1829  sn

The DES-SN5YR sample is uncalibrated and doesn’t measure H0 the relevant combination is

'script M' = M + 5 log10(c/H0)

Here, for pedagogical purposes, H0 and M are individual parameters, which allows this likelihood to be combined with SN calibrators such as the CMB or M-priors (eg SH0ES)

For the likelihood analytically marginalised over M, see 5_COSMOLOGY/SN_only_cosmosis_likelihood.py

[8]:
nDims = 3
nDerived = 1 # as an example usage, derived variable is q0 acceleration parameter in Flat wCDM

SN Ia on their own don’t constrain H0 unless you have calibrated their absolute luminosity M

Here we marginalise over ‘script M’ which is a (degenerate) combination of M and H0

See equations A9 - A12 of Goliath++ at https://arxiv.org/abs/astro-ph/0104009

h0ref is just set for convenience

[9]:
h0ref = 70

def likelihood(theta):

    cosmo = FlatwCDM(H0=h0ref, Om0=theta[0], w0 =theta[1])
    scriptM = theta[2]
    ld = cosmo.luminosity_distance(zhd).value*(1+zhel)/(1+zhd)  #don't use astropy distmod, this formula correctly adjusts for peculiar velocities
    distmod = 5*np.log10(ld)+25
    residual = mu + scriptM - distmod
    residualT = np.transpose(residual)

    chit2 = np.sum(residual @ invcov @ residualT)
    B = np.sum(residual @ invcov)
    C = np.sum(invcov)
    chi2 = chit2 - (B**2 / C) + np.log(C / (2* np.pi))

    q0 = 0.5*(theta[0]+(1+3*theta[1])*(1-theta[0]))

    return -0.5*chi2, [q0]

Uses flat priors for parameters between ranges as below.

Other prior forms are available, see https://github.com/PolyChord/PolyChordLite

[10]:
def prior(hypercube):
    """ Uniform prior from [-1,1]^D. """
    mins = np.array((0.1,-1.5,-1), dtype=float)
    maxs = np.array((0.5,-0.5,1), dtype=float)
    return UniformPrior(mins, maxs)(hypercube)
[11]:
def dumper(live, dead, logweights, logZ, logZerr):
    print("Last dead point:", dead[-1])
[12]:
# Main Polychord settings : uses recommended values
# for a quick run use nlive = 5*nDims, precision_criterion = 0.1
# seed is set for replicability of run

settings = PolyChordSettings(nDims, nDerived)
settings.file_root = 'dessn_fwcdm'
settings.nlive = 25*nDims
settings.num_repeats = 2*nDims
settings.nprior = 10*settings.nlive
settings.feedback = 1
settings.precision_criterion = 0.01
settings.seed = 1234

# Secondary ones :
settings.compression_factor = 0.36787944117144233
settings.logzero = -1.0e+30
settings.boost_posterior = 0
settings.posteriors = True
settings.equals = True
settings.cluster_posteriors = False
settings.write_stats = True
settings.write_dead = True
settings.write_live = True
settings.write_paramnames = True
settings.write_prior= True
settings.do_clustering = False
settings.read_resume = False
settings.write_resume = False
[13]:
output = pypolychord.run_polychord(likelihood, nDims, nDerived, settings, prior, dumper)
output

PolyChord: Next Generation Nested Sampling
copyright: Will Handley, Mike Hobson & Anthony Lasenby
  version: 1.22.1
  release: 10th Jan 2024
    email: wh260@mrao.cam.ac.uk

Run Settings
nlive    :      75
nDims    :       3
nDerived :       1
Synchronous parallelisation
Generating equally weighted posteriors
Generating weighted posteriors

generating live points


all live points generated

Speed  1 =  0.154E+00 seconds
number of repeats:            6
started sampling

Last dead point: [ 1.98631142e-01 -6.43021234e-01 -7.76498634e-01 -2.72945787e-01
 -1.00000000e+30 -8.25934729e+02]
_______________
lives      |75 |
phantoms   | 5 |
posteriors | 0 |
equals     | 0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                 676
nposterior =                 676
nequals    =                  19
nlike      =                 778
<nlike>    =           0.37   (           0.06 per slice )
log(Z)     =         -829.63 +/-  0.15
log(Z_1)   =         -829.63 +/-  0.15 (still evaluating)



Last dead point: [ 2.28762712e-01 -7.03182250e-01 -2.08795187e-01 -3.13480557e-01
 -1.00000000e+30 -8.24634238e+02]
________________
lives      | 75 |
phantoms   |235 |
posteriors |  0 |
equals     |  0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                 752
nposterior =                 752
nequals    =                  79
nlike      =                2401
<nlike>    =          21.64   (           3.61 per slice )
log(Z)     =         -827.78 +/-  0.11
log(Z_1)   =         -827.78 +/-  0.11 (still evaluating)



Last dead point: [ 2.36842748e-01 -7.70688244e-01 -6.86845389e-01 -3.82234484e-01
 -8.24093109e+02 -8.24078321e+02]
________________
lives      | 75 |
phantoms   |299 |
posteriors |  0 |
equals     |  0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                 828
nposterior =                 828
nequals    =                 138
nlike      =                4122
<nlike>    =          22.95   (           3.82 per slice )
log(Z)     =         -827.24 +/-  0.11
log(Z_1)   =         -827.24 +/-  0.11 (still evaluating)



Last dead point: [ 2.28628959e-01 -7.37125238e-01  4.27208274e-01 -3.52895593e-01
 -8.23948949e+02 -8.23925783e+02]
________________
lives      | 75 |
phantoms   |330 |
posteriors |  0 |
equals     |  0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                 904
nposterior =                 904
nequals    =                 165
nlike      =                5778
<nlike>    =          22.08   (           3.68 per slice )
log(Z)     =         -827.05 +/-  0.11
log(Z_1)   =         -827.05 +/-  0.11 (still evaluating)



Last dead point: [ 2.51492949e-01 -7.81301625e-01  5.72502154e-01 -3.77214662e-01
 -8.23882993e+02 -8.23867043e+02]
________________
lives      | 75 |
phantoms   |331 |
posteriors |  0 |
equals     |  0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                 980
nposterior =                 980
nequals    =                 173
nlike      =                7461
<nlike>    =          22.44   (           3.74 per slice )
log(Z)     =         -826.98 +/-  0.11
log(Z_1)   =         -826.98 +/-  0.11 (still evaluating)



Last dead point: [ 2.57543945e-01 -7.81929201e-01 -7.71832538e-01 -3.70822105e-01
 -8.23856322e+02 -8.23845488e+02]
________________
lives      | 75 |
phantoms   |357 |
posteriors |  0 |
equals     |  0 |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
ncluster   =       1 /       1
ndead      =                1056
nposterior =                1056
nequals    =                 178
nlike      =                9139
<nlike>    =          22.37   (           3.73 per slice )
log(Z)     =         -826.95 +/-  0.11
log(Z_1)   =         -826.95 +/-  0.11 (still evaluating)



Last dead point: [ 2.66747377e-01 -8.02002394e-01 -9.11009851e-01 -3.82105539e-01
 -8.23851691e+02 -8.23834548e+02]
[13]:
Global evidence:
log(Z)    -826.937678 +/-  0.113245

Local evidences:
log(Z_1)    -826.937678 +/-  0.113245

Run-time information:
ncluster          1
nposterior     1160
nequals         182
ndead          1160
nlive             0
nlike          9768
<nlike>       [0.0]

Parameter estimates:
p0     2.605E-01 +/- 7.200E-02
p1    -8.109E-01 +/- 1.301E-01
p2    -4.594E-02 +/- 5.692E-01
p3    -3.862E-01 +/- 6.477E-02
 ____________________________________________________
|                                                    |
| ndead  =         1160                              |
| log(Z) =         -826.93768 +/-            0.11324 |
|____________________________________________________|
[14]:
paramnames = [('Omega_m','\Omega_m'), ('w','w'), ('M','M') ,('q0','q_0')]
output.make_paramnames_files(paramnames)
try:
    import getdist.plots
    %matplotlib inline
    posterior = output.posterior
    g = getdist.plots.getSubplotPlotter(width_inch=10, scaling=False, rc_sizes=True)
    g.settings.legend_fontsize = 16
    g.settings.axes_fontsize=12
    g.settings.axes_labelsize =12

    g.triangle_plot(posterior, ['Omega_m', 'w','q0'],
    filled=True,
    legend_labels=['Flat wCDM'],
    legend_loc='upper right',
    line_args=[{'ls':'--', 'color':'green'},
               {'lw':2, 'color':'darkblue'}],
    contour_colors=['green','darkblue'],
    title_limit=1, # first title limit (for 1D plots) is 68% by default
    markers={'w':-1})
except ImportError:
    print("Install matplotlib and getdist for plotting examples")
WARNING:root:outlier fraction 0.20270270270270271
chains/dessn_fwcdm.txt
Removed no burn in
../_images/tutorial_06-Cosmology-DESSN5YR_Flat_wCDM_22_2.png