Exemple #1
0
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 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)
Exemple #3
0
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)
class TestLensingMassFunction(object):
    def setup(self):

        cosmo = Cosmology()
        mlow = 10**6
        mhigh = 10**10
        zlens = 0.5
        zsource = 1.5
        cone_opening_angle = 6.
        m_pivot = 10**8
        mass_function_model = 'sheth99'
        use_lookup_table = True
        geometry_type = 'DOUBLE_CONE'
        self.lmf_lookup_ShethTormen = LensingMassFunction(
            cosmo, zlens, zsource, mlow, mhigh, cone_opening_angle, m_pivot,
            mass_function_model, use_lookup_table, geometry_type)

        use_lookup_table = False
        self.lmf_no_lookup_ShethTormen = LensingMassFunction(
            cosmo, zlens, zsource, mlow, mhigh, cone_opening_angle, m_pivot,
            mass_function_model, use_lookup_table, geometry_type)

        self._m = np.logspace(6., 10, 50)

        self.cosmo = cosmo
        self.cone_opening_angle = cone_opening_angle

    def test_lookup(self):

        dndm_1 = self.lmf_lookup_ShethTormen.dN_dMdV_comoving(self._m, 0.5)
        dndm_2 = self.lmf_no_lookup_ShethTormen.dN_dMdV_comoving(self._m, 0.5)
        npt.assert_almost_equal(dndm_1, dndm_2)

    def test_normalization(self):

        z = 0.5
        plaw_index = self.lmf_lookup_ShethTormen.plaw_index_z(z)
        rho_dv = self.lmf_lookup_ShethTormen.norm_at_z_density(
            z, plaw_index, 10**8)
        dz = 0.01
        rho = self.lmf_no_lookup_ShethTormen.norm_at_z(z, plaw_index, dz,
                                                       10**8)

        radius_arcsec = self.cone_opening_angle * 0.5
        A = self.lmf_lookup_ShethTormen.geometry.angle_to_comoving_area(
            radius_arcsec, z)
        dr = self.cosmo.D_C_transverse(z + dz) - self.cosmo.D_C_transverse(z)
        dv = A * dr
        rho_2 = dv * rho_dv
        npt.assert_almost_equal(rho_2 / rho, 1.0, 2)

    def test_power_law_index(self):

        plaw_index = self.lmf_lookup_ShethTormen.plaw_index_z(0.5)
        npt.assert_almost_equal(plaw_index, -1.91)
        plaw_index = self.lmf_no_lookup_ShethTormen.plaw_index_z(0.5)
        npt.assert_almost_equal(np.round(plaw_index, 2), -1.91)

    def test_two_halo_boost(self):

        z = 0.5
        m_halo = 10**13

        def _integrand(x):
            return self.lmf_no_lookup_ShethTormen.twohaloterm(x, m_halo, z)

        dz = 0.01
        dr = self.cosmo.D_C_transverse(z + dz) - self.cosmo.D_C_transverse(z)
        integral_over_two_halo_term = quad(_integrand, 0.5, dr)[0]
        length = dr - 0.5
        average_value = integral_over_two_halo_term / length

        # factor of two for symmetry in front/behind lens
        boost_factor = 1 + 2 * average_value
        boost_factor_no_lookup = self.lmf_no_lookup_ShethTormen.two_halo_boost(
            m_halo, z, 0.5, dr)
        boost_factor_lookup = self.lmf_lookup_ShethTormen.two_halo_boost(
            m_halo, z, 0.5, dr)
        npt.assert_almost_equal(boost_factor, boost_factor_no_lookup)
        npt.assert_almost_equal(boost_factor, boost_factor_lookup)

    def test_component_density(self):

        f = 1.
        rho = self.lmf_no_lookup_ShethTormen.component_density(f)
        rho_dm = self.cosmo.astropy.Odm(
            0.) * self.cosmo.astropy.critical_density(0.).value
        rho_dm *= self.cosmo.density_to_MsunperMpc
        npt.assert_almost_equal(rho, rho_dm, 4)

    def test_mass_function_fit(self):

        m = np.logspace(6, 10, 50)
        m_pivot = 10**8

        z = 0.2
        norm_mpivot_8, index = self.lmf_no_lookup_ShethTormen._mass_function_params(
            m, z)
        norm_theory = self.lmf_no_lookup_ShethTormen.norm_at_z_density(
            z, index, 10**8)
        norm = norm_mpivot_8 / (m_pivot**index)
        npt.assert_almost_equal(norm / norm_theory, 1., 3)

        z = 1.2
        norm_mpivot_8, index = self.lmf_no_lookup_ShethTormen._mass_function_params(
            m, z)
        norm_theory = self.lmf_no_lookup_ShethTormen.norm_at_z_density(
            z, index, 10**8)
        norm = norm_mpivot_8 / (m_pivot**index)
        npt.assert_almost_equal(norm / norm_theory, 1., 3)

    def test_mass_fraction_in_halos(self):

        z = 0.5
        mlow = 10**6
        mhigh = 10**9
        frac1 = self.lmf_no_lookup_ShethTormen.mass_fraction_in_halos(
            z, mlow, mhigh, mlow_global=10**-4)
        frac2 = self.lmf_no_lookup_ShethTormen.mass_fraction_in_halos(
            z, 10**-4, mhigh, mlow_global=10**-4)
        frac3 = self.lmf_no_lookup_ShethTormen.mass_fraction_in_halos(
            z, 0.99999 * mhigh, mhigh)
        npt.assert_almost_equal(frac2, 1)
        npt.assert_almost_equal(frac1, 0.43799, 3)
        npt.assert_almost_equal(frac3, 0., 3)

    def test_norm(self):

        h = self.cosmo.h

        z = 0.5
        mass_function = self.lmf_no_lookup_ShethTormen.dN_dMdV_comoving

        m = np.logspace(6, 10, 10)

        # units Mpc ^ -3 M ^ -1
        mfunc = mass_function(m, z)

        # to units (Mpc/h) ^ =3 M ^ -1
        mfunc *= h**-3

        # to units (Mpc/h) ^ -3 (M/h) ^ -1
        mfunc *= h**-1
        coefs = np.polyfit(np.log10(m), np.log10(mfunc), 1)
        # coefs = (-1.907, 8.732)

        m_h = m * h
        # units (Mpc/h) ^ -3 ln(M/h)^-1
        dndlogm = massFunction(m_h, z, q_out='dndlnM', model='sheth99')
        # units (Mpc/h) ^ -3 M ^ -1
        dndm = dndlogm / m
        # units (Mpc/h) ^ -3 (M/h) ^ -1
        dndm *= h**-1
        coefs_theory = np.polyfit(np.log10(m), np.log10(dndm), 1)
        # coefs_theory = (-1.907, 8.732)

        npt.assert_almost_equal(coefs_theory, coefs)

    def test_samples(self):

        h = self.cosmo.h
        z = 0.5

        volume_element = 100000.
        nbins = 15
        m = np.logspace(6, 8.7, nbins)
        m_h = m * h
        dndlnmdv = massFunction(m_h, z, q_out='dndlnM', model='sheth99')
        dndm_theory = dndlnmdv * h**3 / m
        coefs_theory = np.polyfit(np.log10(m), np.log10(dndm_theory), 1)

        norm_theory = coefs_theory[1]
        plaw_index_theory = coefs_theory[0]

        norm = volume_element * self.lmf_no_lookup_ShethTormen.norm_at_z_density(
            z, plaw_index_theory, 10**8)

        mfunc = GeneralPowerLaw(6, 8.7, plaw_index_theory, False, norm, None,
                                None, None, None)
        mdraw = mfunc.draw()
        dndm_model = []

        mstep = 0.08
        msteps = 10**np.arange(6, 8.7 + mstep, mstep)
        for i in range(0, len(msteps) - 1):
            cond1 = mdraw >= msteps[i]
            cond2 = mdraw < msteps[i + 1]
            n = np.sum(np.logical_and(cond1, cond2))
            delta_m = msteps[i + 1] - msteps[i]
            new = n / delta_m
            dndm_model.append(new)

        coefs_model = np.polyfit(np.log10(msteps[0:-1]), np.log10(dndm_model),
                                 1)
        norm_model = coefs_model[1]
        npt.assert_almost_equal(
            10**(norm_model - norm_theory) / volume_element, 1, 1)