예제 #1
0
class CurvedArcSPP(LensProfileBase):
    """
    lens model that describes a section of a highly magnified deflector region.
    The parameterization is chosen to describe local observables efficient.

    Observables are:
    - curvature radius (basically bending relative to the center of the profile)
    - radial stretch (plus sign) thickness of arc with parity (more generalized than the power-law slope)
    - tangential stretch (plus sign). Infinity means at critical curve
    - direction of curvature
    - position of arc

    Requirements:
    - Should work with other perturbative models without breaking its meaning (say when adding additional shear terms)
    - Must best reflect the observables in lensing
    - minimal covariances between the parameters, intuitive parameterization.

    """
    param_names = [
        'tangential_stretch', 'radial_stretch', 'curvature', 'direction',
        'center_x', 'center_y'
    ]
    lower_limit_default = {
        'tangential_stretch': -100,
        'radial_stretch': -5,
        'curvature': 0.000001,
        'direction': -np.pi,
        'center_x': -100,
        'center_y': -100
    }
    upper_limit_default = {
        'tangential_stretch': 100,
        'radial_stretch': 5,
        'curvature': 100,
        'direction': np.pi,
        'center_x': 100,
        'center_y': 100
    }

    def __init__(self):
        self._spp = SPP()
        super(CurvedArcSPP, self).__init__()

    @staticmethod
    def stretch2spp(tangential_stretch, radial_stretch, curvature, direction,
                    center_x, center_y):
        """

        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial 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: parameters in terms of a spherical power-law profile resulting in the same observables
        """
        center_x_spp, center_y_spp = center_deflector(curvature, direction,
                                                      center_x, center_y)
        r_curvature = 1. / curvature
        gamma = (1. / radial_stretch - 1) / (1 - 1. / tangential_stretch) + 2
        theta_E = abs(1 - 1. / tangential_stretch)**(1. /
                                                     (gamma - 1)) * r_curvature
        return theta_E, gamma, center_x_spp, center_y_spp

    @staticmethod
    def spp2stretch(theta_E, gamma, center_x_spp, center_y_spp, center_x,
                    center_y):
        """
        turn Singular power-law lens model into stretch parameterization at position (center_x, center_y)
        This is the inverse function of stretch2spp()

        :param theta_E: Einstein radius of SPP model
        :param gamma: power-law slope
        :param center_x_spp: center of SPP model
        :param center_y_spp: center of SPP model
        :param center_x: center of curved model definition
        :param center_y: center of curved model definition
        :return: tangential_stretch, radial_stretch, curvature, direction
        """
        r_curvature = np.sqrt((center_x_spp - center_x)**2 +
                              (center_y_spp - center_y)**2)
        direction = np.arctan2(center_y - center_y_spp,
                               center_x - center_x_spp)
        tangential_stretch = 1 / (1 - (theta_E / r_curvature)**(gamma - 1))
        radial_stretch = 1 / (1 + (gamma - 2) *
                              (theta_E / r_curvature)**(gamma - 1))
        curvature = 1. / r_curvature
        return tangential_stretch, radial_stretch, curvature, direction

    def function(self, x, y, tangential_stretch, radial_stretch, curvature,
                 direction, center_x, center_y):
        """
        ATTENTION: there may not be a global lensing potential!

        :param x:
        :param y:
        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial 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:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        f_ = self._spp.function(x, y, theta_E, gamma, center_x_spp,
                                center_y_spp)
        alpha_x, alpha_y = self._spp.derivatives(center_x, center_y, theta_E,
                                                 gamma, center_x_spp,
                                                 center_y_spp)
        f_0 = alpha_x * (x - center_x) + alpha_y * (y - center_y)
        return f_ - f_0

    def derivatives(self, x, y, tangential_stretch, radial_stretch, curvature,
                    direction, center_x, center_y):
        """

        :param x:
        :param y:
        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial 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:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        f_x, f_y = self._spp.derivatives(x, y, theta_E, gamma, center_x_spp,
                                         center_y_spp)
        f_x0, f_y0 = self._spp.derivatives(center_x, center_y, theta_E, gamma,
                                           center_x_spp, center_y_spp)
        return f_x - f_x0, f_y - f_y0

    def hessian(self, x, y, tangential_stretch, radial_stretch, curvature,
                direction, center_x, center_y):
        """

        :param x:
        :param y:
        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial 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:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        return self._spp.hessian(x, y, theta_E, gamma, center_x_spp,
                                 center_y_spp)
예제 #2
0
class TestCurvedArc(object):
    """
    tests the source model routines
    """
    def setup(self):
        self.model = CurvedArc()
        self.spp = SPP()

    def test_function(self):
        output = self.model.function(1, 1, tangential_stretch=2, radial_stretch=1, r_curvature=2, direction=0, center_x=0, center_y=0)
        theta_E, gamma, center_x_spp, center_y_spp = self.model._input2spp_parameterization(tangential_stretch=2, radial_stretch=1, r_curvature=2, direction=0,
                                               center_x=0, center_y=0)
        out_spp = self.spp.function(1, 1, theta_E, gamma, center_x_spp, center_y_spp) - self.spp.function(0, 0,  theta_E, gamma, center_x_spp, center_y_spp)
        npt.assert_almost_equal(output, out_spp, decimal=8)

    def test_derivatives(self):
        tangential_stretch = 5
        radial_stretch = 1
        r_curvature = 10
        direction = 0.3
        center_x = 0
        center_y = 0
        x, y = 1, 1
        theta_E, gamma, center_x_spp, center_y_spp = self.model._input2spp_parameterization(tangential_stretch,
                                                                                      radial_stretch, r_curvature,
                                                                                      direction, center_x, center_y)
        f_x, f_y = self.spp.derivatives(x, y, theta_E, gamma, center_x_spp, center_y_spp)
        f_x0, f_y0 = self.spp.derivatives(center_x, center_y, theta_E, gamma, center_x_spp, center_y_spp)
        f_x_new, f_y_new = self.model.derivatives(x, y, tangential_stretch, radial_stretch, r_curvature, direction, center_x, center_y)
        npt.assert_almost_equal(f_x_new, f_x - f_x0, decimal=8)
        npt.assert_almost_equal(f_y_new, f_y - f_y0, decimal=8)

    def test_hessian(self):
        lens = LensModel(lens_model_list=['CURVED_ARC'])
        center_x, center_y = 0, 0
        tangential_stretch = 10
        radial_stretch = 1
        kwargs_lens = [
            {'tangential_stretch': tangential_stretch, 'radial_stretch': radial_stretch, 'r_curvature': 10.5, 'direction': 0.,
             'center_x': center_x, 'center_y': center_y}]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag, tangential_stretch * radial_stretch, decimal=8)

        center_x, center_y = 2, 3
        tangential_stretch = 10
        radial_stretch = 1
        kwargs_lens = [
            {'tangential_stretch': tangential_stretch, 'radial_stretch': radial_stretch, 'r_curvature': 10.5, 'direction': 0.,
             'center_x': center_x, 'center_y': center_y}]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag, tangential_stretch * radial_stretch, decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = 3
        radial_stretch = -1
        kwargs_lens = [
            {'tangential_stretch': tangential_stretch, 'radial_stretch': radial_stretch, 'r_curvature': 10.5,
             'direction': 0.,
             'center_x': center_x, 'center_y': center_y}]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag, tangential_stretch * radial_stretch, decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = -3
        radial_stretch = -1
        kwargs_lens = [
            {'tangential_stretch': tangential_stretch, 'radial_stretch': radial_stretch, 'r_curvature': 10.5,
             'direction': 0.,
             'center_x': center_x, 'center_y': center_y}]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag, tangential_stretch * radial_stretch, decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = 10.4
        radial_stretch = 0.6
        kwargs_lens = [
            {'tangential_stretch': tangential_stretch, 'radial_stretch': radial_stretch, 'r_curvature': 10.5,
             'direction': 0.,
             'center_x': center_x, 'center_y': center_y}]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag, tangential_stretch * radial_stretch, decimal=8)
예제 #3
0
class CurvedArc(object):
    """
    lens model that describes a section of a highly magnified deflector region.
    The parameterization is chosen to describe local observables efficient.

    Observables are:
    - curvature radius (basically bending relative to the center of the profile)
    - radial stretch (plus sign) thickness of arc with parity (more generalized than the power-law slope)
    - tangential stretch (plus sign). Infinity means at critical curve
    - direction of curvature
    - position of arc

    Requirements:
    - Should work with other perturbative models without breaking its meaning (say when adding additional shear terms)
    - Must best reflect the observables in lensing
    - minimal covariances between the parameters, intuitive parameterization.

    """
    def __init__(self):
        self._spp = SPP()

    def _input2spp_parameterization(self, tangential_stretch, radial_stretch,
                                    r_curvature, direction, center_x,
                                    center_y):
        """

        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial direction
        :param r_curvature: 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: parameters in terms of a spherical power-law profile resulting in the same observables
        """
        center_x_spp = center_x - r_curvature * np.cos(direction)
        center_y_spp = center_y - r_curvature * np.sin(direction)

        theta_E, gamma = self._stretch2profile(tangential_stretch,
                                               radial_stretch, r_curvature)
        return theta_E, gamma, center_x_spp, center_y_spp

    @staticmethod
    def _stretch2profile(tangential_stretch, radial_stretch, r_curvature):
        """

        :param tangential_stretch: float, stretch of intrinsic source in tangential direction
        :param radial_stretch: float, stretch of intrinsic source in radial direction
        :param r_curvature: radius of SPP where to have the specific tangential and radial stretch values
        :return: theta_E, gamma of SPP profile
        """
        gamma = (1. / radial_stretch - 1) / (1 - 1. / tangential_stretch) + 2
        theta_E = abs(1 - 1. / tangential_stretch)**(1. /
                                                     (gamma - 1)) * r_curvature
        return theta_E, gamma

    def function(self, x, y, tangential_stretch, radial_stretch, r_curvature,
                 direction, center_x, center_y):
        """
        ATTENTION: there may not be a global lensing potential!

        :param x:
        :param y:
        :param tangential_stretch:
        :param radial_stretch:
        :param r_curvature:
        :param direction:
        :param center_x:
        :param center_y:
        :return:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self._input2spp_parameterization(
            tangential_stretch, radial_stretch, r_curvature, direction,
            center_x, center_y)
        return self._spp.function(x, y, theta_E, gamma, center_x_spp,
                                  center_y_spp) - self._spp.function(
                                      center_x, center_y, theta_E, gamma,
                                      center_x_spp, center_y_spp)

    def derivatives(self, x, y, tangential_stretch, radial_stretch,
                    r_curvature, direction, center_x, center_y):
        """

        :param x:
        :param y:
        :param tangential_stretch:
        :param radial_stretch:
        :param r_curvature:
        :param direction:
        :param center_x:
        :param center_y:
        :return:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self._input2spp_parameterization(
            tangential_stretch, radial_stretch, r_curvature, direction,
            center_x, center_y)
        f_x, f_y = self._spp.derivatives(x, y, theta_E, gamma, center_x_spp,
                                         center_y_spp)
        f_x0, f_y0 = self._spp.derivatives(center_x, center_y, theta_E, gamma,
                                           center_x_spp, center_y_spp)
        return f_x - f_x0, f_y - f_y0

    def hessian(self, x, y, tangential_stretch, radial_stretch, r_curvature,
                direction, center_x, center_y):
        """

        :param x:
        :param y:
        :param tangential_stretch:
        :param radial_stretch:
        :param r_curvature:
        :param direction:
        :param center_x:
        :param center_y:
        :return:
        """
        theta_E, gamma, center_x_spp, center_y_spp = self._input2spp_parameterization(
            tangential_stretch, radial_stretch, r_curvature, direction,
            center_x, center_y)
        return self._spp.hessian(x, y, theta_E, gamma, center_x_spp,
                                 center_y_spp)
예제 #4
0
class TestSPEP(object):
    """
    tests the Gaussian methods
    """
    def setup(self):
        self.SPEP = SPEP()
        self.SPP = SPP()
        self.SIS = SIS()

    def test_function(self):
        x = np.array([1])
        y = np.array([2])
        phi_E = 1.
        gamma = 1.9
        q = 1
        phi_G = 0.
        E = phi_E / (((3 - gamma) / 2.)**(1. / (1 - gamma)) * np.sqrt(q))
        values_spep = self.SPEP.function(x, y, E, gamma, q, phi_G)
        values_spp = self.SPP.function(x, y, E, gamma)
        assert values_spep[0] == values_spp[0]
        x = np.array([0])
        y = np.array([0])
        values_spep = self.SPEP.function(x, y, E, gamma, q, phi_G)
        values_spp = self.SPP.function(x, y, E, gamma)
        assert values_spep[0] == values_spp[0]

        x = np.array([2, 3, 4])
        y = np.array([1, 1, 1])
        values_spep = self.SPEP.function(x, y, E, gamma, q, phi_G)
        values_spp = self.SPP.function(x, y, E, gamma)
        assert values_spep[0] == values_spp[0]
        assert values_spep[1] == values_spp[1]
        assert values_spep[2] == values_spp[2]

    def test_derivatives(self):
        x = np.array([1])
        y = np.array([2])
        phi_E = 1.
        gamma = 1.9
        q = 1
        phi_G = 0.
        E = phi_E / (((3 - gamma) / 2.)**(1. / (1 - gamma)) * np.sqrt(q))
        f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, E, gamma, q, phi_G)
        f_x_spp, f_y_spp = self.SPP.derivatives(x, y, E, gamma)
        assert f_x_spep[0] == f_x_spp[0]
        assert f_y_spep[0] == f_y_spp[0]
        x = np.array([0])
        y = np.array([0])
        f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, E, gamma, q, phi_G)
        f_x_spp, f_y_spp = self.SPP.derivatives(x, y, E, gamma)
        assert f_x_spep[0] == f_x_spp[0]
        assert f_y_spep[0] == f_y_spp[0]

        x = np.array([1, 3, 4])
        y = np.array([2, 1, 1])
        f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, E, gamma, q, phi_G)
        f_x_spp, f_y_spp = self.SPP.derivatives(x, y, E, gamma)
        assert f_x_spep[0] == f_x_spp[0]
        assert f_y_spep[0] == f_y_spp[0]
        assert f_x_spep[1] == f_x_spp[1]
        assert f_y_spep[1] == f_y_spp[1]
        assert f_x_spep[2] == f_x_spp[2]
        assert f_y_spep[2] == f_y_spp[2]

    def test_hessian(self):
        x = np.array([1])
        y = np.array([2])
        phi_E = 1.
        gamma = 1.9
        q = 1.
        phi_G = 0.
        E = phi_E / (((3 - gamma) / 2.)**(1. / (1 - gamma)) * np.sqrt(q))
        f_xx, f_yy, f_xy = self.SPEP.hessian(x, y, E, gamma, q, phi_G)
        f_xx_spep, f_yy_spep, f_xy_spep = self.SPEP.hessian(
            x, y, E, gamma, q, phi_G)
        f_xx_spp, f_yy_spp, f_xy_spp = self.SPP.hessian(x, y, E, gamma)
        assert f_xx_spep[0] == f_xx_spp[0]
        assert f_yy_spep[0] == f_yy_spp[0]
        assert f_xy_spep[0] == f_xy_spp[0]
        x = np.array([1, 3, 4])
        y = np.array([2, 1, 1])
        f_xx_spep, f_yy_spep, f_xy_spep = self.SPEP.hessian(
            x, y, E, gamma, q, phi_G)
        f_xx_spp, f_yy_spp, f_xy_spp = self.SPP.hessian(x, y, E, gamma)
        assert f_xx_spep[0] == f_xx_spp[0]
        assert f_yy_spep[0] == f_yy_spp[0]
        assert f_xy_spep[0] == f_xy_spp[0]
        assert f_xx_spep[1] == f_xx_spp[1]
        assert f_yy_spep[1] == f_yy_spp[1]
        assert f_xy_spep[1] == f_xy_spp[1]
        assert f_xx_spep[2] == f_xx_spp[2]
        assert f_yy_spep[2] == f_yy_spp[2]
        assert f_xy_spep[2] == f_xy_spp[2]

    def test_compare_sis(self):
        x = np.array([1])
        y = np.array([2])
        theta_E = 1.
        gamma = 2.
        f_sis = self.SIS.function(x, y, theta_E)
        f_spp = self.SPP.function(x, y, theta_E, gamma)
        f_x_sis, f_y_sis = self.SIS.derivatives(x, y, theta_E)
        f_x_spp, f_y_spp = self.SPP.derivatives(x, y, theta_E, gamma)
        f_xx_sis, f_yy_sis, f_xy_sis = self.SIS.hessian(x, y, theta_E)
        f_xx_spp, f_yy_spp, f_xy_spp = self.SPP.hessian(x, y, theta_E, gamma)
        npt.assert_almost_equal(f_sis[0], f_spp[0], decimal=7)
        npt.assert_almost_equal(f_x_sis[0], f_x_spp[0], decimal=7)
        npt.assert_almost_equal(f_y_sis[0], f_y_spp[0], decimal=7)
        npt.assert_almost_equal(f_xx_sis[0], f_xx_spp[0], decimal=7)
        npt.assert_almost_equal(f_yy_sis[0], f_yy_spp[0], decimal=7)
        npt.assert_almost_equal(f_xy_sis[0], f_xy_spp[0], decimal=7)

    def test_unit_conversion(self):
        theta_E = 2.
        gamma = 2.2
        rho0 = self.SPP.theta2rho(theta_E, gamma)
        theta_E_out = self.SPP.rho2theta(rho0, gamma)
        assert theta_E == theta_E_out

    def test_mass_2d_lens(self):
        r = 1
        theta_E = 1
        gamma = 2
        m_2d = self.SPP.mass_2d_lens(r, theta_E, gamma)
        npt.assert_almost_equal(m_2d, 3.1415926535897931, decimal=8)

    def test_grav_pot(self):
        x, y = 1, 0
        rho0 = 1
        gamma = 2
        grav_pot = self.SPP.grav_pot(x, y, rho0, gamma, center_x=0, center_y=0)
        npt.assert_almost_equal(grav_pot, 12.566370614359172, decimal=8)
예제 #5
0
class TestCurvedArc(object):
    """
    tests the source model routines
    """
    def setup(self):
        self.model = CurvedArc()
        self.spp = SPP()

    def test_spp2stretch(self):
        center_x, center_y = 1, 1
        theta_E = 1
        gamma = 1.9
        center_x_spp, center_y_spp = 0., 0

        tangential_stretch, radial_stretch, curvature, direction = self.model.spp2stretch(
            theta_E, gamma, center_x_spp, center_y_spp, center_x, center_y)
        theta_E_new, gamma_new, center_x_spp_new, center_y_spp_new = self.model.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        npt.assert_almost_equal(center_x_spp_new, center_x_spp, decimal=8)
        npt.assert_almost_equal(center_y_spp_new, center_y_spp, decimal=8)
        npt.assert_almost_equal(theta_E_new, theta_E, decimal=8)
        npt.assert_almost_equal(gamma_new, gamma, decimal=8)

        center_x, center_y = -1, 1
        tangential_stretch, radial_stretch, curvature, direction = self.model.spp2stretch(
            theta_E, gamma, center_x_spp, center_y_spp, center_x, center_y)
        theta_E_new, gamma_new, center_x_spp_new, center_y_spp_new = self.model.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        npt.assert_almost_equal(center_x_spp_new, center_x_spp, decimal=8)
        npt.assert_almost_equal(center_y_spp_new, center_y_spp, decimal=8)
        npt.assert_almost_equal(theta_E_new, theta_E, decimal=8)
        npt.assert_almost_equal(gamma_new, gamma, decimal=8)

        center_x, center_y = 0, 0.5
        tangential_stretch, radial_stretch, curvature, direction = self.model.spp2stretch(
            theta_E, gamma, center_x_spp, center_y_spp, center_x, center_y)
        theta_E_new, gamma_new, center_x_spp_new, center_y_spp_new = self.model.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        npt.assert_almost_equal(center_x_spp_new, center_x_spp, decimal=8)
        npt.assert_almost_equal(center_y_spp_new, center_y_spp, decimal=8)
        npt.assert_almost_equal(theta_E_new, theta_E, decimal=8)
        npt.assert_almost_equal(gamma_new, gamma, decimal=8)

        center_x, center_y = 0, -1.5
        tangential_stretch, radial_stretch, r_curvature, direction = self.model.spp2stretch(
            theta_E, gamma, center_x_spp, center_y_spp, center_x, center_y)
        print(tangential_stretch, radial_stretch, r_curvature, direction)
        theta_E_new, gamma_new, center_x_spp_new, center_y_spp_new = self.model.stretch2spp(
            tangential_stretch, radial_stretch, r_curvature, direction,
            center_x, center_y)
        npt.assert_almost_equal(center_x_spp_new, center_x_spp, decimal=8)
        npt.assert_almost_equal(center_y_spp_new, center_y_spp, decimal=8)
        npt.assert_almost_equal(theta_E_new, theta_E, decimal=8)
        npt.assert_almost_equal(gamma_new, gamma, decimal=8)

    def test_function(self):
        center_x, center_y = 0., 0.
        x, y = 1, 1
        output = self.model.function(x,
                                     y,
                                     tangential_stretch=2,
                                     radial_stretch=1,
                                     curvature=1. / 2,
                                     direction=0,
                                     center_x=0,
                                     center_y=0)
        theta_E, gamma, center_x_spp, center_y_spp = self.model.stretch2spp(
            tangential_stretch=2,
            radial_stretch=1,
            curvature=1. / 2,
            direction=0,
            center_x=0,
            center_y=0)
        out_spp = self.spp.function(1, 1, theta_E, gamma, center_x_spp,
                                    center_y_spp)
        alpha_x, alpha_y = self.spp.derivatives(center_x, center_y, theta_E,
                                                gamma, center_x_spp,
                                                center_y_spp)
        f_0 = alpha_x * (x - center_x) + alpha_y * (y - center_y)

        npt.assert_almost_equal(output, out_spp - f_0, decimal=8)

    def test_derivatives(self):
        tangential_stretch = 5
        radial_stretch = 1
        curvature = 1. / 10
        direction = 0.3
        center_x = 0
        center_y = 0
        x, y = 1, 1
        theta_E, gamma, center_x_spp, center_y_spp = self.model.stretch2spp(
            tangential_stretch, radial_stretch, curvature, direction, center_x,
            center_y)
        f_x, f_y = self.spp.derivatives(x, y, theta_E, gamma, center_x_spp,
                                        center_y_spp)
        f_x0, f_y0 = self.spp.derivatives(center_x, center_y, theta_E, gamma,
                                          center_x_spp, center_y_spp)
        f_x_new, f_y_new = self.model.derivatives(x, y, tangential_stretch,
                                                  radial_stretch, curvature,
                                                  direction, center_x,
                                                  center_y)
        npt.assert_almost_equal(f_x_new, f_x - f_x0, decimal=8)
        npt.assert_almost_equal(f_y_new, f_y - f_y0, decimal=8)

    def test_hessian(self):
        lens = LensModel(lens_model_list=['CURVED_ARC'])
        center_x, center_y = 0, 0
        tangential_stretch = 10
        radial_stretch = 1
        kwargs_lens = [{
            'tangential_stretch': tangential_stretch,
            'radial_stretch': radial_stretch,
            'curvature': 1. / 10.5,
            'direction': 0.,
            'center_x': center_x,
            'center_y': center_y
        }]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag,
                                tangential_stretch * radial_stretch,
                                decimal=8)

        center_x, center_y = 2, 3
        tangential_stretch = 10
        radial_stretch = 1
        kwargs_lens = [{
            'tangential_stretch': tangential_stretch,
            'radial_stretch': radial_stretch,
            'curvature': 1. / 10.5,
            'direction': 0.,
            'center_x': center_x,
            'center_y': center_y
        }]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag,
                                tangential_stretch * radial_stretch,
                                decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = 3
        radial_stretch = -1
        kwargs_lens = [{
            'tangential_stretch': tangential_stretch,
            'radial_stretch': radial_stretch,
            'curvature': 1. / 10.5,
            'direction': 0.,
            'center_x': center_x,
            'center_y': center_y
        }]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag,
                                tangential_stretch * radial_stretch,
                                decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = -3
        radial_stretch = -1
        kwargs_lens = [{
            'tangential_stretch': tangential_stretch,
            'radial_stretch': radial_stretch,
            'curvature': 1. / 10.5,
            'direction': 0.,
            'center_x': center_x,
            'center_y': center_y
        }]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag,
                                tangential_stretch * radial_stretch,
                                decimal=8)

        center_x, center_y = 0, 0
        tangential_stretch = 10.4
        radial_stretch = 0.6
        kwargs_lens = [{
            'tangential_stretch': tangential_stretch,
            'radial_stretch': radial_stretch,
            'curvature': 1. / 10.5,
            'direction': 0.,
            'center_x': center_x,
            'center_y': center_y
        }]
        mag = lens.magnification(center_x, center_y, kwargs=kwargs_lens)
        npt.assert_almost_equal(mag,
                                tangential_stretch * radial_stretch,
                                decimal=8)