def test_function(self): """ :return: """ profile = PowerLaw() spp = SPP() sis = SIS() x = np.linspace(0.1, 10, 10) kwargs_light = {'amp': 1., 'gamma': 2, 'e1': 0, 'e2': 0} kwargs_spp = {'theta_E': 1., 'gamma': 2} kwargs_sis = {'theta_E': 1.} flux = profile.function(x=x, y=1., **kwargs_light) f_xx, f_xy, f_yx, f_yy = spp.hessian(x=x, y=1., **kwargs_spp) kappa_spp = 1 / 2. * (f_xx + f_yy) f_xx, f_xy, f_yx, f_yy = sis.hessian(x=x, y=1., **kwargs_sis) kappa_sis = 1 / 2. * (f_xx + f_yy) npt.assert_almost_equal(kappa_sis, kappa_spp, decimal=5) npt.assert_almost_equal(flux / flux[0], kappa_sis / kappa_sis[0], decimal=5)
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)
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)
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)