Phys165 - Fall 2019
Lab 1 - Fitting SN1a magnitude vs redshift data for $\Omega_M$ and $\Omega_\Lambda$
Author: Evan Shipley
Date: 09/26/2019
We will now extend our work from homework 3 to include magnitude vs redshift data to higher redshift. The data are in the file:
'SN1A_data.csv'
In homework 3, the theoretical relation we used was:
$m(z) = M' + 5 \log_{10} d_L(z;\Omega_M,\Omega_\Lambda) \; \approx M' + 5 \log_{10}z \;\;\; for \; z<<1$
However, for this lab, we must now use the full prediction for the luminosty distance $d_L$, which is a function of the cosmological parameters $\Omega_M,\Omega_\Lambda$.
You are being asked to use the scipy function "curve_fit" to estimate the best fit parameters for $\Omega_M,\Omega_\Lambda$ with the data you are given in the file.
The full function for $d_L$ is:
$d_L(z;\Omega_M,\Omega_\Lambda) = \frac{(1+z)}{\sqrt{|k|}} S(\sqrt{|k|}\int_0^z [(1+z')^2(1+\Omega_M z') -z'(2+z')\Omega_\Lambda]^{-1/2} dz' $
where,
$\begin{array}{lccr} S(x) = sin(x) & k=1-\Omega_M-\Omega_\Lambda & for &\Omega_M+\Omega_\Lambda > 1 \\ S(x) = sinh(x) & k=1-\Omega_M-\Omega_\Lambda & for & \Omega_M+\Omega_\Lambda < 1 \\ S(x) = x & k=1 & for & \Omega_M+\Omega_\Lambda = 1 \end{array}$
Lab 1: write code below to
1) read in the magnitude vs redshift data from 'SN1A_data.csv'
2) write a user defined function for the theory of magnitude vs redshift that is also a function of the cosmological parameters $\Omega_M$ and $\Omega_\Lambda$
3) Plot the mag vs redshift data and best fit on top subplot and residuals vs redshift on bottom subplot clearly showing best fit parameters ($\Omega_M,\Omega_\Lambda$), $\chi_\nu^2$ and $\chi^2$ probability
4) write a user defined function for the theory of magnitude vs redshift that is also a function of the cosmological parameters $\Omega_M$ and $\Omega_\Lambda$, but, with $\Omega_M +\Omega_\Lambda$ constrained to 1.0
5) Plot the mag vs redshift data and best fit on top subplot and residuals vs redshift on bottom subplot, for the constrained case, clearly showing best fit parameters ($\Omega_M,\Omega_\Lambda$), $\chi_\nu^2$ and $\chi^2$ probability
"""
Program to read in magnitude vs redshift data from file
'SN1A_data.csv'
and fit for cosmological parameters Omega_Matter , Omega_Lambda
"""
#standard library modules
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# for numerical integration
from scipy.integrate import quad
#need this for chi**2 probability
import scipy.stats as st
#for curve fit
from scipy.optimize import curve_fit
"""
These provided user functions; I_z and D_l together give
the luminosity distance to be used in
m(z) = M'+5*log10(D_l[z;Om_M,Om_L]) from the reference
astro-ph/9608192v2
The call to D_l returns the distance, D_l calls I_z
requires:
import numpy as np
from scipy.integrate import quad
called above.
"""
def I_z(x,O_M,O_L):
"""
Integrand from paper
O_M = Omega_matter
O_L = Omega_Lambda
x = integration over z'
"""
# Integral part of full function from astro-ph/9608192v2
Integral = 1./np.sqrt((1.+x)**2*(1.+O_M*x)-x*(2.+x)*O_L)
return Integral
def D_l(z,Om_M,Om_L):
"""
calculates the luminosty distance
m(z) = M'+5*log10(D_l[z;Om_M,Om_L])
as a function of redshift (z) given the
cosmological parameters Om_m and Om_L
inputs:
z = array of redshifts
Om_M = Omega Matter
Om_L = Omega Lambda
returns:
D_l(z) = array of Luminosity distances corresonding to z
"""
# first do the integral
zrange = z
intgrl = np.zeros(np.size(zrange))
for i in range(np.size(zrange)):
intgrl[i],err = quad(I_z,0,zrange[i],args=(Om_M,Om_L))
# full function from astro-ph/9608192v2
if (Om_M + Om_L) < 0.999:
K=np.sqrt(np.abs(1.-Om_M-Om_L))
S = np.sinh(K*intgrl)
elif (Om_M + Om_L) > 1.001:
K=np.sqrt(np.abs(1.-Om_M-Om_L))
S = np.sin(K*intgrl)
else:
K=1.
S = K*intgrl
D = (1.0 + z) * S / K
return D
# your code here...
Z, Sig_z, Mag, Sig_M = np.loadtxt('SN1A_data.csv',delimiter=',',unpack=True)
def thry (Z,Om_M,Om_L):
M=23.95
return M+5.0*np.log10(D_l(Z,Om_M,Om_L))
def thry_constrained (Z,Om_M):
M=23.95
Om_L=1.0-Om_M
return M+5.0*np.log10(D_l(Z,Om_M,Om_L))
def thry_constrained_returnOmL (Z,Om_L):
M=23.95
Om_M=1.0-Om_L
return M+5.0*np.log10(D_l(Z,Om_M,Om_L))
p0=.4,.7
popt,pcov=curve_fit(thry,Z,Mag,p0,sigma=Sig_M,absolute_sigma=True)
OmM=popt[0]
OmL=popt[1]
#print(OmM)
#print(OmL)
p0=.3
popt,pcov=curve_fit(thry_constrained,Z,Mag,p0,sigma=Sig_M,absolute_sigma=True)
OmMfit=popt[0]
#print(OmMfit)
p0=.6
popt,pcov=curve_fit(thry_constrained_returnOmL,Z,Mag,p0,sigma=Sig_M,absolute_sigma=True)
OmLfit=popt[0]
#print(OmLfit)
i=np.argsort(Z)
def chi_squared(Theory,Data,sigma):
if np.size(thry(Z[i],OmM,OmL))==np.size(Mag) and np.size(Mag)==np.size(Sig_z):
chi2=np.sum((thry(Z[i],OmM,OmL)-Mag[i])**2/Sig_M[i]**2)
return chi2
else:
print('error - arrays of unequal size')
return -1.
def chi_squared_constrained(Theory,Data,sigma):
if np.size(thry_constrained(Z[i],OmMfit))==np.size(Mag) and np.size(Mag)==np.size(Sig_z):
chi2=np.sum((thry_constrained(Z[i],OmMfit)-Mag[i])**2/Sig_M[i]**2)
return chi2
else:
print('error - arrays of unequal size')
return -1.
dof=np.size(Z)-1
chi2=chi_squared(thry(Z[i],OmM,OmL),Mag[i],Sig_M[i])
chi_2=chi2/dof
chi2_constrained=chi_squared_constrained(thry_constrained(Z[i],OmMfit),Mag[i],Sig_M[i])
chi_2_constrained=chi2_constrained/dof
#print(chi2)
#print(chi2_constrained)
prob=st.chi2.sf(chi2,dof)
prob_constrained=st.chi2.sf(chi2_constrained,dof)
f=plt.figure(figsize=(16,10))
f=plt.subplot2grid((5,1),(0,0),rowspan=3)
f=plt.errorbar(Z,Mag,xerr=Sig_z,yerr=Sig_M,fmt='.',label='Data');
Z_plot=np.linspace(0.01,.9,1000)
plt.plot(Z_plot,thry(Z_plot,OmM,OmL),label='Theory')
plt.xlim(0,0.9)
plt.legend()
plt.grid(True,linestyle='--')
plt.title('Hubble Diagram $\Omega_{M}$, $\Omega_{L}$ Unconstrained')
plt.xlabel('Redshift ($z$)')
plt.ylabel('Magnitude ($M$)')
plt.ticklabel_format(axis='y',style='sci',scilimits=(0,3))
plt.text(.8,16,r'$\chi_v^2$ = {:.2f}'.format(chi_2),size=13)
plt.text(.8,15,r'Prob = {:.1%}'.format(prob),size=13)
plt.text(.8,19,r'$\Omega_M$ = {:.3g}'.format(OmM),size=13)
plt.text(.8,18,r'$\Omega_L$ = {:.3g}'.format(OmL),size=13)
res1plot=plt.figure(figsize=(16,8))
res1plot=plt.subplot2grid((5,1),(0,0),rowspan=2)
res=Mag-thry(Z,OmM,OmL)
plt.errorbar(Z,res,yerr=Sig_M,fmt='o')
plt.xlim(0,0.9) #setting limits for x-axis
plt.plot([0,0.9],[0,0]) #plot flat line at residual=0 from x=0->.11
plt.xlabel('Redshift ($z$)')
plt.ylabel('Residuals')
plt.grid(True,linestyle='--')
plt.ticklabel_format(axis='y',style='sci',scilimits=(0,3))
h=plt.figure(figsize=(16,10))
h=plt.subplot2grid((5,1),(0,0),rowspan=3)
plt.errorbar(Z,Mag,xerr=Sig_z,yerr=Sig_M,fmt='.',label='Data',color='crimson');
Z_plot=np.linspace(0.01,.9,1000)
plt.plot(Z_plot,thry_constrained(Z_plot,OmMfit),label='Theory',color='turquoise')
plt.xlim(0,0.9)
plt.legend()
plt.grid(True,linestyle='--')
plt.title('Hubble Diagram $\Omega_{M}+\Omega_{L}=1$')
plt.xlabel('Redshift ($z$)')
plt.ylabel('Magnitude ($M$)')
plt.ticklabel_format(axis='y',style='sci',scilimits=(0,3))
plt.text(.8,16,r'$\chi_v^2$ = {:.2f}'.format(chi_2_constrained),size=13)
plt.text(.8,15,r'Prob = {:.1%}'.format(prob_constrained),size=13)
plt.text(.8,19,r'$\Omega_M$ = {:.3g}'.format(OmMfit),size=13)
plt.text(.8,18,r'$\Omega_L$ = {:.3g}'.format(OmLfit),size=13)
res2plot=plt.figure(figsize=(16,8))
res2plot=plt.subplot2grid((5,1),(0,0),rowspan=2)
res2=Mag-thry_constrained(Z,OmMfit)
plt.errorbar(Z,res2,yerr=Sig_M,fmt='o',color='crimson')
plt.xlim(0,0.9) #setting limits for x-axis
plt.plot([0,0.9],[0,0],color='turquoise') #plot flat line at residual=0 from x=0->.11
plt.xlabel('Redshift ($z$)')
plt.ylabel('Residuals')
plt.grid(True,linestyle='--')
plt.ticklabel_format(axis='y',style='sci',scilimits=(0,3))
#plt.figure(figsize=(10,8)) #This method of plotting the errorbars using sorted data
#plt.subplot2grid((5,1),(0,0),rowspan=3) #gave slightly different errorbars so I stayed with
#plt.errorbar(Z[i],Mag[i],xerr=Sig_z[i],yerr=Sig_M[i],fmt='.',label='Data') #plotting before sorting
#plt.plot(Z_plot,thry(Z_plot,OmM,OmL),label='Theory');
#for some reason the scilimits on the y-axis residuals did not work this time so my Theory/data plots' x axes
#and their residuals' x axes are not perfectly aligned like they were in HW 3