def test_gaussian1d_fit(): """Test histogram fitting function""" mean_value = 0.5 sigma_value = 0.05 image = np.random.normal(loc=mean_value, scale=sigma_value, size=(100, 100)) hist, bin_edges = np.histogram(image, bins='auto') bin_centers = (bin_edges[1:] + bin_edges[0: -1]) / 2. initial_params = [np.max(hist), 0.55, 0.1] amplitude, peak, width = calculations.gaussian1d_fit(bin_centers, hist, initial_params) assert np.isclose(peak[0], mean_value, atol=0.0015, rtol=0.) assert np.isclose(width[0], sigma_value, atol=0.0015, rtol=0.) assert ((mean_value <= peak[0]+3*peak[1]) & (mean_value >= peak[0]-3*peak[1])) assert ((sigma_value <= width[0]+3*width[1]) & (sigma_value >= width[0]-3*width[1]))
def stats_by_amp(self, image, amps): """Calculate statistics in the input image for each amplifier as well as the full image Parameters ---------- image : numpy.ndarray 2D array on which to calculate statistics amps : dict Dictionary containing amp boundary coordinates (output from ``amplifier_info`` function) ``amps[key] = [(xmin, xmax, xstep), (ymin, ymax, ystep)]`` Returns ------- amp_means : dict Sigma-clipped mean value for each amp. Keys are amp numbers as strings (e.g. ``'1'``) amp_stdevs : dict Sigma-clipped standard deviation for each amp. Keys are amp numbers as strings (e.g. ``'1'``) gaussian_params : dict Best-fit Gaussian parameters to the dark current histogram. Keys are amp numbers as strings. Values are three-element lists ``[amplitude, peak, width]``. Each element in the list is a tuple of the best-fit value and the associated uncertainty. gaussian_chi_squared : dict Reduced chi-squared for the best-fit parameters. Keys are amp numbers as strings double_gaussian_params : dict Best-fit double Gaussian parameters to the dark current histogram. Keys are amp numbers as strings. Values are six- element lists. (3-elements * 2 Gaussians). ``[amplitude1, peak1, stdev1, amplitude2, peak2, stdev2]`` Each element of the list is a tuple containing the best-fit value and associated uncertainty. double_gaussian_chi_squared : dict Reduced chi-squared for the best-fit parameters. Keys are amp numbers as strings hist : numpy.ndarray 1D array of histogram values bin_centers : numpy.ndarray 1D array of bin centers that match the ``hist`` values. """ amp_means = {} amp_stdevs = {} gaussian_params = {} gaussian_chi_squared = {} double_gaussian_params = {} double_gaussian_chi_squared = {} # Add full image coords to the list of amp_boundaries, so that full # frame stats are also calculated. if 'FULL' in self.aperture: maxx = 0 maxy = 0 for amp in amps: mxx = amps[amp][0][1] mxy = amps[amp][1][1] if mxx > maxx: maxx = copy(mxx) if mxy > maxy: maxy = copy(mxy) amps['5'] = [(0, maxx, 1), (0, maxy, 1)] logging.info(( '\tFull frame exposure detected. Adding the full frame to the list ' 'of amplifiers upon which to calculate statistics.')) for key in amps: x_start, x_end, x_step = amps[key][0] y_start, y_end, y_step = amps[key][1] indexes = np.mgrid[y_start:y_end:y_step, x_start:x_end:x_step] # Basic statistics, sigma clipped areal mean and stdev amp_mean, amp_stdev = calculations.mean_stdev(image[indexes[0], indexes[1]]) amp_means[key] = amp_mean amp_stdevs[key] = amp_stdev # Create a histogram lower_bound = (amp_mean - 7 * amp_stdev) upper_bound = (amp_mean + 7 * amp_stdev) hist, bin_edges = np.histogram(image[indexes[0], indexes[1]], bins='auto', range=(lower_bound, upper_bound)) bin_centers = (bin_edges[1:] + bin_edges[0:-1]) / 2. initial_params = [np.max(hist), amp_mean, amp_stdev] # Fit a Gaussian to the histogram. Save best-fit params and # uncertainties, as well as reduced chi squared amplitude, peak, width = calculations.gaussian1d_fit( bin_centers, hist, initial_params) gaussian_params[key] = [amplitude, peak, width] gauss_fit_model = models.Gaussian1D(amplitude=amplitude[0], mean=peak[0], stddev=width[0]) gauss_fit = gauss_fit_model(bin_centers) positive = hist > 0 degrees_of_freedom = len(hist) - 3. total_pix = np.sum(hist[positive]) p_i = gauss_fit[positive] / total_pix gaussian_chi_squared[key] = (np.sum( (hist[positive] - (total_pix * p_i)**2) / (total_pix * p_i)) / degrees_of_freedom) # Double Gaussian fit only for full frame data (and only for # NIRISS, NIRCam at the moment.) if key == '5': if self.instrument.upper() in ['NIRISS', 'NIRCAM']: initial_params = (np.max(hist), amp_mean, amp_stdev * 0.8, np.max(hist) / 7., amp_mean / 2., amp_stdev * 0.9) double_gauss_params, double_gauss_sigma = calculations.double_gaussian_fit( bin_centers, hist, initial_params) double_gaussian_params[key] = [ [param, sig] for param, sig in zip( double_gauss_params, double_gauss_sigma) ] double_gauss_fit = calculations.double_gaussian( bin_centers, *double_gauss_params) degrees_of_freedom = len(bin_centers) - 6. dp_i = double_gauss_fit[positive] / total_pix double_gaussian_chi_squared[key] = np.sum( (hist[positive] - (total_pix * dp_i)**2) / (total_pix * dp_i)) / degrees_of_freedom else: double_gaussian_params[key] = [[0., 0.] for i in range(6)] double_gaussian_chi_squared[key] = 0. else: double_gaussian_params[key] = [[0., 0.] for i in range(6)] double_gaussian_chi_squared[key] = 0. logging.info('\tMean dark rate by amplifier: {}'.format(amp_means)) logging.info( '\tStandard deviation of dark rate by amplifier: {}'.format( amp_means)) logging.info( '\tBest-fit Gaussian parameters [amplitude, peak, width]'.format( gaussian_params)) logging.info( '\tReduced chi-squared associated with Gaussian fit: {}'.format( gaussian_chi_squared)) logging.info( '\tBest-fit double Gaussian parameters [amplitude1, peak1, width1, amplitude2, peak2, ' 'width2]'.format(double_gaussian_params)) logging.info( '\tReduced chi-squared associated with double Gaussian fit: {}'. format(double_gaussian_chi_squared)) return (amp_means, amp_stdevs, gaussian_params, gaussian_chi_squared, double_gaussian_params, double_gaussian_chi_squared, hist.astype(np.float), bin_centers)