def delta_sigma_kawai(r, dm_fraction, lambda_dB, halo_mass, halo_redshift, mc_scatter=True): """ Returns standard deviation of the density fluctuations in projection in convergence units using Equation 30 in Kawai et al. (2021) :param r: the radius at which to evaluate the fluctuation amplitude [units kpc] :param f: the fraction of projected mass in dark matter at the radius r :param lambda_dB: de Broglie wavelength in kpc :param rhos: the density normalization of NFW proifle :param rs: the scale radius of NFW profile :param concentration: :param mc_scatter: :return: """ l = LensCosmo() c = l.NFW_concentration(halo_mass, halo_redshift, scatter=mc_scatter) rhos, rs, _ = l.NFW_params_physical(halo_mass, c, halo_redshift) halo_size = effective_halo_size(r, rhos, rs, c) relative_length_scale = lambda_dB / halo_size prefactor = 16 * np.pi**2 / 3 # extra 4pi from # integrating over the exponential delta_kappa_square = dm_fraction**2 * prefactor * relative_length_scale return delta_kappa_square**0.5
def solve_from_Mz(M, z, cross_section_type, kwargs_cross_section, z_collapse=10., include_c_scatter=False, c_scatter_add_dex=0., **kwargs_solver): """ This routine solves for the SIDM central density given the normalization of an NFW halo rhos, the scale radius rs, and a specific interaction cross section """ try: from pyHalo.Halos.lens_cosmo import LensCosmo from pyHalo.Cosmology.cosmology import Cosmology cosmo = Cosmology() lens_cosmo = LensCosmo() except: raise Exception( 'error importing pyHalo, which is needed to use this routine') c = lens_cosmo.NFW_concentration(M, z, scatter=include_c_scatter) if include_c_scatter is False and c_scatter_add_dex != 0: c = 10**(np.log10(c) + c_scatter_add_dex) rhos, rs, _ = lens_cosmo.NFW_params_physical(M, c, z) halo_age = cosmo.halo_age(z, z_collapse) if halo_age < 0.: raise Exception( 'the halo age is negative, you have probably specified a collapse redshift < halo redshift' ) return solve_from_NFW_params(rhos, rs, halo_age, cross_section_type, kwargs_cross_section, **kwargs_solver)
def delta_sigma(m, z, rein, de_Broglie_wavelength): """ Returns the mean ULDM fluctuation ampltiude of the host dark matter halo in units M_sun/kpc^2 :param m: :param z: :param rein: :param de_Broglie_wavelength: :return: """ l = LensCosmo(None, None) c = l.NFW_concentration(m, z, scatter=False) rhos, rs, _ = l.NFW_params_physical(m, c, z) nfw_rho_squared = projected_density_squared(rein, rhos, rs, c) delta_sigma = (np.sqrt(np.pi) * nfw_rho_squared * de_Broglie_wavelength)**0.5 return delta_sigma
def delta_sigmaNFW(z_lens, m, rein, de_Broglie_wavelength): ''' Returns standard deviation of the density fluctuations in projection normalized by the projected density of the host halo :param z_lens,z_source: lens and source redshifts :param m: main deflector halo mass in M_solar :param rein: Einstein radius in kpc :param de_Broglie_wavelength: de Broglie wavelength of axion in kpc ''' l = LensCosmo(None, None) c = l.NFW_concentration(m, z_lens, scatter=False) rhos, rs, _ = l.NFW_params_physical(m, c, z_lens) kappa_host = projected_squared_density(rein, rhos, rs, c)**0.5 ds = delta_sigma(m, z_lens, rein, de_Broglie_wavelength) return ds / kappa_host
class TestLensCosmo(object): def setup(self): kwargs_cosmo = {'Om0': 0.2} self.cosmo = Cosmology(cosmo_kwargs=kwargs_cosmo) zlens, zsource = 0.3, 1.7 self.lens_cosmo = LensCosmo(zlens, zsource, self.cosmo) self.h = self.cosmo.h self.con = Concentration(self.lens_cosmo) self._colossus_nfw = NFWProfile def test_const(self): D_ds = self.cosmo.D_A(0.3, 1.7) D_d = self.cosmo.D_A_z(0.3) D_s = self.cosmo.D_A_z(1.7) c_Mpc_sec = un.Quantity(c, unit=un.Mpc / un.s) G_Mpc3_Msun_sec2 = un.Quantity(G, unit=un.Mpc ** 3 / un.s ** 2 / un.solMass) const = c_Mpc_sec ** 2 / (4 * np.pi * G_Mpc3_Msun_sec2) sigma_crit_mpc = const.value * D_s / (D_d * D_ds) sigma_crit_kpc = sigma_crit_mpc * 1000 ** -2 npt.assert_almost_equal(self.lens_cosmo.sigma_crit_lensing/sigma_crit_mpc, 1, 4) npt.assert_almost_equal(self.lens_cosmo.sigma_crit_lens_kpc/sigma_crit_kpc, 1, 4) def test_sigma_crit_mass(self): area = 2. sigma_crit_mass = self.lens_cosmo.sigma_crit_mass(0.7, area) sigma_crit = self.lens_cosmo.get_sigma_crit_lensing(0.7, 1.7) npt.assert_almost_equal(sigma_crit_mass, sigma_crit * area) def test_colossus(self): colossus = self.lens_cosmo.colossus npt.assert_almost_equal(colossus.Om0, 0.2) def test_truncate_roche(self): m = 10**9. norm = 1.4 power = 0.9 r3d = 1000 rt = norm * (m / 10 ** 7) ** (1./3) * (r3d / 50) ** power rtrunc = self.lens_cosmo.truncation_roche(m, r3d, norm, power) npt.assert_almost_equal(rt, rtrunc, 3) def test_LOS_trunc(self): rt = self.lens_cosmo.LOS_truncation_rN(10**8, 0.2, 90) rtrunc = self.lens_cosmo.rN_M_nfw_comoving(10**8 * self.lens_cosmo.cosmo.h, 90, 0.2) npt.assert_almost_equal(rt, 1000 * rtrunc * (1+0.2)**-1 / self.lens_cosmo.cosmo.h) def test_NFW_concentration(self): c = self.lens_cosmo.NFW_concentration(10 ** 9, 0.2, model='diemer19', scatter=False) c2 = self.lens_cosmo.NFW_concentration(10 ** 9, 0.2, model='diemer19', scatter=True) npt.assert_raises(AssertionError, npt.assert_array_equal, c, c2) logmhm = 8. kwargs_suppression, suppression_model = {'c_scale': 60., 'c_power': -0.17}, 'polynomial' c_wdm = self.lens_cosmo.NFW_concentration(10 ** 9, 0.2, model='diemer19', scatter=False, logmhm=logmhm, kwargs_suppresion=kwargs_suppression, suppression_model=suppression_model) suppresion = WDM_concentration_suppresion_factor(10**9, 0.2, logmhm, suppression_model, kwargs_suppression) npt.assert_almost_equal(suppresion * c, c_wdm) kwargs_suppression, suppression_model = {'a_mc': 0.5, 'b_mc': 0.17}, 'hyperbolic' c_wdm = self.lens_cosmo.NFW_concentration(10 ** 9, 0.2, model='diemer19', scatter=False, logmhm=logmhm, kwargs_suppresion=kwargs_suppression, suppression_model=suppression_model) suppresion = WDM_concentration_suppresion_factor(10 ** 9, 0.2, logmhm, suppression_model, kwargs_suppression) npt.assert_almost_equal(suppresion * c, c_wdm) def test_subhalo_accretion(self): zi = [self.lens_cosmo.z_accreted_from_zlens(10**8, 0.5) for _ in range(0, 20000)] h, b = np.histogram(zi, bins=np.linspace(0.5, 6, 20)) # number at the lens redshift should be about 5x that at redshift 4 ratio = h[0]/h[12] npt.assert_almost_equal(ratio/5 - 1, 0., 1) def test_nfw_fundamental_parameters(self): for z in [0., 0.74, 1.2]: M, c = 10**8, 17.5 rho_crit_z = self.cosmo.rho_crit(z) rhos, rs, r200 = self.lens_cosmo.nfwParam_physical_Mpc(M, c, z) h = self.cosmo.h _rhos, _rs = self._colossus_nfw.fundamentalParameters(M * h, c, z, '200c') # output in units (M h^2 / kpc^2, kpc/h) rhos_col = _rhos * h ** 2 * 1000 ** 3 rs_col = _rs / h / 1000 r200_col = rs * c npt.assert_almost_equal(rhos/rhos_col, 1, 3) npt.assert_almost_equal(rs/rs_col, 1, 3) npt.assert_almost_equal(r200/r200_col, 1, 3) def _profile(x): fac = x * (1 + x) ** 2 return 1. / fac def _integrand(x): return 4 * np.pi * x ** 2 * _profile(x) volume = 4 * np.pi/3 * r200 ** 3 integral = quad(_integrand, 0, r200/rs)[0] mean_density = rhos * rs ** 3 * integral / volume ratio = mean_density/rho_crit_z npt.assert_almost_equal(ratio/200, 1., 3) def test_mhm_convert(self): mthermal = 5.3 mhm = self.lens_cosmo.mthermal_to_halfmode(mthermal) mthermal_out = self.lens_cosmo.halfmode_to_thermal(mhm) npt.assert_almost_equal(mthermal/mthermal_out, 1, 2) fsl = self.lens_cosmo.mhm_to_fsl(10**8.) npt.assert_array_less(fsl, 100) def test_NFW_phys2angle(self): c = self.lens_cosmo.NFW_concentration(10**8, 0.5, scatter=False) out = self.lens_cosmo.nfw_physical2angle(10**8, c, 0.5) out2 = self.lens_cosmo.nfw_physical2angle_fromM(10**8, 0.5) for (x, y) in zip(out, out2): npt.assert_almost_equal(x, y) rhos_kpc, rs_kpc, _ = self.lens_cosmo.NFW_params_physical(10**8, c, 0.5) rhos_mpc = rhos_kpc * 1000 ** 3 rs_mpc = rs_kpc * 1e-3 rs, theta_rs = self.lens_cosmo.nfw_physical2angle_fromNFWparams(rhos_mpc, rs_mpc, 0.5) npt.assert_almost_equal(rs, out[0]) npt.assert_almost_equal(theta_rs, out[1])
class TestPjaffeHalo(object): def setup(self): mass = 10**7. x = 0.5 y = 1. r3d = np.sqrt(1 + 0.5 ** 2 + 70**2) self.r3d = r3d mdef = 'PJAFFE' self.z = 0.25 sub_flag = True self.H0 = 70 self.omega_baryon = 0.03 self.omega_DM = 0.25 self.sigma8 = 0.82 curvature = 'flat' self.ns = 0.9608 cosmo_params = {'H0': self.H0, 'Om0': self.omega_baryon + self.omega_DM, 'Ob0': self.omega_baryon, 'sigma8': self.sigma8, 'ns': self.ns, 'curvature': curvature} self._dm, self._bar = self.omega_DM, self.omega_baryon cosmo = Cosmology(cosmo_kwargs=cosmo_params) self.lens_cosmo = LensCosmo(self.z, 2., cosmo) kwargs_suppression = {'c_scale': 10.5, 'c_power': -0.2} suppression_model = 'polynomial' profile_args = {'RocheNorm': 1.2, 'RocheNu': 2/3, 'evaluate_mc_at_zlens': True, 'log_mc': 0., 'kwargs_suppression': kwargs_suppression, 'suppression_model': suppression_model, 'c_scatter': False, 'mc_model': 'diemer19', 'LOS_truncation_factor': 40, 'mc_mdef': '200c', 'c_scatter_dex': 0.1} self.profile_args = profile_args self.mass_subhalo = mass self.subhalo = PJaffeSubhalo(mass, x, y, r3d, mdef, self.z, sub_flag, self.lens_cosmo, profile_args, unique_tag=np.random.rand()) mass_field_halo = 10 ** 7. sub_flag = False self.mass_field_halo = mass_field_halo self.field_halo = PJaffeSubhalo(self.mass_field_halo, x, y, r3d, mdef, self.z, sub_flag, self.lens_cosmo, profile_args, unique_tag=np.random.rand()) self._model_lenstronomy = PJaffe() def test_lenstronomy_ID(self): id = self.subhalo.lenstronomy_ID npt.assert_string_equal(id[0], 'PJAFFE') id = self.field_halo.lenstronomy_ID npt.assert_string_equal(id[0], 'PJAFFE') def test_z_infall(self): z_infall = self.subhalo.z_infall npt.assert_equal(True, self.z <= z_infall) def test_total_mass(self): c = float(self.subhalo.profile_args) rhos, rs, r200 = self.lens_cosmo.NFW_params_physical(self.subhalo.mass, c, self.z) fc = np.log(1 + c) - c / (1 + c) m_nfw = 4 * np.pi * rs ** 3 * rhos * fc lenstronomy_kwargs, _ = self.subhalo.lenstronomy_params sigma0, ra, rs = lenstronomy_kwargs[0]['sigma0'], lenstronomy_kwargs[0]['Ra'], lenstronomy_kwargs[0]['Rs'] arcsec_to_kpc = self.lens_cosmo.cosmo.kpc_proper_per_asec(self.z) ra *= arcsec_to_kpc ** -1 rs *= arcsec_to_kpc ** -1 rho = self.subhalo._rho(m_nfw, rs, ra, c*rs) m3d = self._model_lenstronomy.mass_3d(c*rs, rho, ra, rs) npt.assert_almost_equal(np.log10(m3d), np.log10(m_nfw)) def test_profile_args(self): profile_args = self.subhalo.profile_args (c) = profile_args con = concentration(self.lens_cosmo.cosmo.h * self.mass_subhalo, '200c', self.z, model='diemer19') npt.assert_almost_equal(c/con, 1, 2) profile_args = self.field_halo.profile_args (c) = profile_args con = concentration(self.lens_cosmo.cosmo.h * self.mass_field_halo, '200c', self.z, model='diemer19') npt.assert_almost_equal(c / con, 1, 2) profile_args = self.field_halo.profile_args (c) = profile_args con = concentration(self.lens_cosmo.cosmo.h * self.mass_subhalo, '200c', self.z, model='diemer19') npt.assert_almost_equal(c / con, 1, 2) profile_args = self.field_halo.profile_args (c) = profile_args con = concentration(self.lens_cosmo.cosmo.h * self.mass_field_halo, '200c', self.z, model='diemer19') npt.assert_almost_equal(c / con, 1, 2) def test_params_physical(self): params_physical = self.subhalo.params_physical npt.assert_equal(len(params_physical), 4)