def test__grid_with_points_below_magnification_threshold_removed(self): sis = al.mp.SphericalIsothermal(centre=(0.0, 0.0), einstein_radius=1.0) grid = grids.GridIrregularGroupedUniform( grid=[(1.0, 0.0), (0.1, 0.0)], pixel_scales=0.01 ) magnification = np.abs( sis.magnification_irregular_from_grid(grid=grid, buffer=grid.pixel_scale) ) assert magnification[0] > 1000.0 assert magnification[1] < 1000.0 solver = pos.AbstractPositionsSolver(magnification_threshold=1000.0) positions = solver.grid_with_points_below_magnification_threshold_removed( lensing_obj=sis, grid=grid ) assert positions.in_grouped_list == [[(1.0, 0.0)]] assert positions.pixel_scales == (0.01, 0.01) solver = pos.AbstractPositionsSolver(magnification_threshold=0.0) positions = solver.grid_with_points_below_magnification_threshold_removed( lensing_obj=sis, grid=grid ) assert positions.in_grouped_list == [[(1.0, 0.0), (0.1, 0.0)]] assert positions.pixel_scales == (0.01, 0.01)
def solve(self, lensing_obj, source_plane_coordinate): coordinates_list = self.grid_peaks_from( lensing_obj=lensing_obj, grid=self.grid, source_plane_coordinate=source_plane_coordinate, ) coordinates_list = self.grid_with_coordinates_from_mass_profile_centre_removed( lensing_obj=lensing_obj, grid=coordinates_list) coordinates_list = self.grid_with_points_below_magnification_threshold_removed( lensing_obj=lensing_obj, grid=coordinates_list) if not self.use_upscaling: return grids.GridIrregularGrouped(grid=coordinates_list) pixel_scale = self.grid.pixel_scale while pixel_scale > self.pixel_scale_precision: refined_coordinates_list = [] for coordinate in coordinates_list: refined_coordinates = self.refined_coordinates_from_coordinate( coordinate=coordinate, pixel_scale=pixel_scale, lensing_obj=lensing_obj, source_plane_coordinate=source_plane_coordinate, ) if refined_coordinates is not None: refined_coordinates_list += refined_coordinates refined_coordinates_list = grid_remove_duplicates( grid=np.asarray(refined_coordinates_list)) pixel_scale = pixel_scale / self.upscale_factor coordinates_list = refined_coordinates_list coordinates_list = self.grid_within_distance_of_source_plane_centre( lensing_obj=lensing_obj, grid=grids.GridIrregularGroupedUniform(grid=coordinates_list, pixel_scales=(pixel_scale, pixel_scale)), source_plane_coordinate=source_plane_coordinate, distance=self.distance_from_source_centre, ) coordinates_list = self.grid_with_points_below_magnification_threshold_removed( lensing_obj=lensing_obj, grid=coordinates_list) return grids.GridIrregularGrouped(grid=coordinates_list)
def grid_buffed_and_upscaled_around_coordinate_from( self, coordinate, pixel_scales, buffer, upscale_factor): """ For an input (y,x) Catersian coordinate create a buffed and upscaled square grid of (y,x) coordinates where: - The new grid of coordinates are buffed. For example, if buffer=1, the new grid will correspond to a 3x3 grid of coordinates centred on the input (y,x) value with spacings defined by the input pixel_scales. - The new grid is upscaled. For example, if upscale=2, the new grid will be at x2 the resolution of the input pixel_scale. Buffing and upscaling work together, so a buffer=2 and upscale=2 will produce a new 6x6 grid centred around the input coordinate. The `PositionFinder` works by locating pixels that trace closer to the source galaxy than neighboring pixels and iteratively refining the grid to find pixels that trace close at higher and higher resolutions. This function is core to producing these upscaled grids. Parameters ---------- coordinate : (float, float) The (y,x) Cartesian coordinates aroun which the buffed and upscaled grid is created. pixel_scales : (float, float) The pixel-scale resolution of the buffed and upscaled grid that is formed around the input coordinate. If upscale > 1, the pixel_scales are reduced to pixel_scale / upscale_factor. buffer : int The number of pixels around the central (y,x) coordinate that the grid is computed on, i.e. how much it is buffed. A buffer of 1 puts 1 pixel in every direction around the (y,x) coordinate, creating a 3x3 grid. A buffer=2 places two pixels around it in every direction, creating a 5x5 grid. And so on. upscale_factor : int The factor by which the resolution of the grid is increased relative to the input pixel-scales. """ if self.use_upscaling: upscale_factor = upscale_factor else: upscale_factor = 1 grid_buffed = grid_buffed_around_coordinate_from( coordinate=coordinate, pixel_scales=pixel_scales, buffer=buffer, upscale_factor=upscale_factor, ) return grids.GridIrregularGroupedUniform( grid=grid_buffed, pixel_scales=( pixel_scales[0] / upscale_factor, pixel_scales[1] / upscale_factor, ), )
def grid_with_points_below_magnification_threshold_removed( self, lensing_obj, grid): magnifications = np.abs( lensing_obj.magnification_irregular_from_grid( grid=grid, buffer=grid.pixel_scale)) grid_mag = [] for index, magnification in enumerate(magnifications): if magnification > self.magnification_threshold: grid_mag.append(grid[index, :]) return grids.GridIrregularGroupedUniform( grid=grid_mag, pixel_scales=grid.pixel_scales)
def grid_within_distance_of_source_plane_centre(self, lensing_obj, source_plane_coordinate, grid, distance): """ For an input grid of (y,x) coordinates, remove all coordinates that do not trace within a threshold distance of the source-plane centre. This is performed by: 1) Computing the deflection angle of every (y,x) coordinate on the grid using the input lensing object. 2) Ray tracing these coordinates to the source-plane. 3) Computing their distance to the centre of the source in the source-plane. 4) Removing all coordinates that are not within the input distance of the centre. This algorithm is optionally used in the _PositionFiner_. It may be required to remove solutions that are genuine 'peaks' that tracer closer to a source than their 8 neighboring pixels, but which do not truly trace to the centre of the source-centre. Parameters ---------- lensing_obj : autogalaxy.LensingObject An object which has a deflection_from_grid method for performing lensing calculations, for example a `MassProfile`, _Galaxy_, `Plane` or _Tracer_. grid : autoarray.GridIrregularGroupedUniform or ndarray A grid of (y,x) Cartesian coordinates for which the 'peak' values that trace closer to the source than their neighbors are found. source_plane_coordinate : (y,x) The (y,x) coordinate in the source-plane pixels that the distance of traced grid coordinates are computed for. distance : float The distance within which a grid coordinate must trace to the source-plane centre to be retained. """ if distance is None: return grid deflections = lensing_obj.deflections_from_grid(grid=grid) source_plane_grid = grid.grid_from_deflection_grid( deflection_grid=deflections) source_plane_distances = source_plane_grid.distances_from_coordinate( coordinate=source_plane_coordinate) grid_within_distance_of_centre = grid_within_distance( distances_1d=source_plane_distances, grid_1d=grid, within_distance=distance) return grids.GridIrregularGroupedUniform( grid=grid_within_distance_of_centre, pixel_scales=grid.pixel_scales)
def grid_peaks_from(self, lensing_obj, grid, source_plane_coordinate): """Find the 'peaks' of a grid of coordinates, where a peak corresponds to a (y,x) coordinate on the grid which traces closer to the input (y,x) source-plane coordinate than any of its 8 adjacent neighbors. This is performed by: 1) Computing the deflection angle of every (y,x) coordinate on the grid using the input lensing object. 2) Ray tracing these coordinates to the source-plane. 3) Computing their distance to the centre of the source in the source-plane. 4) Finding pixels whose source-plane distance is lower than all 8 neighboring pixels. The `PositionFinder` works by locating pixels that trace closer to the source galaxy than neighboring pixels and iteratively refining the grid to find pixels that trace close at higher and higher resolutions. This function is core to finding pixelsl that meet this criteria. Parameters ---------- lensing_obj : autogalaxy.LensingObject An object which has a deflection_from_grid method for performing lensing calculations, for example a `MassProfile`, _Galaxy_, `Plane` or _Tracer_. grid : autoarray.GridIrregularGroupedUniform or ndarray A grid of (y,x) Cartesian coordinates for which the 'peak' values that trace closer to the source than their neighbors are found. source_plane_coordinate : (y,x) The (y,x) coordinate in the source-plane pixels that the distance of traced grid coordinates are computed for. """ deflections = lensing_obj.deflections_from_grid(grid=grid) source_plane_grid = grid.grid_from_deflection_grid( deflection_grid=deflections) source_plane_distances = source_plane_grid.distances_from_coordinate( coordinate=source_plane_coordinate) neighbors, has_neighbors = grid_square_neighbors_1d_from( shape_1d=grid.shape[0]) grid_peaks = grid_peaks_from( distance_1d=source_plane_distances, grid_1d=grid, neighbors=neighbors.astype("int"), has_neighbors=has_neighbors, ) return grids.GridIrregularGroupedUniform( grid=grid_peaks, pixel_scales=grid.pixel_scales)
def grid_with_coordinates_from_mass_profile_centre_removed( self, lensing_obj, grid): """Remove all coordinates from a grid which are within the distance_from_mass_profile_centre attribute of any mass profile of the lensing object. The `PositionFinder` often finds multiple unphyiscal solutions near a mass profile due to the high levels of demagnification. These are typically not observable in real galaxies and thus may benefit from being removed from the PositionFiner. The positions are removed by computing the distance between all grid points and the mass profile centres of every mass profile in the lensing object. Parameters ---------- lensing_obj : autogalaxy.LensingObject An object which has a deflection_from_grid method for performing lensing calculations, for example a `MassProfile`, _Galaxy_, `Plane` or _Tracer_. grid : autoarray.GridIrregularGroupedUniform or ndarray A gridd of (y,x) Cartesian coordinates for which their distances to the mass profile centres are computed, with points within the threshold removed. """ if self.distance_from_mass_profile_centre is not None: pixel_scales = grid.pixel_scales for centre in lensing_obj.mass_profile_centres.in_1d_list: distances_1d = np.sqrt( np.square(grid[:, 0] - centre[0]) + np.square(grid[:, 1] - centre[1])) grid = grid_outside_distance_mask_from( distances_1d=distances_1d, grid_1d=grid, outside_distance=self.distance_from_mass_profile_centre, ) return grids.GridIrregularGroupedUniform(grid=grid, pixel_scales=pixel_scales) return grid