def test_findOverlap(): x_mins = [0, 1, 0] y_mins = [1, 2, 1] deltapix = 0.5 x_mins, y_mins = image_util.findOverlap(x_mins, y_mins, deltapix) print(x_mins, y_mins) assert x_mins[0] == 0 assert y_mins[0] == 1 assert len(x_mins) == 2
def image_position_stochastic(self, source_x, source_y, kwargs_lens, search_window=10, precision_limit=10**(-10), arrival_time_sort=True, x_center=0, y_center=0, num_random=1000): """ Solves the lens equation stochastically with the scipy minimization routine on the quadratic distance between the backwards ray-shooted proposed image position and the source position. Credits to Giulia Pagano :param source_x: source position :param source_y: source position :param kwargs_lens: lens model list of keyword arguments :param search_window: angular size of search window :param precision_limit: limit required on the precision in the source plane :param arrival_time_sort: bool, if True sorts according to arrival time :param x_center: center of search window :param y_center: center of search window :param num_random: number of random starting points of the non-linear solver in the search window :param verbose: bool, if True, prints performance information :return: x_image, y_image """ kwargs_lens = self._static_lens_settings(kwargs_lens) x_solve, y_solve = [], [] for i in range(num_random): x_init = np.random.uniform(-search_window / 2., search_window / 2) + x_center y_init = np.random.uniform(-search_window / 2., search_window / 2) + y_center xinitial = np.array([x_init, y_init]) result = minimize(self._root, xinitial, args=(kwargs_lens, source_x, source_y), tol=precision_limit**2, method='Nelder-Mead') if self._root(result.x, kwargs_lens, source_x, source_y) < precision_limit**2: x_solve.append(result.x[0]) y_solve.append(result.x[1]) x_mins, y_mins = image_util.findOverlap(x_solve, y_solve, precision_limit) if arrival_time_sort is True: x_mins, y_mins = self.sort_arrival_times(x_mins, y_mins, kwargs_lens) self._make_dynamic() return x_mins, y_mins
def image_position_from_source(self, sourcePos_x, sourcePos_y, kwargs_lens, min_distance=0.01, search_window=5, precision_limit=10**(-10), num_iter_max=100): """ finds image position source position and lense model :param sourcePos_x: source position in units of angle :param sourcePos_y: source position in units of angle :param kwargs_lens: lens model parameters as keyword arguments :param min_distance: minimum separation to consider for two images in units of angle :param search_window: window size to be considered by the solver. Will not find image position outside this window :param precision_limit: required precision in the lens equation solver (in units of angle in the source plane). :param num_iter_max: maximum iteration of lens-source mapping conducted by solver to match the required precision :returns: (exact) angular position of (multiple) images ra_pos, dec_pos in units of angle :raises: AttributeError, KeyError """ # compute number of pixels to cover the search window with the required min_distance numPix = int(round(search_window / min_distance) + 0.5) x_grid, y_grid = util.make_grid(numPix, min_distance) # ray-shoot to find the relative distance to the required source position for each grid point x_mapped, y_mapped = self.lensModel.ray_shooting( x_grid, y_grid, kwargs_lens) absmapped = util.displaceAbs(x_mapped, y_mapped, sourcePos_x, sourcePos_y) # select minima in the grid points and select grid points that do not deviate more than the # width of the grid point to a solution of the lens equation x_mins, y_mins, delta_map = util.neighborSelect( absmapped, x_grid, y_grid) x_mins = x_mins[delta_map <= min_distance] y_mins = y_mins[delta_map <= min_distance] # iterative solving of the lens equation for the selected grid points x_mins, y_mins, solver_precision = self._findIterative( x_mins, y_mins, sourcePos_x, sourcePos_y, kwargs_lens, precision_limit, num_iter_max) # only select iterative results that match the precision limit x_mins = x_mins[solver_precision <= precision_limit] y_mins = y_mins[solver_precision <= precision_limit] # find redundant solutions within the min_distance criterion x_mins, y_mins = image_util.findOverlap(x_mins, y_mins, min_distance) x_mins, y_mins = self.sort_arrival_times(x_mins, y_mins, kwargs_lens) #x_mins, y_mins = lenstronomy_util.coordInImage(x_mins, y_mins, numPix, deltapix) return x_mins, y_mins
def solvelenseq_majoraxis(args, Nmeas=200, Nmeas_extra=50): """Solve the lens equation, where the arguments have been properly rotated to the major-axis""" b, t, y1, y2, q, gamma1, gamma2 = args p1 = np.arctan2(y2 * (1 - gamma1) + gamma2 * y1, y1 * (1 + gamma1) + gamma2 * y2) int_points = [p1] geom = geomlinspace(1e-4, 0.1, Nmeas_extra) thpl = np.sort( np.concatenate(( np.linspace(0., np.pi, Nmeas), *[i % np.pi - geom for i in int_points], *[i % np.pi + geom for i in int_points], ))) the = _getphi(thpl, (b, t, y1, y2, q, gamma1, gamma2)) thetas = np.concatenate((the, the + np.pi)) Rs = np.array( [_getr(theta, (b, t, y1, y2, q, gamma1, gamma2)) for theta in thetas]) stuff = np.array(pol_to_cart(Rs[Rs > 0], thetas[Rs > 0])) diff = -y1 - y2 * 1j + stuff[0] + stuff[1] * 1j - _alpha_epl_shear( stuff[0], stuff[1], b, q, t, gamma1=gamma1, gamma2=gamma2) goodones = np.abs(diff) < 1e-8 return findOverlap(*stuff[:, goodones], 1e-8)
def image_position_from_source(self, sourcePos_x, sourcePos_y, kwargs_lens, min_distance=0.1, search_window=10, precision_limit=10**(-10), num_iter_max=100, arrival_time_sort=True, initial_guess_cut=True, verbose=False, x_center=0, y_center=0, num_random=0, non_linear=False, magnification_limit=None): """ finds image position source position and lense model :param sourcePos_x: source position in units of angle :param sourcePos_y: source position in units of angle :param kwargs_lens: lens model parameters as keyword arguments :param min_distance: minimum separation to consider for two images in units of angle :param search_window: window size to be considered by the solver. Will not find image position outside this window :param precision_limit: required precision in the lens equation solver (in units of angle in the source plane). :param num_iter_max: maximum iteration of lens-source mapping conducted by solver to match the required precision :param arrival_time_sort: bool, if True, sorts image position in arrival time (first arrival photon first listed) :param initial_guess_cut: bool, if True, cuts initial local minima selected by the grid search based on distance criteria from the source position :param verbose: bool, if True, prints some useful information for the user :param x_center: float, center of the window to search for point sources :param y_center: float, center of the window to search for point sources :param non_linear: bool, if True applies a non-linear solver not dependent on Hessian computation :returns: (exact) angular position of (multiple) images ra_pos, dec_pos in units of angle :raises: AttributeError, KeyError """ kwargs_lens = self._static_lens_settings(kwargs_lens) # compute number of pixels to cover the search window with the required min_distance numPix = int(round(search_window / min_distance) + 0.5) x_grid, y_grid = util.make_grid(numPix, min_distance) x_grid += x_center y_grid += y_center # ray-shoot to find the relative distance to the required source position for each grid point x_mapped, y_mapped = self.lensModel.ray_shooting( x_grid, y_grid, kwargs_lens) absmapped = util.displaceAbs(x_mapped, y_mapped, sourcePos_x, sourcePos_y) # select minima in the grid points and select grid points that do not deviate more than the # width of the grid point to a solution of the lens equation x_mins, y_mins, delta_map = util.neighborSelect( absmapped, x_grid, y_grid) if verbose is True: print( "There are %s regions identified that could contain a solution of the lens equation" % len(x_mins)) #mag = np.abs(mag) #print(x_mins, y_mins, 'before requirement of min_distance') if len(x_mins) < 1: return x_mins, y_mins if initial_guess_cut is True: mag = np.abs( self.lensModel.magnification(x_mins, y_mins, kwargs_lens)) mag[mag < 1] = 1 x_mins = x_mins[delta_map <= min_distance * mag * 5] y_mins = y_mins[delta_map <= min_distance * mag * 5] if verbose is True: print( "The number of regions that meet the plausibility criteria are %s" % len(x_mins)) x_mins = np.append( x_mins, np.random.uniform(low=-search_window / 2 + x_center, high=search_window / 2 + x_center, size=num_random)) y_mins = np.append( y_mins, np.random.uniform(low=-search_window / 2 + y_center, high=search_window / 2 + y_center, size=num_random)) # iterative solving of the lens equation for the selected grid points x_mins, y_mins, solver_precision = self._findIterative( x_mins, y_mins, sourcePos_x, sourcePos_y, kwargs_lens, precision_limit, num_iter_max, verbose=verbose, min_distance=min_distance, non_linear=non_linear) # only select iterative results that match the precision limit x_mins = x_mins[solver_precision <= precision_limit] y_mins = y_mins[solver_precision <= precision_limit] # find redundant solutions within the min_distance criterion x_mins, y_mins = image_util.findOverlap(x_mins, y_mins, min_distance) if arrival_time_sort is True: x_mins, y_mins = self.sort_arrival_times(x_mins, y_mins, kwargs_lens) self._make_dynamic() if magnification_limit is not None: mag = np.abs( self.lensModel.magnification(x_mins, y_mins, kwargs_lens)) x_mins = x_mins[mag >= magnification_limit] y_mins = y_mins[mag >= magnification_limit] return x_mins, y_mins
def image_position_from_source(self, sourcePos_x, sourcePos_y, kwargs_lens, min_distance=0.1, search_window=10, precision_limit=10**(-10), num_iter_max=100, arrival_time_sort=True, initial_guess_cut=True, verbose=False, x_center=0, y_center=0, num_random=0, non_linear=False, magnification_limit=None): """ finds image position source position and lens model :param sourcePos_x: source position in units of angle :param sourcePos_y: source position in units of angle :param kwargs_lens: lens model parameters as keyword arguments :param min_distance: minimum separation to consider for two images in units of angle :param search_window: window size to be considered by the solver. Will not find image position outside this window :param precision_limit: required precision in the lens equation solver (in units of angle in the source plane). :param num_iter_max: maximum iteration of lens-source mapping conducted by solver to match the required precision :param arrival_time_sort: bool, if True, sorts image position in arrival time (first arrival photon first listed) :param initial_guess_cut: bool, if True, cuts initial local minima selected by the grid search based on distance criteria from the source position :param verbose: bool, if True, prints some useful information for the user :param x_center: float, center of the window to search for point sources :param y_center: float, center of the window to search for point sources :param num_random: int, number of random positions within the search window to be added to be starting positions for the gradient decent solver :param non_linear: bool, if True applies a non-linear solver not dependent on Hessian computation :param magnification_limit: None or float, if set will only return image positions that have an abs(magnification) larger than this number :returns: (exact) angular position of (multiple) images ra_pos, dec_pos in units of angle :raises: AttributeError, KeyError """ # find pixels in the image plane possibly hosting a solution of the lens equation, related source distances and pixel width x_mins, y_mins, delta_map, pixel_width = self.candidate_solutions( sourcePos_x, sourcePos_y, kwargs_lens, min_distance, search_window, verbose, x_center, y_center) if verbose is True: print( "There are %s regions identified that could contain a solution of the lens equation" % len(x_mins)) #mag = np.abs(mag) #print(x_mins, y_mins, 'before requirement of min_distance') if len(x_mins) < 1: return x_mins, y_mins if initial_guess_cut is True: mag = np.abs( self.lensModel.magnification(x_mins, y_mins, kwargs_lens)) mag[mag < 1] = 1 x_mins = x_mins[delta_map <= min_distance * mag * 5] y_mins = y_mins[delta_map <= min_distance * mag * 5] if verbose is True: print( "The number of regions that meet the plausibility criteria are %s" % len(x_mins)) x_mins = np.append( x_mins, np.random.uniform(low=-search_window / 2 + x_center, high=search_window / 2 + x_center, size=num_random)) y_mins = np.append( y_mins, np.random.uniform(low=-search_window / 2 + y_center, high=search_window / 2 + y_center, size=num_random)) # iterative solving of the lens equation for the selected grid points x_mins, y_mins, solver_precision = self._find_gradient_decent( x_mins, y_mins, sourcePos_x, sourcePos_y, kwargs_lens, precision_limit, num_iter_max, verbose=verbose, min_distance=min_distance, non_linear=non_linear) # only select iterative results that match the precision limit x_mins = x_mins[solver_precision <= precision_limit] y_mins = y_mins[solver_precision <= precision_limit] # find redundant solutions within the min_distance criterion x_mins, y_mins = image_util.findOverlap(x_mins, y_mins, min_distance) if arrival_time_sort is True: x_mins, y_mins = self.sort_arrival_times(x_mins, y_mins, kwargs_lens) if magnification_limit is not None: mag = np.abs( self.lensModel.magnification(x_mins, y_mins, kwargs_lens)) x_mins = x_mins[mag >= magnification_limit] y_mins = y_mins[mag >= magnification_limit] self.lensModel.set_dynamic() return x_mins, y_mins
def image_position_from_source(self, sourcePos_x, sourcePos_y, kwargs_lens, min_distance=0.1, search_window=10, precision_limit=10**(-10), num_iter_max=100, arrival_time_sort=True, initial_guess_cut=True, verbose=False): """ finds image position source position and lense model :param sourcePos_x: source position in units of angle :param sourcePos_y: source position in units of angle :param kwargs_lens: lens model parameters as keyword arguments :param min_distance: minimum separation to consider for two images in units of angle :param search_window: window size to be considered by the solver. Will not find image position outside this window :param precision_limit: required precision in the lens equation solver (in units of angle in the source plane). :param num_iter_max: maximum iteration of lens-source mapping conducted by solver to match the required precision :param arrival_time_sort: bool, if True, sorts image position in arrival time (first arrival photon first listed) :param initial_guess_cut: bool, if True, cuts initial local minima selected by the grid search based on distance criteria from the source position :returns: (exact) angular position of (multiple) images ra_pos, dec_pos in units of angle :raises: AttributeError, KeyError """ # compute number of pixels to cover the search window with the required min_distance numPix = int(round(search_window / min_distance) + 0.5) x_grid, y_grid = util.make_grid(numPix, min_distance) # ray-shoot to find the relative distance to the required source position for each grid point x_mapped, y_mapped = self.lensModel.ray_shooting( x_grid, y_grid, kwargs_lens) absmapped = util.displaceAbs(x_mapped, y_mapped, sourcePos_x, sourcePos_y) # select minima in the grid points and select grid points that do not deviate more than the # width of the grid point to a solution of the lens equation x_mins, y_mins, delta_map = util.neighborSelect( absmapped, x_grid, y_grid) if verbose is True: print( "There are %s regions identified that could contain a solution of the lens equation" % len(x_mins)) #mag = np.abs(mag) #print(x_mins, y_mins, 'before requirement of min_distance') if initial_guess_cut is True: mag = np.abs( self.lensModel.magnification(x_mins, y_mins, kwargs_lens)) x_mins = x_mins[delta_map <= min_distance * mag * 5] y_mins = y_mins[delta_map <= min_distance * mag * 5] if verbose is True: print( "The number of regions that meet the plausibility criteria are %s" % len(x_mins)) #print(x_mins, y_mins, 'after requirement of min_distance') # iterative solving of the lens equation for the selected grid points x_mins, y_mins, solver_precision = self._findIterative(x_mins, y_mins, sourcePos_x, sourcePos_y, kwargs_lens, precision_limit, num_iter_max, verbose=verbose) # only select iterative results that match the precision limit x_mins = x_mins[solver_precision <= precision_limit] y_mins = y_mins[solver_precision <= precision_limit] #print(x_mins, y_mins, 'after precision limit requirement') # find redundant solutions within the min_distance criterion x_mins, y_mins = image_util.findOverlap(x_mins, y_mins, min_distance) #print(x_mins, y_mins, 'after overlap removals') if arrival_time_sort is True: x_mins, y_mins = self.sort_arrival_times(x_mins, y_mins, kwargs_lens) #x_mins, y_mins = lenstronomy_util.coordInImage(x_mins, y_mins, numPix, deltapix) return x_mins, y_mins