예제 #1
0
def test_class_setup():
    cosmology = astropy.cosmology.Planck13
    assert cosmology.Om0 == cosmology.Odm0 + cosmology.Ob0
    assert 1 == (cosmology.Om0 + cosmology.Ode0 + cosmology.Ok0 +
                 cosmology.Ogamma0 + cosmology.Onu0)
    class_parameters = get_class_parameters(cosmology)
    try:
        from classy import Class
        cosmo = Class()
        cosmo.set(class_parameters)
        cosmo.compute()
        assert cosmo.h() == cosmology.h
        assert cosmo.T_cmb() == cosmology.Tcmb0.value
        assert cosmo.Omega_b() == cosmology.Ob0
        # Calculate Omega(CDM)_0 two ways:
        assert abs((cosmo.Omega_m() - cosmo.Omega_b()) -
                   (cosmology.Odm0 - cosmology.Onu0)) < 1e-8
        assert abs(cosmo.Omega_m() - (cosmology.Om0 - cosmology.Onu0)) < 1e-8
        # CLASS calculates Omega_Lambda itself so this is a non-trivial test.
        calculated_Ode0 = cosmo.get_current_derived_parameters(
            ['Omega_Lambda'])['Omega_Lambda']
        assert abs(calculated_Ode0 - (cosmology.Ode0 + cosmology.Onu0)) < 1e-5
        cosmo.struct_cleanup()
        cosmo.empty()
    except ImportError:
        pass
예제 #2
0
b4ar = [
    256.82199304134315, 78.62142674299282, 374.08451421691973,
    -146.54664459312085
]

norm = 1.
# b1 = 1.909433
# b2 = -2.357092
# bG2 = 3.818261e-01
# css0 = -2.911944e+01
# css2 = -1.235181e+01
# Pshot = 2.032084e+03
# bGamma3 = 0.
# b4 = 1.924983e+02

print('S8=', cosmo.sigma8() * (cosmo.Omega_m() / 0.3)**0.5)

kmsMpc = 3.33564095198145e-6
rd = cosmo.rs_drag()
print('rd=', rd)

for j in range(len(chunk)):
    z = zs[j]
    b1 = b1ar[j]
    b2 = b2ar[j]
    bG2 = bG2ar[j]
    css0 = css0ar[j]
    css2 = css2ar[j]
    Pshot = Pshotar[j]
    bGamma3 = bGamma3ar[j]
    b4 = b4ar[j]
    'P_k_max_h/Mpc': '100.',
    'output': 'mPk,tCl',
    'z_pk': z,
    'non linear': ' SPT ',
    'IR resummation': ' Yes ',
    'Bias tracers': ' Yes ',
    'RSD': ' Yes ',
    'RSD only': 'No',
    'AP': 'No'
})
#cosmo.set({'k_pivot':'0.05','ln10^{10}A_s':'3.11655','n_s':'0.9649','alpha_s':'0.','Omega_k':'0.','Omega_fld':'0','YHe':0.25,'z_reio':'10.','T_cmb':'2.726','h':'0.6511406','omega_b':'0.0218022','N_ncdm':'0','N_eff':'3.045','omega_cdm':'0.116977','P_k_max_h/Mpc': '100.','output':'mPk,tCl','z_pk':'0.61','non linear':' SPT ','IR resummation':' Yes ','Bias tracers':' Yes ','RSD':' Yes ','RSD only':'No', 'Alcock-Paczynski effect':'Yes'})
t1 = time()
cosmo.compute()

h = cosmo.h()
omb = cosmo.Omega_m()

print(omb)

#k1 = 0.7*1.028185622909e-5
#k1 = 1.e-6
#z = 0.0
#k1 = 0.1
#print(cosmo.pk(k1,z))
#print(cosmo.pk_lin(k1,z))

k = np.linspace(log(0.0001), log(50), 400)
k = np.exp(k)
testout = [[0 for x in range(42)] for y in range(len(k))]
for i in range(len(k)):
    testout[i][0] = k[i]
예제 #4
0
    def fitEE(self):

        # function to cimpute the band powers

        cosmo = Class()
        cosmo.set(self.cosmoParams)

        if self.settings.include_neutrino:
            cosmo.set(self.other_settings)
            cosmo.set(self.neutrino_settings)

        cosmo.set(self.class_argumets)

        try:
            cosmo.compute()

        except CosmoComputationError as failure_message:

            print(failure_message)

            self.sigma_8 = np.nan

            cosmo.struct_cleanup()
            cosmo.empty()

            return np.array([np.nan] * self.nzcorrs * self.bo_EE), np.array(
                [np.nan] * self.nzcorrs * self.bo_EE), np.array(
                    [np.nan] * self.nzcorrs * self.bo_EE)

        except CosmoSevereError as critical_message:

            print(critical_message)

            self.sigma_8 = np.nan

            cosmo.struct_cleanup()
            cosmo.empty()

            return np.array([np.nan] * self.nzcorrs * self.bo_EE), np.array(
                [np.nan] * self.nzcorrs * self.bo_EE), np.array(
                    [np.nan] * self.nzcorrs * self.bo_EE)

        # retrieve Omega_m and h from cosmo (CLASS)
        self.Omega_m = cosmo.Omega_m()
        self.small_h = cosmo.h()

        self.rho_crit = self.get_critical_density()

        # derive the linear growth factor D(z)
        linear_growth_rate = np.zeros_like(self.redshifts)
        # print self.redshifts
        for index_z, z in enumerate(self.redshifts):
            try:
                # for CLASS ver >= 2.6:
                linear_growth_rate[
                    index_z] = cosmo.scale_independent_growth_factor(z)
            except BaseException:
                # my own function from private CLASS modification:
                linear_growth_rate[index_z] = cosmo.growth_factor_at_z(z)
        # normalize to unity at z=0:
        try:
            # for CLASS ver >= 2.6:
            linear_growth_rate /= cosmo.scale_independent_growth_factor(0.)
        except BaseException:
            # my own function from private CLASS modification:
            linear_growth_rate /= cosmo.growth_factor_at_z(0.)

        # get distances from cosmo-module:
        r, dzdr = cosmo.z_of_r(self.redshifts)

        self.sigma_8 = cosmo.sigma8()

        # Get power spectrum P(k=l/r,z(r)) from cosmological module
        # this doesn't really have to go into the loop over fields!
        pk = np.zeros((self.settings.nellsmax, self.settings.nzmax), 'float64')
        k_max_in_inv_Mpc = self.settings.k_max_h_by_Mpc * self.small_h

        # note that this is being computed at only nellsmax
        # followed by an interplation
        record = np.zeros((self.settings.nellsmax, self.settings.nzmax))
        record_k = np.zeros((self.settings.nellsmax, self.settings.nzmax))
        for index_ells in range(self.settings.nellsmax):
            for index_z in range(1, self.settings.nzmax):
                k_in_inv_Mpc = (self.ells[index_ells] + 0.5) / r[index_z]
                z = self.redshifts[index_z]

                record[index_ells, index_z] = self.baryon_feedback_bias_sqr(
                    k_in_inv_Mpc / self.small_h,
                    self.redshifts[index_z],
                    A_bary=self.systematics['A_bary'])
                record_k[index_ells, index_z] = k_in_inv_Mpc

        self.record_bf = record[:, 1:].flatten()
        self.record_k = record_k[:, 1:].flatten()
        self.k_max_in_inv_Mpc = k_max_in_inv_Mpc

        for index_ells in range(self.settings.nellsmax):
            for index_z in range(1, self.settings.nzmax):
                # standard Limber approximation:
                # k = ells[index_ells] / r[index_z]
                # extended Limber approximation (cf. LoVerde & Afshordi 2008):
                k_in_inv_Mpc = (self.ells[index_ells] + 0.5) / r[index_z]
                if k_in_inv_Mpc > k_max_in_inv_Mpc:
                    pk_dm = 0.
                else:
                    pk_dm = cosmo.pk(k_in_inv_Mpc, self.redshifts[index_z])
                # pk[index_ells,index_z] = cosmo.pk(ells[index_ells]/r[index_z], self.redshifts[index_z])
                if self.settings.baryon_feedback:
                    pk[index_ells,
                       index_z] = pk_dm * self.baryon_feedback_bias_sqr(
                           k_in_inv_Mpc / self.small_h,
                           self.redshifts[index_z],
                           A_bary=self.systematics['A_bary'])
                else:
                    pk[index_ells, index_z] = pk_dm

    # for KiDS-450 constant biases in photo-z are not sufficient:
        if self.settings.bootstrap_photoz_errors:
            # draw a random bootstrap n(z); borders are inclusive!
            random_index_bootstrap = np.random.randint(
                int(self.settings.index_bootstrap_low),
                int(self.settings.index_bootstrap_high) + 1)
            # print 'Bootstrap index:', random_index_bootstrap
            pz = np.zeros((self.settings.nzmax, self.nzbins), 'float64')
            pz_norm = np.zeros(self.nzbins, 'float64')

            for zbin in range(self.nzbins):

                redshift_bin = self.redshift_bins[zbin]
                # ATTENTION: hard-coded subfolder!
                # index can be recycled since bootstraps for tomographic bins
                # are independent!
                fname = os.path.join(
                    self.settings.data_directory,
                    '{:}/bootstraps/{:}/n_z_avg_bootstrap{:}.hist'.format(
                        self.settings.photoz_method, redshift_bin,
                        random_index_bootstrap))
                z_hist, n_z_hist = np.loadtxt(fname, unpack=True)

                shift_to_midpoint = np.diff(z_hist)[0] / 2.
                spline_pz = itp.splrep(z_hist + shift_to_midpoint, n_z_hist)
                mask_min = self.redshifts >= z_hist.min() + shift_to_midpoint
                mask_max = self.redshifts <= z_hist.max() + shift_to_midpoint
                mask = mask_min & mask_max
                # points outside the z-range of the histograms are set to 0!
                pz[mask, zbin] = itp.splev(self.redshifts[mask], spline_pz)

                dz = self.redshifts[1:] - self.redshifts[:-1]
                pz_norm[zbin] = np.sum(0.5 * (pz[1:, zbin] + pz[:-1, zbin]) *
                                       dz)

            pr = pz * (dzdr[:, np.newaxis] / pz_norm)

        else:
            pr = self.pz * (dzdr[:, np.newaxis] / self.pz_norm)
            # pr[pr < 0] = 0

        g = np.zeros((self.settings.nzmax, self.nzbins), 'float64')

        for zbin in range(self.nzbins):
            # assumes that z[0] = 0
            for nr in range(1, self.settings.nzmax - 1):
                # for nr in range(self.nzmax - 1):
                fun = pr[nr:, zbin] * (r[nr:] - r[nr]) / r[nr:]
                g[nr, zbin] = np.sum(0.5 * (fun[1:] + fun[:-1]) *
                                     (r[nr + 1:] - r[nr:-1]))
                g[nr, zbin] *= 2. * r[nr] * (1. + self.redshifts[nr])

        # Start loop over l for computation of C_l^shear
        Cl_GG_integrand = np.zeros(
            (self.settings.nzmax, self.nzbins, self.nzbins), 'float64')
        Cl_GG = np.zeros((self.settings.nellsmax, self.nzbins, self.nzbins),
                         'float64')

        Cl_II_integrand = np.zeros_like(Cl_GG_integrand)
        Cl_II = np.zeros_like(Cl_GG)

        Cl_GI_integrand = np.zeros_like(Cl_GG_integrand)
        Cl_GI = np.zeros_like(Cl_GG)

        dr = r[1:] - r[:-1]
        for index_ell in range(self.settings.nellsmax):

            # find Cl_integrand = (g(r) / r)**2 * P(l/r,z(r))
            for zbin1 in range(self.nzbins):
                for zbin2 in range(zbin1 + 1):  # self.nzbins):
                    Cl_GG_integrand[1:, zbin1, zbin2] = g[1:, zbin1] * \
                        g[1:, zbin2] / r[1:]**2 * pk[index_ell, 1:]

                    factor_IA = self.get_factor_IA(
                        self.redshifts[1:], linear_growth_rate[1:],
                        self.systematics['A_IA'])  # / self.dzdr[1:]
                    # print F_of_x
                    # print self.eta_r[1:, zbin1].shape
                    Cl_II_integrand[1:, zbin1, zbin2] = pr[1:, zbin1] * \
                        pr[1:, zbin2] * factor_IA**2 / r[1:]**2 * pk[index_ell, 1:]
                    pref = g[1:, zbin1] * pr[1:, zbin2] + g[1:, zbin2] * pr[
                        1:, zbin1]
                    Cl_GI_integrand[1:, zbin1,
                                    zbin2] = pref * factor_IA / r[1:]**2 * pk[
                                        index_ell, 1:]

            # Integrate over r to get C_l^shear_ij = P_ij(l)
            # C_l^shear_ii = 9/4 Omega0_m^2 H_0^4 \sum_0^rmax dr (g_i(r) g_j(r)
            # /r**2) P(k=l/r,z(r))
            for zbin1 in range(self.nzbins):
                for zbin2 in range(zbin1 + 1):  # self.nzbins):
                    Cl_GG[index_ell, zbin1, zbin2] = np.sum(
                        0.5 * (Cl_GG_integrand[1:, zbin1, zbin2] +
                               Cl_GG_integrand[:-1, zbin1, zbin2]) * dr)
                    # here we divide by 16, because we get a 2^2 from g(z)!
                    Cl_GG[index_ell, zbin1, zbin2] *= 9. / 16. * \
                        self.Omega_m**2  # in units of Mpc**4
                    # dimensionless
                    Cl_GG[index_ell, zbin1,
                          zbin2] *= (self.small_h / 2997.9)**4

                    Cl_II[index_ell, zbin1, zbin2] = np.sum(
                        0.5 * (Cl_II_integrand[1:, zbin1, zbin2] +
                               Cl_II_integrand[:-1, zbin1, zbin2]) * dr)

                    Cl_GI[index_ell, zbin1, zbin2] = np.sum(
                        0.5 * (Cl_GI_integrand[1:, zbin1, zbin2] +
                               Cl_GI_integrand[:-1, zbin1, zbin2]) * dr)
                    # here we divide by 4, because we get a 2 from g(r)!
                    Cl_GI[index_ell, zbin1, zbin2] *= 3. / 4. * self.Omega_m
                    Cl_GI[index_ell, zbin1,
                          zbin2] *= (self.small_h / 2997.9)**2

        # ordering of redshift bins is correct in definition of theory below!
        theory_EE_GG = np.zeros((self.nzcorrs, self.bo_EE), 'float64')
        theory_EE_II = np.zeros((self.nzcorrs, self.bo_EE), 'float64')
        theory_EE_GI = np.zeros((self.nzcorrs, self.bo_EE), 'float64')

        index_corr = 0
        # A_noise_corr = np.zeros(self.nzcorrs)
        for zbin1 in range(self.nzbins):
            for zbin2 in range(zbin1 + 1):  # self.nzbins):
                # correlation = 'z{:}z{:}'.format(zbin1 + 1, zbin2 + 1)
                # print(zbin1, zbin2)

                Cl_sample_GG = Cl_GG[:, zbin1, zbin2]
                spline_Cl_GG = itp.splrep(self.ells, Cl_sample_GG)
                D_l_EE_GG = self.ell_norm * \
                    itp.splev(self.ells_sum, spline_Cl_GG)

                theory_EE_GG[index_corr, :] = self.get_theory(
                    self.ells_sum,
                    D_l_EE_GG,
                    self.band_window_matrix,
                    index_corr,
                    band_type_is_EE=True)

                Cl_sample_GI = Cl_GI[:, zbin1, zbin2]
                spline_Cl_GI = itp.splrep(self.ells, Cl_sample_GI)
                D_l_EE_GI = self.ell_norm * \
                    itp.splev(self.ells_sum, spline_Cl_GI)
                theory_EE_GI[index_corr, :] = self.get_theory(
                    self.ells_sum,
                    D_l_EE_GI,
                    self.band_window_matrix,
                    index_corr,
                    band_type_is_EE=True)

                Cl_sample_II = Cl_II[:, zbin1, zbin2]
                spline_Cl_II = itp.splrep(self.ells, Cl_sample_II)
                D_l_EE_II = self.ell_norm * \
                    itp.splev(self.ells_sum, spline_Cl_II)
                theory_EE_II[index_corr, :] = self.get_theory(
                    self.ells_sum,
                    D_l_EE_II,
                    self.band_window_matrix,
                    index_corr,
                    band_type_is_EE=True)

                index_corr += 1

        cosmo.struct_cleanup()
        cosmo.empty()

        return theory_EE_GG.flatten(), theory_EE_GI.flatten(
        ), theory_EE_II.flatten()
예제 #5
0
matplotlib.mathtext.rcParams['legend.fontsize']='medium'
plt.rcParams["figure.figsize"] = [8.0,6.0]



M = Class()
# Table I of 1908.06995, third column, best-fit values
# Note: f and m found by trial-and-error to give the best-fit fEDE=.12, zc=10^3.562=3647.
M.set({'f_scf': 3.98e+26, 'm_scf': 5.31e-28, 'thetai_scf': 2.83, 'A_s': 2.215e-09, 'n_s': 0.9889, '100*theta_s': 1.04152, 'omega_b': 0.02253, 'omega_cdm': 0.1306, 'm_ncdm': 0.06, 'tau_reio': 0.072})


#'non linear':can choose 'halofit' or 'HMCODE'
M.set({'non linear':'HMCODE','N_ncdm':1, 'N_ur':2.0328, 'Omega_Lambda':0.0, 'Omega_fld':0, 'Omega_scf':-1, 'n_scf':3, 'CC_scf':1, 'scf_parameters':'1, 1, 1, 1, 1, 0.0', 'scf_tuning_index':3, 'attractor_ic_scf':'no', 'output':'tCl pCl lCl mPk', 'lensing':'yes', 'l_max_scalars':2508, 'P_k_max_h/Mpc':20,'z_max_pk':4.})
M.compute()

print(M.Omega_m())


baM = M.get_background()

fEDE = M.fEDE()
z_c = M.z_c()

baH = baM['H [1/Mpc]']
baT = baM['conf. time [Mpc]']
baa = 1/(1 + baM['z'])
bV = baM['V_e_scf']
bpp = baM["phi'_scf"]
baCrit = baM['(.)rho_crit']
rho_scf = (bpp*bpp/(2*baa*baa) + bV)/3.
예제 #6
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