def profile_slope(self, kwargs_lens, radius, center_x=None, center_y=None, model_list_bool=None, num_points=10): """ computes the logarithmic power-law slope of a profile. ATTENTION: this is not an observable! :param kwargs_lens: lens model keyword argument list :param radius: radius from the center where to compute the logarithmic slope (angular units :param model_list_bool: bool list, indicate which part of the model to consider :param num_points: number of estimates around the Einstein radius :return: logarithmic power-law slope """ center_x, center_y = analysis_util.profile_center( kwargs_lens, center_x, center_y) x, y = util.points_on_circle(radius, num_points) dr = 0.01 x_dr, y_dr = util.points_on_circle(radius + dr, num_points) alpha_E_x_i, alpha_E_y_i = self._lens_model.alpha(center_x + x, center_y + y, kwargs_lens, k=model_list_bool) alpha_E_r = np.sqrt(alpha_E_x_i**2 + alpha_E_y_i**2) alpha_E_dr_x_i, alpha_E_dr_y_i = self._lens_model.alpha( center_x + x_dr, center_y + y_dr, kwargs_lens, k=model_list_bool) alpha_E_dr = np.sqrt(alpha_E_dr_x_i**2 + alpha_E_dr_y_i**2) slope = np.mean( np.log(alpha_E_dr / alpha_E_r) / np.log((radius + dr) / radius)) gamma = -slope + 2 return gamma
def profile_slope(self, kwargs_lens_list, lens_model_internal_bool=None, num_points=10): """ computes the logarithmic power-law slope of a profile :param kwargs_lens_list: lens model keyword argument list :param lens_model_internal_bool: bool list, indicate which part of the model to consider :param num_points: number of estimates around the Einstein radius :return: """ theta_E = self.effective_einstein_radius(kwargs_lens_list) x0 = kwargs_lens_list[0]['center_x'] y0 = kwargs_lens_list[0]['center_y'] x, y = util.points_on_circle(theta_E, num_points) dr = 0.01 x_dr, y_dr = util.points_on_circle(theta_E + dr, num_points) if lens_model_internal_bool is None: lens_model_internal_bool = [True]*len(kwargs_lens_list) alpha_E_x_i, alpha_E_y_i = self._lensModel.alpha(x0 + x, y0 + y, kwargs_lens_list, k=lens_model_internal_bool) alpha_E_r = np.sqrt(alpha_E_x_i**2 + alpha_E_y_i**2) alpha_E_dr_x_i, alpha_E_dr_y_i = self._lensModel.alpha(x0 + x_dr, y0 + y_dr, kwargs_lens_list, k=lens_model_internal_bool) alpha_E_dr = np.sqrt(alpha_E_dr_x_i ** 2 + alpha_E_dr_y_i ** 2) slope = np.mean(np.log(alpha_E_dr / alpha_E_r) / np.log((theta_E + dr) / theta_E)) gamma = -slope + 2 return gamma
def test_points_on_circle(): radius = 1 points = 8 ra, dec = util.points_on_circle(radius, points, connect_ends=True) assert ra[0] == 1 assert dec[0] == 0 ra_, dec_ = util.points_on_circle(radius, points - 1, connect_ends=False) npt.assert_almost_equal(ra[:-1], ra_, decimal=8) npt.assert_almost_equal(dec[:-1], dec_, decimal=8)
def radial_light_profile(self, r_list, kwargs_light, center_x=None, center_y=None, model_bool_list=None): """ :param r_list: list of radii to compute the spherically averaged lens light profile :param center_x: center of the profile :param center_y: center of the profile :param kwargs_light: lens light parameter keyword argument list :param model_bool_list: bool list or None, indicating which profiles to sum over :return: flux amplitudes at r_list radii spherically averaged """ center_x, center_y = analysis_util.profile_center( kwargs_light, center_x, center_y) f_list = [] for r in r_list: x, y = util.points_on_circle(r, num_points=20) f_r = self._light_model.surface_brightness( x + center_x, y + center_y, kwargs_list=kwargs_light, k=model_bool_list) f_list.append(np.average(f_r)) return f_list
def mst_invariant_differential(self, kwargs_lens, radius, center_x=None, center_y=None, model_list_bool=None, num_points=10): """ Average of the radial stretch differential in radial direction, divided by the radial stretch factor. .. math:: \\xi = \\frac{\\partial \\lambda_{\\rm rad}}{\\partial r} \\frac{1}{\\lambda_{\\rm rad}} This quantity is invariant under the MST. The specific definition is provided by Birrer 2021. Equivalent (proportional) definitions are provided by e.g. Kochanek 2020, Sonnenfeld 2018. :param kwargs_lens: lens model keyword argument list :param radius: radius from the center where to compute the MST invariant differential :param center_x: center position :param center_y: center position :param model_list_bool: indicate which part of the model to consider :param num_points: number of estimates around the radius :return: xi """ center_x, center_y = analysis_util.profile_center( kwargs_lens, center_x, center_y) x, y = util.points_on_circle(radius, num_points) ext = LensModelExtensions(lensModel=self._lens_model) lambda_rad, lambda_tan, orientation_angle, dlambda_tan_dtan, dlambda_tan_drad, dlambda_rad_drad, dlambda_rad_dtan, dphi_tan_dtan, dphi_tan_drad, dphi_rad_drad, dphi_rad_dtan = ext.radial_tangential_differentials( x, y, kwargs_lens, center_x=center_x, center_y=center_y) xi = np.mean(dlambda_rad_drad / lambda_rad) return xi
def test_area(): r = 1 x_, y_ = util.points_on_circle(radius=r, connect_ends=True, num_points=1000) vs = np.dstack([x_, y_])[0] a = util.area(vs) npt.assert_almost_equal(a, np.pi * r**2, decimal=3)
def curved_arc_finite_area(self, x, y, kwargs_lens, dr): """ computes an estimated curved arc over a finite extent mimicking the appearance of a finite source with radius dr :param x: x-position (float) :param y: y-position (float) :param kwargs_lens: lens model keyword argument list :param dr: radius of finite source :return: keyword arguments of curved arc """ # estimate curvature centroid as the median around the circle # make circle of points around position of interest x_c, y_c = util.points_on_circle(radius=dr, num_points=20, connect_ends=False) c_x_list, c_y_list = [], [] # loop through curved arc estimate and compute curvature centroid for x_, y_ in zip(x_c, y_c): kwargs_arc_ = self.curved_arc_estimate(x_, y_, kwargs_lens) direction = kwargs_arc_['direction'] curvature = kwargs_arc_['curvature'] center_x = x_ - np.cos(direction) / curvature center_y = y_ - np.sin(direction) / curvature c_x_list.append(center_x) c_y_list.append(center_y) center_x, center_y = np.median(c_x_list), np.median(c_y_list) # compute curvature and direction to the average centroid from the position of interest r = np.sqrt((x - center_x) ** 2 + (y - center_y)**2) curvature = 1 / r direction = np.arctan2(y - center_y, x - center_x) # compute average radial stretch as the inverse difference in the source position x_r = x + np.cos(direction) * dr y_r = y + np.sin(direction) * dr x_r_ = x - np.cos(direction) * dr y_r_ = y - np.sin(direction) * dr xs_r, ys_r = self._lensModel.ray_shooting(x_r, y_r, kwargs_lens) xs_r_, ys_r_ = self._lensModel.ray_shooting(x_r_, y_r_, kwargs_lens) ds = np.sqrt((xs_r - xs_r_)**2 + (ys_r - ys_r_)**2) radial_stretch = (2 * dr) / ds # compute average tangential stretch as the inverse difference in the sosurce position x_t = x - np.sin(direction) * dr y_t = y + np.cos(direction) * dr x_t_ = x + np.sin(direction) * dr y_t_ = y - np.cos(direction) * dr xs_t, ys_t = self._lensModel.ray_shooting(x_t, y_t, kwargs_lens) xs_t_, ys_t_ = self._lensModel.ray_shooting(x_t_, y_t_, kwargs_lens) ds = np.sqrt((xs_t - xs_t_) ** 2 + (ys_t - ys_t_) ** 2) tangential_stretch = (2 * dr) / ds kwargs_arc = {'direction': direction, 'radial_stretch': radial_stretch, 'tangential_stretch': tangential_stretch, 'center_x': x, 'center_y': y, 'curvature': curvature} return kwargs_arc
def plot_arc(ax, tangential_stretch, radial_stretch, curvature, direction, center_x, center_y, stretch_scale=0.1): """ :param ax: :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: """ # plot line to centroid center_x_spp, center_y_spp = center_deflector(curvature, direction, center_x, center_y) ax.plot([center_x, center_x_spp], [center_y, center_y_spp], 'k--', alpha=0.5) ax.plot([center_x_spp], [center_y_spp], 'k*', alpha=0.5) # plot radial and tangential stretch to scale x_r = np.cos(direction) * radial_stretch * stretch_scale y_r = np.sin(direction) * radial_stretch * stretch_scale ax.plot([center_x - x_r, center_x + x_r], [center_y - y_r, center_y + y_r], 'k-') # plot curved tangential stretch #x_t = np.sin(direction) * tangential_stretch / 2 * stretch_scale #y_t = -np.cos(direction) * tangential_stretch / 2 * stretch_scale # compute angle of size of the tangential stretch r = 1. / curvature d_phi = tangential_stretch * stretch_scale / r # linearly interpolate angle around center phi = np.linspace(-1, 1, 50) * d_phi + direction # plot points on circle x_curve = r * np.cos(phi) + center_x_spp y_curve = r * np.sin(phi) + center_y_spp ax.plot(x_curve, y_curve, 'k-') # make round circle with start point to end to close the circle r_c, t_c = util.points_on_circle(radius=stretch_scale, num_points=50) r_c = radial_stretch * r_c + r phi_c = t_c * tangential_stretch / r_c + direction x_c = r_c * np.cos(phi_c) + center_x_spp y_c = r_c * np.sin(phi_c) + center_y_spp ax.plot(x_c, y_c, 'k--')
def plot_arc(ax, tangential_stretch, radial_stretch, curvature, direction, center_x, center_y, stretch_scale=0.1, with_centroid=True, linewidth=1, color='k', dtan_dtan=0): """ :param ax: :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 :param with_centroid: plots the center of the curvature radius :param stretch_scale: float, relative scale of banana to the tangential and radial stretches (effectively intrinsic source size) :return: """ # plot line to centroid center_x_spp, center_y_spp = center_deflector(curvature, direction, center_x, center_y) if with_centroid: ax.plot([center_x, center_x_spp], [center_y, center_y_spp], '--', color=color, alpha=0.5, linewidth=linewidth) ax.plot([center_x_spp], [center_y_spp], '*', color=color, alpha=0.5, linewidth=linewidth) # plot radial stretch to scale x_r = np.cos(direction) * radial_stretch * stretch_scale y_r = np.sin(direction) * radial_stretch * stretch_scale ax.plot([center_x - x_r, center_x + x_r], [center_y - y_r, center_y + y_r], '--', color=color, linewidth=linewidth) # plot curved tangential stretch #x_t = np.sin(direction) * tangential_stretch / 2 * stretch_scale #y_t = -np.cos(direction) * tangential_stretch / 2 * stretch_scale # compute angle of size of the tangential stretch r = 1. / curvature # make sure tangential stretch * stretch_scale is not larger than r * 2pi such that the full circle is only plotted once tangential_stretch_ = min(tangential_stretch, np.pi * r / stretch_scale) d_phi = tangential_stretch_ * stretch_scale / r # linearly interpolate angle around center phi = np.linspace(-1, 1, 50) * d_phi + direction # plot points on circle x_curve = r * np.cos(phi) + center_x_spp y_curve = r * np.sin(phi) + center_y_spp ax.plot(x_curve, y_curve, '--', color=color, linewidth=linewidth) # make round circle with start point to end to close the circle r_c, t_c = util.points_on_circle(radius=stretch_scale, num_points=200) r_c = radial_stretch * r_c + r phi_c = t_c * tangential_stretch_ / r_c + direction x_c = r_c * np.cos(phi_c) + center_x_spp y_c = r_c * np.sin(phi_c) + center_y_spp ax.plot(x_c, y_c, '-', color=color, linewidth=linewidth)
def position_size_estimate(self, ra_pos, dec_pos, kwargs_lens, kwargs_else, delta, scale=1): """ estimate the magnification at the positions and define resolution limit :param ra_pos: :param dec_pos: :param kwargs_lens: :param kwargs_else: :return: """ x, y = self.LensModel.ray_shooting(ra_pos, dec_pos, kwargs_else, **kwargs_lens) d_x, d_y = util.points_on_circle(delta*2, 10) x_s, y_s = self.LensModel.ray_shooting(ra_pos + d_x, dec_pos + d_y, kwargs_else, **kwargs_lens) x_m = np.mean(x_s) y_m = np.mean(y_s) r_m = np.sqrt((x_s - x_m) ** 2 + (y_s - y_m) ** 2) r_min = np.sqrt(r_m.min(axis=0)*r_m.max(axis=0))/2 * scale return x, y, r_min
def test_points_on_circle(): radius = 1 points = 8 ra, dec = util.points_on_circle(radius, points) assert ra[0] == 1 assert dec[0] == 0