[1]:
import os, sys
import numpy as np
import corner

# sys.path.append('../')
import py21cmfish as p21fish

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.mathtext as mathtext
import matplotlib.lines as mlines

%matplotlib inline

plt.style.use(['default','seaborn','seaborn-ticks'])
mpl.rcParams['xtick.direction'] = 'in'
mpl.rcParams['ytick.direction'] = 'in'
mpl.rcParams['figure.figsize'] = (4,3)
mpl.rcParams['figure.dpi'] = 150

if os.path.exists(os.environ['WORK_DIR']+'/code/matplotlibrc'):
    from matplotlib import rc_file
    rc_file(os.environ['WORK_DIR']+'/code/matplotlibrc')

    mathtext.FontConstantsBase.sup1 = 0.5
    mathtext.FontConstantsBase.sub1 = 0.2
    mathtext.FontConstantsBase.sub2 = 0.2
[3]:
# Color palette
try:
    from palettable.tableau import Tableau_20, ColorBlind_10
    cols = ColorBlind_10.hex_colors

    col_pess  = cols[6]
    col_mod   = cols[0]
    col_alpha = 'k'
    col_mcmc  = cols[3]
    col_P19   = cols[1]

except:
    col_pess  = '0.5'
    col_mod   = 'tab:blue'
    col_alpha = 'k'
    col_mcmc  = '0.7'
    col_P19   = 'tab:orange'
[4]:
%load_ext autoreload
%autoreload 2

Fisher plots

This notebook loads and plots posteriors based on the 21cm power spectrum for the 21cmfish paper.

To run the notebook you must first unpack the data directories in /examples/

  1. EOS21 - CDM fiducial with pop II and pop III galaxies

  2. Comparison with Park+19

  3. Adding your own new parameter

[23]:
p21fish.base_path = '/Users/cmason/Documents/Research/21cmFAST/21cmfish/'

examples_dir = p21fish.base_path+'examples/'
data_dir     = examples_dir+'data/'

noise_dir = data_dir+'21cmSense_noise/'
figs_dir  = examples_dir

print('Loading data from',data_dir)
Loading data from /Users/cmason/Documents/Research/21cmFAST/21cmfish/examples/data/

EOS21

This is a fiducial case from Munoz+2021 with CDM, and with both pop II and pop III galaxies.

[7]:
# Find the parameters we varied and fiducials from the config file
# but you could also list these yourself (especially if you want to change the order)
print(p21fish.base_path+'21cmFAST_config_files/EoS_mini.config')
astro_params_vary, astro_params_fid = p21fish.get_params_fid(
                                        config_file=p21fish.base_path+'21cmFAST_config_files/EoS_mini.config')

print('Varying parameters:',astro_params_vary)
print('Fiducial parameter values:',astro_params_fid)

assert type(astro_params_vary) == list, 'astro_params_vary must be a list'
assert type(astro_params_fid) == dict, 'astro_params_vary must be a dict'
/Users/cmason/Documents/Research/21cmFAST/21cmfish/21cmFAST_config_files/EoS_mini.config
Varying parameters: ['ALPHA_STAR', 'F_STAR10', 'ALPHA_ESC', 'F_ESC10', 'ALPHA_STAR_MINI', 'F_STAR7_MINI', 'F_ESC7_MINI', 'L_X', 'NU_X_THRESH', 'A_LW']
Fiducial parameter values: {'ALPHA_ESC': -0.3, 'F_ESC10': -1.35, 'ALPHA_STAR': 0.5, 'F_STAR10': -1.25, 't_STAR': 0.5, 'F_STAR7_MINI': -2.5, 'ALPHA_STAR_MINI': 0.0, 'F_ESC7_MINI': -1.35, 'L_X': 40.5, 'L_X_MINI': 40.5, 'NU_X_THRESH': 500.0, 'A_VCB': 1.0, 'A_LW': 2.0}

Load parameters

Moderate noise

[9]:
# Load each parameter into a dictionary
params_EoS = {}
astro_params_vary_EoS = ['F_STAR10', 'ALPHA_STAR', 'F_ESC10', 'ALPHA_ESC',
                         'F_STAR7_MINI', 'ALPHA_STAR_MINI', 'F_ESC7_MINI', 'A_LW', 'L_X', 'NU_X_THRESH',]

for param in astro_params_vary_EoS:
    params_EoS[param] = p21fish.Parameter(param=param,
                                          output_dir=data_dir+'EOS21/',
                                          PS_err_dir=noise_dir+'21cmSense_fid_EOS21/',
                                          clobber=False, Park19=None,
                                          vb=False, new=False)
########### fisher set up for F_STAR10
    Loading global signal and power spectra from saved files
    Fiducial: F_STAR10=-1.25
########### fisher set up for ALPHA_STAR
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_STAR=0.5
########### fisher set up for F_ESC10
    Loading global signal and power spectra from saved files
    Fiducial: F_ESC10=-1.35
########### fisher set up for ALPHA_ESC
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_ESC=-0.3
########### fisher set up for F_STAR7_MINI
    Loading global signal and power spectra from saved files
    Fiducial: F_STAR7_MINI=-2.5
########### fisher set up for ALPHA_STAR_MINI
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_STAR_MINI=0.0
########### fisher set up for F_ESC7_MINI
    Loading global signal and power spectra from saved files
    Fiducial: F_ESC7_MINI=-1.35
########### fisher set up for A_LW
    Loading global signal and power spectra from saved files
    Fiducial: A_LW=2.0
########### fisher set up for L_X
    Loading global signal and power spectra from saved files
    Fiducial: L_X=40.5
########### fisher set up for NU_X_THRESH
    Loading global signal and power spectra from saved files
    Fiducial: NU_X_THRESH=500.0

Pessimistic noise

[10]:
# Load each parameter into a dictionary
params_EoS_pess = {}

for param in astro_params_vary_EoS:
    params_EoS_pess[param] = p21fish.Parameter(param=param,
                                          output_dir=data_dir+'EOS21/',
                                          PS_err_dir=noise_dir+'21cmSense_pess_EOS21/',
                                          clobber=False, Park19=None,
                                          vb=False)
########### fisher set up for F_STAR10
    Loading global signal and power spectra from saved files
    Fiducial: F_STAR10=-1.25
########### fisher set up for ALPHA_STAR
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_STAR=0.5
########### fisher set up for F_ESC10
    Loading global signal and power spectra from saved files
    Fiducial: F_ESC10=-1.35
########### fisher set up for ALPHA_ESC
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_ESC=-0.3
########### fisher set up for F_STAR7_MINI
    Loading global signal and power spectra from saved files
    Fiducial: F_STAR7_MINI=-2.5
########### fisher set up for ALPHA_STAR_MINI
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_STAR_MINI=0.0
########### fisher set up for F_ESC7_MINI
    Loading global signal and power spectra from saved files
    Fiducial: F_ESC7_MINI=-1.35
########### fisher set up for A_LW
    Loading global signal and power spectra from saved files
    Fiducial: A_LW=2.0
########### fisher set up for L_X
    Loading global signal and power spectra from saved files
    Fiducial: L_X=40.5
########### fisher set up for NU_X_THRESH
    Loading global signal and power spectra from saved files
    Fiducial: NU_X_THRESH=500.0

Fisher matrix analysis

make_fisher_matrix() creates the Fisher matrix and its inverse from a Parameters dictionary. The resulting ellipses can be plotted with plot_triangle().

[11]:
Fij_matrix_PS, Finv_PS = p21fish.make_fisher_matrix(params_EoS, fisher_params=astro_params_vary_EoS,
                                                     hpeak=0.0, obs='PS',
                                                     k_min=0.1, k_max=1,
                                                     z_min=5., z_max=30.,
                                                     sigma_mod_frac=0.2,
                                                     add_sigma_poisson=True)

fid_params = np.array([astro_params_fid[param] for param in params_EoS])
fid_labels = np.array([p21fish.astro_params_labels[param] for param in params_EoS])
PS shape: (23, 24)
[12]:
p21fish.plot_triangle(params=astro_params_vary_EoS,
                      fiducial=fid_params,
                      labels=fid_labels,
                      cov=Finv_PS,
                      ellipse_color=col_mod,
                      title_fontsize=14,
                      xlabel_kwargs={'labelpad': 5, 'fontsize':22},
                      ylabel_kwargs={'labelpad': 5, 'fontsize':22},
                      fig_kwargs={'figsize':(18,18)});

plt.savefig(figs_dir+'corner_EoS_mini_fisher.png', bbox_inches='tight')
generating new axis
../_images/tutorials_fisher_examples_13_1.png

Add a prior

E.g. Park+2019 find \(\sigma(\alpha_\star^{II}) \approx 0.07\).

To add a prior, we can add 1/\(\sigma^2\) to the diagonal element for that parameter (e.g. Coe 2009)

[13]:
sigma_alpha_star_II = 0.07
idx_alpha_star = list(params_EoS).index("ALPHA_STAR")
print(f'ALPHA_STAR is at index={idx_alpha_star}')
Fij_matrix_PS_alpha_star_prior = Fij_matrix_PS.copy()
Fij_matrix_PS_alpha_star_prior[idx_alpha_star,idx_alpha_star] += 1/sigma_alpha_star_II**2.

Finv_alpha_star_prior = np.linalg.inv(Fij_matrix_PS_alpha_star_prior)
ALPHA_STAR is at index=1
[14]:
fig, ax = plt.subplots(len(fid_params), len(fid_params), figsize=(18,18))
cols = [col_mod, col_alpha]

for i, cov in enumerate([Finv_PS, Finv_alpha_star_prior]):

    col = cols[i]
    if i == 0:
        # No prior
        resize_lims=True
        ellipse_color=col
        ellipse_kwargs=[{'alpha':0.8},{'alpha':0.2}]
        plot1D_kwargs={'c':col, 'lw':1}
    else:
        # with prior
        ls='solid'
        resize_lims=False
        ellipse_color='None'
        ellipse_kwargs=[{'edgecolor':col,'lw':2,'ls':ls},
                      {'edgecolor':col,'lw':2,'ls':ls,'alpha':0.8}]
        plot1D_kwargs={'c':col, 'lw':2, 'ls':ls}

    p21fish.plot_triangle(params=astro_params_vary_EoS,
                          fiducial=fid_params,
                          labels=fid_labels,
                          cov=cov,
                          ellipse_color=ellipse_color,
                          ellipse_kwargs=ellipse_kwargs,
                          plot1D_kwargs=plot1D_kwargs,
                          resize_lims=resize_lims,
                          title_fontsize=14,
                          xlabel_kwargs={'labelpad': 5, 'fontsize':22},
                          ylabel_kwargs={'labelpad': 5, 'fontsize':22},
                          ax=ax, fig=fig);

    p21fish.title_double_ellipses(axes=ax, labels=fid_labels,
               med=fid_params, sigma=np.sqrt(cov.diagonal()),
               title_fontsize=18, title_pad=55,
               vspace=i/5,
               color=col
               )

no_prior = mlines.Line2D([], [], color=col_mod, lw=2, label='EOS, 21cm only')
w_prior  = mlines.Line2D([], [], color=col_alpha, lw=3, ls=ls, label=r'+ LF $\alpha_\star^\mathrm{II}$ prior')

ax[0,5].legend(handles=[no_prior, w_prior], loc='upper left', fontsize=24)

plt.savefig(figs_dir+'corner_EoS_mini_fisher_ALPHA_STAR_prior.png', bbox_inches='tight')
../_images/tutorials_fisher_examples_16_0.png

Pessimistic noise case

[15]:
Fij_matrix_PS_pess, Finv_PS_pess = p21fish.make_fisher_matrix(params_EoS_pess,
                                                             fisher_params=astro_params_vary_EoS,
                                                             hpeak=0.0, obs='PS',
                                                             k_min=0.1, k_max=1,
                                                             z_min=5., z_max=30.,
                                                             sigma_mod_frac=0.2,
                                                             add_sigma_poisson=True)
PS shape: (23, 24)
[16]:
fig, ax = plt.subplots(len(fid_params), len(fid_params), figsize=(18,18))
cols = [col_pess, col_mod]

for i, cov in enumerate([Finv_PS_pess, Finv_PS]):

    col = cols[i]
    if i == 0:
        # Pessimistic
        resize_lims=True
        plot_rescale=2
        ellipse_color='None'
        ellipse_kwargs=[{'edgecolor':col,'lw':1,'ls':'dashed'},
                      {'edgecolor':col,'lw':1,'ls':'dashed','alpha':1}]
        plot1D_kwargs={'c':col, 'lw':1, 'ls':'dashed'}
    else:
        # Moderate
        ls='solid'
        resize_lims=False
        plot_rescale=4
        ellipse_color=col
        ellipse_kwargs=[{},{'alpha':0.5}]
        plot1D_kwargs={'c':col, 'lw':2}

    p21fish.plot_triangle(params=astro_params_vary_EoS,
                          fiducial=fid_params,
                          labels=fid_labels,
                          cov=cov,
                          ellipse_color=ellipse_color,
                          ellipse_kwargs=ellipse_kwargs,
                          plot1D_kwargs=plot1D_kwargs,
                          resize_lims=resize_lims,
                          plot_rescale=plot_rescale,
                          title_fontsize=14,
                          xlabel_kwargs={'labelpad': 5, 'fontsize':22},
                          ylabel_kwargs={'labelpad': 5, 'fontsize':22},
                          ax=ax, fig=fig);

    p21fish.title_double_ellipses(axes=ax, labels=fid_labels,
               med=fid_params, sigma=np.sqrt(cov.diagonal()),
               title_fontsize=18, title_pad=50,
               vspace=i/5, color=col)

no_prior = mlines.Line2D([], [], color=col_pess, lw=2, ls='dashed', label='Pessimistic foregrounds')
w_prior  = mlines.Line2D([], [], color=col_mod, lw=4, label=r'Moderate foregrounds')

ax[0,5].legend(handles=[w_prior, no_prior], loc='upper left', fontsize=28)

plt.savefig(figs_dir+'corner_EoS_mini_fisher_pessimistic.png', bbox_inches='tight')
../_images/tutorials_fisher_examples_19_0.png

Comparison of forecasts

S/N

[17]:
param_test = params_EoS['ALPHA_ESC']
param_test_pess = params_EoS_pess['ALPHA_ESC']

SNR = np.zeros((len(param_test.PS_z_HERA),2))
for i in range(len(param_test.PS_z_HERA)):
    PS = param_test.PS['CDM']['ALPHA_ESC=-0.3'][i]['delta']
    k  = param_test.PS['CDM']['ALPHA_ESC=-0.3'][i]['k'][~np.isnan(PS)]
    PS = PS[~np.isnan(PS)]

    # Get rid of nans and interp PS on HERA grid
    PS_interp = np.interp(param_test.PS_err[i]['k']*0.7,
                           k, PS)

    # Use HERA errors
    PS_err = np.array([param_test.PS_err[i]['err_mod'],
                        param_test_pess.PS_err[i]['err_mod']])

    SNR[i] = np.sqrt(np.sum((PS_interp/PS_err)**2., axis=1))

SNR_EoR = np.sqrt(np.sum(SNR[:,0][param_test.PS_z_HERA<7.]**2.)) # ~300
SNR_CD  = np.sqrt(np.sum(SNR[:,0][param_test.PS_z_HERA>=7.]**2.)) # ~300

print(SNR_EoR, SNR_CD)

plt.figure(figsize=(6.5,4))
labels = ['Moderate','Pessimistic']
cols = [col_mod, col_pess]
lss  = ['solid', 'dashed']
for i, s in enumerate(SNR.T):
    SNR_total = np.sqrt(np.sum(s**2.)) # ~300
    plt.plot(param_test.PS_z_HERA, s, c=cols[i], ls=lss[i], label=f'{labels[i]} foregrounds, total S/N = {SNR_total:.0f}')
plt.xlabel('Redshift, z')
plt.ylabel('HERA $\Delta_{21}^2$ S/N')

plt.annotate("Reionization", xy=(7, 20),  xycoords='data',
            xytext=(7, 0.6), ha='center', fontsize=10,
            arrowprops=dict(arrowstyle="->", lw=0.5))

plt.annotate("Epoch of\nHeating", xy=(12, 4),  xycoords='data',
            xytext=(12, 0.1), ha='center', fontsize=10,
            arrowprops=dict(arrowstyle="->", lw=0.5))

plt.annotate("Cosmic\nDawn", xy=(18, 0.5),  xycoords='data',
            xytext=(18, 0.05), ha='center', fontsize=10,
            arrowprops=dict(arrowstyle="->", lw=0.5))

plt.axhline(10., lw=0.5, ls='solid', c='0.5', zorder=0)
plt.legend()


plt.yscale('log')
plt.savefig(figs_dir+'SNR_EoS.pdf', bbox_inches='tight')
218.50718001785071 285.78849803538145
../_images/tutorials_fisher_examples_22_1.png

Errors for each parameter

[18]:
cols    = [col_mod, col_pess, col_mod, col_pess]
lss     = ['solid', 'dashed','solid', 'dashed']
lws     = [3,3,1.5,1.5]
markers = ['o','s','o','s']
labels  = ['Moderate foregrounds','Pessimistic foregrounds',r'+ LF $\alpha_\star^\mathrm{II}$ prior','']#r'with LF $\alpha_\star^\mathrm{II}$ prior']
alphas  = [1,1,0.6,0.6]

# Add alpha star II prior
sigma_alpha_star_II = 0.07
idx_alpha_star = list(params_EoS).index("ALPHA_STAR")
print(f'ALPHA_STAR is at index={idx_alpha_star}')
Fij_matrix_PS_alpha_star_prior_pess = Fij_matrix_PS_pess.copy()
Fij_matrix_PS_alpha_star_prior_pess[idx_alpha_star,idx_alpha_star] += 1/sigma_alpha_star_II**2.
Finv_alpha_star_prior_pess = np.linalg.inv(Fij_matrix_PS_alpha_star_prior_pess)

# Fractional error
plt.figure(figsize=(7,4))
for cc, cov in enumerate([Finv_PS, Finv_PS_pess, Finv_alpha_star_prior, Finv_alpha_star_prior_pess]):
    mean = fid_params
    err  = np.sqrt(np.diag(cov))

    frac_err = np.abs(err/mean)
    frac_err[np.isinf(frac_err)] = err[np.isinf(frac_err)]#/0.01

    plt.semilogy(fid_labels, frac_err, c=cols[cc], marker=markers[cc],
                 lw=lws[cc], ls=lss[cc], label=labels[cc], ms=7, alpha=alphas[cc])

# plt.ylim(0.,2.)
plt.axhline(0.1, lw=1, c='k', zorder=0)
plt.legend()
plt.gca().set_xticklabels(fid_labels, rotation = 90, ha="center")
plt.minorticks_on()
plt.gca().tick_params(axis='x', which='minor', bottom=False, top=False)
plt.ylabel('Fractional error')
plt.ylabel(r'$|\sigma(\theta)/\theta_\mathrm{fid}|$')

plt.savefig(figs_dir+'fraction_error_EoS.pdf', bbox_inches='tight')
ALPHA_STAR is at index=1
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/693560164.py:22: RuntimeWarning: divide by zero encountered in true_divide
  frac_err = np.abs(err/mean)
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/693560164.py:22: RuntimeWarning: divide by zero encountered in true_divide
  frac_err = np.abs(err/mean)
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/693560164.py:22: RuntimeWarning: divide by zero encountered in true_divide
  frac_err = np.abs(err/mean)
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/693560164.py:22: RuntimeWarning: divide by zero encountered in true_divide
  frac_err = np.abs(err/mean)
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/693560164.py:31: UserWarning: FixedFormatter should only be used together with FixedLocator
  plt.gca().set_xticklabels(fid_labels, rotation = 90, ha="center")
../_images/tutorials_fisher_examples_24_2.png

Parameter uncertainty as a function of z

How does noise on each parameter change as a function of z?

[20]:
# Rolling loop through HERA z_bins
z_bins = params_EoS['ALPHA_STAR'].PS_z_HERA
bin_i = 2

z_err = np.zeros((len(z_bins)-bin_i,len(params_EoS)))
for zz in range(len(z_bins)):
    if zz < len(z_bins) - bin_i:
        Fij_matrix_PS_z, Finv_PS_z = p21fish.make_fisher_matrix(params_EoS,
                                                         fisher_params=astro_params_vary_EoS,
                                                         hpeak=0.0, obs='PS',
                                                         k_min=0.1, k_max=1,
                                                         z_min=z_bins[zz], z_max=z_bins[zz+bin_i],
                                                         sigma_mod_frac=0.2,
                                                         add_sigma_poisson=True)

        z_err[zz] = np.sqrt(np.diag(Finv_PS_z))
    try:
        print(z_err[zz])
    except:
        print(f'could not do for z_min={z_bins[zz]}')
PS shape: (3, 24)
[1.73627339e-01 3.21997284e-01 1.64274933e-01 3.54371796e-01
 6.43228227e-01 2.18440916e+00 9.14333462e-01 5.47960990e+00
 3.31960353e+00 1.41965402e+03]
PS shape: (3, 24)
[5.69850700e-01 4.33426673e-01 5.74504689e-01 4.71365660e-01
 9.38422255e-01 2.81596463e+00 1.19019524e+00 5.66340515e+00
 3.30127823e+00 1.41117918e+03]
PS shape: (3, 24)
[9.57823876e-01 6.25345235e-01 9.83876034e-01 6.19645407e-01
 2.09700055e+00 3.04682008e+00 2.35507809e+00 9.08661934e+00
 4.95058623e+00 2.28170497e+03]
PS shape: (3, 24)
[1.29039754e+00 1.11743289e+00 1.28640278e+00 1.09660340e+00
 2.43973823e+00 3.56788641e+00 2.20000473e+00 1.01747053e+01
 5.53384048e+00 3.14006363e+03]
PS shape: (3, 24)
[1.42347618e+00 1.02975807e+00 1.42237059e+00 1.00031553e+00
 2.35255424e+00 3.45803485e+00 2.42988755e+00 1.01283615e+01
 3.89155274e+00 2.44288794e+03]
PS shape: (3, 24)
[2.00898199e+00 1.03708211e+00 2.05638690e+00 1.00663800e+00
 2.80485967e+00 3.93572488e+00 2.85483480e+00 1.14190180e+01
 4.02622973e+00 2.94352950e+03]
PS shape: (3, 24)
[2.83314797e+00 1.04695408e+00 2.92667762e+00 1.07212043e+00
 3.37826162e+00 4.55540694e+00 3.16791512e+00 1.18427086e+01
 4.41766419e+00 3.82393954e+03]
PS shape: (3, 24)
[2.83715369e+00 1.27069997e+00 2.93067068e+00 1.29798668e+00
 3.37881859e+00 4.15470244e+00 3.35996461e+00 1.13491570e+01
 2.99187043e+00 1.62406559e+03]
PS shape: (3, 24)
[2.42690839e+00 9.69404819e-01 2.49015381e+00 1.00789548e+00
 3.22585525e+00 3.29751587e+00 3.35672250e+00 1.04717535e+01
 2.55887591e+00 1.15416093e+03]
PS shape: (3, 24)
[  2.18895132   0.89452448   2.26287453   0.82882134   2.89809027
   3.00959964   2.6665641    7.97997123   2.14463165 511.11476398]
PS shape: (3, 24)
[  2.30253173   1.09834841   2.39621442   0.7044284    2.7189927
   4.54343258   2.35622739   6.57932659   2.0492352  181.71146417]
PS shape: (3, 24)
[  2.47398262   1.38578634   2.51251628   0.77094446   3.27952769
   5.495576     2.45835311   7.7119268    1.9562515  197.2576004 ]
PS shape: (3, 24)
[  2.10965978   1.66444569   2.14777429   1.04804706   3.15203387
   5.87810564   2.36037784   9.31892967   1.44931999 153.08614851]
PS shape: (3, 24)
[ 3.45878663  2.63031743  3.90317019  2.06343023  4.64134308  7.42270772
  3.78534975 23.18942052  2.13982131 84.52774824]
PS shape: (3, 24)
[  4.91226697   3.96552484   4.34806075   3.29412742   6.69401367
   6.90566649   5.92364083  51.72607217   3.02892226 166.24944922]
PS shape: (3, 24)
[  3.33283762   2.69103934   4.19583621   3.80850855   4.99314859
   4.65599166   4.08427946  47.87914369   1.49643627 155.18310369]
PS shape: (3, 24)
[  3.94727591   3.01077852   5.63330895   4.91043253   4.80404203
   4.56218837   4.98341338  55.7363171    0.566741   170.11927535]
PS shape: (3, 24)
[  4.39386608   3.29057927   6.07370211   6.35074796   3.59518085
   3.48371375   4.7130184   51.96322023   0.58270932 243.68248413]
PS shape: (3, 24)
[  7.58682717   5.22683021   7.82772596   5.82829266   3.18337457
   3.28843803   4.39499209  56.45200407   1.22915709 583.2666204 ]
PS shape: (3, 24)
[  37.35097905   21.91121519   24.35661314   12.52172589    6.06648355
    5.60374057    9.78753992  106.96693703    2.8663244  1048.04966578]
PS shape: (3, 24)
[ 221.07024477  114.79571427   81.527433     40.03929817   16.86206265
   17.62594181   37.04349478  239.18451863   28.11076634 5748.68785231]
could not do for z_min=21.909972214717644
could not do for z_min=25.308702138693505
[22]:
from palettable.colorbrewer.sequential import Blues_5, YlGn_5, RdPu_6

z_plot = (z_bins[bin_i:]+z_bins[bin_i-1:-1])/2

fig1, ax1 = plt.subplots(1,1, figsize=(6,4))

sum_err = np.zeros(len(astro_params_vary_EoS))
for pp,p in enumerate(astro_params_vary_EoS):
    if pp < 4:
        # popII
        ls = 'dashed'
        lw = 2
        colors = RdPu_6.hex_colors[::-1]
        i = pp
        alpha=1
    elif 3 < pp <= 7:
        ls = 'solid'
        lw = 3
        colors = YlGn_5.hex_colors[::-1]
        alpha=0.8
        i = pp-4
    else:
        ls = 'dotted'
        lw = 2
        colors = Blues_5.hex_colors[::-1]
        i = (pp-8)*2
        alpha=1

#     print(p, pp, i)
    frac_err = z_err[:,pp]/fid_params[pp]
    frac_err[np.isinf(frac_err)] = z_err[:,pp][np.isinf(frac_err)]

    sum_err[pp] = np.sqrt(np.mean(np.abs(frac_err)**2.))
#     print(p, sum_err[pp])

    ax1.semilogy(z_plot, np.abs(frac_err), label=fid_labels[pp],
                 c=colors[i], ls=ls, lw=lw, alpha=alpha)

ax1.legend(ncol=3, fontsize=10, handlelength=1.5, handletextpad=0.5, columnspacing=1., loc='upper left')

ax1.set_xlabel('Redshift, z')
ax1.set_ylabel('$\sigma$')
ax1.set_ylabel(r'$|\sigma(\theta, z)/\theta_\mathrm{fid}|$')


plt.plot(z_bins, [0.01]*len(z_bins), '|', color='k')

plt.ylim(7e-3, 2e3)
plt.savefig(figs_dir+'fraction_error_EoS_z.pdf', bbox_inches='tight')
/var/folders/sy/j00h6jjd19z46r9qd031n3080000gn/T/ipykernel_46372/1430737097.py:30: RuntimeWarning: divide by zero encountered in true_divide
  frac_err = z_err[:,pp]/fid_params[pp]
../_images/tutorials_fisher_examples_27_1.png

Comparison to Park+19

Compare Fisher matrix with Park+2019 fiducial to their MCMC (21cm power spectrum only)

[24]:
output_dir_Park19 = data_dir+'Park19/'
PS_err_dir_Park19 = noise_dir+'21cmSense_noise_Park19/'

astro_params_vary_Park19, astro_params_fid_Park19 = p21fish.get_params_fid(
                                                    config_file=p21fish.base_path+'21cmFAST_config_files/Park19.config')

# Reorder to match Park+19
astro_params_vary_Park19 = ['F_STAR10', 'ALPHA_STAR',
                             'F_ESC10', 'ALPHA_ESC',
                             'M_TURN', 't_STAR',
                             'L_X', 'NU_X_THRESH']
[25]:
# Load parameters
params_Park19 = {}
for param in astro_params_vary_Park19:

    params_Park19[param] = p21fish.Parameter(param=param,
                                             output_dir=output_dir_Park19,
                                             HII_DIM=128, BOX_LEN=250,
                                             min_redshift=5.9,
                                             PS_err_dir=PS_err_dir_Park19,
                                             clobber=False, Park19='real',
                                             vb=False, new=False)
########### fisher set up for F_STAR10
    Loading global signal and power spectra from saved files
    Fiducial: F_STAR10=-1.3
########### fisher set up for ALPHA_STAR
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_STAR=0.5
########### fisher set up for F_ESC10
    Loading global signal and power spectra from saved files
    Fiducial: F_ESC10=-1.0
########### fisher set up for ALPHA_ESC
    Loading global signal and power spectra from saved files
    Fiducial: ALPHA_ESC=-0.5
########### fisher set up for M_TURN
    Loading global signal and power spectra from saved files
    Fiducial: M_TURN=8.7
########### fisher set up for t_STAR
    Loading global signal and power spectra from saved files
    Fiducial: t_STAR=0.5
########### fisher set up for L_X
    Loading global signal and power spectra from saved files
    Fiducial: L_X=40.5
########### fisher set up for NU_X_THRESH
    Loading global signal and power spectra from saved files
    Fiducial: NU_X_THRESH=500.0

Make Fisher matrix

[26]:
Fij_matrix_PS_Park19, Finv_PS_Park19 = p21fish.make_fisher_matrix(params_Park19,
                                                                fisher_params=astro_params_vary_Park19,
                                                                hpeak=0.0, obs='PS',
                                                                k_min=0.1, k_max=1,
                                                                z_min=5.7, z_max=30.,
                                                                sigma_mod_frac=0.2,
                                                                cosmo_key='CDM',
                                                                add_sigma_poisson=True)

fid_params_Park19 = np.array([astro_params_fid_Park19[param] for param in params_Park19])
fid_labels_Park19 = np.array([p21fish.astro_params_labels[param] for param in params_Park19])
PS shape: (12, 23)

Load Park19 chains and compare

Load their 21cm-only chains and compare the contours

[28]:
Park19_chains = np.load(f'{data_dir}Park19/Park19_chains.npz')
print(Park19_chains['params'])

# Make posteriors from the covariance matrix
mean = fid_params_Park19.copy()
cov  = Finv_PS_Park19.copy()
fisher_chain = np.random.multivariate_normal(mean, cov, size=10000)

# Corner plot
fig = plt.figure(figsize=(15,15))

colors = [col_mcmc,col_P19]
lws = [1.5,3]

# Plot 2 sigma confidence interval (https://corner.readthedocs.io/en/latest/pages/sigmas.html)
levels = 1.0 - np.exp(-0.5 * np.array([1,2,]) ** 2)

for cc, chain in enumerate([Park19_chains['chains'],fisher_chain]):

    if cc == 0:
        # MCMC
        ls='solid'
        lw=lws[cc]
        hist_kwargs = {'lw':lw,'ls':ls,'density':True}
        color=colors[cc]
        smooth=None
        fill_contours    = False
        no_fill_contours = True
        contour_kwargs = {'linewidths':lw,'linestyles':ls}
        contourf_kwargs={}
        zorder=10
    else:
        # fisher
        ls='solid'
        lw=lws[cc]
        hist_kwargs = {'lw':lw,'density':True,'histtype':'stepfilled', 'alpha':0.8}
        fill_contours=True
        no_fill_contours=False
        color=colors[cc]
        smooth=1
        contour_kwargs = {'linewidths':0.}
        contourf_kwargs = {}
        zorder=0

    corner.corner(chain, fig=fig,
                labels=fid_labels_Park19,
                smooth=smooth,
                color=color, use_math_text=True,
                plot_datapoints=False, plot_density=False,
                no_fill_contours=no_fill_contours, fill_contours=fill_contours,
                hist_kwargs=hist_kwargs,
                contour_kwargs=contour_kwargs,contourf_kwargs=contourf_kwargs,
                levels=levels,
                range=[1,1,1,1,1,1,(40.,41.),(300,700)], # throws out a couple of outlier points in the chains [better for Lx]
                show_titles=True,
                zorder=zorder
                );

    # Format the quantile display
    ax = np.reshape(fig.axes, (chain.shape[1],chain.shape[1]))

    p21fish.title_double_ellipses(axes=ax, labels=fid_labels_Park19,
                   chain=chain,
                   med=None, sigma=None,
                   title_fontsize=18, title_pad=58,
                   vspace=cc/5,
                   color=color
                   )

lab_P19 = mlines.Line2D([], [], color=col_mcmc, ls='solid', lw=lws[0]+1, label='Park+19 MCMC')
lab_TW  = mlines.Line2D([], [], color=col_P19, lw=lws[1]+1, label=r'This Work - Fisher Matrix')

fig.get_axes()[5].legend(handles=[lab_P19, lab_TW], loc='center left', fontsize=24)

plt.savefig(figs_dir+'corner_Park19_fisher_compare_2sigma.png', bbox_inches='tight')
['F_STAR10' 'ALPHA_STAR' 'F_ESC10' 'ALPHA_ESC' 'M_TURN' 't_STAR' 'L_X'
 'E0']
../_images/tutorials_fisher_examples_34_1.png

Adding a new parameter

If you want to add your own new parameter, you should:

  1. Create lightcones varying that parameter.

    1. Create a config file for the parameters you want to change (take one of the examples in ../21cmFAST_config_files/ and replace the astro_params_vary list with your list of new parameters.

    2. Note that the fiducial parameter value for your new parameter will be the 21cmFAST default unless the fiducial value is specified in the config file. If you want a non-default fiducial parameter value you will need to create a new set of lightcones with your parameter’s fiducial included in astro_params.

    3. Create the lightcones using scripts/make_lightcones_for_fisher.py

  2. Load your new parameter by adding it to the dictionary as above

See more details on running scripts/make_lightcones_for_fisher.py in the docs

[ ]:

[ ]: