def radial_profile(light_grid, x_grid, y_grid, center_x=0, center_y=0, n=None): """ computes radial profile :param light_grid: array of surface brightness :param x_grid: x-axis coordinates :param y_grid: y-axis coordinates :param center_x: center of light :param center_y: center of light :param n: number of discrete steps :return: I(r), r with r in units of the coordinate grid """ r_max = np.max(np.sqrt((x_grid - center_x)**2 + (y_grid - center_y)**2)) if n is None: n = int(np.sqrt(len(x_grid))) I_r = np.zeros(n) I_enclosed = 0 r = np.linspace(1. / n * r_max, r_max, n) for i, r_i in enumerate(r): mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x, center_y, r_i) flux_enclosed = np.sum(np.array(light_grid) * mask) I_r[i] = flux_enclosed - I_enclosed I_enclosed = flux_enclosed return I_r, r
def mass_fraction_within_radius(self, kwargs_lens, center_x, center_y, theta_E, numPix=100): """ computes the mean convergence of all the different lens model components within a spherical aperture :param kwargs_lens: lens model keyword argument list :param center_x: center of the aperture :param center_y: center of the aperture :param theta_E: radius of aperture :return: list of average convergences for all the model components """ x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=2. * theta_E / numPix) x_grid += center_x y_grid += center_y mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x, center_y, theta_E) kappa_list = [] for i in range(len(kwargs_lens)): kappa = self._lens_model.kappa(x_grid, y_grid, kwargs_lens, k=i) kappa_mean = np.sum(kappa * mask) / np.sum(mask) kappa_list.append(kappa_mean) return kappa_list
def error_map_estimate(self, kernel, star_cutout_list, amp, x_pos, y_pos, error_map_radius=None): """ provides a psf_error_map based on the goodness of fit of the given PSF kernel on the point source cutouts, their estimated amplitudes and positions :param kernel: PSF kernel :param star_cutout_list: list of 2d arrays of cutouts of the point sources with all other model components subtracted :param amp: list of amplitudes of the estimated PSF kernel :param x_pos: pixel position (in original data unit, not in cutout) of the point sources (same order as amp and star cutouts) :param y_pos: pixel position (in original data unit, not in cutout) of the point sources (same order as amp and star cutouts) :param error_map_radius: float, radius (in arc seconds) of the outermost error in the PSF estimate (e.g. to avoid double counting of overlapping PSF erros) :return: relative uncertainty in the psf model (in quadrature) per pixel based on residuals achieved in the image """ error_map_list = np.zeros((len(star_cutout_list), len(kernel), len(kernel))) for i, star in enumerate(star_cutout_list): x, y, amp_i = x_pos[i], y_pos[i], amp[i] # shift kernel x_int = int(round(x)) y_int = int(round(y)) shift_x = x_int - x shift_y = y_int - y kernel_shifted = interp.shift(kernel, [-shift_y, -shift_x], order=1) # multiply kernel with amplitude model = kernel_shifted * amp_i # compute residuals residual = np.abs(star - model) # subtract background and Poisson noise residuals C_D_cutout = kernel_util.cutout_source(x_int, y_int, self._image_model_class.Data.C_D, len(star), shift=False) mask = kernel_util.cutout_source(x_int, y_int, self._image_model_class.likelihood_mask, len(star), shift=False) residual -= np.sqrt(C_D_cutout) residual[residual < 0] = 0 # estimate relative error per star residual /= amp_i error_map_list[i, :, :] = residual**2*mask # take median absolute error for each pixel error_map = np.median(error_map_list, axis=0) error_map[kernel > 0] /= kernel[kernel > 0]**2 error_map = np.nan_to_num(error_map) error_map[error_map > 1] = 1 # cap on error to be the same # mask the error map outside a certain radius (can avoid double counting of errors when map is overlapping if error_map_radius is not None: pixel_scale = self._image_model_class.Data.pixel_width x_grid, y_grid = util.make_grid(numPix=len(error_map), deltapix=pixel_scale) mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x=0, center_y=0, r=error_map_radius) error_map *= util.array2image(mask) return error_map
def mask_point_source(x_pos, y_pos, x_grid, y_grid, radius, i=0): """ :param x_pos: x-position of list of point sources :param y_pos: y-position of list of point sources :param x_grid: x-coordinates of grid :param y_grid: y-coordinates of grid :param i: index of point source not to mask out :param radius: radius to mask out other point sources :return: a mask of the size of the image with cutouts around the position """ mask = np.ones_like(x_grid) for k in range(len(x_pos)): if k != i: mask_point = 1 - mask_util.mask_azimuthal(x_grid, y_grid, x_pos[k], y_pos[k], radius) mask *= mask_point return util.array2image(mask)
def moments(I_xy_input, x, y): """ compute quadrupole moments from a light distribution :param I_xy_input: light distribution :param x: x-coordinates of I_xy :param y: y-coordinates of I_xy :return: Q_xx, Q_xy, Q_yy """ I_xy = copy.deepcopy(I_xy_input) background = np.minimum(0, np.min(I_xy)) I_xy -= background x_ = np.sum(I_xy * x) y_ = np.sum(I_xy * y) r = (np.max(x) - np.min(x)) / 3. mask = mask_util.mask_azimuthal(x, y, center_x=x_, center_y=y_, r=r) Q_xx = np.sum(I_xy * mask * (x - x_)**2) Q_xy = np.sum(I_xy * mask * (x - x_) * (y - y_)) Q_yy = np.sum(I_xy * mask * (y - y_)**2) return Q_xx, Q_xy, Q_yy, background / np.mean(I_xy)
def half_light_radius(lens_light, x_grid, y_grid, center_x=0, center_y=0): """ :param lens_light: array of surface brightness :param x_grid: x-axis coordinates :param y_grid: y-axis coordinates :param center_x: center of light :param center_y: center of light :return: """ lens_light[lens_light < 0] = 0 total_flux_2 = np.sum(lens_light) / 2. r_max = np.max(np.sqrt((x_grid - center_x)**2 + (y_grid - center_y)**2)) for i in range(1000): r = i / 500. * r_max mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x, center_y, r) flux_enclosed = np.sum(np.array(lens_light) * mask) if flux_enclosed > total_flux_2: return r return -1
def error_map_estimate_new(self, psf_kernel, psf_kernel_list, ra_image, dec_image, point_amp, supersampling_factor, error_map_radius=None): """ relative uncertainty in the psf model (in quadrature) per pixel based on residuals achieved in the image :param psf_kernel: PSF kernel (super-sampled) :param psf_kernel_list: list of individual best PSF kernel estimates :param ra_image: image positions in angles :param dec_image: image positions in angles :param point_amp: image amplitude :param supersampling_factor: super-sampling factor :param error_map_radius: radius (in angle) to cut the error map :return: psf error map such that square of the uncertainty gets boosted by error_map * (psf * amp)**2 """ kernel_low = kernel_util.degrade_kernel(psf_kernel, supersampling_factor) error_map_list = np.zeros( (len(psf_kernel_list), len(kernel_low), len(kernel_low))) x_pos, y_pos = self._image_model_class.Data.map_coord2pix( ra_image, dec_image) for i, psf_kernel_i in enumerate(psf_kernel_list): kernel_low_i = kernel_util.degrade_kernel(psf_kernel_i, supersampling_factor) x, y, amp_i = x_pos[i], y_pos[i], point_amp[i] x_int = int(round(x)) y_int = int(round(y)) C_D_cutout = kernel_util.cutout_source( x_int, y_int, self._image_model_class.Data.C_D, len(kernel_low_i), shift=False) residuals_i = np.abs(kernel_low - kernel_low_i) residuals_i -= np.sqrt(C_D_cutout) / amp_i residuals_i[residuals_i < 0] = 0 error_map_list[i, :, :] = residuals_i**2 error_map = np.median(error_map_list, axis=0) error_map[kernel_low > 0] /= kernel_low[kernel_low > 0]**2 error_map = np.nan_to_num(error_map) error_map[error_map > 1] = 1 # cap on error to be the same # mask the error map outside a certain radius (can avoid double counting of errors when map is overlapping if error_map_radius is not None: pixel_scale = self._image_model_class.Data.pixel_width x_grid, y_grid = util.make_grid(numPix=len(error_map), deltapix=pixel_scale) mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x=0, center_y=0, r=error_map_radius) error_map *= util.array2image(mask) return error_map