Esempio n. 1
0
def compute_Cls(par,hod_par=hod_params,z_cent=z_s_cents,N_gal_sample=N_gal_bin,k_arr=k_ar,z_arr=z_ar,a_arr=a_ar,ell=ells,
                compute_cov=False, compute_inv_cov=False,plot_for_sanity=False,powerspec='halofit',simple_bias=True):
    
    if powerspec == 'halofit':
        # Compute matter pk using halofit
        pk_mm_arr = np.array([ccl.nonlin_matter_power(cosmo_fid, k_arr, a) for a in a_arr])
    elif powerspec == 'halomodel':
        # Alternatively use halo model
        pk_mm_arr = np.array([ccl.halomodel.halomodel_matter_power(cosmo_fid, k_arr, a) for a in a_arr])
        
    if simple_bias == True:
        pk_gg_arr = pk_mm_arr.copy() # because we later include bias
        pk_gm_arr = pk_mm_arr.copy() # because we later include bias
    else:
        # Compute HOD
        hodpars = hod_funcs_evol_fit.HODParams(hod_par, islogm0=True, islogm1=True)
        
        hodprof = hod.HODProfile(cosmo_fid, hodpars.lmminf, hodpars.sigmf,\
                                 hodpars.fcf, hodpars.m0f, hodpars.m1f, hodpars.alphaf)
        # Compute galaxy pk using halofit
        pk_gg_arr = np.array([hodprof.pk(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        # Compute galaxy-matter pk using halofit
        pk_gm_arr = np.array([hodprof.pk_gm(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        
    # Create pk2D objects for interpolation
    pk_mm = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_mm_arr), is_logp=True)
    pk_gg = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_gg_arr), is_logp=True)
    pk_gm = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_gm_arr), is_logp=True)

    # load the bias parameters
    # k # indicates which of N_tomo sampling bins
    b_z = np.array([par['b_%02d'%k]['val'] for k in range(N_zsamples)])
    
    # load the dndz parameters
    dndz_z = np.zeros((N_tomo,N_zsamples))
    for i_z in range(N_tomo):
        dndz_z[i_z,:] = np.array([par['dndz_%02d_%02d'%(i_z,k)]['val'] for k in range(N_zsamples)])
    

    # per type gg gs ss
    tot_corr = N_ell*(N_tomo*(2*N_tomo+1))
    
    # make Cl_all of size N_ell*N_tomo*(2N_tomo+1)
    CL_ALL = np.zeros(tot_corr)
    temp = np.arange(2*N_tomo)
    temp = np.vstack((temp,temp)).T
    combs = np.array(list(combinations(range(2*N_tomo),2)))
    all_combos = np.vstack((temp,combs))
    
    for c, comb in enumerate(all_combos):
        i = comb[0]%N_tomo # first redshift bin
        j = comb[1]%N_tomo # second redshift bin
        t_i = comb[0]//N_tomo # tracer type 0 means g and 1 means s
        t_j = comb[1]//N_tomo # tracer type 0 means g and 1 means s
        
        # NOISE
        if (i == j):
            # number density of galaxies
            N_gal = N_gal_sample[i]            
            n_gal = N_gal/area_COSMOS # in rad^-2
            
            
            # Adding noise
            noise_gal = 1./n_gal
            noise_shape = sigma_e2[i]/n_gal
        else:
            noise_gal = 0.
            noise_shape = 0.
        
        # Now create corresponding Cls with pk2D objects matched to pk
        if t_i*2+t_j == 0: # this is gg
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[j,:]),mag_bias=None, \
                                               has_rsd=False)

            cl_gg = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_gg)
            cl_gg_no = cl_gg + noise_gal

            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_gg_no
        elif t_i*2+t_j == 1: # this is gs
            
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[j,:]))
            cl_gs = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_gm)
            cl_gs_no = cl_gs
            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_gs_no
            
        elif t_i*2+t_j == 3: # this is ss
            
            tracer_z1 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[i,:]))
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[j,:]))
            cl_ss = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_mm)
            cl_ss_no = cl_ss + noise_shape

            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_ss_no

        if plot_for_sanity == True:
            if c == 0:
                # Plot for sanity
                plt.loglog(ells, cl_gg, label=r'$\mathrm{gg}$')
                plt.loglog(ells, cl_gg_no, label=r'$\mathrm{gg}+{\rm noise}$')
                plt.loglog(ells, cl_ss, label=r'$\mathrm{ss}$')
                plt.loglog(ells, cl_gs, label=r'$\mathrm{gs}$')
                plt.xlabel(r'$\ell$')
                plt.ylabel(r'$C_{\ell}$')
                plt.legend()
                plt.savefig('Cls.png')
                plt.close()

    if compute_inv_cov == False and compute_cov == False:
        print(len(CL_ALL))
        return CL_ALL

    print(len(CL_ALL))
    print(np.sum(CL_ALL>0))
    
    COV_ALL = np.zeros((len(CL_ALL),len(CL_ALL)))    
    # COMPUTE COVARIANCE MATRIX 
    for c_A, comb_A in enumerate(all_combos):
        for c_B, comb_B in enumerate(all_combos):
            i = comb_A[0]%N_tomo # first redshift bin
            j = comb_A[1]%N_tomo # second redshift bin
            m = comb_B[0]%N_tomo # first redshift bin
            n = comb_B[1]%N_tomo # second redshift bin                        
            
            c_im = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_B[0]]))==all_combos,axis=1))
            c_jn = np.argmax(np.product(np.sort(np.array([comb_A[1],comb_B[1]]))==all_combos,axis=1))
            c_in = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_B[1]]))==all_combos,axis=1))
            c_jm = np.argmax(np.product(np.sort(np.array([comb_A[1],comb_B[0]]))==all_combos,axis=1))

            # PAIRS A,B ARE (ti,tj),(tm,tn) at same ell
            #cov(ij,mn) = im,jn + in,jm                    
            C_im = CL_ALL[(c_im*N_ell):(c_im*N_ell)+N_ell]
            C_jn = CL_ALL[(c_jn*N_ell):(c_jn*N_ell)+N_ell]
            C_in = CL_ALL[(c_in*N_ell):(c_in*N_ell)+N_ell]
            C_jm = CL_ALL[(c_jm*N_ell):(c_jm*N_ell)+N_ell]

            
           # Knox formula
            Cov_ijmn = (C_im*C_jn+C_in*C_jm)/((2*ell+1.)*delta_ell*f_sky)
            
            if plot_for_sanity == True:
                if (c_A == c_B):
                    print(i,j,'=',m,n)
                    print(c_A)
                    Cl_err = np.sqrt(Cov_ijmn)

                    t_i = comb_A[0]//N_tomo
                    t_j = comb_A[1]//N_tomo
                    print(N_tomo*i+j+1)
                    
                    plt.subplot(N_tomo, N_tomo, N_tomo*i+j+1)
                    plt.title("z=%f x z=%f"%(z_bin_cents[i],z_bin_cents[j]))
                    c_ij = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_A[1]]))==all_combos,axis=1))
                    C_ij = CL_ALL[(c_ij*N_ell):(c_ij*N_ell)+N_ell]
                    # maybe add legend
                    (_,caps,eb)=plt.errorbar(ell,C_ij,yerr=Cl_err,lw=2.,ls='-',capsize=5,label=str(t_i*2+t_j)) 
                    plt.legend()
                    plt.xscale('log')
                    plt.yscale('log')



            COV_ALL[(N_ell*c_A):(N_ell*c_A)+\
                    N_ell,(N_ell*c_B):(N_ell*c_B)+N_ell] = np.diag(Cov_ijmn)
            COV_ALL[(N_ell*c_B):(N_ell*c_B)+\
                    N_ell,(N_ell*c_A):(N_ell*c_A)+N_ell] = np.diag(Cov_ijmn)


    if compute_cov:
        return COV_ALL

    evals,evecs = la.eig(COV_ALL)
    
    if (is_pos_def(COV_ALL) != True): print("Covariance is not positive definite!"); exit(0)
    ICOV_ALL = la.inv(COV_ALL)
    return ICOV_ALL 
Esempio n. 2
0
def compute_Cls(cosmo_fid,
                dndz_z,
                b_z,
                z_cent,
                N_gal_sample,
                ell,
                a_arr,
                k_arr,
                sigma_e2,
                area_overlap,
                powerspec='halofit',
                simple_bias=True):
    N_ell = len(ell)
    N_zsamples_theo = len(z_cent)
    N_tomo = len(N_gal_sample)
    # choose a scheme for evaluating the matter power spectrum -- halofit is recommended
    if powerspec == 'halofit':
        # Compute matter pk using halofit
        pk_mm_arr = np.array(
            [ccl.nonlin_matter_power(cosmo_fid, k_arr, a) for a in a_arr])
    elif powerspec == 'halomodel':
        # Alternatively use halo model
        pk_mm_arr = np.array([
            ccl.halomodel.halomodel_matter_power(cosmo_fid, k_arr, a)
            for a in a_arr
        ])

    # choose a scheme for evaluating the galaxy power spectrum between simple bias and HOD model
    if simple_bias == True:
        # Set the power spectra equal to the matter PS -- this changes later in the code
        pk_gg_arr = pk_mm_arr.copy()
        pk_gm_arr = pk_mm_arr.copy()
    else:
        # HOD parameter values
        hod_par = {'sigm_0': 0.4,'sigm_1': 0.,'alpha_0': 1.0,'alpha_1': 0.,'fc_0': 1.,'fc_1': 0.,\
                  'lmmin_0': 3.71,'lmmin_1': 9.99,'m0_0': 1.28,'m0_1': 10.34,'m1_0': 7.08,'m1_1': 9.34}
        # Evolve HOD parameters and create an HOD profile
        hodpars = hod_funcs_evol_fit.HODParams(hod_par,
                                               islogm0=True,
                                               islogm1=True)
        hodprof = hod.HODProfile(cosmo_fid, hodpars.lmminf, hodpars.sigmf,\
                                 hodpars.fcf, hodpars.m0f, hodpars.m1f, hodpars.alphaf)
        # Compute galaxy pk using halofit
        pk_gg_arr = np.array(
            [hodprof.pk(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        # Compute galaxy-matter pk using halofit
        pk_gm_arr = np.array(
            [hodprof.pk_gm(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        # Wipe b_z since HOD is adopted
        b_z[:, :] = 1.

    # Create pk2D objects for interpolation
    pk_mm = ccl.Pk2D(a_arr=a_arr,
                     lk_arr=np.log(k_arr),
                     pk_arr=np.log(pk_mm_arr),
                     is_logp=True)
    pk_gg = ccl.Pk2D(a_arr=a_arr,
                     lk_arr=np.log(k_arr),
                     pk_arr=np.log(pk_gg_arr),
                     is_logp=True)
    pk_gm = ccl.Pk2D(a_arr=a_arr,
                     lk_arr=np.log(k_arr),
                     pk_arr=np.log(pk_gm_arr),
                     is_logp=True)

    # number of indep correlation functions per type gg gs ss
    N_tot_corr = N_ell * (N_tomo * (2 * N_tomo + 1))

    # make C_ell of size N_ell*N_tomo*(2N_tomo+1)
    C_ell = np.zeros(N_tot_corr)

    # List all redshift bin combinations
    temp = np.arange(2 * N_tomo)
    temp = np.vstack((temp, temp)).T
    combs = np.array(list(combinations(range(2 * N_tomo), 2)))
    all_combos = np.vstack((temp, combs))

    for c, comb in enumerate(all_combos):
        i = comb[0] % N_tomo  # first redshift bin
        j = comb[1] % N_tomo  # second redshift bin
        t_i = comb[0] // N_tomo  # tracer type 0 means g and 1 means s
        t_j = comb[1] // N_tomo  # tracer type 0 means g and 1 means s

        # Noise
        if (i == j):
            # number density of galaxies
            N_gal = N_gal_sample[i]
            n_gal = N_gal / area_overlap  # in rad^-2

            # Adding noise
            noise_gal = 1. / n_gal
            noise_shape = sigma_e2[i] / n_gal
        else:
            noise_gal = 0.
            noise_shape = 0.

        # Now create corresponding Cls with pk2D objects matched to pk
        # this is gg
        if t_i * 2 + t_j == 0:
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z[i,:]), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z[j,:]), \
                                               dndz=(z_cent, dndz_z[j,:]),mag_bias=None, \
                                               has_rsd=False)

            cl_gg = ccl.angular_cl(cosmo_fid,
                                   tracer_z1,
                                   tracer_z2,
                                   ell,
                                   p_of_k_a=pk_gg)
            cl_gg_no = cl_gg + noise_gal

            C_ell[(N_ell * c):(N_ell * c) + N_ell] = cl_gg_no

        # this is gs
        elif t_i * 2 + t_j == 1:
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z[i,:]), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid,
                                              dndz=(z_cent, dndz_z[j, :]))
            cl_gs = ccl.angular_cl(cosmo_fid,
                                   tracer_z1,
                                   tracer_z2,
                                   ell,
                                   p_of_k_a=pk_gm)
            cl_gs_no = cl_gs

            C_ell[(N_ell * c):(N_ell * c) + N_ell] = cl_gs_no

        # this is ss
        elif t_i * 2 + t_j == 3:
            tracer_z1 = ccl.WeakLensingTracer(cosmo_fid,
                                              dndz=(z_cent, dndz_z[i, :]))
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid,
                                              dndz=(z_cent, dndz_z[j, :]))
            cl_ss = ccl.angular_cl(cosmo_fid,
                                   tracer_z1,
                                   tracer_z2,
                                   ell,
                                   p_of_k_a=pk_mm)
            cl_ss_no = cl_ss + noise_shape

            C_ell[(N_ell * c):(N_ell * c) + N_ell] = cl_ss_no

    print(len(C_ell))
    return C_ell
Esempio n. 3
0
def compute_Cls(par,z_cent=z_s_cents,N_gal_sample=N_gal_bin,k_arr=k_ar,z_arr=z_ar,a_arr=a_ar,ell=ells,compute_inv_cov=False,plot_for_sanity=False,powerspec='halofit',simple_bias=False):
    # HOD parameters -- don't need to be called every time so can be taken out
    hod_par = {
    'sigm_0': 0.4,
    'sigm_1': 0.,
    'alpha_0': 1.0,
    'alpha_1': 0.,
    'fc_0': 1.,
    'fc_1': 0.,
    'lmmin_0': par['lmmin_0']['val'],
    'lmmin_1': par['lmmin_1']['val'],
    'm0_0': par['m0_0']['val'],
    'm0_1': par['m0_1']['val'],
    'm1_0': par['m1_0']['val'],
    'm1_1': par['m1_1']['val']}
    
    if powerspec == 'halofit':
        # Compute matter pk using halofit -- preferred
        pk_mm_arr = np.array([ccl.nonlin_matter_power(cosmo_fid, k_arr, a) for a in a_arr])
    elif powerspec == 'halomodel':
        # Alternatively use halo model
        pk_mm_arr = np.array([ccl.halomodel.halomodel_matter_power(cosmo_fid, k_arr, a) for a in a_arr])
        
    if simple_bias == True:
        # Using bias parameters
        # Pk_gg = b^2 Pmm and Pk_gm = b Pmm; however, this is taken into account when def tracers
        pk_gg_arr = pk_mm_arr.copy() 
        pk_gm_arr = pk_mm_arr.copy()
        # load bias parameter
        b_z = np.array([par['b_%02d'%k]['val'] for k in range(N_zsamples)])
    else:
        # Using the HOD model
        # load HOD and compute profile
        hodpars = hod_funcs_evol_fit.HODParams(hod_par, islogm0=True, islogm1=True)
        hodprof = hod.HODProfile(cosmo_fid, hodpars.lmminf, hodpars.sigmf,\
                                 hodpars.fcf, hodpars.m0f, hodpars.m1f, hodpars.alphaf)
        # Compute galaxy power spectrum using halofit
        pk_gg_arr = np.array([hodprof.pk(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        # Compute galaxy-matter pk using halofit
        pk_gm_arr = np.array([hodprof.pk_gm(k_arr, a_arr[i]) for i in range(a_arr.shape[0])])
        # Here we don't vary the bias parameters
        b_z = np.ones(N_zsamples) 
        
    # Create pk2D objects for interpolation
    pk_mm = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_mm_arr), is_logp=True)
    pk_gg = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_gg_arr), is_logp=True)
    pk_gm = ccl.Pk2D(a_arr=a_arr, lk_arr=np.log(k_arr), pk_arr=np.log(pk_gm_arr), is_logp=True)


    # Assume a functional form of 0.95/D(a) for the bias parameters (notice how this plays in
    # the case of varying b(z)) it doesn't matter a lot in this case for we take finite diff
    #a_cent = 1./(1.+z_cent)
    #b_z *= 0.95/ccl.growth_factor(cosmo_fid,a_cent)
    
    # load the dndz parameters
    dndz_z = np.zeros((N_tomo,N_zsamples))
    for i_z in range(N_tomo):
        dndz_z[i_z,:] = np.array([par['dndz_%02d_%02d'%(i_z,k)]['val'] for k in range(N_zsamples)])
    
    # Number of total correlation elements for all of gg gs and ss variants
    tot_corr = N_ell*(N_tomo*(2*N_tomo+1))
    
    # make CL_all of size N_ell*N_tomo*(2N_tomo+1)
    CL_ALL = np.zeros(tot_corr)

    # this lists all possible combinations of all gg gs and ss's for a given number of tomo bins
    # here is how it works: say we have 3 tomo bins, then we make an array of 2x3 = 6 numbers
    # from 0 through 5; where 0 through 2 correspond to galaxy tracer (g) and 3 through 5 to
    # shear tracer (s). 
    # Our final list all_combos consists of every possible pair between
    # tracer 1 which can be any of 3 tomos and either g or s and tracer 2 which can also be
    # any of 3 tomos and either g or s. The way I do this is by first listing in temp
    # the 6 pairs making up all the tracer 1 and tracer 2 combs where they are either
    # both g or both s at the same tomographic redshift, i.e. temp is (0,0), (1,1) ... (5,5)
    # then I use the function combinations which finds all unique combinations between
    # two lists i.e. (0,1),(0,2)...(0,5),(1,2)...(1,5),(2,3)...(2,5),(3,4),(3,5),(4,5)
    # and call this list combs. Finally I combine the two in all_combos.
    # Note: combs does not have (1,0) for it contributes the same info as (0,1)
    # example pair (2,4) in this example corresponds to tracer 1 being galaxies in third tomographic
    # bin and tracer 2 being shear in second tomographic bin, in short (2,4)=(g2,s1)
    temp = np.arange(2*N_tomo)
    temp = np.vstack((temp,temp)).T
    combs = np.array(list(combinations(range(2*N_tomo),2)))
    all_combos = np.vstack((temp,combs))

    
    for c, comb in enumerate(all_combos):
        # comb is the list pair, e.g. (2,5) while c is its order no. (b/n 0 and Ntomo(2Ntomo+1)-1)
        i = comb[0]%N_tomo # redshift bin of tracer 1 (b/n 0 and N_tomo-1 regardless of g or s)
        j = comb[1]%N_tomo # redshift bin of tracer 2 (b/n 0 and N_tomo-1 regardless of g or s)
        t_i = comb[0]//N_tomo # tracer type (0 or 1): 0 means g and 1 means s
        t_j = comb[1]//N_tomo # tracer type (0 or 1): 0 means g and 1 means s
        
        # Adding NOISE to only the diagonal elements
        if (i == j):
            # number density of galaxies - use area cosmos for these are the gals that overlap
            N_gal = N_gal_sample[i]
            n_gal = N_gal/area_COSMOS # in rad^-2
            
            # Adding noise
            noise_gal = 1./n_gal
            noise_shape = sigma_e2[i]/n_gal
        else:
            noise_gal = 0.
            noise_shape = 0.
        
        # Now create corresponding Cls with pk2D objects matched to pk
        if t_i*2+t_j == 0: # this is gg (notice that this can only be 2*0+0 = 0)
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[j,:]),mag_bias=None, \
                                               has_rsd=False)
            cl_gg = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_gg)
            cl_gg_no = cl_gg + noise_gal

            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_gg_no
        elif t_i*2+t_j == 1: # this is gs (notice that this can only be 2*0+1 = 1, never 2*1+0=2)
            tracer_z1 = ccl.NumberCountsTracer(cosmo_fid, bias=(z_cent, b_z), \
                                               dndz=(z_cent, dndz_z[i,:]),mag_bias=None, \
                                               has_rsd=False)
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[j,:]))
            cl_gs = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_gm)
            cl_gs_no = cl_gs

            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_gs_no
            
        elif t_i*2+t_j == 3: # this is ss (notice that this can only be 2*1+1 = 3)
            tracer_z1 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[i,:]))
            tracer_z2 = ccl.WeakLensingTracer(cosmo_fid, dndz=(z_cent, dndz_z[j,:]))
            cl_ss = ccl.angular_cl(cosmo_fid, tracer_z1, tracer_z2, ell, p_of_k_a=pk_mm)
            cl_ss_no = cl_ss + noise_shape
            
            CL_ALL[(N_ell*c):(N_ell*c)+N_ell] = cl_ss_no

        # check whether things make sense
        if plot_for_sanity == True:
            if c == 0:
                # Plot for sanity
                plt.loglog(ells, cl_gg, label=r'$\mathrm{gg}$')
                plt.loglog(ells, cl_gg_no, label=r'$\mathrm{gg}+{\rm noise}$')
                plt.loglog(ells, cl_ss, label=r'$\mathrm{ss}$')
                plt.loglog(ells, cl_gs, label=r'$\mathrm{gs}$')
                plt.xlabel(r'$\ell$')
                plt.ylabel(r'$C_{\ell}$')
                plt.legend()
                plt.savefig('Cls.png')
                plt.close()

    # if we don't want the inverse covariance matrix
    if compute_inv_cov == False:
        print(len(CL_ALL))
        return CL_ALL

    # print out numbers to make sure there is internet connection
    print(len(CL_ALL))
    print(np.sum(CL_ALL>0))

    # initiate covariance matrix into the trade
    COV_ALL = np.zeros((len(CL_ALL),len(CL_ALL)))    
    # COMPUTE COVARIANCE MATRIX: Cov(A,B)
    for c_A, comb_A in enumerate(all_combos):
        # remove half the computations
        for c_B, comb_B in enumerate(all_combos):
            # pair A=(ti,tj), pair B=(tm,tn) at same ell, where t stands for either g or s
            i = comb_A[0]%N_tomo # redshift bin of tracer A_1 (i.e. along rows of Cov)
            j = comb_A[1]%N_tomo # redshift bin of tracer A_2 (i.e. along rows of Cov)
            m = comb_B[0]%N_tomo # redshift bin of tracer B_1 (i.e. along columns of Cov)
            n = comb_B[1]%N_tomo # redshift bin of tracer B_2 (i.e. along columns of Cov)

            # These are the pairs (their order number in all_combos) we need for Knox
            # cov(ij,mn) = im,jn + in,jm
            c_im = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_B[0]]))==all_combos,axis=1))
            c_jn = np.argmax(np.product(np.sort(np.array([comb_A[1],comb_B[1]]))==all_combos,axis=1))
            c_in = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_B[1]]))==all_combos,axis=1))
            c_jm = np.argmax(np.product(np.sort(np.array([comb_A[1],comb_B[0]]))==all_combos,axis=1))
            # retrieving their Cls
            C_im = CL_ALL[(c_im*N_ell):(c_im*N_ell)+N_ell]
            C_jn = CL_ALL[(c_jn*N_ell):(c_jn*N_ell)+N_ell]
            C_in = CL_ALL[(c_in*N_ell):(c_in*N_ell)+N_ell]
            C_jm = CL_ALL[(c_jm*N_ell):(c_jm*N_ell)+N_ell]
            
            # Knox formula
            Cov_ijmn = (C_im*C_jn+C_in*C_jm)/((2*ell+1.)*delta_ell*f_sky)
            
            if plot_for_sanity == True:
                if (c_A == c_B):
                    print(i,j,'=',m,n)
                    print(c_A)
                    Cl_err = np.sqrt(Cov_ijmn)

                    t_i = comb_A[0]//N_tomo
                    t_j = comb_A[1]//N_tomo
                    print(N_tomo*i+j+1)
                    
                    plt.subplot(N_tomo, N_tomo, N_tomo*i+j+1)
                    plt.title("z=%f x z=%f"%(z_bin_cents[i],z_bin_cents[j]))
                    c_ij = np.argmax(np.product(np.sort(np.array([comb_A[0],comb_A[1]]))==all_combos,axis=1))
                    C_ij = CL_ALL[(c_ij*N_ell):(c_ij*N_ell)+N_ell]
                    # maybe add legend and make sure colors are the same for each type
                    (_,caps,eb)=plt.errorbar(ell,C_ij,yerr=Cl_err,lw=2.,ls='-',capsize=5,label=str(t_i*2+t_j)) 
                    plt.legend()
                    plt.xscale('log')
                    plt.yscale('log')
                    #plt.ylim([1.e-12,1.e-5])

            # fill in the diagonals of the cov matrix and make use of its symmetry Cov(A,B)=Cov(B,A)
            COV_ALL[(N_ell*c_A):(N_ell*c_A)+\
                    N_ell,(N_ell*c_B):(N_ell*c_B)+N_ell] = np.diag(Cov_ijmn)
            COV_ALL[(N_ell*c_B):(N_ell*c_B)+\
                    N_ell,(N_ell*c_A):(N_ell*c_A)+N_ell] = np.diag(Cov_ijmn)

    # check matrix is positive definite
    if (is_pos_def(COV_ALL) != True): print("Covariance is not positive definite!"); exit(0)
    # compute and return inverse
    ICOV_ALL = la.inv(COV_ALL)
    return ICOV_ALL