def test_volume(self): cone_arcsec = 3 radius = cone_arcsec * 0.5 angle_pad = 0.7 zlens = 1. zsrc = 1.8 geo = Geometry(self.cosmo, zlens, zsrc, cone_arcsec, 'DOUBLE_CONE', angle_pad=angle_pad) astropy = geo._cosmo.astropy delta_z = 1e-3 dV_pyhalo = geo.volume_element_comoving(0.6, delta_z) dV = astropy.differential_comoving_volume(0.6).value dV_astropy = dV * delta_z steradian = np.pi * (radius * self.arcsec)**2 npt.assert_almost_equal(dV_astropy * steradian, dV_pyhalo, 5) angle_scale = geo.rendering_scale(1.3) dV_pyhalo = geo.volume_element_comoving(1.3, delta_z) dV = astropy.differential_comoving_volume(1.3).value dV_astropy = dV * delta_z steradian = np.pi * (radius * angle_scale * self.arcsec)**2 npt.assert_almost_equal(dV_astropy * steradian, dV_pyhalo, 5)
def test_total_volume(self): cone_arcsec = 4 radius_radians = cone_arcsec * 0.5 * self.cosmo.arcsec geo = Geometry(self.cosmo, 0.5, 1.5, cone_arcsec, 'DOUBLE_CONE', angle_pad=1.) volume_pyhalo = 0 z = np.linspace(0.0, 1.5, 200) for i in range(0, len(z) - 1): delta_z = z[i + 1] - z[i] volume_pyhalo += geo.volume_element_comoving(z[i], delta_z) ds = self.cosmo.D_C_z(1.5) dz = self.cosmo.D_C_z(0.5) volume_true = 1. / 3 * np.pi * radius_radians**2 * dz**2 * ds npt.assert_almost_equal(volume_true, volume_pyhalo, 3)
class TestLOS(object): def setup(self): zlens, zsource = 0.5, 2. zmin = 0.01 zmax = 1.98 log_mlow = 6. log_mhigh = 9. host_m200 = 10**13 LOS_normalization = 1. draw_poisson = False log_mass_sheet_min = 7. log_mass_sheet_max = 10. kappa_scale = 1. delta_power_law_index = -0.1 delta_power_law_index_coupling = 0.5 cone_opening_angle = 6. m_pivot = 10**8 sigma_sub = 0.1 power_law_index = -1.9 subhalo_spatial_distribution = 'HOST_NFW' kwargs_cdm = { 'zmin': zmin, 'zmax': zmax, 'log_mc': None, 'log_mlow': log_mlow, 'sigma_sub': sigma_sub, 'c_scale': None, 'c_power': None, 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'c_scatter_dex': 0.2, 'log_mhigh': log_mhigh, 'mdef_los': 'TNFW', 'host_m200': host_m200, 'LOS_normalization': LOS_normalization, 'draw_poisson': draw_poisson, 'subhalo_spatial_distribution': subhalo_spatial_distribution, 'log_mass_sheet_min': log_mass_sheet_min, 'log_mass_sheet_max': log_mass_sheet_max, 'kappa_scale': kappa_scale, 'power_law_index': power_law_index, 'delta_power_law_index': delta_power_law_index, 'delta_power_law_index_coupling': delta_power_law_index_coupling, 'm_pivot': m_pivot, 'cone_opening_angle': cone_opening_angle, 'subhalo_mass_sheet_scale': 1., 'subhalo_convergence_correction_profile': 'NFW', 'r_tidal': '0.5Rs' } pyhalo = pyHalo(zlens, zsource) self.realization_cdm = pyhalo.render(['TWO_HALO'], kwargs_cdm)[0] lens_plane_redshifts, delta_zs = pyhalo.lens_plane_redshifts( kwargs_cdm) cosmo = Cosmology() self.lens_plane_redshifts = lens_plane_redshifts self.delta_zs = delta_zs self.halo_mass_function = LensingMassFunction( cosmo, zlens, zsource, kwargs_cdm['log_mlow'], kwargs_cdm['log_mhigh'], kwargs_cdm['cone_opening_angle'], m_pivot=kwargs_cdm['m_pivot'], geometry_type='DOUBLE_CONE') self.geometry = Geometry(cosmo, zlens, zsource, kwargs_cdm['cone_opening_angle'], 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.kwargs_cdm = kwargs_cdm self.rendering_class = TwoHaloContribution( kwargs_cdm, self.halo_mass_function, self.geometry, self.lens_cosmo, self.lens_plane_redshifts, self.delta_zs) def test_norm_slope(self): delta_z = self.delta_zs[1] norm, slope = self.rendering_class._norm_slope(self.lens_cosmo.z_lens, delta_z) slope_theory = self.halo_mass_function.plaw_index_z( self.lens_cosmo.z_lens) + self.kwargs_cdm['delta_power_law_index'] npt.assert_almost_equal(slope, slope_theory) norm_theory_background = self.halo_mass_function.norm_at_z_density( self.lens_cosmo.z_lens, slope, self.kwargs_cdm['m_pivot']) norm_theory_background *= self.geometry.volume_element_comoving( self.lens_cosmo.z_lens, delta_z) rmax = self.lens_cosmo.cosmo.D_C_transverse(self.lens_cosmo.z_lens + delta_z) - \ self.lens_cosmo.cosmo.D_C_transverse(self.lens_cosmo.z_lens) boost = self.halo_mass_function.two_halo_boost( self.kwargs_cdm['host_m200'], self.lens_cosmo.z_lens, rmax=rmax) norm_theory = (boost - 1) * norm_theory_background npt.assert_almost_equal(norm_theory, norm) def test_rendering(self): m = self.rendering_class.render_masses_at_z(self.lens_cosmo.z_lens, 0.02) npt.assert_equal(True, len(m) > 0) npt.assert_raises(Exception, self.rendering_class.render_masses_at_z, 0.9, 0.02) x, y = self.rendering_class.render_positions_at_z( self.lens_cosmo.z_lens, 10000) rmax = np.max(np.hypot(x, y)) rmax_theory = 0.5 * self.kwargs_cdm[ 'cone_opening_angle'] * self.geometry.rendering_scale( self.lens_cosmo.z_lens) npt.assert_array_less(rmax, rmax_theory) x, y = self.rendering_class.render_positions_at_z( self.lens_cosmo.z_lens, 0) npt.assert_equal(True, len(x) == 0) m, x, y, r3, redshifts, flag = self.rendering_class.render() npt.assert_equal(len(m), len(x)) npt.assert_equal(len(y), len(r3)) n = 0 for z in np.unique(redshifts): n += np.sum(redshifts == z) npt.assert_equal(True, n == len(m)) npt.assert_equal(True, len(self.realization_cdm.halos) == len(m)) def test_convergence_correction(self): kwargs_out, profile_names_out, redshifts = self.rendering_class.convergence_sheet_correction( ) npt.assert_equal(0, len(kwargs_out)) npt.assert_equal(0, len(profile_names_out)) npt.assert_equal(0, len(redshifts)) def test_keys_convergence_sheets(self): keywords_out = self.rendering_class.keys_convergence_sheets() npt.assert_equal(len(keywords_out), 0) def test_keys_rendering(self): keywords_out = self.rendering_class.keyword_parse_render( self.kwargs_cdm) required_keys = [ 'log_mlow', 'log_mhigh', 'host_m200', 'LOS_normalization', 'draw_poisson', 'delta_power_law_index', 'm_pivot', 'log_mc', 'a_wdm', 'b_wdm', 'c_wdm' ] for x in required_keys: npt.assert_equal(x in keywords_out.keys(), True) kw_cdm = deepcopy(self.kwargs_cdm) kw_cdm['log_mc'] = None keywords_out = self.rendering_class.keyword_parse_render(kw_cdm) npt.assert_equal(keywords_out['a_wdm'] is None, True) npt.assert_equal(keywords_out['b_wdm'] is None, True) npt.assert_equal(keywords_out['c_wdm'] is None, True)
class TestRenderedPopulations(object): def setup(self): zlens, zsource = 0.5, 2. zmin = 0.01 zmax = 1.98 log_mlow = 6. log_mhigh = 9. host_m200 = 10**13 LOS_normalization = 100. draw_poisson = False log_mass_sheet_min = 7. log_mass_sheet_max = 10. kappa_scale = 1. delta_power_law_index = -0.17 delta_power_law_index_coupling = 0.7 cone_opening_angle = 6. m_pivot = 10**8 sigma_sub = 0.6 power_law_index = -1.8 subhalo_spatial_distribution = 'HOST_NFW' kwargs_cdm = { 'zmin': zmin, 'zmax': zmax, 'log_mc': None, 'log_mlow': log_mlow, 'sigma_sub': sigma_sub, 'c_scale': None, 'c_power': None, 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'c_scatter_dex': 0.2, 'log_mhigh': log_mhigh, 'host_m200': host_m200, 'LOS_normalization': LOS_normalization, 'draw_poisson': draw_poisson, 'subhalo_spatial_distribution': subhalo_spatial_distribution, 'log_mass_sheet_min': log_mass_sheet_min, 'log_mass_sheet_max': log_mass_sheet_max, 'kappa_scale': kappa_scale, 'power_law_index': power_law_index, 'delta_power_law_index': delta_power_law_index, 'delta_power_law_index_coupling': delta_power_law_index_coupling, 'm_pivot': m_pivot, 'cone_opening_angle': cone_opening_angle, 'subhalo_mass_sheet_scale': 1., 'subhalo_convergence_correction_profile': 'NFW', 'r_tidal': '0.5Rs', 'mdef_subs': 'TNFW', 'mdef_los': 'TNFW' } kwargs_wdm = deepcopy(kwargs_cdm) log_mc = 7.1 a_wdm = 1. b_wdm = 0.8 c_wdm = -1.3 kwargs_wdm['log_mc'] = log_mc kwargs_wdm['a_wdm'] = a_wdm kwargs_wdm['b_wdm'] = b_wdm kwargs_wdm['c_wdm'] = c_wdm kwargs_wdm['c_scale'] = 60. kwargs_wdm['c_power'] = -0.17 pyhalo = pyHalo(zlens, zsource) lens_plane_redshifts, delta_zs = pyhalo.lens_plane_redshifts( kwargs_cdm) cosmo = Cosmology() self.lens_plane_redshifts = lens_plane_redshifts self.delta_zs = delta_zs self.halo_mass_function = LensingMassFunction( cosmo, zlens, zsource, kwargs_cdm['log_mlow'], kwargs_cdm['log_mhigh'], kwargs_cdm['cone_opening_angle'], m_pivot=kwargs_cdm['m_pivot'], geometry_type='DOUBLE_CONE', use_lookup_table=True) self.geometry = Geometry(cosmo, zlens, zsource, kwargs_cdm['cone_opening_angle'], 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.kwargs_cdm = kwargs_cdm self.kwargs_wdm = kwargs_wdm pyhalo = pyHalo(zlens, zsource) model_list_field = ['LINE_OF_SIGHT'] model_list_sub = ['SUBHALOS'] self.realization_cdm = pyhalo.render(model_list_sub + model_list_field, kwargs_cdm)[0] self.realization_cdm_field = pyhalo.render(model_list_field, kwargs_cdm)[0] self.realization_wdm_field = pyhalo.render(model_list_field, kwargs_wdm)[0] self.realization_wdm_subhalos = pyhalo.render(model_list_sub, kwargs_wdm)[0] def test_mass_rendered_subhalos(self): plaw_index = self.kwargs_cdm['power_law_index'] + \ self.kwargs_cdm['delta_power_law_index'] * self.kwargs_cdm['delta_power_law_index_coupling'] norm = normalization_sigmasub(self.kwargs_cdm['sigma_sub'], self.kwargs_cdm['host_m200'], self.lens_cosmo.z_lens, self.geometry.kpc_per_arcsec_zlens, self.kwargs_cdm['cone_opening_angle'], plaw_index, self.kwargs_cdm['m_pivot']) mtheory = integrate_power_law_analytic( norm, 10**self.kwargs_cdm['log_mlow'], 10**self.kwargs_cdm['log_mhigh'], 1., plaw_index) m_subs = 0. for halo in self.realization_cdm.halos: if halo.is_subhalo: m_subs += halo.mass ratio = mtheory / m_subs npt.assert_array_less(1 - ratio, 0.05) plaw_index = self.kwargs_wdm['power_law_index'] + \ self.kwargs_wdm['delta_power_law_index'] * self.kwargs_wdm['delta_power_law_index_coupling'] norm = normalization_sigmasub(self.kwargs_wdm['sigma_sub'], self.kwargs_wdm['host_m200'], self.lens_cosmo.z_lens, self.geometry.kpc_per_arcsec_zlens, self.kwargs_cdm['cone_opening_angle'], plaw_index, self.kwargs_wdm['m_pivot']) mtheory = integrate_power_law_quad( norm, 10**self.kwargs_wdm['log_mlow'], 10**self.kwargs_wdm['log_mhigh'], self.kwargs_wdm['log_mc'], 1., plaw_index, self.kwargs_wdm['a_wdm'], self.kwargs_wdm['b_wdm'], self.kwargs_wdm['c_wdm']) m_subs = 0. for halo in self.realization_wdm_subhalos.halos: if halo.is_subhalo: m_subs += halo.mass ratio = mtheory / m_subs npt.assert_array_less(1 - ratio, 0.1) def test_mass_rendered_line_of_sight(self): m_theory = 0 m_rendered = 0 for z, dz in zip(self.lens_plane_redshifts, self.delta_zs): m_rendered += self.realization_cdm_field.mass_at_z_exact(z) slope = self.halo_mass_function.plaw_index_z( z) + self.kwargs_cdm['delta_power_law_index'] norm = self.kwargs_cdm['LOS_normalization'] * \ self.halo_mass_function.norm_at_z_density(z, slope, self.kwargs_cdm['m_pivot']) * \ self.geometry.volume_element_comoving(z, dz) m_theory += integrate_power_law_analytic( norm, 10**self.kwargs_cdm['log_mlow'], 10**self.kwargs_cdm['log_mhigh'], 1, slope) ratio = m_theory / m_rendered npt.assert_array_less(1 - ratio, 0.05) m_theory = 0 m_rendered = 0 for z, dz in zip(self.lens_plane_redshifts, self.delta_zs): m_rendered += self.realization_wdm_field.mass_at_z_exact(z) slope = self.halo_mass_function.plaw_index_z( z) + self.kwargs_wdm['delta_power_law_index'] norm = self.kwargs_cdm['LOS_normalization'] * \ self.halo_mass_function.norm_at_z_density(z, slope, self.kwargs_wdm['m_pivot']) * \ self.geometry.volume_element_comoving(z, dz) m_theory += integrate_power_law_quad( norm, 10**self.kwargs_wdm['log_mlow'], 10**self.kwargs_wdm['log_mhigh'], self.kwargs_wdm['log_mc'], 1, slope, self.kwargs_wdm['a_wdm'], self.kwargs_wdm['b_wdm'], self.kwargs_wdm['c_wdm']) ratio = m_theory / m_rendered npt.assert_array_less(1 - ratio, 0.05) def test_wdm_mass_function(self): mass_bins = np.linspace(6, 9, 20) halo_masses_wdm = [ halo.mass for halo in self.realization_wdm_field.halos ] log_halo_mass = np.log10(halo_masses_wdm) h_wdm, logM = np.histogram(log_halo_mass, bins=mass_bins) logmstep = (logM[1] - logM[0]) / 2 logM = logM[0:-1] + logmstep mass_bins = np.linspace(6, 9, 20) halo_masses_cdm = [ halo.mass for halo in self.realization_cdm_field.halos ] log_halo_mass = np.log10(halo_masses_cdm) h_cdm, _ = np.histogram(log_halo_mass, bins=mass_bins) suppression_factor = WDM_suppression( 10**logM, 10**self.kwargs_wdm['log_mc'], self.kwargs_wdm['a_wdm'], self.kwargs_wdm['b_wdm'], self.kwargs_wdm['c_wdm'], ) for i in range(0, 10): ratio = h_wdm[i] / h_cdm[i] npt.assert_almost_equal(ratio, suppression_factor[i], 1) def test_cdm_mass_function(self): mass_bins = np.linspace(6, 9., 20) halo_masses_sub = [] halo_masses_field = [] for halo in self.realization_cdm.halos: if halo.is_subhalo: halo_masses_sub.append(halo.mass) else: halo_masses_field.append(halo.mass) log_halo_mass_sub = np.log10(halo_masses_sub) log_halo_mass_field = np.log10(halo_masses_field) h_sub, logM_sub = np.histogram(log_halo_mass_sub, bins=mass_bins) h_field, logM_field = np.histogram(log_halo_mass_field, bins=mass_bins) logN_sub = np.log10(h_sub) logN_field = np.log10(h_field) slope_theory = -0.9 + self.kwargs_cdm['delta_power_law_index'] slope = np.polyfit(logM_field[0:-1], logN_field, 1)[0] npt.assert_array_less(abs(1 - slope / slope_theory), 0.05, 2) slope_theory = (1+self.kwargs_cdm['power_law_index']) + self.kwargs_cdm['delta_power_law_index'] * \ self.kwargs_cdm['delta_power_law_index_coupling'] slope = np.polyfit(logM_sub[0:-1], logN_sub, 1)[0] npt.assert_array_less(abs(1 - slope / slope_theory), 0.05, 2)
def add_primordial_black_holes(self, pbh_mass_fraction, kwargs_pbh_mass_function, mass_fraction_in_halos, x_image_interp_list, y_image_interp_list, r_max_arcsec, arcsec_per_pixel=0.005): """ This routine renders populations of primordial black holes modeled as point masses along the line of sight. The population of objects includes a smoothly distributed component, and a component that is clustered according to the population of halos generated in the instance of Realization used to instantiate the class. :param pbh_mass_fraction: the mass fraction of dark matter contained in primordial black holes :param kwargs_pbh_mass_function: keyword arguments for the PBH mass function :param mass_fraction_in_halos: the fraction of dark matter mass contained in halos in the mass range used to generate the instance of realization used to instantiate the class :param x_image_interp_list: a list of interp1d functions that return the angular x coordinate of a light ray given a comoving distance :param y_image_interp_list: a list of interp1d functions that return the angular y coordinate of a light ray given a comoving distance :param r_max_arcsec: the radius of the rendering region in arcsec :param arcsec_per_pixel: the resolution of the grid used to compute the population of PBH whose spatial distribution tracks the dark matter density along the LOS specific by the instance of Realization used to instantiate the class :return: a new instance of Realization that contains primordial black holes modeled as point masses """ mass_definition = 'PT_MASS' plane_redshifts = self._realization.unique_redshifts delta_z = [] for i, zi in enumerate(plane_redshifts[0:-1]): delta_z.append(plane_redshifts[i + 1] - plane_redshifts[i]) delta_z.append(self._realization.lens_cosmo.z_source - plane_redshifts[-1]) geometry = Geometry(self._realization.lens_cosmo.cosmo, self._realization.lens_cosmo.z_lens, self._realization.lens_cosmo.z_source, 2 * r_max_arcsec, 'DOUBLE_CONE') mass_fraction_smooth = (1 - mass_fraction_in_halos) * pbh_mass_fraction mass_fraction_clumpy = pbh_mass_fraction * mass_fraction_in_halos masses = np.array([]) xcoords = np.array([]) ycoords = np.array([]) redshifts = np.array([]) for x_image_interp, y_image_interp in zip(x_image_interp_list, y_image_interp_list): for zi, delta_zi in zip(plane_redshifts, delta_z): d = geometry._cosmo.D_C_transverse(zi) angle_x, angle_y = x_image_interp(d), y_image_interp(d) rendering_radius = r_max_arcsec * geometry.rendering_scale(zi) spatial_distribution_model_smooth = Uniform(rendering_radius, geometry) if kwargs_pbh_mass_function['mass_function_type'] == 'DELTA': rho_smooth = mass_fraction_smooth * self._realization.lens_cosmo.cosmo.rho_dark_matter_crit volume = geometry.volume_element_comoving(zi, delta_zi) mass_function_smooth = DeltaFunction(10 ** kwargs_pbh_mass_function['logM'], volume, rho_smooth) else: raise Exception('no mass function type for PBH currently implemented besides DELTA') m_smooth = mass_function_smooth.draw() if len(m_smooth) > 0: kpc_per_asec = geometry.kpc_per_arcsec(zi) x_kpc, y_kpc = spatial_distribution_model_smooth.draw(len(m_smooth), zi, center_x=angle_x, center_y=angle_y) x_arcsec, y_arcsec = x_kpc / kpc_per_asec, y_kpc / kpc_per_asec masses = np.append(masses, m_smooth) xcoords = np.append(xcoords, x_arcsec) ycoords = np.append(ycoords, y_arcsec) redshifts = np.append(redshifts, np.array([zi] * len(m_smooth))) mdefs = [mass_definition] * len(masses) r3d = np.array([None] * len(masses)) subhalo_flag = [False] * len(masses) realization_smooth = Realization(masses, xcoords, ycoords, r3d, mdefs, redshifts, subhalo_flag, self._realization.lens_cosmo, kwargs_realization=self._realization._prof_params) kwargs_pbh_mass_function['mass_fraction'] = mass_fraction_clumpy realization_with_clustering = self.add_correlated_structure(kwargs_pbh_mass_function, mass_definition, x_image_interp_list, y_image_interp_list, r_max_arcsec, arcsec_per_pixel) return realization_with_clustering.join(realization_smooth)
class TestLOS(object): def setup(self): zlens, zsource = 0.5, 2. zmin = 0.01 zmax = 1.98 log_mlow = 6. log_mhigh = 9. host_m200 = 10**13 LOS_normalization = 1. draw_poisson = False log_mass_sheet_min = 7. log_mass_sheet_max = 10. kappa_scale = 1. delta_power_law_index = -0.1 delta_power_law_index_coupling = 0.5 cone_opening_angle = 6. m_pivot = 10**8 sigma_sub = 0.1 power_law_index = -1.9 subhalo_spatial_distribution = 'HOST_NFW' kwargs_cdm = { 'zmin': zmin, 'zmax': zmax, 'log_mc': None, 'log_mlow': log_mlow, 'sigma_sub': sigma_sub, 'c_scale': None, 'c_power': None, 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'c_scatter_dex': 0.2, 'log_mhigh': log_mhigh, 'mdef_los': 'TNFW', 'host_m200': host_m200, 'LOS_normalization': LOS_normalization, 'draw_poisson': draw_poisson, 'subhalo_spatial_distribution': subhalo_spatial_distribution, 'log_mass_sheet_min': log_mass_sheet_min, 'log_mass_sheet_max': log_mass_sheet_max, 'kappa_scale': kappa_scale, 'power_law_index': power_law_index, 'delta_power_law_index': delta_power_law_index, 'delta_power_law_index_coupling': delta_power_law_index_coupling, 'm_pivot': m_pivot, 'cone_opening_angle': cone_opening_angle, 'subhalo_mass_sheet_scale': 1., 'subhalo_convergence_correction_profile': 'NFW', 'r_tidal': '0.5Rs' } pyhalo = pyHalo(zlens, zsource) self.realization_cdm = pyhalo.render(['LINE_OF_SIGHT'], kwargs_cdm)[0] lens_plane_redshifts, delta_zs = pyhalo.lens_plane_redshifts( kwargs_cdm) cosmo = Cosmology() self.lens_plane_redshifts = lens_plane_redshifts self.delta_zs = delta_zs self.halo_mass_function = LensingMassFunction( cosmo, zlens, zsource, kwargs_cdm['log_mlow'], kwargs_cdm['log_mhigh'], kwargs_cdm['cone_opening_angle'], m_pivot=kwargs_cdm['m_pivot'], geometry_type='DOUBLE_CONE') self.geometry = Geometry(cosmo, zlens, zsource, kwargs_cdm['cone_opening_angle'], 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.kwargs_cdm = kwargs_cdm self.rendering_class = LineOfSight(kwargs_cdm, self.halo_mass_function, self.geometry, self.lens_cosmo, self.lens_plane_redshifts, self.delta_zs) self.logdelta_mass = 5. kwargs_delta = { 'zmin': zmin, 'zmax': zmax, 'log_mc': None, 'log_mlow': log_mlow, 'sigma_sub': sigma_sub, 'c_scale': None, 'c_power': None, 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'c_scatter_dex': 0.2, 'log_mhigh': log_mhigh, 'mdef_los': 'TNFW', 'host_m200': host_m200, 'LOS_normalization': LOS_normalization, 'draw_poisson': draw_poisson, 'subhalo_spatial_distribution': subhalo_spatial_distribution, 'log_mass_sheet_min': log_mass_sheet_min, 'log_mass_sheet_max': log_mass_sheet_max, 'kappa_scale': kappa_scale, 'power_law_index': power_law_index, 'delta_power_law_index': delta_power_law_index, 'delta_power_law_index_coupling': delta_power_law_index_coupling, 'm_pivot': m_pivot, 'logM': self.logdelta_mass, 'mass_fraction': 0.1, 'cone_opening_angle': cone_opening_angle, 'subhalo_mass_sheet_scale': 1., 'subhalo_convergence_correction_profile': 'NFW', 'r_tidal': '0.5Rs', 'mass_function_LOS_type': 'DELTA' } self.rendering_class_delta = LineOfSight( kwargs_delta, self.halo_mass_function, self.geometry, self.lens_cosmo, self.lens_plane_redshifts, self.delta_zs) def test_norm_slope(self): test_index = [10, 20] for i in test_index: z = self.lens_plane_redshifts[i] dz = self.delta_zs[i] norm, slope = self.rendering_class._normalization_slope(z, dz) slope_theory = self.halo_mass_function.plaw_index_z( z) + self.kwargs_cdm['delta_power_law_index'] norm_theory = self.halo_mass_function.norm_at_z_density( z, slope_theory, self.kwargs_cdm['m_pivot']) dv = self.geometry.volume_element_comoving(z, dz) norm_theory *= self.kwargs_cdm['LOS_normalization'] * dv npt.assert_almost_equal(slope, slope_theory) npt.assert_almost_equal(norm_theory, norm) def test_rendering(self): m = self.rendering_class.render_masses_at_z(0.7, 0.02) npt.assert_equal(True, len(m) > 0) x, y = self.rendering_class.render_positions_at_z(0.9, 10000) rmax = np.max(np.hypot(x, y)) rmax_theory = 0.5 * self.kwargs_cdm[ 'cone_opening_angle'] * self.geometry.rendering_scale(0.9) npt.assert_array_less(rmax, rmax_theory) x, y = self.rendering_class.render_positions_at_z(0.2, 0) npt.assert_equal(True, len(x) == 0) m, x, y, r3, redshifts, flag = self.rendering_class.render() npt.assert_equal(len(m), len(x)) npt.assert_equal(len(y), len(r3)) n = 0 for z in np.unique(redshifts): n += np.sum(redshifts == z) npt.assert_equal(True, n == len(m)) npt.assert_equal(True, len(self.realization_cdm.halos) == len(m)) def test_convergence_correction(self): idx = 20 z = self.lens_plane_redshifts[idx] dz = self.delta_zs[idx] log_mass_sheet_min = 8. # factor of two because the kappa sheets are added at every other lens plane norm, slope = self.rendering_class._normalization_slope(z, 2 * dz) mtheory = integrate_power_law_analytic( norm, 10**self.kwargs_cdm['log_mass_sheet_min'], 10**self.kwargs_cdm['log_mass_sheet_max'], 1., slope) mtheory_2 = integrate_power_law_analytic( norm, 10**log_mass_sheet_min, 10**self.kwargs_cdm['log_mass_sheet_max'], 1., slope) area = self.geometry.angle_to_physical_area( 0.5 * self.kwargs_cdm['cone_opening_angle'], z) kappa_theory = mtheory / self.lens_cosmo.sigma_crit_mass(z, area) kappa_theory_2 = mtheory_2 / self.lens_cosmo.sigma_crit_mass(z, area) kwargs_out, profile_names_out, redshifts = self.rendering_class.convergence_sheet_correction( ) kwargs_out_2, profile_names_out_2, redshifts_2 = self.rendering_class.\ convergence_sheet_correction({'log_mass_sheet_min': log_mass_sheet_min}) idx = np.where(redshifts == z)[0][0] kw = kwargs_out[idx] kw2 = kwargs_out_2[idx] name = profile_names_out[idx] npt.assert_equal(True, name == 'CONVERGENCE') kappa_generated = -kw['kappa'] kappa_generated_2 = -kw2['kappa'] npt.assert_almost_equal(kappa_theory, kappa_generated) npt.assert_almost_equal(kappa_theory_2, kappa_generated_2) npt.assert_equal(True, kw['kappa'] < 0.) def test_keys_convergence_sheets(self): keywords_out = self.rendering_class.keys_convergence_sheets( self.kwargs_cdm) required_keys = [ 'log_mass_sheet_min', 'log_mass_sheet_max', 'kappa_scale', 'zmin', 'zmax', 'delta_power_law_index' ] for x in required_keys: npt.assert_equal(x in keywords_out.keys(), True) def test_keys_rendering(self): keywords_out = self.rendering_class.keyword_parse_render( self.kwargs_cdm) required_keys = [ 'zmin', 'zmax', 'log_mc', 'log_mlow', 'log_mhigh', 'host_m200', 'LOS_normalization', 'draw_poisson', 'log_mass_sheet_min', 'log_mass_sheet_max', 'kappa_scale', 'a_wdm', 'b_wdm', 'c_wdm', 'delta_power_law_index', 'm_pivot' ] for x in required_keys: npt.assert_equal(x in keywords_out.keys(), True) kw_cdm = deepcopy(self.kwargs_cdm) kw_cdm['log_mc'] = None keywords_out = self.rendering_class.keyword_parse_render(kw_cdm) npt.assert_equal(keywords_out['a_wdm'] is None, True) npt.assert_equal(keywords_out['b_wdm'] is None, True) npt.assert_equal(keywords_out['c_wdm'] is None, True) def test_delta_function_rendering(self): m = self.rendering_class_delta.render_masses_at_z(0.5, 0.01) for mi in m: npt.assert_equal(np.log10(mi), self.logdelta_mass)
class TestConeGeometry(object): def setup(self): self.arcsec = 2 * np.pi / 360 / 3600 self.zlens = 1 self.zsource = 2 self.angle_diameter = 2 / self.arcsec self.angle_radius = 0.5 * self.angle_diameter H0 = 70 omega_baryon = 0.0 omega_DM = 0.3 sigma8 = 0.82 curvature = 'flat' ns = 0.9608 cosmo_params = { 'H0': H0, 'Om0': omega_baryon + omega_DM, 'Ob0': omega_baryon, 'sigma8': sigma8, 'ns': ns, 'curvature': curvature } self.cosmo = Cosmology(cosmo_kwargs=cosmo_params) self.geometry_cylinder = Geometry(self.cosmo, self.zlens, self.zsource, self.angle_diameter, 'CYLINDER') def test_angle_scale(self): scale = self.geometry_cylinder.rendering_scale(self.zlens) npt.assert_almost_equal(scale, 1.) scale = self.geometry_cylinder.rendering_scale(self.zlens + 0.35) dratio = self.geometry_cylinder._cosmo.D_C_z( self.zlens) / self.geometry_cylinder._cosmo.D_C_z(self.zlens + 0.35) val = 0.5 * self.geometry_cylinder.cone_opening_angle * self.arcsec * dratio npt.assert_almost_equal(scale, val, 3) dratio = self.geometry_cylinder._cosmo.D_C_z( self.zlens) / self.geometry_cylinder._cosmo.D_C_z(self.zsource) val = 0.5 * self.geometry_cylinder.cone_opening_angle * self.arcsec * dratio npt.assert_almost_equal( self.geometry_cylinder.rendering_scale(self.zsource), val) def test_distances_lensing(self): z = 0.3 radius_physical = self.geometry_cylinder.angle_to_physicalradius( self.angle_radius, z) dratio = self.geometry_cylinder._cosmo.D_C_z( self.zlens) / self.geometry_cylinder._cosmo.D_C_z(z) radius = self.geometry_cylinder._cosmo.D_A_z( z) * self.angle_radius * self.arcsec * dratio npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_cylinder.angle_to_comovingradius( self.angle_radius, z) npt.assert_almost_equal(comoving_radius, radius_physical * (1 + z), 3) z = 1 radius_physical = self.geometry_cylinder.angle_to_physicalradius( self.angle_radius, z) dratio = self.geometry_cylinder._cosmo.D_C_z( self.zlens) / self.geometry_cylinder._cosmo.D_C_z(z) radius = self.geometry_cylinder._cosmo.D_A_z( z) * self.angle_radius * self.arcsec * dratio npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_cylinder.angle_to_comovingradius( self.angle_radius, z) npt.assert_almost_equal(comoving_radius, radius_physical * (1 + z), 3) z = 1.25 radius_physical = self.geometry_cylinder.angle_to_physicalradius( self.angle_radius, z) dratio = self.geometry_cylinder._cosmo.D_C_z( self.zlens) / self.geometry_cylinder._cosmo.D_C_z(z) radius = self.geometry_cylinder._cosmo.D_A_z( z) * self.angle_radius * self.arcsec * dratio npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_cylinder.angle_to_comovingradius( self.angle_radius, z) npt.assert_almost_equal(comoving_radius, radius_physical * (1 + z), 3) def test_total_volume(self): delta_z = 0.001 volume_pyhalo = 0 for zi in np.arange(0, self.zsource + delta_z, delta_z): dV_pyhalo = self.geometry_cylinder.volume_element_comoving( zi, delta_z) volume_pyhalo += dV_pyhalo r = self.geometry_cylinder._cosmo.D_C_z( self.zlens ) * self.geometry_cylinder.cone_opening_angle * 0.5 * self.arcsec d = self.geometry_cylinder._cosmo.D_C_z(self.zsource) volume = np.pi * r**2 * d npt.assert_almost_equal(volume / volume_pyhalo, 1, 3)