def test_double_gaussian_fit(): """Test the double Gaussian fitting function""" amplitude1 = 500 mean_value1 = 0.5 sigma_value1 = 0.05 amplitude2 = 300 mean_value2 = 0.4 sigma_value2 = 0.03 bin_centers = np.arange(0., 1.1, 0.007) input_params = [ amplitude1, mean_value1, sigma_value1, amplitude2, mean_value2, sigma_value2 ] input_values = calculations.double_gaussian(bin_centers, *input_params) initial_params = [ np.max(input_values), 0.55, 0.1, np.max(input_values), 0.5, 0.05 ] params, sigma = calculations.double_gaussian_fit(bin_centers, input_values, initial_params) assert np.allclose(np.array(params[0:3]), np.array([amplitude2, mean_value2, sigma_value2]), atol=0, rtol=0.000001) assert np.allclose(np.array(params[3:]), np.array([amplitude1, mean_value1, sigma_value1]), atol=0, rtol=0.000001)
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)