Ejemplo n.º 1
0
class PTmass:

    #pcrit = 2.77536627e+11

    def __init__(self, z=None, zsrc=None, cosmology=None):
        """
        adopting a standard cosmology, other cosmologies not yet implemented
        :param z1: lens redshift
        :param z2: source redshift
        :param h: little h
        """
        if cosmology is None:
            self.cosmology = Cosmo(zd=z, zsrc=zsrc, compute=True)
            self.D_s, self.D_d, self.D_ds = self.cosmology.D_s, self.cosmology.D_d, self.cosmology.D_ds
        else:
            self.cosmology = cosmology
            try:
                self.D_s, self.D_d, self.D_ds = self.cosmology.D_s, self.cosmology.D_d, self.cosmology.D_ds
            except:
                self.D_s = self.cosmology.D_A(0, self.cosmology.zsrc)
                self.D_d = self.cosmology.D_A(0, self.cosmology.zd)
                self.D_ds = self.cosmology.D_A(self.cosmology.zd,
                                               self.cosmology.zsrc)

        self.rmin = 10**-9

    def def_angle(self, x, y, center_x=0, center_y=0, theta_E=None, **kwargs):

        x_grid = x - center_x
        y_grid = y - center_y

        r = np.sqrt(x_grid**2 + y_grid**2)
        r[np.where(r < self.rmin)] = self.rmin
        magdef = theta_E**2 * r**-1

        return magdef * x_grid * r**-1, magdef * y_grid * r**-1

    def params(self, x=None, y=None, mass=None):

        subkwargs = {}
        otherkwargs = {}
        otherkwargs['name'] = 'POINT_MASS'
        otherkwargs['mass'] = mass

        subkwargs['theta_E'] = self.R_ein(mass)
        subkwargs['center_x'] = x
        subkwargs['center_y'] = y

        return subkwargs, otherkwargs

    def R_ein(self, M):

        const = 4 * self.cosmology.G * self.cosmology.c**-2 * self.D_ds * (
            self.D_d * self.D_s)**-1
        return self.cosmology.arcsec**-1 * (M * const)**.5
Ejemplo n.º 2
0
class TNFW:
    def __init__(self, z=None, zsrc=None, c_turnover=True, cosmology=None):
        """
        adopting a standard cosmology, other cosmologies not yet implemented
        :param z1: lens redshift
        :param z2: source redshift
        :param h: little h
        """

        if cosmology is None:
            if z is None or zsrc is None:
                print('Warning; no cosmology specified.')
            else:
                self.cosmology = Cosmo(zd=z, zsrc=zsrc, compute=False)
                self.z, self.zsrc = z, zsrc

        else:
            self.cosmology = cosmology
            self.z, self.zsrc = cosmology.zd, cosmology.zsrc

        self.c_turnover = c_turnover

    def M_finite(self, rho, Rs, tau):

        t2 = tau**2
        return 4 * np.pi * Rs**3 * rho * t2 * (t2 + 1)**-2 * (
            (t2 - 1) * np.log(tau) + np.pi * tau - (t2 + 1))

    def def_angle(self,
                  x,
                  y,
                  Rs=None,
                  theta_Rs=None,
                  r_trunc=None,
                  center_x=0,
                  center_y=0):

        x_loc = x - center_x
        y_loc = y - center_y

        r = np.sqrt(x_loc**2 + y_loc**2)

        xnfw = r * Rs**-1

        tau = r_trunc * Rs**-1

        xmin = 0.00000001

        if isinstance(xnfw, float) or isinstance(xnfw, int):
            xnfw = max(xmin, xnfw)
        else:
            xnfw[np.where(xnfw < xmin)] = xmin

        magdef = theta_Rs * (1 + np.log(0.5))**-1 * self.t_fac(xnfw,
                                                               tau) * xnfw**-1

        return magdef * x_loc * (xnfw * Rs)**-1, magdef * y_loc * (xnfw *
                                                                   Rs)**-1

    def F(self, x):

        if isinstance(x, np.ndarray):
            nfwvals = np.ones_like(x)
            inds1 = np.where(x < 1)
            inds2 = np.where(x > 1)
            nfwvals[inds1] = (1 - x[inds1]**2)**-.5 * np.arctanh(
                (1 - x[inds1]**2)**.5)
            nfwvals[inds2] = (x[inds2]**2 - 1)**-.5 * np.arctan(
                (x[inds2]**2 - 1)**.5)
            return nfwvals

        elif isinstance(x, float) or isinstance(x, int):
            if x == 1:
                return 1
            if x < 1:
                return (1 - x**2)**-.5 * np.arctanh((1 - x**2)**.5)
            else:
                return (x**2 - 1)**-.5 * np.arctan((x**2 - 1)**.5)

    def L(self, x, tau):

        return np.log(x * (tau + np.sqrt(tau**2 + x**2))**-1)

    def t_fac(self, x, tau):
        return tau**2 * (tau**2 + 1)**-2 * (
            (tau**2 + 1 + 2 * (x**2 - 1)) * self.F(x) + tau * np.pi +
            (tau**2 - 1) * np.log(tau) + np.sqrt(tau**2 + x**2) *
            (-np.pi + self.L(x, tau) * (tau**2 - 1) * tau**-1))

    def _F(self, X, tau):
        """
        analytic solution of the projection integral
        (convergence)

        :param x: R/Rs
        :type x: float >0
        """
        t2 = tau**2
        Fx = self.F(X)

        return t2 * (2 * np.pi * (t2 + 1)**2)**-1 * (
            ((t2 + 1) *
             (X**2 - 1)**-1) * (1 - Fx) + 2 * Fx - np.pi * (t2 + X**2)**-.5 +
            (t2 - 1) * (tau * (t2 + X**2)**.5)**-1 * self.L(X, tau))

    def kappa(self,
              x,
              y,
              Rs=None,
              theta_Rs=None,
              r_trunc=None,
              center_x=0,
              center_y=0):

        x_loc = x - center_x
        y_loc = y - center_y

        r = np.sqrt(x_loc**2 + y_loc**2)

        xnfw = r * Rs**-1

        tau = r_trunc * Rs**-1

        xmin = 0.00000001

        if isinstance(xnfw, float) or isinstance(xnfw, int):
            xnfw = max(xmin, xnfw)
        else:
            xnfw[np.where(xnfw < xmin)] = xmin

        ks = theta_Rs * (4 * Rs * (np.log(0.5) + 1))**-1

        return 2 * ks * self._F(xnfw, tau)

    def params(self,
               x=None,
               y=None,
               mass=float,
               mhm=None,
               truncation=None,
               c=None,
               **kwargs):

        assert mhm is not None
        assert mass is not None

        rsdef, Rs, rho_mpc, Rs_mpc, r200_mpc = self.nfw_physical2angle(mass, c)

        #ks = rsdef*(4*rs*(np.log(0.5)+1))**-1

        subkwargs = {}
        otherkwargs = {}

        otherkwargs['name'] = 'TNFW'
        subkwargs['theta_Rs'] = rsdef
        subkwargs['Rs'] = Rs
        subkwargs['center_x'] = x
        subkwargs['center_y'] = y

        if 'r_trunc' in kwargs:
            subkwargs['r_trunc'] = kwargs['r_trunc']
        else:
            if truncation.routine == 'fixed_radius':
                subkwargs['r_trunc'] = truncation.fixed_radius(Rs * c)
            elif truncation.routine == 'virial3d':
                subkwargs['r_trunc'] = truncation.virial3d(mass)
            else:
                raise Exception('specify truncation.')

        otherkwargs['mass'] = mass
        otherkwargs['c'] = c
        otherkwargs['name'] = 'TNFW'

        otherkwargs['mass_finite'] = self.M_finite(
            rho_mpc, Rs_mpc, subkwargs['r_trunc'] * Rs**-1)

        return subkwargs, otherkwargs

    def M200(self, Rs, rho0, c):
        """
        M(R_200) calculation for NFW profile

        :param Rs: scale radius
        :type Rs: float
        :param rho0: density normalization (characteristic density)
        :type rho0: float
        :param c: concentration
        :type c: float [4,40]
        :return: M(R_200) density
        """
        return 4 * np.pi * rho0 * Rs**3 * (np.log(1 + c) - c / (1 + c))

    def r200_M(self, M):
        """
        computes the radius R_200 of a halo of mass M in comoving distances M/h

        :param M: halo mass in M_sun/h
        :type M: float or numpy array
        :return: radius R_200 in comoving Mpc/h
        """

        return (3 * M / (4 * np.pi * self.cosmology.get_rhoc() * 200))**(1. /
                                                                         3.)

    def M_r200(self, r200):
        """

        :param r200: r200 in comoving Mpc/h
        :return: M200
        """
        return self.cosmology.get_rhoc() * 200 * r200**3 * 4 * np.pi / 3.

    def rho0_c(self, c):
        """
        computes density normalization as a function of concentration parameter
        :return: density normalization in h^2/Mpc^3 (comoving)
        """
        return 200. / 3 * self.cosmology.get_rhoc() * c**3 / (np.log(1 + c) -
                                                              c / (1 + c))

    def tau(self, m, rt, mhm=False):

        ks, rs = self.nfw_params(m, mhm=mhm)

        return rt * rs**-1

    def nfwParam_physical(self, M, c):
        """
        returns the NFW parameters in physical units
        :param M: physical mass in M_sun
        :param c: concentration
        :return:
        """
        h = self.cosmology.cosmo.h
        r200 = self.r200_M(M * h) * h * self.cosmology.a_z(
            self.z)  # physical radius r200
        rho0 = self.rho0_c(c) / h**2 / self.cosmology.a_z(
            self.z)**3  # physical density in M_sun/Mpc**3
        Rs = r200 / c
        return rho0, Rs, r200

    def nfw_physical2angle(self, M, c):
        """
        converts the physical mass and concentration parameter of an NFW profile into the lensing quantities
        :param M: mass enclosed 200 \rho_crit
        :param c: NFW concentration parameter (r200/r_s)
        :return: theta_Rs (observed bending angle at the scale radius, Rs_angle (angle at scale radius) (in units of arcsec)
        """

        rho0, Rs, r200 = self.nfwParam_physical(M, c)
        Rs_angle = Rs / self.cosmology.D_A(
            0, self.z) / self.cosmology.arcsec  #Rs in asec

        theta_Rs = rho0 * (4 * Rs**2 * (1 + np.log(1. / 2.)))

        return theta_Rs / self.cosmology.get_epsiloncrit(self.z,self.cosmology.zsrc) / self.cosmology.D_A(0,self.z) / self.cosmology.arcsec, \
               Rs_angle, rho0, Rs, r200

    def M_physical(self, m200, mhm=0):
        """

        :param m200: m200
        :return: physical mass corresponding to m200
        """
        c = self.nfw_concentration(m200, mhm=mhm)
        rho0, Rs, r200 = self.nfwParam_physical(m200, c)
        return 4 * np.pi * rho0 * Rs**3 * (np.log(1 + c) - c * (1 + c)**-1)

    def f(tau):
        return tau**2 * (tau**2 + 1)**-2 * (
            (tau**2 - 1) * np.log(tau) + tau * np.pi - tau**2 - 1)

    def tau_factor(x, t):
        return t**2 * (
            (1 + x) *
            (1 + t**2)**2)**-1 * (-x * (1 + t**2) + 2 *
                                  (1 + x) * t * np.arctan(x * t**-1) +
                                  (1 + x) *
                                  (t**2 - 1) * np.log(t * (1 + x)) - 0.5 *
                                  (1 + x) * (-1 + t**2) * np.log(x**2 + t**2))