class SIE(object): """ class for singular isothermal ellipsoid (SIS with ellipticity) """ def __init__(self): self.spemd = SPEMD() def function(self, x, y, theta_E, q, phi_G, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ gamma = 2 return self.spemd.function(x, y, theta_E, gamma, q, phi_G, center_x, center_y) def derivatives(self, x, y, theta_E, q, phi_G, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ gamma = 2 return self.spemd.derivatives(x, y, theta_E, gamma, q, phi_G, center_x, center_y) def hessian(self, x, y, theta_E, q, phi_G, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ gamma = 2 return self.spemd.hessian(x, y, theta_E, gamma, q, phi_G, center_x, center_y)
class TestSIE(object): """ tests the Gaussian methods """ def setup(self): from lenstronomy.LensModel.Profiles.sie import SIE from lenstronomy.LensModel.Profiles.spemd import SPEMD self.sie = SIE() self.spemd = SPEMD() def test_function(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. values = self.sie.function(x, y, theta_E, q, phi_G) gamma = 2 values_spemd = self.spemd.function(x, y, theta_E, gamma, q, phi_G) assert values == values_spemd def test_derivatives(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. values = self.sie.derivatives(x, y, theta_E, q, phi_G) gamma = 2 values_spemd = self.spemd.derivatives(x, y, theta_E, gamma, q, phi_G) assert values == values_spemd def test_hessian(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. values = self.sie.hessian(x, y, theta_E, q, phi_G) gamma = 2 values_spemd = self.spemd.hessian(x, y, theta_E, gamma, q, phi_G) assert values[0] == values_spemd[0]
class TestSPEMD(object): """ tests the Gaussian methods """ def setup(self): from lenstronomy.LensModel.Profiles.spemd import SPEMD self.SPEMD = SPEMD(suppress_fastell=True) from lenstronomy.LensModel.Profiles.nie import NIE self.NIE = NIE() def test_function(self): phi_E = 1. gamma = 2. q = 0.999 phi_G = 1. s_scale = 0.1 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) x = np.array([1., 2]) y = np.array([2, 0]) values = self.SPEMD.function(x, y, phi_E, gamma, e1, e2, s_scale) if fastell4py_bool: values_nie = self.NIE.function(x, y, phi_E, e1, e2, s_scale) delta_f = values[0] - values[1] delta_f_nie = values_nie[0] - values_nie[1] npt.assert_almost_equal(delta_f, delta_f_nie, decimal=5) else: npt.assert_almost_equal(values, 0, decimal=5) def test_derivatives(self): x = np.array([1]) y = np.array([2]) phi_E = 1. gamma = 2. q = 1. phi_G = 1. s_scale = 0.1 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2, s_scale) if fastell4py_bool: f_x_nie, f_y_nie = self.NIE.derivatives(x, y, phi_E, e1, e2, s_scale) npt.assert_almost_equal(f_x, f_x_nie, decimal=4) npt.assert_almost_equal(f_y, f_y_nie, decimal=4) else: npt.assert_almost_equal(f_x, 0, decimal=7) npt.assert_almost_equal(f_y, 0, decimal=7) q = 0.7 phi_G = 1. s_scale = 0.001 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2, s_scale) if fastell4py_bool: f_x_nie, f_y_nie = self.NIE.derivatives(x, y, phi_E, e1, e2, s_scale) npt.assert_almost_equal(f_x, f_x_nie, decimal=4) npt.assert_almost_equal(f_y, f_y_nie, decimal=4) else: npt.assert_almost_equal(f_x, 0, decimal=7) npt.assert_almost_equal(f_y, 0, decimal=7) def test_hessian(self): x = np.array([1.]) y = np.array([2.]) phi_E = 1. gamma = 2. q = 0.9 phi_G = 1. s_scale = 0.001 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_xx, f_xy, f_yx, f_yy = self.SPEMD.hessian(x, y, phi_E, gamma, e1, e2, s_scale) if fastell4py_bool: f_xx_nie, f_xy_nie, f_yx_nie, f_yy_nie = self.NIE.hessian( x, y, phi_E, e1, e2, s_scale) npt.assert_almost_equal(f_xx, f_xx_nie, decimal=4) npt.assert_almost_equal(f_yy, f_yy_nie, decimal=4) npt.assert_almost_equal(f_xy, f_xy_nie, decimal=4) npt.assert_almost_equal(f_yx, f_yx_nie, decimal=4) else: npt.assert_almost_equal(f_xx, 0, decimal=7) npt.assert_almost_equal(f_yy, 0, decimal=7) npt.assert_almost_equal(f_xy, 0, decimal=7) npt.assert_almost_equal(f_xy, f_yx, decimal=8) def test_bounds(self): compute_bool = self.SPEMD._parameter_constraints(q_fastell=-1, gam=-1, s2=-1, q=-1) assert compute_bool is False def test_is_not_empty(self): func = self.SPEMD.is_not_empty assert func(0.1, 0.2) assert func([0.1], [0.2]) assert func((0.1, 0.3), (0.2, 0.4)) assert func(np.array([0.1]), np.array([0.2])) assert not func([], []) assert not func(np.array([]), np.array([]))
class TestNIE(object): """ tests the Gaussian methods """ def setup(self): self.nie = NIE() self.spemd = SPEMD(suppress_fastell=True) self.sis = SIS() def test_function(self): y = np.array([1., 2]) x = np.array([0., 0.]) theta_E = 1. q = 0.9999 s = 0.00001 phi_G = 0 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) values = self.nie.function(x, y, theta_E, e1, e2, s_scale=s) delta_pot = values[1] - values[0] values_spemd = self.sis.function(x, y, theta_E) delta_pot_spemd = values_spemd[1] - values_spemd[0] npt.assert_almost_equal(delta_pot, delta_pot_spemd, decimal=4) if bool_test is True: q = 0.99 s = 0.000001 phi_G = 0 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) values = self.nie.function(x, y, theta_E, e1, e2, s_scale=s) delta_pot = values[1] - values[0] gamma = 2. values_spemd = self.spemd.function(x, y, theta_E, gamma, e1, e2, s_scale=s) delta_pot_spemd = values_spemd[1] - values_spemd[0] npt.assert_almost_equal(delta_pot, delta_pot_spemd, decimal=2) def test_derivatives(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.99999 phi_G = 0 s = 0.0000001 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.nie.derivatives(x, y, theta_E, e1, e2, s_scale=s) f_x_spemd, f_y_spemd = self.sis.derivatives(x, y, theta_E) npt.assert_almost_equal(f_x, f_x_spemd, decimal=4) npt.assert_almost_equal(f_y, f_y_spemd, decimal=4) if bool_test is True: q = 0.99 s = 0.000001 phi_G = 0 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.nie.derivatives(x, y, theta_E, e1, e2, s_scale=s) gamma = 2. f_x_spemd, f_y_spemd = self.spemd.derivatives(x, y, theta_E, gamma, e1, e2, s_scale=s) print(f_x/f_x_spemd, 'ratio deflections') print(1+(1-q)/2) npt.assert_almost_equal(f_x, f_x_spemd, decimal=2) npt.assert_almost_equal(f_y, f_y_spemd, decimal=2) def test_hessian(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.999999 phi_G = 0 s = 0.0000001 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_xx, f_yy, f_xy = self.nie.hessian(x, y, theta_E, e1, e2, s_scale=s) f_xx_spemd, f_yy_spemd, f_xy_spemd = self.sis.hessian(x, y, theta_E) npt.assert_almost_equal(f_xx, f_xx_spemd, decimal=4) npt.assert_almost_equal(f_yy, f_yy_spemd, decimal=4) npt.assert_almost_equal(f_xy, f_xy_spemd, decimal=4) def test_convergence2surface_brightness(self): from lenstronomy.LightModel.Profiles.nie import NIE as NIE_Light nie_light = NIE_Light() kwargs = {'e1': 0.3, 'e2': -0.05, 's_scale': 0.5} x, y = util.make_grid(numPix=10, deltapix=0.1) f_xx, f_yy, f_xy = self.nie.hessian(x, y, theta_E=1, **kwargs) kappa = 1/2. * (f_xx + f_yy) flux = nie_light.function(x, y, amp=1, **kwargs) npt.assert_almost_equal(kappa/np.sum(kappa), flux/np.sum(flux), decimal=5) def test_static(self): x, y = 1., 1. phi_G, q = 0.3, 0.8 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) kwargs_lens = {'theta_E': 1., 's_scale': .1, 'e1': e1, 'e2': e2} f_ = self.nie.function(x, y, **kwargs_lens) self.nie.set_static(**kwargs_lens) f_static = self.nie.function(x, y, **kwargs_lens) npt.assert_almost_equal(f_, f_static, decimal=8) self.nie.set_dynamic() kwargs_lens = {'theta_E': 2., 's_scale': .1, 'e1': e1, 'e2': e2} f_dyn = self.nie.function(x, y, **kwargs_lens) assert f_dyn != f_static
class SIE(LensProfileBase): """ class for singular isothermal ellipsoid (SIS with ellipticity) """ param_names = ['theta_E', 'e1', 'e2', 'center_x', 'center_y'] lower_limit_default = { 'theta_E': 0, 'e1': -0.5, 'e2': -0.5, 'center_x': -100, 'center_y': -100 } upper_limit_default = { 'theta_E': 100, 'e1': 0.5, 'e2': 0.5, 'center_x': 100, 'center_y': 100 } def __init__(self, NIE=True): self._nie = NIE if NIE: from lenstronomy.LensModel.Profiles.nie import NIE self.profile = NIE() else: from lenstronomy.LensModel.Profiles.spemd import SPEMD self.profile = SPEMD() self._s_scale = 0.0000000001 self._gamma = 2 super(SIE, self).__init__() def function(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.function(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.function(x, y, theta_E, self._gamma, e1, e2, center_x, center_y) def derivatives(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.derivatives(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.derivatives(x, y, theta_E, self._gamma, e1, e2, center_x, center_y) def hessian(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.hessian(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.hessian(x, y, theta_E, self._gamma, e1, e2, center_x, center_y) @staticmethod def theta2rho(theta_E): """ converts projected density parameter (in units of deflection) into 3d density parameter :param theta_E: :return: """ fac1 = np.pi * 2 rho0 = theta_E / fac1 return rho0 @staticmethod def mass_3d(r, rho0, e1=0, e2=0): """ mass enclosed a 3d sphere or radius r :param r: radius in angular units :param rho0: density at angle=1 :return: mass in angular units """ mass_3d = 4 * np.pi * rho0 * r return mass_3d def mass_3d_lens(self, r, theta_E, e1=0, e2=0): """ mass enclosed a 3d sphere or radius r given a lens parameterization with angular units :param r: radius in angular units :param theta_E: Einstein radius :return: mass in angular units """ rho0 = self.theta2rho(theta_E) return self.mass_3d(r, rho0) def mass_2d(self, r, rho0, e1=0, e2=0): """ mass enclosed projected 2d sphere of radius r :param r: :param rho0: :param a: :param s: :return: """ alpha = np.pi * np.pi * 2 * rho0 mass_2d = alpha * r return mass_2d def mass_2d_lens(self, r, theta_E, e1=0, e2=0): """ :param r: :param theta_E: :return: """ rho0 = self.theta2rho(theta_E) return self.mass_2d(r, rho0) def grav_pot(self, x, y, rho0, e1=0, e2=0, center_x=0, center_y=0): """ gravitational potential (modulo 4 pi G and rho0 in appropriate units) :param x: :param y: :param rho0: :param a: :param s: :param center_x: :param center_y: :return: """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) mass_3d = self.mass_3d(r, rho0) pot = mass_3d / r return pot def density_lens(self, r, theta_E, e1=0, e2=0): """ computes the density at 3d radius r given lens model parameterization. The integral in the LOS projection of this quantity results in the convergence quantity. :param r: radius in angles :param theta_E: Einstein radius :param e1: eccentricity component :param e2: eccentricity component :return: density """ rho0 = self.theta2rho(theta_E) return self.density(r, rho0) @staticmethod def density(r, rho0, e1=0, e2=0): """ computes the density :param r: radius in angles :param rho0: density at angle=1 :return: density at r """ rho = rho0 / r**2 return rho @staticmethod def density_2d(x, y, rho0, e1=0, e2=0, center_x=0, center_y=0): """ projected density :param x: :param y: :param rho0: :param center_x: :param center_y: :return: """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) sigma = np.pi * rho0 / r return sigma
class PEMD(LensProfileBase): """ class for power law ellipse mass density profile. This class effectively calls the class SPEMD_SMOOTH with a fixed and very small central smoothing scale to perform the numerical integral using the FASTELL code by Renan Barkana. .. math:: \\kappa(x, y) = \\frac{3-\\gamma}{2} \\left(\\frac{\\theta_{E}}{\\sqrt{q x^2 + y^2/q}} \\right)^{\\gamma-1} with :math:`\\theta_{E}` is the (circularized) Einstein radius, :math:`\\gamma` is the negative power-law slope of the 3D mass distributions, :math:`q` is the minor/major axis ratio, and :math:`x` and :math:`y` are defined in a coordinate system aligned with the major and minor axis of the lens. In terms of eccentricities, this profile is defined as .. math:: \\kappa(r) = \\frac{3-\\gamma}{2} \\left(\\frac{\\theta'_{E}}{r \\sqrt{1 − e*\\cos(2*\\phi)}} \\right)^{\\gamma-1} with :math:`\\epsilon` is the ellipticity defined as .. math:: \\epsilon = \\frac{1-q^2}{1+q^2} And an Einstein radius :math:`\\theta'_{\\rm E}` related to the definition used is .. math:: \\left(\\frac{\\theta'_{\\rm E}}{\\theta_{\\rm E}}\\right)^{2} = \\frac{2q}{1+q^2}. """ param_names = ['theta_E', 'gamma', 'e1', 'e2', 'center_x', 'center_y'] lower_limit_default = { 'theta_E': 0, 'gamma': 1.5, 'e1': -0.5, 'e2': -0.5, 'center_x': -100, 'center_y': -100 } upper_limit_default = { 'theta_E': 100, 'gamma': 2.5, 'e1': 0.5, 'e2': 0.5, 'center_x': 100, 'center_y': 100 } def __init__(self, suppress_fastell=False): """ :param suppress_fastell: bool, if True, does not raise if fastell4py is not installed """ self._s_scale = 0.0000001 # smoothing scale as used to numerically compute a power-law profile self.spp = SPP() self.spemd_smooth = SPEMD(suppress_fastell=suppress_fastell) super(PEMD, self).__init__() def function(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: lensing potential """ return self.spemd_smooth.function(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def derivatives(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: deflection angles alpha_x, alpha_y """ return self.spemd_smooth.derivatives(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def hessian(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: Hessian components f_xx, f_xy, f_yx, f_yy """ return self.spemd_smooth.hessian(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def mass_3d_lens(self, r, theta_E, gamma, e1=None, e2=None): """ computes the spherical power-law mass enclosed (with SPP routine) :param r: radius within the mass is computed :param theta_E: Einstein radius :param gamma: power-law slope :param e1: eccentricity component (not used) :param e2: eccentricity component (not used) :return: mass enclosed a 3D radius r """ return self.spp.mass_3d_lens(r, theta_E, gamma) def density_lens(self, r, theta_E, gamma, e1=None, e2=None): """ computes the density at 3d radius r given lens model parameterization. The integral in the LOS projection of this quantity results in the convergence quantity. :param r: radius within the mass is computed :param theta_E: Einstein radius :param gamma: power-law slope :param e1: eccentricity component (not used) :param e2: eccentricity component (not used) :return: mass enclosed a 3D radius r """ return self.spp.density_lens(r, theta_E, gamma)
class SIE(LensProfileBase): """ class for singular isothermal ellipsoid (SIS with ellipticity) """ param_names = ['theta_E', 'e1', 'e2', 'center_x', 'center_y'] lower_limit_default = { 'theta_E': 0, 'e1': -0.5, 'e2': -0.5, 'center_x': -100, 'center_y': -100 } upper_limit_default = { 'theta_E': 100, 'e1': 0.5, 'e2': 0.5, 'center_x': 100, 'center_y': 100 } def __init__(self, NIE=True): self._nie = NIE if NIE: from lenstronomy.LensModel.Profiles.nie import NIE self.profile = NIE() else: from lenstronomy.LensModel.Profiles.spemd import SPEMD self.profile = SPEMD() self._s_scale = 0.0000000001 self._gamma = 2 super(SIE, self).__init__() def function(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.function(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.function(x, y, theta_E, self._gamma, e1, e2, center_x, center_y) def derivatives(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.derivatives(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.derivatives(x, y, theta_E, self._gamma, e1, e2, center_x, center_y) def hessian(self, x, y, theta_E, e1, e2, center_x=0, center_y=0): """ :param x: :param y: :param theta_E: :param q: :param phi_G: :param center_x: :param center_y: :return: """ if self._nie: return self.profile.hessian(x, y, theta_E, e1, e2, self._s_scale, center_x, center_y) else: return self.profile.hessian(x, y, theta_E, self._gamma, e1, e2, center_x, center_y)
class TestSIE(object): """ tests the Gaussian methods """ def setup(self): from lenstronomy.LensModel.Profiles.sie import SIE from lenstronomy.LensModel.Profiles.spemd import SPEMD from lenstronomy.LensModel.Profiles.nie import NIE self.sie = SIE(NIE=False) self.sie_nie = SIE(NIE=True) self.spemd = SPEMD() self.nie = NIE() def test_function(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) values = self.sie.function(x, y, theta_E, e1, e2) gamma = 2 values_spemd = self.spemd.function(x, y, theta_E, gamma, e1, e2) assert values == values_spemd values = self.sie_nie.function(x, y, theta_E, e1, e2) s_scale = 0.0000001 values_spemd = self.nie.function(x, y, theta_E, e1, e2, s_scale) npt.assert_almost_equal(values, values_spemd, decimal=6) def test_derivatives(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) values = self.sie.derivatives(x, y, theta_E, e1, e2) gamma = 2 values_spemd = self.spemd.derivatives(x, y, theta_E, gamma, e1, e2) assert values == values_spemd values = self.sie_nie.derivatives(x, y, theta_E, e1, e2) s_scale = 0.0000001 values_spemd = self.nie.derivatives(x, y, theta_E, e1, e2, s_scale) npt.assert_almost_equal(values, values_spemd, decimal=6) def test_hessian(self): x = np.array([1]) y = np.array([2]) theta_E = 1. q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) values = self.sie.hessian(x, y, theta_E, e1, e2) gamma = 2 values_spemd = self.spemd.hessian(x, y, theta_E, gamma, e1, e2) assert values[0] == values_spemd[0] values = self.sie_nie.hessian(x, y, theta_E, e1, e2) s_scale = 0.0000001 values_spemd = self.nie.hessian(x, y, theta_E, e1, e2, s_scale) npt.assert_almost_equal(values, values_spemd, decimal=5)
class TestSPEMD(object): """ tests the Gaussian methods """ def setup(self): from lenstronomy.LensModel.Profiles.spemd import SPEMD from lenstronomy.LensModel.Profiles.spep import SPEP self.SPEMD = SPEMD() self.SPEP = SPEP() def test_function(self): phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) x = np.array([1.]) y = np.array([2]) a = np.zeros_like(x) values = self.SPEMD.function(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: assert values == 2.1567297115381039 else: assert values == 0 a += values x = np.array(1.) y = np.array(2.) a = np.zeros_like(x) values = self.SPEMD.function(x, y, phi_E, gamma, e1, e2) print(x, values) a += values if fastell4py_bool: assert values == 2.1567297115381039 else: assert values == 0 assert type(x) == type(values) x = np.array([2, 3, 4]) y = np.array([1, 1, 1]) values = self.SPEMD.function(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(values[0], 2.1798076611034141, decimal=7) npt.assert_almost_equal(values[1], 3.209319798597186, decimal=7) npt.assert_almost_equal(values[2], 4.3105937398856398, decimal=7) else: npt.assert_almost_equal(values[0], 0, decimal=7) npt.assert_almost_equal(values[1], 0, decimal=7) npt.assert_almost_equal(values[2], 0, decimal=7) def test_derivatives(self): x = np.array([1]) y = np.array([2]) phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_x[0], 0.46663367437984204, decimal=7) npt.assert_almost_equal(f_y[0], 0.95307422686028065, decimal=7) else: npt.assert_almost_equal(f_x[0], 0, decimal=7) npt.assert_almost_equal(f_y[0], 0, decimal=7) x = np.array([1., 3, 4]) y = np.array([2., 1, 1]) a = np.zeros_like(x) values = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(values[0][0], 0.46663367437984204, decimal=7) npt.assert_almost_equal(values[1][0], 0.95307422686028065, decimal=7) npt.assert_almost_equal(values[0][1], 1.0722152681324291, decimal=7) npt.assert_almost_equal(values[1][1], 0.31400298272329669, decimal=7) else: npt.assert_almost_equal(values[0][0], 0, decimal=7) npt.assert_almost_equal(values[1][0], 0, decimal=7) npt.assert_almost_equal(values[0][1], 0, decimal=7) npt.assert_almost_equal(values[1][1], 0, decimal=7) a += values[0] x = 1. y = 2. phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_x, 0.46663367437984204, decimal=7) npt.assert_almost_equal(f_y, 0.95307422686028065, decimal=7) else: npt.assert_almost_equal(f_x, 0, decimal=7) npt.assert_almost_equal(f_y, 0, decimal=7) x = 0. y = 0. f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2) assert f_x == 0. assert f_y == 0. def test_hessian(self): x = np.array([1]) y = np.array([2]) phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_xx, f_yy, f_xy = self.SPEMD.hessian(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_xx, 0.41789957732890953, decimal=7) npt.assert_almost_equal(f_yy, 0.14047593655054141, decimal=7) npt.assert_almost_equal(f_xy, -0.18560737698052343, decimal=7) else: npt.assert_almost_equal(f_xx, 0, decimal=7) npt.assert_almost_equal(f_yy, 0, decimal=7) npt.assert_almost_equal(f_xy, 0, decimal=7) x = 1. y = 2. phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) a = np.zeros_like(x) f_xx, f_yy, f_xy = self.SPEMD.hessian(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_xx, 0.41789957732890953, decimal=7) npt.assert_almost_equal(f_yy, 0.14047593655054141, decimal=7) npt.assert_almost_equal(f_xy, -0.18560737698052343, decimal=7) else: npt.assert_almost_equal(f_xx, 0, decimal=7) npt.assert_almost_equal(f_yy, 0, decimal=7) npt.assert_almost_equal(f_xy, 0, decimal=7) a += f_xx x = np.array([1, 3, 4]) y = np.array([2, 1, 1]) values = self.SPEMD.hessian(x, y, phi_E, gamma, e1, e2) print(values, 'values') if fastell4py_bool: npt.assert_almost_equal(values[0][0], 0.41789957732890953, decimal=7) npt.assert_almost_equal(values[1][0], 0.14047593655054141, decimal=7) npt.assert_almost_equal(values[2][0], -0.18560737698052343, decimal=7) npt.assert_almost_equal(values[0][1], 0.068359818958208918, decimal=7) npt.assert_almost_equal(values[1][1], 0.32494089371516482, decimal=7) npt.assert_almost_equal(values[2][1], -0.097845438684594374, decimal=7) else: npt.assert_almost_equal(values[0][0], 0, decimal=7) def test_spep_spemd(self): x = np.array([1]) y = np.array([0]) phi_E = 1. gamma = 2. q = 1. phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, e1, e2) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, phi_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=2) else: pass theta_E = 2. gamma = 2. q = 1. phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, theta_E, gamma, e1, e2) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, theta_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=2) else: pass theta_E = 2. gamma = 1.7 q = 1. phi_G = 1. e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) f_x, f_y = self.SPEMD.derivatives(x, y, theta_E, gamma, e1, e2) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, theta_E, gamma, e1, e2) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=4) def test_bounds(self): from lenstronomy.LensModel.Profiles.spemd_smooth import SPEMD_SMOOTH profile = SPEMD_SMOOTH() theta_E, gamma, q, phi_G, s_scale = profile._parameter_constraints( theta_E=-1, s_scale=0, gamma=3, q=2, phi_G=0) assert theta_E == 0 def test_is_not_empty(self): func = self.SPEMD.spemd_smooth.is_not_empty assert func(0.1, 0.2) assert func([0.1], [0.2]) assert func((0.1, 0.3), (0.2, 0.4)) assert func(np.array([0.1]), np.array([0.2])) assert not func([], []) assert not func(np.array([]), np.array([])) def test_density_lens(self): r = 1 kwargs = {'theta_E': 1, 'gamma': 2, 'e1': 0, 'e2': 0} rho = self.SPEMD.density_lens(r, **kwargs) rho_spep = self.SPEP.density_lens(r, **kwargs) npt.assert_almost_equal(rho, rho_spep, decimal=7)
class PEMD(LensProfileBase): """ class for power law ellipse mass density profile. This class effectively calls the class SPEMD_SMOOTH with a fixed and very small central smoothing scale to perform the numerical integral using the FASTELL code by Renan Barkana. The Einstein ring parameter converts to the definition used by GRAVLENS as follow: (theta_E / theta_E_gravlens) = sqrt[ (1+q^2) / (2 q) ] """ param_names = ['theta_E', 'gamma', 'e1', 'e2', 'center_x', 'center_y'] lower_limit_default = { 'theta_E': 0, 'gamma': 1.5, 'e1': -0.5, 'e2': -0.5, 'center_x': -100, 'center_y': -100 } upper_limit_default = { 'theta_E': 100, 'gamma': 2.5, 'e1': 0.5, 'e2': 0.5, 'center_x': 100, 'center_y': 100 } def __init__(self, suppress_fastell=False): """ :param suppress_fastell: bool, if True, does not raise if fastell4py is not installed """ self._s_scale = 0.0001 # smoothing scale as used to numerically compute a power-law profile self.spp = SPP() self.spemd_smooth = SPEMD(suppress_fastell=suppress_fastell) super(PEMD, self).__init__() def function(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: lensing potential """ return self.spemd_smooth.function(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def derivatives(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: deflection angles alpha_x, alpha_y """ return self.spemd_smooth.derivatives(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def hessian(self, x, y, theta_E, gamma, e1, e2, center_x=0, center_y=0): """ :param x: x-coordinate (angle) :param y: y-coordinate (angle) :param theta_E: Einstein radius (angle), pay attention to specific definition! :param gamma: logarithmic slope of the power-law profile. gamma=2 corresponds to isothermal :param e1: eccentricity component :param e2: eccentricity component :param center_x: x-position of lens center :param center_y: y-position of lens center :return: Hessian components f_xx, f_yy, f_xy """ return self.spemd_smooth.hessian(x, y, theta_E, gamma, e1, e2, self._s_scale, center_x, center_y) def mass_3d_lens(self, r, theta_E, gamma, e1=None, e2=None): """ computes the spherical power-law mass enclosed (with SPP routine) :param r: radius within the mass is computed :param theta_E: Einstein radius :param gamma: power-law slope :param e1: eccentricity component (not used) :param e2: eccentricity component (not used) :return: mass enclosed a 3D radius r """ return self.spp.mass_3d_lens(r, theta_E, gamma) def density_lens(self, r, theta_E, gamma, e1=None, e2=None): """ computes the density at 3d radius r given lens model parameterization. The integral in the LOS projection of this quantity results in the convergence quantity. :param r: radius within the mass is computed :param theta_E: Einstein radius :param gamma: power-law slope :param e1: eccentricity component (not used) :param e2: eccentricity component (not used) :return: mass enclosed a 3D radius r """ return self.spp.density_lens(r, theta_E, gamma)
class TestSPEMD(object): """ tests the Gaussian methods """ def setup(self): from lenstronomy.LensModel.Profiles.spemd import SPEMD from lenstronomy.LensModel.Profiles.spep import SPEP self.SPEMD = SPEMD() self.SPEP = SPEP() def test_function(self): phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. x = np.array([1.]) y = np.array([2]) a = np.zeros_like(x) values = self.SPEMD.function(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: assert values == 2.1567297115381039 else: assert values == 0 a += values x = np.array(1.) y = np.array(2.) a = np.zeros_like(x) values = self.SPEMD.function(x, y, phi_E, gamma, q, phi_G) print(x, values) a += values if fastell4py_bool: assert values == 2.1567297115381039 else: assert values == 0 assert type(x) == type(values) x = np.array([2, 3, 4]) y = np.array([1, 1, 1]) values = self.SPEMD.function(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(values[0], 2.1798076611034141, decimal=7) npt.assert_almost_equal(values[1], 3.209319798597186, decimal=7) npt.assert_almost_equal(values[2], 4.3105937398856398, decimal=7) else: npt.assert_almost_equal(values[0], 0, decimal=7) npt.assert_almost_equal(values[1], 0, decimal=7) npt.assert_almost_equal(values[2], 0, decimal=7) def test_derivatives(self): x = np.array([1]) y = np.array([2]) phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_x[0], 0.46663367437984204, decimal=7) npt.assert_almost_equal(f_y[0], 0.95307422686028065, decimal=7) else: npt.assert_almost_equal(f_x[0], 0, decimal=7) npt.assert_almost_equal(f_y[0], 0, decimal=7) x = np.array([1., 3, 4]) y = np.array([2., 1, 1]) a = np.zeros_like(x) values = self.SPEMD.derivatives(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(values[0][0], 0.46663367437984204, decimal=7) npt.assert_almost_equal(values[1][0], 0.95307422686028065, decimal=7) npt.assert_almost_equal(values[0][1], 1.0722152681324291, decimal=7) npt.assert_almost_equal(values[1][1], 0.31400298272329669, decimal=7) else: npt.assert_almost_equal(values[0][0], 0, decimal=7) npt.assert_almost_equal(values[1][0], 0, decimal=7) npt.assert_almost_equal(values[0][1], 0, decimal=7) npt.assert_almost_equal(values[1][1], 0, decimal=7) a += values[0] x = 1. y = 2. phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_x, 0.46663367437984204, decimal=7) npt.assert_almost_equal(f_y, 0.95307422686028065, decimal=7) else: npt.assert_almost_equal(f_x, 0, decimal=7) npt.assert_almost_equal(f_y, 0, decimal=7) x = 0. y = 0. f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, q, phi_G) assert f_x == 0. assert f_y == 0. def test_hessian(self): x = np.array([1]) y = np.array([2]) phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. f_xx, f_yy,f_xy = self.SPEMD.hessian(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_xx, 0.41789957732890953, decimal=7) npt.assert_almost_equal(f_yy, 0.14047593655054141, decimal=7) npt.assert_almost_equal(f_xy, -0.18560737698052343, decimal=7) else: npt.assert_almost_equal(f_xx, 0, decimal=7) npt.assert_almost_equal(f_yy, 0, decimal=7) npt.assert_almost_equal(f_xy, 0, decimal=7) x = 1. y = 2. phi_E = 1. gamma = 1.9 q = 0.9 phi_G = 1. a = np.zeros_like(x) f_xx, f_yy,f_xy = self.SPEMD.hessian(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_xx, 0.41789957732890953, decimal=7) npt.assert_almost_equal(f_yy, 0.14047593655054141, decimal=7) npt.assert_almost_equal(f_xy, -0.18560737698052343, decimal=7) else: npt.assert_almost_equal(f_xx, 0, decimal=7) npt.assert_almost_equal(f_yy, 0, decimal=7) npt.assert_almost_equal(f_xy, 0, decimal=7) a += f_xx x = np.array([1,3,4]) y = np.array([2,1,1]) values = self.SPEMD.hessian(x, y, phi_E, gamma, q, phi_G) print(values, 'values') if fastell4py_bool: npt.assert_almost_equal(values[0][0], 0.41789957732890953, decimal=7) npt.assert_almost_equal(values[1][0], 0.14047593655054141, decimal=7) npt.assert_almost_equal(values[2][0], -0.18560737698052343, decimal=7) npt.assert_almost_equal(values[0][1], 0.068359818958208918, decimal=7) npt.assert_almost_equal(values[1][1], 0.32494089371516482, decimal=7) npt.assert_almost_equal(values[2][1], -0.097845438684594374, decimal=7) else: npt.assert_almost_equal(values[0][0], 0, decimal=7) def test_spep_spemd(self): x = np.array([1]) y = np.array([0]) phi_E = 1. gamma = 2. q = 1. phi_G = 1. f_x, f_y = self.SPEMD.derivatives(x, y, phi_E, gamma, q, phi_G) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, phi_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=2) else: pass theta_E = 2. gamma = 2. q = 1. phi_G = 1. f_x, f_y = self.SPEMD.derivatives(x, y, theta_E, gamma, q, phi_G) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, theta_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=2) else: pass theta_E = 2. gamma = 1.7 q = 1. phi_G = 1. f_x, f_y = self.SPEMD.derivatives(x, y, theta_E, gamma, q, phi_G) f_x_spep, f_y_spep = self.SPEP.derivatives(x, y, theta_E, gamma, q, phi_G) if fastell4py_bool: npt.assert_almost_equal(f_x[0], f_x_spep[0], decimal=4)