Source code for pyccl.halos.hmfunc.nishimichi19

__all__ = ("MassFuncNishimichi19",)

import numpy as np

from . import MassFunc


[docs] class MassFuncNishimichi19(MassFunc): """Implements the mass function emulator of `Nishimichi et al. 2019 <https://arxiv.org/abs/1811.09504>`_. documentation is `here <https://dark-emulator.readthedocs.io/en/latest/index.html#>`_. This parametrization is only valid for '200m' masses. Args: mass_def (:class:`~pyccl.halos.massdef.MassDef` or :obj:`str`): a mass definition object, or a name string. mass_def_strict (:obj:`bool`): if ``False``, consistency of the mass definition will be ignored. extrapolate (:obj:`bool`): if ``True``, extrapolation will be used to calculate the the mass function for small halo masses, below the range supported by the Dark Emulator. Otherwise, an error is thrown when evaluating the mass function on these masses. """ name = 'Nishimichi19' def __init__(self, *, mass_def="200m", mass_def_strict=True, extrapolate=False): super().__init__(mass_def=mass_def, mass_def_strict=mass_def_strict) from dark_emulator import model_hod self.hod = model_hod.darkemu_x_hod({"fft_num": 1}) self.extrapolate = extrapolate def _check_mass_def_strict(self, mass_def): return mass_def.name != '200m' def __call__(self, cosmo, M, a): # Set up cosmology h = cosmo['h'] ob = cosmo['Omega_b']*h**2 oc = cosmo['Omega_c']*h**2 As = cosmo['A_s'] if np.isnan(As): raise ValueError("A_s must be provided to use the Dark Emulator " "halo mass function.") ns = cosmo['n_s'] w0 = cosmo['w0'] onu = 0.00064 # we fix this value (Nishimichi et al. 2019) Ode = 1.-(ob+oc+onu)/h**2. # (omega_b,omega_c,Omega_de,ln(10^10As),ns,w) cparam = np.array([ob, oc, Ode, np.log(As*1E10), ns, w0]) self.hod.set_cosmology(cparam) # calculating interpolated dndM array is (ln(M), ln(dndM)) self.hod._compute_dndM_spl(redshift=1./a-1.) # Filter out masses beyond emulator range M_use = np.atleast_1d(M) # Add h-inverse Mh = M_use * h m_hi = Mh > 1E16 m_lo = Mh < 1E12 m_good = ~(m_hi | m_lo) mfh = np.zeros_like(Mh) # Populate low-halo masses through extrapolation if needed if np.any(m_lo): if self.extrapolate: # Evaluate slope at low masses m0 = 10**np.array([12.0, 12.1]) mfp = self.hod.dndM_spl(np.log(m0)) mfp = np.exp(mfp) slope = np.log(mfp[1]/mfp[0])/np.log(m0[1]/m0[0]) mfh[m_lo] = mfp[0]*(Mh[m_lo]/m0[0])**slope else: raise RuntimeError( "Input mass range is not supported. " "The supported range is from 10^12 to 10^16 Msun/h. " "If you want to obtain mass function at " "M200m<10^12 Msun/h, use 'extrapolate=True'. " "This function will then extrapolate outside the " "supported range.") # Predict in good range of masses if np.any(m_good): mfp = self.hod.dndM_spl(np.log(Mh[m_good])) mfp = np.exp(mfp) mfh[m_good] = mfp # For masses above emulator range, n(M) will be set to zero # Remove h-inverse and correct for dn/dM -> dn/dlog10(M) # ln10 = 2.30258509299 mf = mfh*Mh*2.30258509299*h**3. if np.ndim(M) == 0: return mf[0] return mf