def _objective(arg): sys.stdout.write('.') sys.stdout.flush() pos_y = arg[0] pos_x = arg[1] mag = arg[2] sep_ang = cartesian_to_polar(center, pos_y, pos_x) fake = fake_planet(images=images, psf=psf, parang=parang, position=(sep_ang[0], sep_ang[1]), magnitude=mag, psf_scaling=self.m_psf_scaling) mask = create_mask(fake.shape[-2:], (self.m_cent_size, self.m_edge_size)) if self.m_reference_in_port is None: _, im_res = pca_psf_subtraction(images=fake*mask, angles=-1.*parang+self.m_extra_rot, pca_number=self.m_pca_number, pca_sklearn=None, im_shape=None, indices=None) else: im_reshape = np.reshape(fake*mask, (im_shape[0], im_shape[1]*im_shape[2])) _, im_res = pca_psf_subtraction(images=im_reshape, angles=-1.*parang+self.m_extra_rot, pca_number=self.m_pca_number, pca_sklearn=sklearn_pca, im_shape=im_shape, indices=None) res_stack = combine_residuals(method=self.m_residuals, res_rot=im_res) self.m_res_out_port.append(res_stack, data_dim=3) chi_square = merit_function(residuals=res_stack[0, ], merit=self.m_merit, aperture=aperture, sigma=self.m_sigma) position = rotate_coordinates(center, (pos_y, pos_x), -self.m_extra_rot) res = np.asarray([position[1], position[0], sep_ang[0]*pixscale, (sep_ang[1]-self.m_extra_rot) % 360., mag, chi_square]) self.m_flux_position_port.append(res, data_dim=2) return chi_square
def _objective(arg): sys.stdout.write('.') sys.stdout.flush() pos_y = arg[0] pos_x = arg[1] mag = arg[2] sep_ang = cartesian_to_polar(center, pos_x, pos_y) fake = fake_planet(images=images, psf=psf, parang=parang, position=(sep_ang[0], sep_ang[1]), magnitude=mag, psf_scaling=self.m_psf_scaling) im_shape = (fake.shape[-2], fake.shape[-1]) mask = create_mask(im_shape, [self.m_cent_size, self.m_edge_size]) _, im_res = pca_psf_subtraction(images=fake*mask, angles=-1.*parang+self.m_extra_rot, pca_number=self.m_pca_number) stack = combine_residuals(method=self.m_residuals, res_rot=im_res) self.m_res_out_port.append(stack, data_dim=3) merit = merit_function(residuals=stack[0, ], function=self.m_merit, variance="poisson", aperture=self.m_aperture, sigma=self.m_sigma) position = rotate_coordinates(center, (pos_y, pos_x), -self.m_extra_rot) res = np.asarray((position[1], position[0], sep_ang[0]*pixscale, (sep_ang[1]-self.m_extra_rot)%360., mag, merit)) self.m_flux_position_port.append(res, data_dim=2) return merit
def run(self) -> None: """ Run method of the module. Calculates the SNR and FPF for a specified position in a post- processed image with the Student's t-test (Mawet et al. 2014). This approach assumes Gaussian noise but accounts for small sample statistics. Returns ------- NoneType None """ def _snr_optimize(arg): pos_x, pos_y = arg _, _, snr, _ = false_alarm(image=image, x_pos=pos_x, y_pos=pos_y, size=self.m_aperture, ignore=self.m_ignore) return -snr self.m_snr_out_port.del_all_data() self.m_snr_out_port.del_all_attributes() pixscale = self.m_image_in_port.get_attribute('PIXSCALE') self.m_aperture /= pixscale nimages = self.m_image_in_port.get_shape()[0] bounds = ((self.m_position[0]+self.m_bounds[0][0], self.m_position[0]+self.m_bounds[0][1]), (self.m_position[1]+self.m_bounds[1][0], self.m_position[1]+self.m_bounds[1][1])) start_time = time.time() for j in range(nimages): progress(j, nimages, 'Calculating S/N and FPF...', start_time) image = self.m_image_in_port[j, ] center = center_subpixel(image) if self.m_optimize: result = minimize(fun=_snr_optimize, x0=[self.m_position[0], self.m_position[1]], method='SLSQP', bounds=bounds, tol=None, options={'ftol': self.m_tolerance}) _, _, snr, fpf = false_alarm(image=image, x_pos=result.x[0], y_pos=result.x[1], size=self.m_aperture, ignore=self.m_ignore) x_pos, y_pos = result.x[0], result.x[1] else: _, _, snr, fpf = false_alarm(image=image, x_pos=self.m_position[0], y_pos=self.m_position[1], size=self.m_aperture, ignore=self.m_ignore) x_pos, y_pos = self.m_position[0], self.m_position[1] sep_ang = cartesian_to_polar(center, y_pos, x_pos) result = np.column_stack((x_pos, y_pos, sep_ang[0]*pixscale, sep_ang[1], snr, fpf)) self.m_snr_out_port.append(result, data_dim=2) history = f'aperture [arcsec] = {self.m_aperture*pixscale:.2f}' self.m_snr_out_port.copy_attributes(self.m_image_in_port) self.m_snr_out_port.add_history('FalsePositiveModule', history) self.m_snr_out_port.close_port()
def pixel_variance(var_type: str, images: np.ndarray, parang: np.ndarray, cent_size: Optional[float], edge_size: Optional[float], pca_number: int, residuals: str, aperture: Tuple[int, int, float], sigma: float) -> float: """ Function to calculate the variance of the noise. After the PSF subtraction, images are rotated in opposite direction of the regular derotation, therefore dispersing any companion or disk signal. The noise is measured within an annulus. Parameters ---------- var_type : str Variance type ('gaussian' or 'hessian'). images : numpy.ndarray Input images (3D). parang : numpy.ndarray Parallactic angles. cent_size : float, None Radius of the central mask (pix). No mask is used when set to None. edge_size : float, None Outer radius (pix) beyond which pixels are masked. No outer mask is used when set to None. pca_number : int Number of principal components (PCs) used for the PSF subtraction. residuals : str Method for combining the residuals ('mean', 'median', 'weighted', or 'clipped'). aperture : tuple(int, int, float) Aperture position (y, x) and radius (pix). sigma : float, None Standard deviation (pix) of the Gaussian kernel which is used to smooth the images. Returns ------- float Variance of the pixel values. Either the variance of the pixel values ('gaussian') or the variance of the determinant of the Hessian ('hessian'). """ mask = create_mask(images.shape[-2:], (cent_size, edge_size)) _, im_res_derot = pca_psf_subtraction(images * mask, parang, pca_number) res_noise = combine_residuals(residuals, im_res_derot) sep_ang = cartesian_to_polar(center_subpixel(res_noise), aperture[0], aperture[1]) if var_type == 'gaussian': selected = select_annulus(res_noise[0, ], sep_ang[0] - aperture[2], sep_ang[0] + aperture[2]) elif var_type == 'hessian': hessian_rr, hessian_rc, hessian_cc = hessian_matrix( image=res_noise[0, ], sigma=sigma, mode='constant', cval=0., order='rc') hes_det = (hessian_rr * hessian_cc) - (hessian_rc * hessian_rc) selected = select_annulus(hes_det, sep_ang[0] - aperture[2], sep_ang[0] + aperture[2]) return float(np.var(selected))
def merit_function(residuals: np.ndarray, merit: str, aperture: Tuple[int, int, float], sigma: float) -> float: """ Function to calculate the figure of merit at a given position in the image residuals. Parameters ---------- residuals : numpy.ndarray Residuals of the PSF subtraction (2D). merit : str Figure of merit for the chi-square function ('hessian', 'poisson', or 'gaussian'). aperture : tuple(int, int, float) Position (y, x) of the aperture center (pix) and aperture radius (pix). sigma : float Standard deviation (pix) of the Gaussian kernel which is used to smooth the residuals before the chi-square is calculated. Returns ------- float Chi-square ('poisson' and 'gaussian') or sum of the absolute values ('hessian'). """ rr_grid = pixel_distance(im_shape=residuals.shape, position=(aperture[0], aperture[1])) indices = np.where(rr_grid < aperture[2]) if merit == 'hessian': # This is not the chi-square but simply the sum of the absolute values hessian_rr, hessian_rc, hessian_cc = hessian_matrix(image=residuals, sigma=sigma, mode='constant', cval=0., order='rc') hes_det = (hessian_rr * hessian_cc) - (hessian_rc * hessian_rc) chi_square = np.sum(np.abs(hes_det[indices])) elif merit == 'poisson': if sigma > 0.: residuals = gaussian_filter(input=residuals, sigma=sigma) chi_square = np.sum(np.abs(residuals[indices])) elif merit == 'gaussian': # separation (pix) and position angle (deg) sep_ang = cartesian_to_polar(center=center_subpixel(residuals), y_pos=aperture[0], x_pos=aperture[1]) if sigma > 0.: residuals = gaussian_filter(input=residuals, sigma=sigma) selected = select_annulus(image_in=residuals, radius_in=sep_ang[0] - aperture[2], radius_out=sep_ang[0] + aperture[2], mask_position=aperture[0:2], mask_radius=aperture[2]) chi_square = np.sum(residuals[indices]**2) / np.var(selected) else: raise ValueError( 'Figure of merit not recognized. Please use \'hessian\', \'poisson\' ' 'or \'gaussian\'. Previous use of \'sum\' should now be set as ' '\'poisson\'.') return chi_square
def run(self): """ Run method of the module. Calculates the SNR and FPF for a specified position in a post- processed image with the Student's t-test (Mawet et al. 2014). This approach assumes Gaussian noise but accounts for small sample statistics. Returns ------- NoneType None """ def _fpf_minimize(arg): pos_x, pos_y = arg try: _, _, _, fpf = false_alarm(image=image, x_pos=pos_x, y_pos=pos_y, size=self.m_aperture, ignore=self.m_ignore) except ValueError: fpf = float('inf') return fpf self.m_snr_out_port.del_all_data() self.m_snr_out_port.del_all_attributes() pixscale = self.m_image_in_port.get_attribute('PIXSCALE') self.m_aperture /= pixscale nimages = self.m_image_in_port.get_shape()[0] start_time = time.time() for j in range(nimages): progress(j, nimages, 'Running FalsePositiveModule...', start_time) image = self.m_image_in_port[j, ] center = center_subpixel(image) if self.m_optimize: result = minimize(fun=_fpf_minimize, x0=[self.m_position[0], self.m_position[1]], method='Nelder-Mead', tol=None, options={ 'xatol': self.m_tolerance, 'fatol': float('inf') }) _, _, snr, fpf = false_alarm(image=image, x_pos=result.x[0], y_pos=result.x[1], size=self.m_aperture, ignore=self.m_ignore) x_pos, y_pos = result.x[0], result.x[1] else: _, _, snr, fpf = false_alarm(image=image, x_pos=self.m_position[0], y_pos=self.m_position[1], size=self.m_aperture, ignore=self.m_ignore) x_pos, y_pos = self.m_position[0], self.m_position[1] sep_ang = cartesian_to_polar(center, x_pos, y_pos) result = np.column_stack( (x_pos, y_pos, sep_ang[0] * pixscale, sep_ang[1], snr, fpf)) self.m_snr_out_port.append(result, data_dim=2) sys.stdout.write('Running FalsePositiveModule... [DONE]\n') sys.stdout.flush() history = f'aperture [arcsec] = {self.m_aperture*pixscale:.2f}' self.m_snr_out_port.copy_attributes(self.m_image_in_port) self.m_snr_out_port.add_history('FalsePositiveModule', history) self.m_snr_out_port.close_port()