class SersicEllipse(LensProfileBase):
    """
    this class contains functions to evaluate a Sersic mass profile: https://arxiv.org/pdf/astro-ph/0311559.pdf
    """
    param_names = ['k_eff', 'R_sersic', 'n_sersic', 'e1', 'e2', 'center_x', 'center_y']
    lower_limit_default = {'k_eff': 0, 'R_sersic': 0, 'n_sersic': 0.5, 'e1': -0.5, 'e2': -0.5, 'center_x': -100, 'center_y': -100}
    upper_limit_default = {'k_eff': 10, 'R_sersic': 100, 'n_sersic': 8, 'e1': 0.5, 'e2': 0.5, 'center_x': 100, 'center_y': 100}

    def __init__(self):
        self.sersic = Sersic()
        self._diff = 0.000001
        super(SersicEllipse, self).__init__()

    def function(self, x, y, n_sersic, R_sersic, k_eff, e1, e2, center_x=0, center_y=0):
        """
        returns Gaussian
        """
        # phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        x_, y_ = param_util.transform_e1e2_square_average(x, y, e1, e2, center_x, center_y)
        # x_, y_ = self._coord_transf(x, y, q, phi_G, center_x, center_y)
        f_ = self.sersic.function(x_, y_, n_sersic, R_sersic, k_eff)
        return f_

    def derivatives(self, x, y, n_sersic, R_sersic, k_eff, e1, e2, center_x=0, center_y=0):
        """
        returns df/dx and df/dy of the function
        """
        phi_G, q = param_util.ellipticity2phi_q(e1, e2)
        e = param_util.q2e(q)
        # e = abs(1. - q)
        cos_phi = np.cos(phi_G)
        sin_phi = np.sin(phi_G)
        x_, y_ = param_util.transform_e1e2_square_average(x, y, e1, e2, center_x, center_y)
        # x_, y_ = self._coord_transf(x, y, q, phi_G, center_x, center_y)
        f_x_prim, f_y_prim = self.sersic.derivatives(x_, y_, n_sersic, R_sersic, k_eff)
        f_x_prim *= np.sqrt(1 - e)
        f_y_prim *= np.sqrt(1 + e)
        f_x = cos_phi*f_x_prim-sin_phi*f_y_prim
        f_y = sin_phi*f_x_prim+cos_phi*f_y_prim
        return f_x, f_y

    def hessian(self, x, y, n_sersic, R_sersic, k_eff, 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
        """
        alpha_ra, alpha_dec = self.derivatives(x, y, n_sersic, R_sersic, k_eff, e1, e2, center_x, center_y)
        diff = self._diff
        alpha_ra_dx, alpha_dec_dx = self.derivatives(x + diff, y, n_sersic, R_sersic, k_eff, e1, e2, center_x, center_y)
        alpha_ra_dy, alpha_dec_dy = self.derivatives(x, y + diff, n_sersic, R_sersic, k_eff, e1, e2, center_x, center_y)

        f_xx = (alpha_ra_dx - alpha_ra)/diff
        f_xy = (alpha_ra_dy - alpha_ra)/diff
        f_yx = (alpha_dec_dx - alpha_dec)/diff
        f_yy = (alpha_dec_dy - alpha_dec)/diff

        return f_xx, f_xy, f_yx, f_yy
Exemplo n.º 2
0
    def test_sersic(self):
        from lenstronomy.LensModel.Profiles.sersic import Sersic
        from lenstronomy.LightModel.Profiles.sersic import Sersic as SersicLight
        sersic_lens = Sersic()
        sersic_light = SersicLight()
        kwargs_light = {
            'n_sersic': 2,
            'R_sersic': 0.5,
            'I0_sersic': 1,
            'center_x': 0,
            'center_y': 0
        }
        kwargs_lens = {
            'n_sersic': 2,
            'R_sersic': 0.5,
            'k_eff': 1,
            'center_x': 0,
            'center_y': 0
        }
        deltaPix = 0.01
        numPix = 1000
        x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix)
        x_grid2d = util.array2image(x_grid)
        y_grid2d = util.array2image(y_grid)

        f_xx, f_yy, _ = sersic_lens.hessian(x_grid, y_grid, **kwargs_lens)
        f_x, f_y = sersic_lens.derivatives(x_grid, y_grid, **kwargs_lens)
        f_x = util.array2image(f_x)
        kappa = util.array2image((f_xx + f_yy) / 2.)
        f_x_num, f_y_num = convergence_integrals.deflection_from_kappa_grid(
            kappa, deltaPix)
        x1, y1 = 500, 550
        x0, y0 = int(numPix / 2.), int(numPix / 2.)
        npt.assert_almost_equal(f_x[x1, y1], f_x_num[x1, y1], decimal=2)
        f_num = convergence_integrals.potential_from_kappa_grid(
            kappa, deltaPix)
        f_ = sersic_lens.function(x_grid2d[x1, y1], y_grid2d[x1, y1],
                                  **kwargs_lens)
        f_00 = sersic_lens.function(x_grid2d[x0, y0], y_grid2d[x0, y0],
                                    **kwargs_lens)
        npt.assert_almost_equal(f_ - f_00,
                                f_num[x1, y1] - f_num[x0, y0],
                                decimal=2)
Exemplo n.º 3
0
class TestMassAngleConversion(object):
    """
    test angular to mass unit conversions
    """
    def setup(self):
        self.composite = CompositeSersicNFW()
        self.sersic = Sersic()
        self.nfw = NFW_ELLIPSE()

    def test_convert(self):
        theta_E = 1.
        mass_light = 1 / 2.
        Rs = 5.
        n_sersic = 2.
        r_eff = 0.7
        theta_Rs, k_eff = self.composite.convert_mass(theta_E, mass_light, Rs,
                                                      n_sersic, r_eff)

        alpha_E_sersic, _ = self.sersic.derivatives(theta_E,
                                                    0,
                                                    n_sersic,
                                                    r_eff,
                                                    k_eff=1)
        alpha_E_nfw, _ = self.nfw.derivatives(theta_E,
                                              0,
                                              Rs,
                                              theta_Rs=1,
                                              q=1,
                                              phi_G=0)
        a = theta_Rs * alpha_E_nfw + (k_eff * alpha_E_sersic)
        b = theta_Rs * alpha_E_nfw / (k_eff * alpha_E_sersic)
        npt.assert_almost_equal(a, theta_E, decimal=10)
        npt.assert_almost_equal(b, mass_light, decimal=10)

    def test_function(self):
        theta_E = 1.
        mass_light = 1 / 2.
        Rs = 5.
        n_sersic = 2.
        r_eff = 0.7
        q, phi_G = 0.9, 0
        q_s, phi_G_s = 0.7, 0.5
        x, y, = 1, 1
        f_ = self.composite.function(x,
                                     y,
                                     theta_E,
                                     mass_light,
                                     Rs,
                                     q,
                                     phi_G,
                                     n_sersic,
                                     r_eff,
                                     q_s,
                                     phi_G_s,
                                     center_x=0,
                                     center_y=0)
        npt.assert_almost_equal(f_, 1.1983595285200526, decimal=10)

    def test_derivatives(self):
        theta_E = 1.
        mass_light = 1 / 2.
        Rs = 5.
        n_sersic = 2.
        r_eff = 0.7
        q, phi_G = 0.9, 0
        q_s, phi_G_s = 0.7, 0.5
        x, y, = 1, 1
        f_x, f_y = self.composite.derivatives(x,
                                              y,
                                              theta_E,
                                              mass_light,
                                              Rs,
                                              q,
                                              phi_G,
                                              n_sersic,
                                              r_eff,
                                              q_s,
                                              phi_G_s,
                                              center_x=0,
                                              center_y=0)
        npt.assert_almost_equal(f_x, 0.54138666294863724, decimal=10)
        npt.assert_almost_equal(f_y, 0.75841883763728535, decimal=10)

    def test_hessian(self):
        theta_E = 1.
        mass_light = 1 / 2.
        Rs = 5.
        n_sersic = 2.
        r_eff = 0.7
        q, phi_G = 0.9, 0
        q_s, phi_G_s = 0.7, 0.5
        x, y, = 1, 1
        f_xx, f_yy, f_xy = self.composite.hessian(x,
                                                  y,
                                                  theta_E,
                                                  mass_light,
                                                  Rs,
                                                  q,
                                                  phi_G,
                                                  n_sersic,
                                                  r_eff,
                                                  q_s,
                                                  phi_G_s,
                                                  center_x=0,
                                                  center_y=0)
        npt.assert_almost_equal(f_xx, 0.43275276043197586, decimal=10)
        npt.assert_almost_equal(f_yy, 0.37688935994317774, decimal=10)
        npt.assert_almost_equal(f_xy, -0.46895575042671389, decimal=10)
Exemplo n.º 4
0
class SersicEllipse(object):
    """
    this class contains functions to evaluate a Sersic mass profile: https://arxiv.org/pdf/astro-ph/0311559.pdf
    """
    def __init__(self):
        self.sersic = Sersic()
        self._diff = 0.000001

    def function(self,
                 x,
                 y,
                 n_sersic,
                 r_eff,
                 k_eff,
                 q,
                 phi_G,
                 center_x=0,
                 center_y=0):
        """
        returns Gaussian
        """
        x_, y_ = self._coord_transf(x, y, q, phi_G, center_x, center_y)
        f_ = self.sersic.function(x_, y_, n_sersic, r_eff, k_eff)
        return f_

    def derivatives(self,
                    x,
                    y,
                    n_sersic,
                    r_eff,
                    k_eff,
                    q,
                    phi_G,
                    center_x=0,
                    center_y=0):
        """
        returns df/dx and df/dy of the function
        """
        e = abs(1. - q)
        cos_phi = np.cos(phi_G)
        sin_phi = np.sin(phi_G)
        x_, y_ = self._coord_transf(x, y, q, phi_G, center_x, center_y)
        f_x_prim, f_y_prim = self.sersic.derivatives(x_, y_, n_sersic, r_eff,
                                                     k_eff)
        f_x_prim *= np.sqrt(1 - e)
        f_y_prim *= np.sqrt(1 + e)
        f_x = cos_phi * f_x_prim - sin_phi * f_y_prim
        f_y = sin_phi * f_x_prim + cos_phi * f_y_prim
        return f_x, f_y

    def hessian(self,
                x,
                y,
                n_sersic,
                r_eff,
                k_eff,
                q,
                phi_G,
                center_x=0,
                center_y=0):
        """
        returns Hessian matrix of function d^2f/dx^2, d^f/dy^2, d^2/dxdy
        """
        alpha_ra, alpha_dec = self.derivatives(x, y, n_sersic, r_eff, k_eff, q,
                                               phi_G, center_x, center_y)
        diff = self._diff
        alpha_ra_dx, alpha_dec_dx = self.derivatives(x + diff, y, n_sersic,
                                                     r_eff, k_eff, q, phi_G,
                                                     center_x, center_y)
        alpha_ra_dy, alpha_dec_dy = self.derivatives(x, y + diff, n_sersic,
                                                     r_eff, k_eff, q, phi_G,
                                                     center_x, center_y)

        f_xx = (alpha_ra_dx - alpha_ra) / diff
        f_xy = (alpha_ra_dy - alpha_ra) / diff
        f_yx = (alpha_dec_dx - alpha_dec) / diff
        f_yy = (alpha_dec_dy - alpha_dec) / diff

        return f_xx, f_yy, f_xy

    def _coord_transf(self, x, y, q, phi_G, center_x, center_y):
        """

        :param x:
        :param y:
        :param q:
        :param phi_G:
        :param center_x:
        :param center_y:
        :return:
        """
        x_shift = x - center_x
        y_shift = y - center_y
        cos_phi = np.cos(phi_G)
        sin_phi = np.sin(phi_G)
        e = abs(1 - q)
        x_ = (cos_phi * x_shift + sin_phi * y_shift) * np.sqrt(1 - e)
        y_ = (-sin_phi * x_shift + cos_phi * y_shift) * np.sqrt(1 + e)
        return x_, y_
Exemplo n.º 5
0
class TestSersic(object):
    """
    tests the Gaussian methods
    """
    def setup(self):

        self.sersic_2 = SersicEllipseKappa()
        self.sersic = Sersic()
        self.sersic_light = Sersic_light()

    def test_function(self):

        x = 1
        y = 2
        n_sersic = 2.
        R_sersic = 1.
        k_eff = 0.2
        values = self.sersic.function(x, y, n_sersic, R_sersic, k_eff)
        npt.assert_almost_equal(values, 1.0272982586319199, decimal=10)

        x = np.array([0])
        y = np.array([0])
        values = self.sersic.function(x, y, n_sersic, R_sersic, k_eff)
        npt.assert_almost_equal(values[0], 0., decimal=9)

        x = np.array([2, 3, 4])
        y = np.array([1, 1, 1])
        values = self.sersic.function(x, y, n_sersic, R_sersic, k_eff)

        npt.assert_almost_equal(values[0], 1.0272982586319199, decimal=10)
        npt.assert_almost_equal(values[1], 1.3318743892966658, decimal=10)
        npt.assert_almost_equal(values[2], 1.584299393114988, decimal=10)

    def test_derivatives(self):
        x = np.array([1])
        y = np.array([2])
        n_sersic = 2.
        R_sersic = 1.
        k_eff = 0.2
        f_x, f_y = self.sersic.derivatives(x, y, n_sersic, R_sersic, k_eff)
        f_x2, f_y2 = self.sersic_2.derivatives(x, y, n_sersic, R_sersic, k_eff,
                                               0, 0.00000001)

        assert f_x[0] == 0.16556078301997193
        assert f_y[0] == 0.33112156603994386
        npt.assert_almost_equal(f_x2[0], f_x[0])
        npt.assert_almost_equal(f_y2[0], f_y[0])

        x = np.array([0])
        y = np.array([0])
        f_x, f_y = self.sersic.derivatives(x, y, n_sersic, R_sersic, k_eff)
        f_x2, f_y2 = self.sersic_2.derivatives(x, y, n_sersic, R_sersic, k_eff,
                                               0, 0.00000001)
        assert f_x[0] == 0
        assert f_y[0] == 0
        npt.assert_almost_equal(f_x2[0], f_x[0])
        npt.assert_almost_equal(f_y2[0], f_y[0])

        x = np.array([1, 3, 4])
        y = np.array([2, 1, 1])
        values = self.sersic.derivatives(x, y, n_sersic, R_sersic, k_eff)
        values2 = self.sersic_2.derivatives(x, y, n_sersic, R_sersic, k_eff, 0,
                                            0.00000001)
        assert values[0][0] == 0.16556078301997193
        assert values[1][0] == 0.33112156603994386
        assert values[0][1] == 0.2772992378623737
        assert values[1][1] == 0.092433079287457892
        npt.assert_almost_equal(values2[0][0], values[0][0])
        npt.assert_almost_equal(values2[1][0], values[1][0])
        npt.assert_almost_equal(values2[0][1], values[0][1])
        npt.assert_almost_equal(values2[1][1], values[1][1])

        values2 = self.sersic_2.derivatives(0.3, -0.2, n_sersic, R_sersic,
                                            k_eff, 0, 0.00000001)
        values = self.sersic.derivatives(0.3, -0.2, n_sersic, R_sersic, k_eff,
                                         0, 0.00000001)
        npt.assert_almost_equal(values2[0], values[0])
        npt.assert_almost_equal(values2[1], values[1])

    def test_differentails(self):
        x_, y_ = 1., 1
        n_sersic = 2.
        R_sersic = 1.
        k_eff = 0.2
        r = np.sqrt(x_**2 + y_**2)

        d_alpha_dr = self.sersic.d_alpha_dr(x_, y_, n_sersic, R_sersic, k_eff)
        alpha = self.sersic.alpha_abs(x_, y_, n_sersic, R_sersic, k_eff)

        f_xx_ = d_alpha_dr * calc_util.d_r_dx(
            x_, y_) * x_ / r + alpha * calc_util.d_x_diffr_dx(x_, y_)
        f_yy_ = d_alpha_dr * calc_util.d_r_dy(
            x_, y_) * y_ / r + alpha * calc_util.d_y_diffr_dy(x_, y_)
        f_xy_ = d_alpha_dr * calc_util.d_r_dy(
            x_, y_) * x_ / r + alpha * calc_util.d_x_diffr_dy(x_, y_)

        f_xx = (d_alpha_dr / r - alpha / r**2) * y_**2 / r + alpha / r
        f_yy = (d_alpha_dr / r - alpha / r**2) * x_**2 / r + alpha / r
        f_xy = (d_alpha_dr / r - alpha / r**2) * x_ * y_ / r
        npt.assert_almost_equal(f_xx, f_xx_, decimal=10)
        npt.assert_almost_equal(f_yy, f_yy_, decimal=10)
        npt.assert_almost_equal(f_xy, f_xy_, decimal=10)

    def test_hessian(self):
        x = np.array([1])
        y = np.array([2])
        n_sersic = 2.
        R_sersic = 1.
        k_eff = 0.2
        f_xx, f_xy, f_yx, f_yy = self.sersic.hessian(x, y, n_sersic, R_sersic,
                                                     k_eff)
        assert f_xx[0] == 0.1123170666045793
        npt.assert_almost_equal(f_yy[0], -0.047414082641598576, decimal=10)
        npt.assert_almost_equal(f_xy[0], -0.10648743283078525, decimal=10)
        npt.assert_almost_equal(f_xy, f_yx, decimal=5)
        x = np.array([1, 3, 4])
        y = np.array([2, 1, 1])
        values = self.sersic.hessian(x, y, n_sersic, R_sersic, k_eff)
        assert values[0][0] == 0.1123170666045793
        npt.assert_almost_equal(values[3][0],
                                -0.047414082641598576,
                                decimal=10)
        npt.assert_almost_equal(values[1][0], -0.10648743283078525, decimal=10)
        npt.assert_almost_equal(values[0][1],
                                -0.053273787681591328,
                                decimal=10)
        npt.assert_almost_equal(values[3][1], 0.076243427402007985, decimal=10)
        npt.assert_almost_equal(values[1][1],
                                -0.048568955656349749,
                                decimal=10)

        f_xx2, f_xy2, f_yx2, f_yy2 = self.sersic_2.hessian(
            x, y, n_sersic, R_sersic, k_eff, 0.0000001, 0)
        npt.assert_almost_equal(f_xx2, values[0])
        npt.assert_almost_equal(f_yy2, values[3], decimal=6)
        npt.assert_almost_equal(f_xy2, values[1], decimal=6)
        npt.assert_almost_equal(f_yx2, values[2], decimal=6)

    def test_alpha_abs(self):
        x = 1.
        dr = 0.0000001
        n_sersic = 2.5
        R_sersic = .5
        k_eff = 0.2
        alpha_abs = self.sersic.alpha_abs(x, 0, n_sersic, R_sersic, k_eff)
        f_dr = self.sersic.function(x + dr, 0, n_sersic, R_sersic, k_eff)
        f_ = self.sersic.function(x, 0, n_sersic, R_sersic, k_eff)
        alpha_abs_num = -(f_dr - f_) / dr
        npt.assert_almost_equal(alpha_abs_num, alpha_abs, decimal=3)

    def test_dalpha_dr(self):
        x = 1.
        dr = 0.0000001
        n_sersic = 1.
        R_sersic = .5
        k_eff = 0.2
        d_alpha_dr = self.sersic.d_alpha_dr(x, 0, n_sersic, R_sersic, k_eff)
        alpha_dr = self.sersic.alpha_abs(x + dr, 0, n_sersic, R_sersic, k_eff)
        alpha = self.sersic.alpha_abs(x, 0, n_sersic, R_sersic, k_eff)
        d_alpha_dr_num = (alpha_dr - alpha) / dr
        npt.assert_almost_equal(d_alpha_dr, d_alpha_dr_num, decimal=3)

    def test_mag_sym(self):
        """

        :return:
        """
        r = 2.
        angle1 = 0.
        angle2 = 1.5
        x1 = r * np.cos(angle1)
        y1 = r * np.sin(angle1)

        x2 = r * np.cos(angle2)
        y2 = r * np.sin(angle2)
        n_sersic = 4.5
        R_sersic = 2.5
        k_eff = 0.8
        f_xx1, f_xy1, f_yx1, f_yy1 = self.sersic.hessian(
            x1, y1, n_sersic, R_sersic, k_eff)
        f_xx2, f_xy2, f_yx2, f_yy2 = self.sersic.hessian(
            x2, y2, n_sersic, R_sersic, k_eff)
        kappa_1 = (f_xx1 + f_yy1) / 2
        kappa_2 = (f_xx2 + f_yy2) / 2
        npt.assert_almost_equal(kappa_1, kappa_2, decimal=10)
        A_1 = (1 - f_xx1) * (1 - f_yy1) - f_xy1 * f_yx1
        A_2 = (1 - f_xx2) * (1 - f_yy2) - f_xy2 * f_yx2
        npt.assert_almost_equal(A_1, A_2, decimal=10)

    def test_convergernce(self):
        """
        test the convergence and compares it with the original Sersic profile
        :return:
        """
        x = np.array([0, 0, 0, 0, 0])
        y = np.array([0.5, 1, 1.5, 2, 2.5])
        n_sersic = 4.5
        R_sersic = 2.5
        k_eff = 0.2
        f_xx, f_xy, f_yx, f_yy = self.sersic.hessian(x, y, n_sersic, R_sersic,
                                                     k_eff)
        kappa = (f_xx + f_yy) / 2.
        assert kappa[0] > 0
        flux = self.sersic_light.function(x,
                                          y,
                                          amp=1.,
                                          R_sersic=R_sersic,
                                          n_sersic=n_sersic)
        flux /= flux[0]
        kappa /= kappa[0]
        npt.assert_almost_equal(flux[1], kappa[1], decimal=5)

        xvalues = np.linspace(0.5, 3., 100)

        e1, e2 = 0.4, 0.
        q = ellipticity2phi_q(e1, e2)[1]
        kappa_ellipse = self.sersic_2.projected_mass(xvalues, 0, q, n_sersic,
                                                     R_sersic, k_eff)
        fxx, _, _, fyy = self.sersic_2.hessian(xvalues, 0, n_sersic, R_sersic,
                                               k_eff, e1, e2)

        npt.assert_almost_equal(kappa_ellipse, 0.5 * (fxx + fyy), decimal=5)

    def test_sersic_util(self):
        n = 1.
        Re = 2.
        k, bn = self.sersic.k_bn(n, Re)
        Re_new = self.sersic.k_Re(n, k)
        assert Re == Re_new
class TestSersicEllipseGaussDec(object):
    """
    This class tests the methods for Gauss-decomposed elliptic Sersic
    convergence.
    """
    def setup(self):
        self.sersic_gauss = SersicEllipseGaussDec()
        self.sersic_light = SersicElliptic()
        self.sersic_sphere = Sersic()

    def test_function(self):
        """
        Test the potential function of Gauss-decomposed elliptical Sersic by
        asserting that the numerical derivative of the computed potential
        matches with the analytical derivative values.

        :return:
        :rtype:
        """
        k_eff = 1.
        R_sersic = 1.
        n_sersic = 1.
        e1 = 0.2
        e2 = 0.2
        center_x = 0.
        center_y = 0.

        diff = 1.e-6

        n = 5
        xs = np.linspace(0.5 * R_sersic, 2. * R_sersic, n)
        ys = np.linspace(0.5 * R_sersic, 2. * R_sersic, n)

        for x, y in zip(xs, ys):
            func = self.sersic_gauss.function(x, y, e1=e1, e2=e2,
                                              center_x=center_x,
                                              center_y=center_y,
                                              n_sersic=n_sersic,
                                              R_sersic=R_sersic,
                                              k_eff=k_eff
                                              )

            func_dx = self.sersic_gauss.function(x+diff, y, e1=e1, e2=e2,
                                                 center_x=center_x,
                                                 center_y=center_y,
                                                 n_sersic=n_sersic,
                                                 R_sersic=R_sersic,
                                                 k_eff=k_eff
                                                 )

            func_dy = self.sersic_gauss.function(x, y+diff, e1=e1, e2=e2,
                                                 center_x=center_x,
                                                 center_y=center_y,
                                                 n_sersic=n_sersic,
                                                 R_sersic=R_sersic,
                                                 k_eff=k_eff
                                                 )

            f_x_num = (func_dx - func) / diff
            f_y_num = (func_dy - func) / diff

            f_x, f_y = self.sersic_gauss.derivatives(x, y, e1=e1, e2=e2,
                                                     center_x=center_x,
                                                     center_y=center_y,
                                                     n_sersic=n_sersic,
                                                     R_sersic=R_sersic,
                                                     k_eff=k_eff
                                                     )

            npt.assert_almost_equal(f_x_num, f_x, decimal=4)
            npt.assert_almost_equal(f_y_num, f_y, decimal=4)

    def test_derivatives(self):
        """
        Test the derivative function of Gauss-decomposed elliptical Sersic by
        matching with the spherical case.

        :return:
        :rtype:
        """
        k_eff = 1.
        R_sersic = 1.
        n_sersic = 1.
        e1 = 5.e-5
        e2 = 0.
        center_x = 0.
        center_y = 0.

        n = 10
        x = np.linspace(0.5*R_sersic, 2.*R_sersic, n)
        y = np.linspace(0.5*R_sersic, 2.*R_sersic, n)

        X, Y = np.meshgrid(x, y)

        f_x_s, f_y_s = self.sersic_sphere.derivatives(X, Y, center_x=center_x,
                                                      center_y=center_y,
                                                      n_sersic=n_sersic,
                                                      R_sersic=R_sersic,
                                                      k_eff=k_eff
                                                      )
        f_x, f_y = self.sersic_gauss.derivatives(X, Y, e1=e1, e2=e2,
                                                 center_x=center_x,
                                                 center_y=center_y,
                                                 n_sersic=n_sersic,
                                                 R_sersic=R_sersic,
                                                 k_eff=k_eff
                                                 )

        npt.assert_allclose(f_x, f_x_s, rtol=1e-3, atol=0.)
        npt.assert_allclose(f_y, f_y_s, rtol=1e-3, atol=0.)

        npt.assert_almost_equal(f_x, f_x_s, decimal=3)
        npt.assert_almost_equal(f_y, f_y_s, decimal=3)

    def test_hessian(self):
        """
        Test the Hessian function of Gauss-decomposed elliptical Sersic by
        matching with the spherical case.

        :return:
        :rtype:
        """
        k_eff = 1.
        R_sersic = 1.
        n_sersic = 1.
        e1 = 5e-5
        e2 = 0.
        center_x = 0.
        center_y = 0.

        n = 10
        x = np.linspace(0.5 * R_sersic, 2. * R_sersic, n)
        y = np.linspace(0.5 * R_sersic, 2. * R_sersic, n)

        X, Y = np.meshgrid(x, y)

        f_xx_s, f_yy_s, f_xy_s = self.sersic_sphere.hessian(X, Y,
                                                            center_x=center_x,
                                                            center_y=center_y,
                                                            n_sersic=n_sersic,
                                                            R_sersic=R_sersic,
                                                            k_eff=k_eff)
        f_xx, f_yy, f_xy = self.sersic_gauss.hessian(X, Y, e1=e1, e2=e2,
                                                     center_x=center_x,
                                                     center_y=center_y,
                                                     n_sersic=n_sersic,
                                                     R_sersic=R_sersic,
                                                     k_eff=k_eff)

        npt.assert_almost_equal(f_xx_s, f_xx, decimal=3)
        npt.assert_almost_equal(f_yy_s, f_yy, decimal=3)
        npt.assert_almost_equal(f_xy_s, f_xy, decimal=3)

    def test_density_2d(self):
        """
        Test the density function of Gauss-decomposed elliptical Sersic by
        checking with the spherical case.

        :return:
        :rtype:
        """
        k_eff = 1.
        R_sersic = 1.
        n_sersic = 1.
        e1 = 0.2
        e2 = 0.2
        center_x = 0.
        center_y = 0.

        n = 100
        x = np.logspace(-1., 1., n)
        y = np.logspace(-1., 1., n)

        X, Y = np.meshgrid(x, y)

        sersic_analytic = self.sersic_light.function(X, Y, e1=e1, e2=e2,
                                                 center_x=center_x,
                                                 center_y=center_y,
                                                 n_sersic=n_sersic,
                                                 R_sersic=R_sersic,
                                                 amp=k_eff)

        sersic_gauss = self.sersic_gauss.density_2d(X, Y, e1=e1, e2=e2,
                                                    center_x=center_x,
                                                    center_y=center_y,
                                                    n_sersic=n_sersic,
                                                    R_sersic=R_sersic,
                                                    k_eff=k_eff)

        assert np.all(
            np.abs(sersic_analytic - sersic_gauss) / np.sqrt(sersic_analytic)
            * 100. < 1.)

    def test_gauss_decompose_sersic(self):
        """
        Test that `gauss_decompose_sersic()` decomposes the Sersic profile within 1%
        Poission noise at R_sersic.

        :return:
        :rtype:
        """
        y = np.logspace(-1., 1., 100)

        k_eff = 1.
        R_sersic = 1.
        n_sersic = 1.

        amps, sigmas = self.sersic_gauss.gauss_decompose(n_sersic=n_sersic,
                                               R_sersic=R_sersic, k_eff=k_eff)

        sersic = self.sersic_gauss.get_kappa_1d(y, n_sersic=n_sersic,
                                               R_sersic=R_sersic, k_eff=k_eff)

        back_sersic = np.zeros_like(y)

        for a, s in zip(amps, sigmas):
            back_sersic += a * np.exp(-y ** 2 / 2. / s ** 2)

        assert np.all(np.abs(sersic-back_sersic)/np.sqrt(sersic)*100. < 1.)