Ejemplo n.º 1
0
def constraints(params, zs):
    cosmo = Class()
    cosmo.set(params)
    cosmo.compute()
    h = cosmo.Hubble(0) * 299792.458
    om0 = cosmo.Omega0_m()
    #print(cosmo.pars)
    zarr2 = cosmo.get_background().get('z')
    hz = cosmo.get_background().get('H [1/Mpc]')
    hf = interpolate.InterpolatedUnivariateSpline(zarr2[-1:0:-1], hz[-1:0:-1])
    chiz = cosmo.get_background().get('comov. dist.')
    chif = interpolate.InterpolatedUnivariateSpline(zarr2[-1:0:-1],
                                                    chiz[-1:0:-1])

    pkz = np.zeros((nk, nz))
    pklz2 = np.zeros((nk, nz))
    dprime = np.zeros((nk, 1))
    zarr = np.linspace(0, zmax, nz)
    karr = np.logspace(-3, np.log10(20), nk)
    rcollarr = np.zeros(nz)
    kcarr = np.zeros(nz)
    delz = 0.01

    for i in np.arange(nz):
        Dz = (cosmo.scale_independent_growth_factor(zarr[i]) /
              cosmo.scale_independent_growth_factor(0))
        sigz = lambda x: Dz * cosmo.sigma(x, zarr[i]) - 1.192182033080519
        if (sigz(1e-5) > 0) & (sigz(10) < 0):
            rcollarr[i] = optimize.brentq(sigz, 1e-5, 10)
        else:
            rcollarr[i] = 0
        for j in np.arange(nk):
            pkz[j, i] = cosmo.pk(karr[j], zarr[i])
    for i in np.arange(nk):
        pklz0 = np.log(cosmo.pk(karr[i], zs - delz) / cosmo.pk(karr[i], 0))
        pklz1 = np.log(cosmo.pk(karr[i], zs + delz) / cosmo.pk(karr[i], 0))
        pklz2[i] = cosmo.pk(karr[i], 0)
        dprime[i] = -hf(zs) * np.sqrt(
            cosmo.pk(karr[i], zs) / pklz2[i, 0]) * (pklz1 - pklz0) / 4 / delz
        #divided by 2 for step size, another for defining D'

    w0 = params.get('w0_fld')
    wa = params.get('wa_fld')
    mt = 5 * np.log10(cosmo.luminosity_distance(zs))
    #mt = 5*np.log10(fanal.dlatz(zs, om0, og0, w0, wa))
    Rc = (2 * 4.302e-9 * Mc / h**2 / om0)**(1 / 3)
    mask = (0 < rcollarr) & (rcollarr < Rc)
    kcarr[mask] = 2 * np.pi / rcollarr[mask]
    mask = (rcollarr >= Rc)
    kcarr[mask] = 2 * np.pi / Rc
    #plt.semilogy(zarr, kcarr)
    pksmooth = pdf.pkint(karr, zarr, pkz, kcarr)

    par2 = {'w0': w0, 'wa': wa, 'Omega_m': om0}
    print(par2)
    #kmin = conv.kmin(zs, chif, hf)*(-3./2.*hf(0)**2*om0)
    kvar = conv.kvar(zs, pksmooth, chif, hf) * (3. / 2. * hf(0)**2 * om0)**2
    #sigln = np.log(1+kvar/np.abs(kmin)**2)
    #L = pdf.convpdf(kmin, sigln, sig, mfid-mt)
    #sigln = np.sqrt(sig**2+(5/np.log(10))**2*kvar)
    #L = pdf.gausspdf(sig, mfid-mt)
    #lnL = mt/sig
    vvar = np.trapz(pklz2[:, 0] * dprime[:, 0]**2,
                    karr) / 6 / np.pi**2 * (1 -
                                            (1 + zs) / hf(zs) / chif(zs))**2
    #var_tot = norm*kvar+sig**2
    lnL = -mt**2 / 2
    print('Sigmasq = {}, {}, Likelihood = {}'.format(kvar, vvar, lnL))
    cosmo.struct_cleanup()
    cosmo.empty()
    return [mt, kvar, vvar]


#[mt, var_tot]
Ejemplo n.º 2
0
class Cosmology(object):
    """
    Class to hold the basic cosmology and CLASS attributes. This can be initialized by a set of cosmological parameters or a pre-defined cosmology.

    Loaded cosmological models:

    - **Planck18**: Bestfit cosmology from Planck 2018, using the baseline TT,TE,EE+lowE+lensing likelihood.
    - **Quijote**: Fiducial cosmology from the Quijote simulations of Francisco Villaescusa-Navarro et al.
    - **Abacus**: Fiducial cosmology from the Abacus simulations of Lehman Garrison et al.

    Args:
        redshift (float): Desired redshift :math:`z`
        name (str): Load cosmology from a list of predetermined cosmologies (see above).
        params (kwargs): Any other CLASS parameters. (Note that sigma8 does not seem to be supported by CLASS in Python 3).

    Keyword Args:
        verb (bool): If true output useful messages througout run-time, default: False.
        npoints (int): Number of points to use in the interpolators for sigma^2, default: 100000

    """

    loaded_models = {'Quijote':{"h":0.6711,"omega_cdm":(0.3175 - 0.049)*0.6711**2,
                                "Omega_b":0.049, "n_s":0.9624,
                                "N_eff":3.046, "A_s":2.134724e-09}, #"sigma8":0.834,
                     'Abacus':{"h":0.6726,"omega_cdm":0.1199,
                                "omega_b":0.02222,"n_s":0.9652,"A_s":2.135472e-09,#"sigma8":0.830,
                                "N_eff":3.046},
                     'Planck18':{"h":0.6732,"omega_cdm":0.12011,"omega_b":0.022383,
                                "n_s":0.96605,"A_s":2.042644e-09}}#,"sigma8":0.8120}}

    def __init__(self,redshift,name="",verb=False,npoints=int(1e5),**params):

        """
        Initialize the cosmology class with cosmological parameters or a defined model.

        """
        ## Load parameters into a dictionary to pass to CLASS
        class_params = dict(**params)
        if len(name)>0:
            if len(params.items())>0:
                raise Exception('Must either choose a preset cosmology or specify parameters!')
            if name in self.loaded_models.keys():
                if verb: print('Loading the %s cosmology at z = %.2f'%(name,redshift))
                loaded_model = self.loaded_models[name]
                for key in loaded_model.keys():
                    class_params[key] = loaded_model[key]
            else:
                raise Exception("This cosmology isn't yet implemented")
        else:
            if len(params.items())==0:
                if verb: print('Using default CLASS cosmology')
            for name, param in params.items():
                class_params[name] = param

        ## # Check we have the correct parameters
        if 'sigma8' in class_params.keys() and 'A_s' in class_params.keys():
            raise NameError('Cannot specify both A_s and sigma8!')

        ## Define other parameters
        self.z = redshift
        self.a = 1./(1.+redshift)
        if 'output' not in class_params.keys():
            class_params['output']='mPk'
        if 'P_k_max_h/Mpc' not in class_params.keys() and 'P_k_max_1/Mpc' not in class_params.keys():
            class_params['P_k_max_h/Mpc']=300.
        if 'z_pk' in class_params.keys():
            assert class_params['z_pk']==redshift, "Can't pass multiple redshifts!"
        else:
            class_params['z_pk']=redshift

        ## Load CLASS and set parameters
        if verb: print('Loading CLASS')
        self.cosmo = Class()
        self.cosmo.set(class_params)
        self.cosmo.compute()
        self.h = self.cosmo.h()
        self.name = name
        self.npoints = npoints
        self.verb = verb

        ## Check if we're using neutrinos here
        if self.cosmo.Omega_nu>0.:
            if self.verb: print("Using a neutrino fraction of Omega_nu = %.3e"%self.cosmo.Omega_nu)
            self.use_neutrinos = True
            # Define neutrino mass fraction
            self.f_nu = self.cosmo.Omega_nu/self.cosmo.Omega_m()
            if self.cosmo.Neff()>3.5:
                print("N_eff > 3.5, which seems large (standard value: 3.046). This may indicate that N_ur has not been set.")
        else:
            if self.verb: print("Assuming massless neturinos.")
            self.use_neutrinos = False

        ## Create a vectorized sigma(R) function from CLASS
        if self.use_neutrinos:
            self.vector_sigma_R = np.vectorize(lambda r: self.cosmo.sigma_cb(r/self.h,self.z))
        else:
            self.vector_sigma_R = np.vectorize(lambda r: self.cosmo.sigma(r/self.h,self.z))

        # get density in physical units at z = 0
        # rho_critical is in Msun/h / (Mpc/h)^3 units
        # rhoM is in **physical** units of Msun/Mpc^3
        self.rho_critical = ((3.*100.*100.)/(8.*np.pi*6.67408e-11)) * (1000.*1000.*3.085677581491367399198952281E+22/1.9884754153381438E+30)
        self.rhoM = self.rho_critical*self.cosmo.Omega0_m()

    def compute_linear_power(self,kh,kh_min=0.,with_neutrinos=False):
        """Compute the linear power spectrum from CLASS for a vector of input k.

        If set, we remove any modes below some minimum k.

        Args:
            kh (float, np.ndarray): Wavenumber or vector of wavenumbers (in h/Mpc units) to compute linear power with.

        Keyword Args:
            kh_min (float): Value of k (in h/Mpc units) below which to set :math:`P(k) = 0`, default: 0.
            with_neutrinos (bool): If True, return the full matter power spectrum, else return the CDM+baryon power spectrum (which is generally used in the halo model). Default: False.

        Returns:
            np.ndarray: Linear power spectrum in :math:`(h^{-1}\mathrm{Mpc})^3` units
        """

        if type(kh)==np.ndarray:

            # Define output vector and filter modes with too-small k
            output = np.zeros_like(kh)
            filt = np.where(kh>kh_min)
            N_k = len(filt[0])

            # Compute Pk using CLASS (vectorized)
            if not hasattr(self,'vector_linear_power'):
                ## NB: This works in physical 1/Mpc units so we convert here
                if self.use_neutrinos:
                    # Here we need both the CDM+baryon (cb) power spectra and the full matter power spectra
                    # The CDM+baryon spectrum is used for the halo model parts, and the residual (matter-cb) added at the end
                    self.vector_linear_power = np.vectorize(lambda k: self.cosmo.pk_cb_lin(k*self.h,self.z)*self.h**3.)
                    self.vector_linear_power_total = np.vectorize(lambda k: self.cosmo.pk_lin(k*self.h,self.z)*self.h**3.)
                else:
                    self.vector_linear_power = np.vectorize(lambda k: self.cosmo.pk_lin(k*self.h,self.z)*self.h**3.)

            if self.use_neutrinos and with_neutrinos:
                output[filt] = self.vector_linear_power_total(kh[filt])
            else:
                output[filt] = self.vector_linear_power(kh[filt])
            return output

        else:
            if kh<kh_min:
                return 0.
            else:
                if self.use_neutrinos and with_neutrinos:
                    return self.vector_linear_power_total(kh)
                else:
                    return self.vector_linear_power(kh)

    def sigma_logM_int(self,logM_h):
        """Return the value of :math:`\sigma(M,z)` using the prebuilt interpolators, which are constructed if not present.

        Args:
            logM (np.ndarray): Input :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`

        Returns:
            np.ndarray: :math:`\sigma(M,z)`
        """
        if not hasattr(self,'sigma_logM_int_func'):
            self._interpolate_sigma_and_deriv(npoints=self.npoints)
        return self._sigma_logM_int_func(logM_h)

    def dlns_dlogM_int(self,logM_h):
        """Return the value of :math:`d\ln\sigma/d\log M` using the prebuilt interpolators, which are constructed if not present.

        Args:
            logM (np.ndarray): Input :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`

        Returns:
            np.ndarray: :math:`d\ln\sigma/d\log M`
        """
        if not hasattr(self,'dlns_dlogM_int_func'):
            self._interpolate_sigma_and_deriv(npoints=self.npoints)
        return self._dlns_dlogM_int_func(logM_h)

    def _sigmaM(self,M_h):
        """Compute :math:`\sigma(M,z)` from CLASS as a vector function.

        Args:
            M_h (np.ndarray): Mass in :math:`h^{-1}M_\mathrm{sun}` units.
            z (float): Redshift.

        Returns:
            np.ndarray: :math:`\sigma(M,z)`
        """
        # convert to Lagrangian radius
        r_h = np.power((3.*M_h)/(4.*np.pi*self.rhoM),1./3.)
        sigma_func = self.vector_sigma_R(r_h)
        return sigma_func

    def _interpolate_sigma_and_deriv(self,logM_h_min=6,logM_h_max=17,npoints=int(1e5)):
        """Create an interpolator function for :math:`d\ln\sigma/d\log M` and :math:`sigma(M)`.

        NB: This has no effect if the interpolator has already been computed.

        Keyword Args:
            logM_min (float): Minimum mass in :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`, default: 6
            logM_max (float): Maximum mass in :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`, default 17
            npoints (int): Number of sampling points, default 100000

        """

        if not hasattr(self,'_sigma_logM_int_func'):
            if self.verb: print("Creating an interpolator for sigma(M) and its derivative.")
            ## Compute log derivative by interpolation and numerical differentiation
            # First compute the grid of M and sigma
            M_h_grid = np.logspace(logM_h_min,logM_h_max,10000)
            all_sigM = self._sigmaM(M_h_grid)
            logM_h_grid = np.log10(M_h_grid)

            # Define ln(sigma) and numerical derivatives
            all_lns = np.log(all_sigM)
            all_diff = -np.diff(all_lns)/np.diff(logM_h_grid)
            mid_logM_h = 0.5*(logM_h_grid[:-1]+logM_h_grid[1:])

            self._sigma_logM_int_func = interp1d(logM_h_grid,all_sigM)
            self._dlns_dlogM_int_func = interp1d(mid_logM_h,all_diff)

    def _h_over_h0(self):
        """Return the value of :math:`H(z)/H(0)` at the class redshift

        Returns:
            float: :math:`H(z)/H(0)`
        """
        Omega0_k = 1.-self.cosmo.Omega0_m()-self.cosmo.Omega_Lambda()
        Ea = np.sqrt((self.cosmo.Omega0_m()+self.cosmo.Omega_Lambda()*pow(self.a,-3)+Omega0_k*self.a)/pow(self.a,3))
        return Ea

    def _Omega_m(self):
        """Return the value of :math:`\Omega_m(z)` at the class redshift