Example #1
0
    def derivatives(self,
                    x,
                    y,
                    theta_E,
                    e1,
                    e2,
                    s_scale,
                    center_x=0,
                    center_y=0):
        """

        :param x: x-coordinate in image plane
        :param y: y-coordinate in image plane
        :param theta_E: Einstein radius
        :param e1: eccentricity component
        :param e2: eccentricity component
        :param s_scale: smoothing scale
        :param center_x: profile center
        :param center_y: profile center
        :return: alpha_x, alpha_y
        """
        b, s, q, phi_G = self.param_conv(theta_E, e1, e2, s_scale)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f__x, f__y = self.nie_major_axis.derivatives(x__, y__, b, s, q)
        # rotate back
        f_x, f_y = util.rotate(f__x, f__y, -phi_G)
        return f_x, f_y
    def derivatives(self, x, y, a, s, e1, e2, center_x, center_y):
        """

        :param x: coordinate in image plane (angle)
        :param y: coordinate in image plane (angle)
        :param a: lensing strength
        :param s: core radius
        :param e1: eccentricity
        :param e2: eccentricity
        :param center_x: center of profile
        :param center_y: center of profile
        :return: deflection in x- and y-direction
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)

        f__x, f__y = self.major_axis_model.derivatives(x__, y__, a, s, q)

        # rotate deflections back
        f_x, f_y = util.rotate(f__x, f__y, -phi_q)
        return f_x, f_y
Example #3
0
    def derivatives(self, x, y, Rs, alpha_Rs, e1, e2, center_x=0, center_y=0):
        """
        returns df/dx and df/dy of the function, calculated as an elliptically distorted deflection angle of the
        spherical NFW profile

        :param x: angular position (normally in units of arc seconds)
        :param y: angular position (normally in units of arc seconds)
        :param Rs: turn over point in the slope of the NFW profile in angular unit
        :param alpha_Rs: deflection (angular units) at projected Rs
        :param e1: eccentricity component in x-direction
        :param e2: eccentricity component in y-direction
        :param center_x: center of halo (in angular units)
        :param center_y: center of halo (in angular units)
        :return: deflection in x-direction, deflection in y-direction
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)
        f__x, f__y = self.cse_major_axis_set.derivatives(
            x__ / Rs, y__ / Rs, self._a_list, self._s_list, q)

        # rotate deflections back
        f_x, f_y = util.rotate(f__x, f__y, -phi_q)
        const = self._normalization(alpha_Rs, Rs, q) / Rs
        return const * f_x, const * f_y
Example #4
0
    def derivatives(self, x, y, theta_E, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x:
        :param y:
        :param theta_E:
        :param e1:
        :param e2:
        :param s_scale:
        :param center_x:
        :param center_y:
        :return:
        """
        phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        theta_E = self._theta_E_q_convert(theta_E, q)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f__x, f__y = self.nie_simple.derivatives(x__, y__, theta_E, s_scale, q)
        # rotate back
        f_x, f_y = util.rotate(f__x, f__y, -phi_G)
        return f_x, f_y
Example #5
0
 def derivatives(self, x, y, theta_E, theta_c, e1, e2, center_x=0, center_y=0):
     """
     
     :param x: x-coord (in angles)
     :param y: y-coord (in angles)
     :param theta_E: Einstein radius (in angles)
     :param theta_c: core radius  (in angles)
     :param e1: eccentricity component, x direction(dimensionless)        
     :param e2: eccentricity component, y direction (dimensionless)       
     :return: deflection angle (in angles)
     """ 
     theta_E_conv, theta_c_conv, eps, phi_G = self.param_conv(theta_E, theta_c, e1, e2)     
     
     # shift
     x_ = x - center_x
     y_ = y - center_y
     
     # rotate
     x__, y__ = util.rotate(x_, y_, phi_G)
     
     # evaluate
     f__x, f__y = self.nie_potential_major_axis.derivatives(x__, y__, theta_E_conv, theta_c_conv, eps)
     
     # rotate back
     f_x, f_y = util.rotate(f__x, f__y, -phi_G)
     return f_x, f_y
Example #6
0
    def hessian(self, x, y, theta_E, theta_c, e1, e2, center_x=0, center_y=0):
        """
        
        :param x: x-coord (in angles)
        :param y: y-coord (in angles)
        :param theta_E: Einstein radius (in angles)
        :param theta_c: core radius  (in angles)
        :param e1: eccentricity component, x direction(dimensionless)        
        :param e2: eccentricity component, y direction (dimensionless)                  
        :return: hessian matrix (in angles)
        """
        theta_E_conv, theta_c_conv, eps, phi_G = self.param_conv(
            theta_E, theta_c, e1, e2)

        # shift
        x_ = x - center_x
        y_ = y - center_y

        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)

        # evaluate
        f__xx, f__yy, f__xy = self.nie_potential_major_axis.hessian(
            x__, y__, theta_E_conv, theta_c_conv, eps)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_G) * gamma1__ - np.sin(2 * phi_G) * gamma2__
        gamma2 = +np.sin(2 * phi_G) * gamma1__ + np.cos(2 * phi_G) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        return f_xx, f_yy, f_xy
Example #7
0
    def function(self, x, y, Rs, alpha_Rs, e1, e2, center_x=0, center_y=0):
        """
        returns elliptically distorted NFW lensing potential

        :param x: angular position (normally in units of arc seconds)
        :param y: angular position (normally in units of arc seconds)
        :param Rs: turn over point in the slope of the NFW profile in angular unit
        :param alpha_Rs: deflection (angular units) at projected Rs
        :param e1: eccentricity component in x-direction
        :param e2: eccentricity component in y-direction
        :param center_x: center of halo (in angular units)
        :param center_y: center of halo (in angular units)
        :return: lensing potential
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)

        # potential calculation
        f_ = self.cse_major_axis_set.function(x__ / Rs, y__ / Rs, self._a_list,
                                              self._s_list, q)
        const = self._normalization(alpha_Rs, Rs, q)
        return const * f_
Example #8
0
    def hessian(self, x, y, theta_E, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x: x-coordinate in image plane
        :param y: y-coordinate in image plane
        :param theta_E: Einstein radius
        :param e1: eccentricity component
        :param e2: eccentricity component
        :param s_scale: smoothing scale
        :param center_x: profile center
        :param center_y: profile center
        :return: f_xx, f_xy, f_yx, f_yy
        """
        b, s, q, phi_G = self.param_conv(theta_E, e1, e2, s_scale)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f__xx, f__xy, _, f__yy = self.nie_major_axis.hessian(x__, y__, b, s, q)
        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_G) * gamma1__ - np.sin(2 * phi_G) * gamma2__
        gamma2 = +np.sin(2 * phi_G) * gamma1__ + np.cos(2 * phi_G) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        return f_xx, f_xy, f_xy, f_yy
Example #9
0
    def hessian(self, x, y, theta_E, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x:
        :param y:
        :param theta_E:
        :param e1:
        :param e2:
        :param s_scale:
        :param center_x:
        :param center_y:
        :return:
        """
        theta_E, phi_G, q = self.param_conv(theta_E, e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f__xx, f__yy, f__xy = self.nie_simple.hessian(x__, y__, theta_E, s_scale, q)
        # rotate back
        kappa = 1./2 * (f__xx + f__yy)
        gamma1__ = 1./2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_G) * gamma1__ - np.sin(2 * phi_G) * gamma2__
        gamma2 = +np.sin(2 * phi_G) * gamma1__ + np.cos(2 * phi_G) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        return f_xx, f_yy, f_xy
Example #10
0
    def hessian(self, x, y, sigma0, Rs, e1, e2, center_x=0, center_y=0):
        """
        returns Hessian matrix of function d^2f/dx^2, d^2/dxdy, d^2/dydx, d^f/dy^2
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)
        f__xx, f__xy, __, f__yy = self.cse_major_axis_set.hessian(
            x__ / Rs, y__ / Rs, self._a_list, self._s_list, q)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_q) * gamma1__ - np.sin(2 * phi_q) * gamma2__
        gamma2 = +np.sin(2 * phi_q) * gamma1__ + np.cos(2 * phi_q) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        const = self._normalization(sigma0, Rs, q) / Rs**2

        return const * f_xx, const * f_xy, const * f_xy, const * f_yy
    def hessian(self, x, y, a, s, e1, e2, center_x, center_y):
        """

        :param x: coordinate in image plane (angle)
        :param y: coordinate in image plane (angle)
        :param a: lensing strength
        :param s: core radius
        :param e1: eccentricity
        :param e2: eccentricity
        :param center_x: center of profile
        :param center_y: center of profile
        :return: hessian elements f_xx, f_xy, f_yx, f_yy
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)

        f__xx, f__xy, __, f__yy = self.major_axis_model.hessian(x__, y__, a, s, q)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_q) * gamma1__ - np.sin(2 * phi_q) * gamma2__
        gamma2 = +np.sin(2 * phi_q) * gamma1__ + np.cos(2 * phi_q) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2

        return f_xx, f_xy, f_xy, f_yy
Example #12
0
    def derivatives(self, x, y, sigma0, Rs, e1, e2, center_x=0, center_y=0):
        """
        returns df/dx and df/dy of the function (integral of NFW)
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)
        f__x, f__y = self.cse_major_axis_set.derivatives(
            x__ / Rs, y__ / Rs, self._a_list, self._s_list, q)

        # rotate deflections back
        f_x, f_y = util.rotate(f__x, f__y, -phi_q)
        const = self._normalization(sigma0, Rs, q) / Rs
        return const * f_x, const * f_y
Example #13
0
    def derivatives(self, x, y, tangential_stretch, curvature, direction,
                    center_x, center_y):
        """

        :param x:
        :param y:
        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param curvature: 1/curvature radius
        :param direction: float, angle in radian
        :param center_x: center of source in image plane
        :param center_y: center of source in image plane
        :return:
        """

        r = 1 / curvature
        # deflection angle to allow for tangential stretch
        # (ratio of source position around zero point relative to radius is tangential stretch)
        alpha = r * (1 / tangential_stretch + 1)

        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, direction)
        # evaluate

        # move x-coordinate to circle intercept with x-axis
        if isinstance(x, int) or isinstance(x, float):
            if abs(y__) > r:
                f__x, f__y = 0, 0
            else:
                f__x, f__y = self._deflection(y__, r, tangential_stretch)

        else:
            f__x, f__y = np.zeros_like(x__), np.zeros_like(y__)
            _y__ = y__[y__ <= r]
            _f__x, _f__y = self._deflection(_y__, r, tangential_stretch)
            f__x[y__ <= r] = _f__x
            f__y[y__ <= r] = _f__y

        # rotate back
        f_x, f_y = util.rotate(f__x, f__y, -direction)
        return f_x, f_y
Example #14
0
    def magnification_finite(self,
                             x_pos,
                             y_pos,
                             kwargs_lens,
                             source_sigma=0.003,
                             window_size=0.1,
                             grid_number=100,
                             polar_grid=False,
                             aspect_ratio=0.5):
        """
        returns the magnification of an extended source with Gaussian light profile
        :param x_pos: x-axis positons of point sources
        :param y_pos: y-axis position of point sources
        :param kwargs_lens: lens model kwargs
        :param source_sigma: Gaussian sigma in arc sec in source
        :param window_size: size of window to compute the finite flux
        :param grid_number: number of grid cells per axis in the window to numerically compute the flux
        :return: numerically computed brightness of the sources
        """

        mag_finite = np.zeros_like(x_pos)
        deltaPix = float(window_size) / grid_number
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        quasar = Gaussian()
        x_grid, y_grid = util.make_grid(numPix=grid_number,
                                        deltapix=deltaPix,
                                        subgrid_res=1)

        if polar_grid is True:
            a = window_size * 0.5
            b = window_size * 0.5 * aspect_ratio
            ellipse_inds = (x_grid * a**-1)**2 + (y_grid * b**-1)**2 <= 1
            x_grid, y_grid = x_grid[ellipse_inds], y_grid[ellipse_inds]

        for i in range(len(x_pos)):
            ra, dec = x_pos[i], y_pos[i]

            center_x, center_y = self._lensModel.ray_shooting(
                ra, dec, kwargs_lens)

            if polar_grid is True:
                theta = np.arctan2(dec, ra)
                xcoord, ycoord = util.rotate(x_grid, y_grid, theta)
            else:
                xcoord, ycoord = x_grid, y_grid

            betax, betay = self._lensModel.ray_shooting(
                xcoord + ra, ycoord + dec, kwargs_lens)

            I_image = quasar.function(betax, betay, 1., source_sigma, center_x,
                                      center_y)
            mag_finite[i] = np.sum(I_image) * deltaPix**2
        return mag_finite
Example #15
0
    def hessian(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0):
        phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        gamma, q = self._param_bounds(gamma, q)
        phi_E_new = theta_E * q
        #x_shift = x - center_x
        #y_shift = y - center_y

        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)

        E = phi_E_new / (((3 - gamma) / 2.)**(1. / (1 - gamma)) * np.sqrt(q))
        if E <= 0:
            return np.zeros_like(x), np.zeros_like(x), np.zeros_like(
                x), np.zeros_like(x)
        # E = phi_E
        eta = float(-gamma + 3)
        #xt1 = np.cos(phi_G)*x_shift+np.sin(phi_G)*y_shift
        #xt2 = -np.sin(phi_G)*x_shift+np.cos(phi_G)*y_shift
        xt1, xt2 = x__, y__
        P2 = xt1**2 + xt2**2 / q**2

        if isinstance(P2, int) or isinstance(P2, float):
            a = max(0.000001, P2)
        else:
            a = np.empty_like(P2)
            p2 = P2[P2 > 0]  #in the SIS regime
            a[P2 == 0] = 0.000001
            a[P2 > 0] = p2
        s2 = 0.  # softening

        kappa = 1. / eta * (a / E**2)**(eta / 2 - 1) * (
            (eta - 2) * (xt1**2 + xt2**2 / q**4) / a + (1 + 1 / q**2))
        gamma1_value = 1. / eta * (a / E**2)**(
            eta / 2 - 1) * (1 - 1 / q**2 + (eta / 2 - 1) *
                            (2 * xt1**2 - 2 * xt2**2 / q**4) / a)
        gamma2_value = 4 * xt1 * xt2 / q**2 * (1. / 2 - 1 / eta) * (
            a / E**2)**(eta / 2 - 2) / E**2

        gamma1 = np.cos(2 * phi_G) * gamma1_value - np.sin(
            2 * phi_G) * gamma2_value
        gamma2 = +np.sin(2 * phi_G) * gamma1_value + np.cos(
            2 * phi_G) * gamma2_value

        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        return f_xx, f_xy, f_xy, f_yy
Example #16
0
    def function(self, x, y, sigma0, Rs, e1, e2, center_x=0, center_y=0):
        """
        returns double integral of NFW profile
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)

        # potential calculation
        f_ = self.cse_major_axis_set.function(x__ / Rs, y__ / Rs, self._a_list,
                                              self._s_list, q)
        const = self._normalization(sigma0, Rs, q)
        return const * f_
Example #17
0
    def coord2image_pixel(ra, dec, center_x, center_y, phi_G, scale):
        """

        :param ra: angular coordinate
        :param dec: angular coordinate
        :param center_x: center of image in angular coordinates
        :param center_y: center of image in angular coordinates
        :param phi_G: rotation angle
        :param scale: pixel scale of image
        :return: pixel coordinates
        """
        ra_ = ra - center_x
        dec_ = dec - center_y
        x_ = ra_ / scale
        y_ = dec_ / scale
        x, y = util.rotate(x_, y_, phi_G)
        return x, y
Example #18
0
def mask_ellipse(x, y, center_x, center_y, a, b, angle):
    """

    :param x: x-coordinates of pixels
    :param y: y-coordinates of pixels
    :param center_x: center of mask
    :param center_y: center of mask
    :param a: major axis
    :param b: minor axis
    :param angle: angle of major axis
    :return: mask (list of zeros and ones)
    """
    x_shift = x - center_x
    y_shift = y - center_y
    x_rot, y_rot = util.rotate(x_shift, y_shift, angle)
    r_ab = x_rot**2 / a**2 + y_rot**2 / b**2
    mask = np.empty_like(r_ab)
    mask[r_ab > 1] = 0
    mask[r_ab <= 1] = 1
    return mask
Example #19
0
    def function(self, x, y, amp, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x: x-coordinate
        :param y: y-coordinate
        :param amp: surface brightness normalization
        :param e1: eccentricity component
        :param e2: eccentricity component
        :param s_scale: smoothing scale (square averaged of minor and major axis)
        :param center_x: center of profile
        :param center_y: center of profile
        :return: surface brightness of NIE profile
        """

        x_ = x - center_x
        y_ = y - center_y
        phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        s = s_scale * np.sqrt((1 + q ** 2) / (2 * q ** 2))
        f_ = amp/2. * (q**2 * (s**2 + x__**2) + y__**2)**(-1./2)
        return f_
    def function(self, x, y, a, s, e1, e2, center_x, center_y):
        """

        :param x: coordinate in image plane (angle)
        :param y: coordinate in image plane (angle)
        :param a: lensing strength
        :param s: core radius
        :param e1: eccentricity
        :param e2: eccentricity
        :param center_x: center of profile
        :param center_y: center of profile
        :return: lensing potential
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)

        # potential calculation
        f_ = self.major_axis_model.function(x__, y__, a, s, q)
        return f_
Example #21
0
    def function(self, x, y, amp, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x:
        :param y:
        :param theta_E:
        :param e1:
        :param e2:
        :param s_scale:
        :param center_x:
        :param center_y:
        :return:
        """
        phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f_ = self._nie_simple_function(x__, y__, amp, s_scale, q)
        # rotate back
        return f_
Example #22
0
    def function(self, x, y, theta_E, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x:
        :param y:
        :param theta_E:
        :param e1:
        :param e2:
        :param s_scale:
        :param center_x:
        :param center_y:
        :return:
        """
        theta_E, phi_G, q = self.param_conv(theta_E, e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f_ = self.nie_simple.function(x__, y__, theta_E, s_scale, q)
        # rotate back
        return f_
Example #23
0
    def function(self, x, y, theta_E, e1, e2, s_scale, center_x=0, center_y=0):
        """

        :param x: x-coordinate in image plane
        :param y: y-coordinate in image plane
        :param theta_E: Einstein radius
        :param e1: eccentricity component
        :param e2: eccentricity component
        :param s_scale: smoothing scale
        :param center_x: profile center
        :param center_y: profile center
        :return: lensing potential
        """
        b, s, q, phi_G = self.param_conv(theta_E, e1, e2, s_scale)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_G)
        # evaluate
        f_ = self.nie_major_axis.function(x__, y__, b, s, q)
        # rotate back
        return f_
Example #24
0
    def hessian(self, x, y, Rs, alpha_Rs, e1, e2, center_x=0, center_y=0):
        """
        returns Hessian matrix of function d^2f/dx^2, d^f/dy^2, d^2/dxdy
        the calculation is performed as a numerical differential from the deflection field.
        Analytical relations are possible.

        :param x: angular position (normally in units of arc seconds)
        :param y: angular position (normally in units of arc seconds)
        :param Rs: turn over point in the slope of the NFW profile in angular unit
        :param alpha_Rs: deflection (angular units) at projected Rs
        :param e1: eccentricity component in x-direction
        :param e2: eccentricity component in y-direction
        :param center_x: center of halo (in angular units)
        :param center_y: center of halo (in angular units)
        :return: d^2f/dx^2, d^2/dxdy, d^2/dydx, d^f/dy^2
        """
        phi_q, q = param_util.ellipticity2phi_q(e1, e2)
        # shift
        x_ = x - center_x
        y_ = y - center_y
        # rotate
        x__, y__ = util.rotate(x_, y_, phi_q)
        f__xx, f__xy, __, f__yy = self.cse_major_axis_set.hessian(
            x__ / Rs, y__ / Rs, self._a_list, self._s_list, q)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_q) * gamma1__ - np.sin(2 * phi_q) * gamma2__
        gamma2 = +np.sin(2 * phi_q) * gamma1__ + np.cos(2 * phi_q) * gamma2__
        f_xx = kappa + gamma1
        f_yy = kappa - gamma1
        f_xy = gamma2
        const = self._normalization(alpha_Rs, Rs, q) / Rs**2

        return const * f_xx, const * f_xy, const * f_xy, const * f_yy
Example #25
0
    def test_derivatives(self):
        x = np.array([1])
        y = np.array([2])

        mu_r = 1.
        mu_t = 10.

        # positive parity

        parity = 1

        ############
        # rotation 1
        ############

        phi_G = np.pi

        f_x, f_y = self.const_mag.derivatives(x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__x, f__y = self.const_mag.derivatives(x__, y__, mu_r, mu_t, parity,
                                                0.0)

        # rotate back
        f_x_rot, f_y_rot = util.rotate(f__x, f__y, -phi_G)

        # compare
        npt.assert_almost_equal(f_x, f_x_rot, decimal=4)
        npt.assert_almost_equal(f_y, f_y_rot, decimal=4)

        ############
        # rotation 2
        ############

        phi_G = np.pi / 3.

        f_x, f_y = self.const_mag.derivatives(x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__x, f__y = self.const_mag.derivatives(x__, y__, mu_r, mu_t, parity,
                                                0.0)

        # rotate back
        f_x_rot, f_y_rot = util.rotate(f__x, f__y, -phi_G)

        # compare
        npt.assert_almost_equal(f_x, f_x_rot, decimal=4)
        npt.assert_almost_equal(f_y, f_y_rot, decimal=4)

        #===========================================================

        # negative parity

        parity = -1

        ############
        # rotation 1
        ############

        phi_G = np.pi

        f_x, f_y = self.const_mag.derivatives(x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__x, f__y = self.const_mag.derivatives(x__, y__, mu_r, mu_t, parity,
                                                0.0)

        # rotate back
        f_x_rot, f_y_rot = util.rotate(f__x, f__y, -phi_G)

        # compare
        npt.assert_almost_equal(f_x, f_x_rot, decimal=4)
        npt.assert_almost_equal(f_y, f_y_rot, decimal=4)

        ############
        # rotation 2
        ############

        phi_G = np.pi / 3.

        f_x, f_y = self.const_mag.derivatives(x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__x, f__y = self.const_mag.derivatives(x__, y__, mu_r, mu_t, parity,
                                                0.0)

        # rotate back
        f_x_rot, f_y_rot = util.rotate(f__x, f__y, -phi_G)

        # compare
        npt.assert_almost_equal(f_x, f_x_rot, decimal=4)
        npt.assert_almost_equal(f_y, f_y_rot, decimal=4)
    def magnification_finite_adaptive(self, x_image, y_image, source_x, source_y, kwargs_lens,
                                      source_fwhm_parsec, z_source,
                                      cosmo=None, grid_resolution=None,
                                      grid_radius_arcsec=None, axis_ratio=0.5,
                                      tol=0.001, step_size=0.05,
                                      use_largest_eigenvalue=True,
                                      source_light_model='SINGLE_GAUSSIAN',
                                      dx=None, dy=None, size_scale=None, amp_scale=None,
                                      fixed_aperture_size=False):
        """
        This method computes image magnifications with a finite-size background source assuming a Gaussian or a
        double Gaussian source light profile. It can be much faster that magnification_finite for lens models with many
        deflectors and a compact source. This is because most pixels in a rectangular window around a lensed
        image of a compact source do not map onto the source, and therefore don't contribute to the integrated flux in
        the image plane.

        Rather than ray tracing through a rectangular grid, this routine accelerates the computation of image
        magnifications with finite-size sources by ray tracing through an elliptical region oriented such that
        tracks the surface brightness of the lensed image. The aperture size is initially quite small,
        and increases in size until the flux inside of it (and hence the magnification) converges. The orientation of
        the elliptical aperture is computed from the magnification tensor evaluated at the image coordinate.

        If for whatever reason you prefer a circular aperture to the elliptical approximation using the hessian
        eigenvectors, you can just set axis_ratio = 1.

        To use the eigenvalues of the hessian matrix to estimate the optimum axis ratio, set axis_ratio = 0.

        The default settings for the grid resolution and ray tracing window size work well for sources with fwhm between
        0.5 - 100 pc.

        :param x_image: a list or array of x coordinates [units arcsec]
        :param y_image: a list or array of y coordinates [units arcsec]
        :param source_x: float, source position
        :param source_y: float, source position
        :param kwargs_lens: keyword arguments for the lens model
        :param source_fwhm_parsec: the size of the background source [units parsec]
        :param z_source: the source redshift
        :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
        :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
         be estimated from the source size
        :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
         will be estimated from the source size
        :param axis_ratio: the axis ratio of the ellipse used for ray tracing; if axis_ratio = 0, then the eigenvalues
         the hessian matrix will be used to estimate an appropriate axis ratio. Be warned: if the image is highly
         magnified it will tend to curve out of the resulting ellipse
        :param tol: tolerance for convergence in the magnification
        :param step_size: sets the increment for the successively larger ray tracing windows
        :param use_largest_eigenvalue: bool; if True, then the major axis of the ray tracing ellipse region
         will be aligned with the eigenvector corresponding to the largest eigenvalue of the hessian matrix
        :param source_light_model: the model for backgourn source light; currently implemented are 'SINGLE_GAUSSIAN' and
         'DOUBLE_GAUSSIAN'.
        :param dx: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
         [arcsec]
        :param dy: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
         [arcsec]
        :param size_scale: used with source model 'DOUBLE_GAUSSIAN', the size of the second source light profile relative
         to the first
        :param amp_scale: used with source model 'DOUBLE_GAUSSIAN', the peak brightness of the second source light profile
         relative to the first
        :param fixed_aperture_size: bool, if True the flux is computed inside a fixed aperture size with radius
         grid_radius_arcsec
        :return: an array of image magnifications
        """

        grid_x_0, grid_y_0, source_model, kwargs_source, grid_resolution, grid_radius_arcsec = setup_mag_finite(cosmo,
                                                                                                                self._lensModel,
                                                                                                                grid_radius_arcsec,
                                                                                                                grid_resolution,
                                                                                                                source_fwhm_parsec,
                                                                                                                source_light_model,
                                                                                                                z_source,
                                                                                                                source_x,
                                                                                                                source_y,
                                                                                                                dx, dy,
                                                                                                                amp_scale,
                                                                                                                size_scale)
        grid_x_0, grid_y_0 = grid_x_0.ravel(), grid_y_0.ravel()

        minimum_magnification = 1e-5

        magnifications = []

        for xi, yi in zip(x_image, y_image):

            if axis_ratio == 1:
                grid_r = np.hypot(grid_x_0, grid_y_0)
            else:
                w1, w2, v11, v12, v21, v22 = self.hessian_eigenvectors(xi, yi, kwargs_lens)
                _v = [np.array([v11, v12]), np.array([v21, v22])]
                _w = [abs(w1), abs(w2)]
                if use_largest_eigenvalue:
                    idx = int(np.argmax(_w))
                else:
                    idx = int(np.argmin(_w))
                v = _v[idx]

                rotation_angle = np.arctan(v[1] / v[0]) - np.pi / 2
                grid_x, grid_y = util.rotate(grid_x_0, grid_y_0, rotation_angle)

                if axis_ratio == 0:
                    sort = np.argsort(_w)
                    q = _w[sort[0]] / _w[sort[1]]
                    grid_r = np.hypot(grid_x, grid_y / q).ravel()
                else:
                    grid_r = np.hypot(grid_x, grid_y / axis_ratio).ravel()

            flux_array = np.zeros_like(grid_x_0)
            step = step_size * grid_radius_arcsec

            r_min = 0
            if fixed_aperture_size:
                r_max = grid_radius_arcsec
            else:
                r_max = step
            magnification_current = 0.

            while True:

                flux_array = self._magnification_adaptive_iteration(flux_array, xi, yi, grid_x_0, grid_y_0, grid_r,
                                                                    r_min, r_max, self._lensModel, kwargs_lens,
                                                                    source_model, kwargs_source)
                new_magnification = np.sum(flux_array) * grid_resolution ** 2
                diff = abs(new_magnification - magnification_current) / new_magnification

                if r_max >= grid_radius_arcsec:
                    break
                elif diff < tol and new_magnification > minimum_magnification:
                    break
                else:
                    r_min += step
                    r_max += step
                    magnification_current = new_magnification

            magnifications.append(new_magnification)

        return np.array(magnifications)
Example #27
0
    def test_function(self):
        y = np.array([1., 2])
        x = np.array([0., 0.])

        mu_r = 1.
        mu_t = 10.

        # positive parity

        parity = 1

        ############
        # rotation 1
        ############

        phi_G = np.pi

        values = self.const_mag.function(x, y, mu_r, mu_t, parity, phi_G)
        delta_pot = values[1] - values[0]

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f_ = self.const_mag.function(x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back

        delta_pot_rot = f_[1] - f_[0]

        # compare
        npt.assert_almost_equal(delta_pot, delta_pot_rot, decimal=4)

        ############
        # rotation 2
        ############

        phi_G = np.pi / 3.

        values = self.const_mag.function(x, y, mu_r, mu_t, parity, phi_G)
        delta_pot = values[1] - values[0]

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f_ = self.const_mag.function(x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back

        delta_pot_rot = f_[1] - f_[0]

        # compare
        npt.assert_almost_equal(delta_pot, delta_pot_rot, decimal=4)

        #===========================================================

        # negative parity

        parity = -1

        ############
        # rotation 1
        ############

        phi_G = np.pi

        values = self.const_mag.function(x, y, mu_r, mu_t, parity, phi_G)
        delta_pot = values[1] - values[0]

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f_ = self.const_mag.function(x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back

        delta_pot_rot = f_[1] - f_[0]

        # compare
        npt.assert_almost_equal(delta_pot, delta_pot_rot, decimal=4)

        ############
        # rotation 2
        ############

        phi_G = np.pi / 3.

        values = self.const_mag.function(x, y, mu_r, mu_t, parity, phi_G)
        delta_pot = values[1] - values[0]

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f_ = self.const_mag.function(x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back

        delta_pot_rot = f_[1] - f_[0]

        # compare
        npt.assert_almost_equal(delta_pot, delta_pot_rot, decimal=4)
Example #28
0
    def test_hessian(self):
        x = np.array([1])
        y = np.array([2])

        mu_r = 1.
        mu_t = 10.

        # positive parity

        parity = 1

        ############
        # rotation 1
        ############

        phi_G = np.pi

        f_xx, f_xy, f_yx, f_yy = self.const_mag.hessian(
            x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__xx, f__xy, f__yx, f__yy = self.const_mag.hessian(
            x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_G) * gamma1__ - np.sin(2 * phi_G) * gamma2__
        gamma2 = +np.sin(2 * phi_G) * gamma1__ + np.cos(2 * phi_G) * gamma2__
        f_xx_rot = kappa + gamma1
        f_yy_rot = kappa - gamma1
        f_xy_rot = gamma2

        # compare
        npt.assert_almost_equal(f_xx, f_xx_rot, decimal=4)
        npt.assert_almost_equal(f_yy, f_yy_rot, decimal=4)
        npt.assert_almost_equal(f_xy, f_xy_rot, decimal=4)
        npt.assert_almost_equal(f_xy, f_yx, decimal=8)

        ############
        # rotation 2
        ############

        phi_G = np.pi / 3.

        f_xx, f_xy, f_yx, f_yy = self.const_mag.hessian(
            x, y, mu_r, mu_t, parity, phi_G)

        # rotate
        x__, y__ = util.rotate(x, y, phi_G)

        # evaluate
        f__xx, f__xy, f__yx, f__yy = self.const_mag.hessian(
            x__, y__, mu_r, mu_t, parity, 0.0)

        # rotate back
        kappa = 1. / 2 * (f__xx + f__yy)
        gamma1__ = 1. / 2 * (f__xx - f__yy)
        gamma2__ = f__xy
        gamma1 = np.cos(2 * phi_G) * gamma1__ - np.sin(2 * phi_G) * gamma2__
        gamma2 = +np.sin(2 * phi_G) * gamma1__ + np.cos(2 * phi_G) * gamma2__
        f_xx_rot = kappa + gamma1
        f_yy_rot = kappa - gamma1
        f_xy_rot = gamma2

        # compare
        npt.assert_almost_equal(f_xx, f_xx_rot, decimal=4)
        npt.assert_almost_equal(f_yy, f_yy_rot, decimal=4)
        npt.assert_almost_equal(f_xy, f_xy_rot, decimal=4)
        npt.assert_almost_equal(f_yx, f_xy_rot, decimal=4)
Example #29
0
    def magnification_finite_adaptive(self,
                                      x_image,
                                      y_image,
                                      source_x,
                                      source_y,
                                      kwargs_lens,
                                      source_fwhm_parsec,
                                      z_source,
                                      cosmo=None,
                                      grid_resolution=None,
                                      grid_radius_arcsec=None,
                                      axis_ratio=0.5,
                                      tol=0.001,
                                      step_size=0.05,
                                      use_largest_eigenvalue=True):
        """
        This method computes image magnifications with a finite-size background source assuming a Gaussian
        source light profile. It can be much faster that magnification_finite for lens models with many
        deflectors and a relatively compact source. This is because most pixels in a rectangular window around a lensed
        image of a compact source will contain zero flux, and therefore don't contribute to the image brightness.

        Rather than ray tracing through a rectangular grid, this routine accelerates the computation of image
        magnifications with finite-size sources by ray tracing through an elliptical aperture oriented such that
        it resembles the surface brightness of the lensed image itself. The aperture size is initially quite small,
        and increases in size until the flux inside of it (and hence the magnification) converges. The orientation of
        the elliptical aperture is computed from the magnification tensor at the image coordinate.

        If for whatever reason you prefer a circular aperture to the elliptical approximation using the hessian eigenvectors,
        you can just set axis_ratio = 1.

        To use the eigenvalues of the hessian matrix to estimate the optimum axis ratio, set axis_ratio = 0.

        The default settings for the grid resolution and ray tracing window size work well for sources with fwhm between
        0.5 - 100 pc.

        :param x_image: a list or array of x coordinates [units arcsec]
        :param y_image: a list or array of y coordinates [units arcsec]
        :param kwargs_lens: keyword arguments for the lens model
        :param source_fwhm_parsec: the size of the background source [units parsec]
        :param z_source: the source redshift
        :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
        :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
        be estimated from the source size
        :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
        will be estimated from the source size
        :param axis_ratio: the axis ratio of the ellipse used for ray tracing; if axis_ratio = 0, then the eigenvalues
        the hessian matrix will be used to estimate an appropriate axis ratio. Be warned: if the image is highly
        magnified it will tend to curve out of the resulting ellipse
        :param tol: tolerance for convergence in the magnification
        :param step_size: sets the increment for the successively larger ray tracing windows
        :param use_largest_eigenvalue: bool; if True, then the major axis of the ray tracing ellipse region
        will be aligned with the eigenvector corresponding to the largest eigenvalue of the hessian matrix
        :return: an array of image magnifications
        """

        if cosmo is None:
            cosmo = self._lensModel.cosmo

        if grid_radius_arcsec is None:
            grid_radius_arcsec = auto_raytracing_grid_size(source_fwhm_parsec)
        if grid_resolution is None:
            grid_resolution = auto_raytracing_grid_resolution(
                source_fwhm_parsec)

        pc_per_arcsec = 1000 / cosmo.arcsec_per_kpc_proper(z_source).value
        source_fwhm_arcsec = source_fwhm_parsec / pc_per_arcsec
        source_sigma_arcsec = fwhm2sigma(source_fwhm_arcsec)
        kwargs_source = [{
            'amp': 1.,
            'center_x': source_x,
            'center_y': source_y,
            'sigma': source_sigma_arcsec
        }]
        source_model = LightModel(['GAUSSIAN'])

        npix = int(2 * grid_radius_arcsec / grid_resolution)
        _grid_x = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)
        _grid_y = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)

        magnifications = []
        minimum_magnification = 1e-4
        grid_x_0, grid_y_0 = np.meshgrid(_grid_x, _grid_y)
        grid_x_0, grid_y_0 = grid_x_0.ravel(), grid_y_0.ravel()

        for xi, yi in zip(x_image, y_image):

            w1, w2, v11, v12, v21, v22 = self.hessian_eigenvectors(
                xi, yi, kwargs_lens)
            _v = [np.array([v11, v12]), np.array([v21, v22])]
            _w = [abs(w1), abs(w2)]
            if use_largest_eigenvalue:
                idx = int(np.argmax(_w))
            else:
                idx = int(np.argmin(_w))
            v = _v[idx]

            rotation_angle = np.arctan(v[1] / v[0]) - np.pi / 2
            grid_x, grid_y = util.rotate(grid_x_0, grid_y_0, rotation_angle)

            if axis_ratio == 0:
                sort = np.argsort(_w)
                q = _w[sort[0]] / _w[sort[1]]
                grid_r = np.hypot(grid_x, grid_y / q).ravel()
            else:
                grid_r = np.hypot(grid_x, grid_y / axis_ratio).ravel()

            flux_array = np.zeros_like(grid_x_0)
            step = step_size * grid_radius_arcsec
            r_min = 0
            r_max = step
            magnification_current = 0.

            while True:

                flux_array = self._magnification_adaptive_iteration(
                    flux_array, xi, yi, grid_x_0, grid_y_0, grid_r, r_min,
                    r_max, self._lensModel, kwargs_lens, source_model,
                    kwargs_source)
                new_magnification = np.sum(flux_array) * grid_resolution**2
                diff = abs(new_magnification -
                           magnification_current) / new_magnification

                # the sqrt(2) will allow this algorithm to fill up the entire square window
                if r_max > np.sqrt(2) * grid_radius_arcsec:
                    break
                elif diff < tol and new_magnification > minimum_magnification:
                    break
                else:
                    r_min += step
                    r_max += step
                    magnification_current = new_magnification

            magnifications.append(new_magnification)

        return np.array(magnifications)