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._angle_pad = 0.75 self.geometry_double_cone = Geometry(self.cosmo, self.zlens, self.zsource, self.angle_diameter, 'DOUBLE_CONE', self._angle_pad)
def setup(self): cosmo = Cosmology() self.geometry = Geometry(cosmo, 0.5, 1.5, 6., 'DOUBLE_CONE') self.uni = Uniform(3, self.geometry) self.lenscone_uni = LensConeUniform(6., self.geometry)
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)
class TestUniform(object): def setup(self): cosmo = Cosmology() self.geometry = Geometry(cosmo, 0.5, 1.5, 6., 'DOUBLE_CONE') self.uni = Uniform(3, self.geometry) self.lenscone_uni = LensConeUniform(6., self.geometry) def test_uniform(self): x, y = self.uni.draw(1000, 0.3, 1., 0., 0.) kpc_per_asec = self.geometry.kpc_per_arcsec(0.3) x *= kpc_per_asec ** -1 y *= kpc_per_asec ** -1 r2d = np.hypot(x, y) npt.assert_equal(True, max(r2d) < 3) x, y = self.uni.draw(1000, 0.3, 0.5, 0., 0.) x *= kpc_per_asec ** -1 y *= kpc_per_asec ** -1 r2d = np.hypot(x, y) npt.assert_equal(True, max(r2d) < 1.5) def test_lens_cone_uniform(self): x, y = self.lenscone_uni.draw(10000, 0.5) kpc_per_asec = self.geometry.kpc_per_arcsec(0.5) x *= kpc_per_asec ** -1 y *= kpc_per_asec ** -1 x2, y2 = self.lenscone_uni.draw(10000, 0.9) kpc_per_asec = self.geometry.kpc_per_arcsec(0.9) x2 *= kpc_per_asec ** -1 y2 *= kpc_per_asec ** -1 scale1 = self.geometry.rendering_scale(0.5) scale2 = self.geometry.rendering_scale(0.9) max1 = max(np.hypot(x, y)) max2 = max(np.hypot(x2, y2)) npt.assert_almost_equal(max1/max2, scale1/scale2, 2) def test_distribution(self): x, y = self.uni.draw(1000000, 0.2, 1., 0., 0.) r2 = np.hypot(x, y) rbins = np.arange(1., 3.+0.5, 0.5) n = [] for i in range(0, len(rbins)-1): condition = np.logical_and(r2 >= rbins[i], r2<rbins[i+1]) N = np.sum(condition) area = np.pi * (rbins[i+1]**2 - rbins[i]**2) n.append(N/area) npt.assert_almost_equal(n[0]/n[1], 1, 1) npt.assert_almost_equal(n[2]/n[3], 1, 1)
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 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 self.cosmo = Cosmology(cosmo_kwargs=cosmo_params) self.geometry = Geometry(self.cosmo, self.zlens, self.zsource, self.angle_diameter, 'DOUBLE_CONE')
def __init__(self, kwargs_rendering, realization, r_max_arcsec): """ :param kwargs_rendering: keyword arguments that specify the mass function model :param realization: an instance of Realization used to compute the convergence at each lens plane :param r_max_arcsec: the radius of area at which the halos are rendered """ self.kwargs_rendering = kwargs_rendering self._realization = realization self.cylinder_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') self.spatial_distribution_model = Correlated2D(self.cylinder_geometry) self._rmax = r_max_arcsec
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)
def setup(self): zlens, zsource = 0.5, 1.5 self.rs = 60 self.rmax2d = 40 self.rvir = 350 self.rcore = 10. self.nfw = ProjectedNFW(self.rmax2d, self.rs, self.rcore, self.rvir) cosmo = Cosmology() self.geometry = Geometry(cosmo, 0.5, 1.5, 6., 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo)
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.17 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_suppression = {'c_scale': 10.5, 'c_power': -0.2} suppression_model = 'polynomial' kwargs_cdm = { 'zmin': zmin, 'zmax': zmax, 'log_mc': None, 'log_mlow': log_mlow, 'sigma_sub': sigma_sub, 'kwargs_suppression': kwargs_suppression, 'suppression_model': suppression_model, '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', 'mass_function_LOS_type': 'POWER_LAW' } kwargs_wdm = deepcopy(kwargs_cdm) log_mc = 7.3 a_wdm = 0.8 b_wdm = 1.1 c_wdm = -1.2 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['kwargs_suppression'] = kwargs_suppression kwargs_wdm['suppression_model'] = suppression_model kwargs_no_sheet = deepcopy(kwargs_cdm) kwargs_no_sheet['mass_function_LOS_type'] = 'DELTA' kwargs_no_sheet['mass_fraction'] = 0.1 kwargs_no_sheet['logM'] = 6. lens_plane_redshifts = np.append(np.arange(0.01, 0.5, 0.02), np.arange(0.5, 1.5, 0.02)) delta_zs = [] for i in range(0, len(lens_plane_redshifts) - 1): delta_zs.append(lens_plane_redshifts[i + 1] - lens_plane_redshifts[i]) delta_zs.append(1.5 - lens_plane_redshifts[-1]) cosmo = Cosmology() self.lens_plane_redshifts = lens_plane_redshifts self.delta_zs = delta_zs self.halo_mass_function = LensingMassFunction( cosmo, 0.5, 1.5, kwargs_cdm['log_mlow'], kwargs_cdm['log_mhigh'], 6., m_pivot=kwargs_cdm['m_pivot'], geometry_type='DOUBLE_CONE') self.geometry = Geometry(cosmo, 0.5, 1.5, 6., 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.kwargs_cdm = kwargs_cdm self.kwargs_wdm = kwargs_wdm self.kwargs_no_sheet = kwargs_no_sheet
class TestSubhalos(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.5 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_uniform = { '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_subs': 'TNFW', 'log_m_host': np.log10(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': 'UNIFORM', 'r_tidal': '0.5Rs' } kwargs_cdm_nfw = deepcopy(kwargs_cdm_uniform) kwargs_cdm_nfw['subhalo_convergence_correction_profile'] = 'NFW' pyhalo = pyHalo(zlens, zsource) self.realization_cdm = pyhalo.render(['SUBHALOS'], kwargs_cdm_uniform)[0] self.realization_cdm_nfw = pyhalo.render(['SUBHALOS'], kwargs_cdm_nfw)[0] lens_plane_redshifts, delta_zs = pyhalo.lens_plane_redshifts( kwargs_cdm_uniform) cosmo = Cosmology() self.lens_plane_redshifts = lens_plane_redshifts self.delta_zs = delta_zs self.halo_mass_function = LensingMassFunction( cosmo, zlens, zsource, kwargs_cdm_uniform['log_mlow'], kwargs_cdm_uniform['log_mhigh'], kwargs_cdm_uniform['cone_opening_angle'], m_pivot=kwargs_cdm_uniform['m_pivot'], geometry_type='DOUBLE_CONE') self.geometry = Geometry(cosmo, zlens, zsource, kwargs_cdm_uniform['cone_opening_angle'], 'DOUBLE_CONE') self.lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.kwargs_cdm = kwargs_cdm_uniform self.rendering_class_uniform = Subhalos(kwargs_cdm_uniform, self.geometry, self.lens_cosmo) self.rendering_class_nfw = Subhalos(kwargs_cdm_nfw, self.geometry, self.lens_cosmo) def test_normalization(self): norm = normalization_sigmasub( self.kwargs_cdm['sigma_sub'], 10**self.kwargs_cdm['log_m_host'], self.lens_cosmo.z_lens, self.geometry.kpc_per_arcsec_zlens, self.kwargs_cdm['cone_opening_angle'], self.kwargs_cdm['power_law_index'] + self.kwargs_cdm['delta_power_law_index'] * self.kwargs_cdm['delta_power_law_index_coupling'], self.kwargs_cdm['m_pivot']) k1, k2 = 0.88, 1.7 slope = self.kwargs_cdm['power_law_index'] + self.kwargs_cdm['delta_power_law_index'] * \ self.kwargs_cdm['delta_power_law_index_coupling'] mhalo = 10**self.kwargs_cdm['log_m_host'] scale = k1 * np.log10( mhalo / 10**13) + k2 * np.log10(self.lens_cosmo.z_lens + 0.5) host_scaling = 10**scale norm_theory = self.kwargs_cdm['sigma_sub'] * host_scaling kpc_per_arcsec_zlens = self.geometry.kpc_per_arcsec( self.lens_cosmo.z_lens) norm_theory *= np.pi * (0.5 * self.kwargs_cdm['cone_opening_angle'] * kpc_per_arcsec_zlens)**2 norm_theory *= self.kwargs_cdm['m_pivot']**-(slope + 1) npt.assert_almost_equal(norm, norm_theory) _norm, _slope = self.rendering_class_uniform._norm_slope() npt.assert_almost_equal(_norm, norm) npt.assert_almost_equal(_slope, slope) def test_rendering(self): m = self.rendering_class_uniform.render_masses_at_z() npt.assert_equal(True, len(m) > 0) x, y, r3 = self.rendering_class_uniform.render_positions_at_z(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, r3 = self.rendering_class_uniform.render_positions_at_z(0) npt.assert_equal(True, len(x) == 0) m, x, y, r3, redshifts, flag = self.rendering_class_uniform.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): z = self.lens_cosmo.z_lens norm, slope = self.rendering_class_uniform._norm_slope() # factor of two because the kappa sheets are added at every other lens plane mtheory = integrate_power_law_analytic( norm, 10**self.kwargs_cdm['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) kwargs_out, profile_names_out, redshifts = self.rendering_class_uniform.convergence_sheet_correction( ) kw = kwargs_out[0] name = profile_names_out[0] npt.assert_equal(True, name == 'CONVERGENCE') kappa_generated = -kw['kappa'] npt.assert_array_less(abs(kappa_theory / kappa_generated - 1), 0.05) def test_keys_convergence_sheets(self): keywords_out = self.rendering_class_uniform.keys_convergence_sheets( self.kwargs_cdm) required_keys = [ 'log_mass_sheet_min', 'log_mass_sheet_max', 'subhalo_mass_sheet_scale', 'subhalo_convergence_correction_profile', 'r_tidal', 'delta_power_law_index', 'delta_power_law_index_coupling' ] for x in required_keys: npt.assert_equal(x in keywords_out.keys(), True) def test_keys_rendering(self): keywords_out = self.rendering_class_uniform.keyword_parse_render( self.kwargs_cdm) required_keys = [ 'power_law_index', 'log_mlow', 'log_mhigh', 'log_mc', 'sigma_sub', 'a_wdm', 'b_wdm', 'c_wdm', 'log_mass_sheet_min', 'log_mass_sheet_max', 'subhalo_mass_sheet_scale', 'draw_poisson', 'host_m200', 'subhalo_convergence_correction_profile', 'r_tidal', 'delta_power_law_index', 'm_pivot', 'delta_power_law_index_coupling', 'cone_opening_angle' ] 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_uniform.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 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)
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._angle_pad = 0.75 self.geometry_double_cone = Geometry(self.cosmo, self.zlens, self.zsource, self.angle_diameter, 'DOUBLE_CONE', self._angle_pad) def test_angle_scale(self): reduced_to_phys = self.geometry_double_cone._cosmo.D_A(0, self.zsource) / \ self.geometry_double_cone._cosmo.D_A(self.zlens, self.zsource) ratio_double_cone = reduced_to_phys * \ self.cosmo.D_A(self.zlens, self.zsource)/self.cosmo.D_A_z(self.zsource) angle_scale_zsource = 1 - self._angle_pad * ratio_double_cone npt.assert_almost_equal( self.geometry_double_cone.rendering_scale(self.zlens), 1.) npt.assert_almost_equal( self.geometry_double_cone.rendering_scale(self.zsource), angle_scale_zsource) npt.assert_almost_equal( self.geometry_double_cone.rendering_scale(self.zlens), 1) def test_distances_lensing(self): z = 0.3 radius_physical = self.geometry_double_cone.angle_to_physicalradius( self.angle_radius, z) radius = self.geometry_double_cone._cosmo.D_A( 0., z) * self.angle_radius * self.arcsec npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_double_cone.angle_to_comovingradius( self.angle_radius, z) npt.assert_almost_equal(comoving_radius, radius_physical * (1 + z), 3) z = 1 radius_physical = self.geometry_double_cone.angle_to_physicalradius( self.angle_radius, z) radius = self.geometry_double_cone._cosmo.D_A( 0., z) * self.angle_radius * self.arcsec npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_double_cone.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_double_cone.angle_to_physicalradius( self.angle_radius, z) D_dz = self.geometry_double_cone._cosmo.D_A(self.zlens, z) D_s = self.geometry_double_cone._cosmo.D_A(0, self.zsource) D_z = self.geometry_double_cone._cosmo.D_A(0, z) D_ds = self.geometry_double_cone._cosmo.D_A(self.zlens, self.zsource) rescale = 1 - self._angle_pad * D_dz * D_s / (D_z * D_ds) radius = self.geometry_double_cone._cosmo.D_A( 0., z) * self.angle_radius * self.arcsec * rescale npt.assert_almost_equal(radius_physical, radius, 0) comoving_radius = self.geometry_double_cone.angle_to_comovingradius( self.angle_radius, z) npt.assert_almost_equal(comoving_radius, radius_physical * (1 + z), 3) 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)
def setup(self): zlens, zsource = 0.4, 2. masses = [10**9.04, 10**8.2, 10**7.345, 10**7, 10**6.05, 10**7, 10**7] x = [0.5, 0.1, -0.9, -1.4, 1.2, 0., -1.] y = [0., 0.9, -1.4, -1., -0.4, 1., 0.9] redshifts = [0.1, 0.2, 0.3, zlens, zlens, 0.94, 0.94] subflags = [False, False, False, True, True, False, False] r3d = [100] * len(masses) mdefs_TNFW = ['TNFW'] * len(masses) # self.x = x self.y = y self.masses = masses self.redshifts = redshifts self.subflags = subflags self.r3d = r3d self.mdefs = mdefs_TNFW masses2 = [10**6.34, 10**9.2, 10**8.36] x2 = [1.5, 0.15, -1.9] y2 = [0.2, 0.3, -0.44] redshifts2 = [zlens, 0.4, 1.9] subflags2 = [True, False, False] r3d2 = [100] * len(masses2) profile_args_TNFW = { 'mc_model': 'diemer19', 'c_scatter': False, 'c_scatter_dex': 0.1 } cosmo = Cosmology() halo_mass_function = LensingMassFunction(cosmo, zlens, zsource, 10**6, 10**9, 6., m_pivot=10**8) self.halo_mass_function = halo_mass_function kwargs_cdm = { 'zmin': 0.01, 'zmax': 1.98, 'log_mc': None, 'log_mlow': 6., 'log_mhigh': 9., 'host_m200': 10**13, 'LOS_normalization': 2000., 'LOS_normalization_mass_sheet': 1., 'draw_poisson': False, 'log_mass_sheet_min': 7., 'log_mass_sheet_max': 10., 'kappa_scale': 1., 'delta_power_law_index': 0., 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'm_pivot': 10**8, 'cone_opening_angle': 6., 'mass_function_LOS_type': 'POWER_LAW' } kwargs_cdm_2 = { 'zmin': 0.01, 'zmax': 1.98, 'log_mc': None, 'log_mlow': 6., 'log_mhigh': 9., 'host_m200': 10**13, 'LOS_normalization': 2000., 'LOS_normalization_mass_sheet': 1., 'draw_poisson': False, 'log_mass_sheet_min': 7., 'log_mass_sheet_max': 10., 'kappa_scale': 1., 'delta_power_law_index': 0., 'a_wdm': None, 'b_wdm': None, 'c_wdm': None, 'm_pivot': 10**8, 'cone_opening_angle': 6., 'subtract_exact_mass_sheets': True, 'mass_function_LOS_type': 'POWER_LAW' } kwargs_cdm.update(profile_args_TNFW) self.kwargs_cdm = kwargs_cdm self.kwargs_cdm_2 = kwargs_cdm_2 lens_plane_redshifts = np.append(np.arange(0.01, 0.5, 0.02), np.arange(0.5, 1.5, 0.02)) delta_zs = [] for i in range(0, len(lens_plane_redshifts) - 1): delta_zs.append(lens_plane_redshifts[i + 1] - lens_plane_redshifts[i]) delta_zs.append(1.5 - lens_plane_redshifts[-1]) geometry = Geometry(cosmo, 0.5, 1.5, 6., 'DOUBLE_CONE') lens_cosmo = LensCosmo(zlens, zsource, cosmo) self.lens_cosmo = lens_cosmo halo_population = HaloPopulation(['LINE_OF_SIGHT'], self.kwargs_cdm, lens_cosmo, geometry, halo_mass_function, lens_plane_redshifts, delta_zs) self.rendering_classes = halo_population.rendering_classes mdef = ['NFW'] * len(masses) self.realization_cdm = Realization( masses, x, y, r3d, mdef, redshifts, subflags, lens_cosmo, halos=None, kwargs_realization=self.kwargs_cdm_2, mass_sheet_correction=True, rendering_classes=self.rendering_classes, geometry=geometry) mdef = ['PT_MASS'] * len(masses) self.realization_cdm2 = Realization( masses2, x2, y2, r3d2, mdef, redshifts2, subflags2, lens_cosmo, halos=None, kwargs_realization=self.kwargs_cdm, mass_sheet_correction=True, rendering_classes=self.rendering_classes, geometry=geometry) mdef = ['PJAFFE'] * len(masses) self.realization_cdm3 = Realization( masses2, x2, y2, r3d2, mdef, redshifts2, subflags2, lens_cosmo, halos=None, kwargs_realization=self.kwargs_cdm, mass_sheet_correction=True, rendering_classes=self.rendering_classes, geometry=geometry) self.halos_cdm = self.realization_cdm.halos halo_tags = [] for halo in self.realization_cdm.halos: halo_tags.append(halo.unique_tag) self.halo_tags = halo_tags halo_tags = [] for halo in self.realization_cdm2.halos: halo_tags.append(halo.unique_tag) self.halo_tags2 = halo_tags self.real_1_data = [x, y, masses, redshifts, subflags, redshifts] self.real_2_data = [x2, y2, masses2, redshifts2, subflags2, redshifts2]
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 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 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 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]
class CorrelatedStructure(RenderingClassBase): """ This class generates a population of halos with a spatial distribution that tracks the dark matter density in halos at each lens plane """ def __init__(self, kwargs_rendering, realization, r_max_arcsec): """ :param kwargs_rendering: keyword arguments that specify the mass function model :param realization: an instance of Realization used to compute the convergence at each lens plane :param r_max_arcsec: the radius of area at which the halos are rendered """ self.kwargs_rendering = kwargs_rendering self._realization = realization self.cylinder_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') self.spatial_distribution_model = Correlated2D(self.cylinder_geometry) self._rmax = r_max_arcsec def render(self, x_center_interp_list, y_center_interp_list, arcsec_per_pixel): """ Generates halo masses and positions for correlated structure along the line of sight around the angular coordinate of each light ray :param x_center_interp_list: a list of interp1d functions that return the x angular position of a ray given a comoving distance :param y_center_interp_list: a list of interp1d functions that return the y angular position of a ray given a comoving distance :param arcsec_per_pixel: sets the spatial resolution for the rendering of correlated structure :return: mass (in Msun), x (arcsec), y (arcsec), r3d (kpc), redshift """ masses = np.array([]) x = np.array([]) y = np.array([]) redshifts = np.array([]) plane_redshifts = self._realization.unique_redshifts delta_z = [] rescale_inds = [] rescale_factor = 1. 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]) 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]) for x_image_interp, y_image_interp in zip(x_center_interp_list, y_center_interp_list): for z, dz in zip(plane_redshifts, delta_z): if dz > 0.2: print( 'WARNING: redshift spacing is possibly too large due to the few number of halos ' 'in the lens model!') rendering_radius = self._rmax * self.cylinder_geometry.rendering_scale( z) d = self.cylinder_geometry._cosmo.D_C_transverse(z) x_angle = x_image_interp(d) y_angle = y_image_interp(d) _m, _x, _y, halo_inds, rescale_factor = self.render_at_z( z, x_angle, y_angle, rendering_radius, arcsec_per_pixel) if len(_m) > 0: _z = np.array([z] * len(_x)) masses = np.append(masses, _m) x = np.append(x, _x) y = np.append(y, _y) redshifts = np.append(redshifts, _z) rescale_inds += halo_inds subhalo_flag = [False] * len(masses) r3d = np.array([None] * len(masses)) return masses, x, y, r3d, redshifts, subhalo_flag, rescale_inds, rescale_factor def render_at_z(self, z, angular_coordinate_x, angular_coordinate_y, rendering_radius, arcsec_per_pixel): """ :param n: number of objects to render :param z: redshift :param angular_coordinate_x: the angular coordinate in arcsec of a light ray at redshift z :param angular_coordinate_y: the angular coordinate in arcsec of a light ray at redshift z :param rendering_radius: the angular radius inside which to render objects :param arcsec_per_pixel: sets the spatial resolution for the rendering of correlated structure :return: the positions in arcsec of the rendered objects """ kpc_per_asec = self.cylinder_geometry.kpc_per_arcsec(z) pdf, mass_in_area, halo_indexes = self._kappa_at_lens_plane( z, angular_coordinate_x, angular_coordinate_y, rendering_radius, arcsec_per_pixel) if np.sum(pdf) == 0: return np.array([]), np.array([]), np.array([]), [], 1. m, rescale_factor = self.render_masses_at_z(mass_in_area) n_halos = len(m) if n_halos > 0: x_kpc, y_kpc = self.spatial_distribution_model.draw( n_halos, rendering_radius, pdf, z, angular_coordinate_x, angular_coordinate_y) x_arcsec = x_kpc / kpc_per_asec y_arcsec = y_kpc / kpc_per_asec return m, x_arcsec, y_arcsec, halo_indexes, rescale_factor else: return np.array([]), np.array([]), np.array([]), [], 1. def render_masses_at_z(self, mass_in_area): """ :param z: redshift at which to render masses :param delta_z: thickness of the redshift slice :return: halo masses at the desired redshift in units Msun """ if self.kwargs_rendering['mass_function_type'] == 'DELTA': rescale_factor = 1. - self.kwargs_rendering['mass_fraction'] rho = self.kwargs_rendering['mass_fraction'] * mass_in_area volume = 1. mass = 10**self.kwargs_rendering['logM'] mass_function = DeltaFunction(mass, volume, rho) else: raise Exception( 'no other mass function for correlated structure currently implemented' ) return mass_function.draw(), rescale_factor def _kappa_at_lens_plane(self, z, angular_coordinate_x, angular_coordinate_y, rendering_radius, arcsec_per_pixel): realization_at_plane, halo_indexes = realization_at_z( self._realization, z, angular_coordinate_x, angular_coordinate_y, 2 * rendering_radius, mass_sheet_correction=False) lens_model_list, _, kwargs_lens, numerical_interp = realization_at_plane.lensing_quantities( add_mass_sheet_correction=False) if len(lens_model_list) == 0: return np.array([]), np.array([]), [] lens_model = LensModel(lens_model_list, numerical_alpha_class=numerical_interp) npix = int(2 * rendering_radius / arcsec_per_pixel) _r = np.linspace(-rendering_radius, rendering_radius, npix) xx, yy = np.meshgrid(_r, _r) shape0 = xx.shape xx, yy = xx.ravel(), yy.ravel() rr = np.sqrt(xx**2 + yy**2) inds_zero = np.where(rr > rendering_radius)[0].ravel() pdf = lens_model.kappa(xx + angular_coordinate_x, yy + angular_coordinate_y, kwargs_lens) pdf[inds_zero] = 0. inds_nan = np.where(np.isnan(pdf)) pdf[inds_nan] = 0. npixels = len(inds_zero) rendering_radius_mpc = rendering_radius * ( 0.001 * self.cylinder_geometry.kpc_per_arcsec(z)) effective_area = np.pi * rendering_radius_mpc**2 / npixels mass_in_area = self._mass_in_area(pdf, z, effective_area) return pdf.reshape(shape0), mass_in_area, halo_indexes def _mass_in_area(self, kappa_pdf, z, area): sigma_crit = self._realization.lens_cosmo.get_sigma_crit_lensing( z, self._realization.lens_cosmo.z_source) mass_in_area = np.sum(kappa_pdf * sigma_crit) * area return mass_in_area @staticmethod def keys_convergence_sheets(keywords_master): return {} def convergence_sheet_correction(self, kwargs_mass_sheets=None): return [{}], [], [] @staticmethod def keyword_parse_render(keywords_master): return {}
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)