def add_epoch(table, epoch): """ Add an epoch column to the table. :param table: :param epoch: :return: """ col = table.Column(data=np.ones(len(table), dtype=np.int32) * epoch, name='epoch') table.add_column(col) return table
def process_table(table, epochs, band, blind=True,quiet=True, report=False): print 'Removing large boxes' too_large_rows=np.where(table['stamp_size']>100)[0] table.remove_rows(too_large_rows) print "Lower casing" lowercase(table) lowercase(epochs) print "Sorting and grouping" epochs.sort(["id", "expnum"]) table.sort("identifier") print 'Adding chi2_pixel' chi2 = -2 * table['likelihood'] effective_npix = table['stamp_size']**2 * table['n_exposure'] * (1-table['mean_mask_fraction']) chi2_pixel = chi2 / effective_npix col = astropy.table.Column(name='chi2_pixel', data=chi2_pixel) table.add_column(col) print 'Renaming identifier->coadd_objects_ids' table.rename_column("identifier", "coadd_objects_id") epochs.rename_column('id', 'coadd_objects_id') #print 'NOT NOT NOT NOT NOT NOT NOT Adding extra columns flags' print "adding new columns" extra_columns.add_standard_cols(table) print 'Flagging' #error cuts cuts = cut_data.error_cuts + getattr(cut_data, "error_cuts_%s"%band) flags, fractions = cut_data.compute_flags(table, cuts, verb=not quiet) col = astropy.table.Column(name='error_flag', data=flags) table.add_column(col) if report: print "INFO CUTS" cut_data.report(cuts) #info cuts cuts = cut_data.info_cuts1 + getattr(cut_data, "info_cuts_%s"%band) + cut_data.info_cuts2 flags, fractions = cut_data.compute_flags(table, cuts, verb=not quiet) col = astropy.table.Column(name='info_flag', data=flags) table.add_column(col) if report: print "ERROR CUTS" cut_data.report(cuts) return table, epochs #blinding if blind: print 'Blinding' e1,e2 = blind_catalog.blind_arrays(table['e1'],table['e2']) table['e1'][:] = e1 table['e2'][:] = e2 print "Reticulating splines" return table, epochs
def build_table_from_output_dict(output_dict): """ Traverses the output dict to build a plottable table. """ table = astropy.table.Table() column_names = ("trial_number", "noise_added", "n_clouds", "total_mass", 'inner_larson_A', 'inner_larson_beta', 'outer_larson_A', 'outer_larson_beta', 'inner_M0', 'inner_N0', 'inner_gamma', 'outer_M0', 'outer_N0', 'outer_gamma') for name in column_names: col = astropy.table.Column(data=[], name=name) table.add_column(col) for key, value in output_dict.items(): # we are gonna try and add things row by row preamble = value[0:4] larson, mspec = value[-2:] larson_names = [ 'inner_larson_A', 'inner_larson_beta', 'outer_larson_A', 'outer_larson_beta' ] larson_tuple = tuple(larson[name] for name in larson_names) mspec_names = [ 'inner_M0', 'inner_N0', 'inner_gamma', 'outer_M0', 'outer_N0', 'outer_gamma' ] mspec_tuple = tuple(mspec[name] for name in mspec_names) table.add_row((preamble + larson_tuple + mspec_tuple)) return table
def add_tex_tau_to_table(table): import pyradex R = pyradex.Radex(species='o-h2co_troscompt', h2column=1e21, abundance=10**-8.5) newcols = {'tau1':[], 'tau2':[], 'tex1':[], 'tex2':[]} for t in table: R.temperature = t['TEMPERATURE'] R.column = 10**t['COLUMN'] orthofrac = 10**t['ORTHOPARA']/(1+10**t['ORTHOPARA']) R.density = {'oH2': 10**t['DENSITY']*orthofrac, 'pH2': 10**t['DENSITY']*(1-orthofrac)} R.run_radex() newcols['tex1'].append(R.tex[0].value) newcols['tex2'].append(R.tex[2].value) newcols['tau1'].append(R.tau[0]) newcols['tau2'].append(R.tau[2]) for k in newcols: table.add_column(astropy.table.Column(name=k, data=newcols[k])) return table
def table_latex_strings_test(write=False, begin=0, end=30): """ This is a 'test' for generating pretty LaTeX-style tables. In particular, I want to see if I can make a) sexagesimal coordinate output and b) value \pm errorbar columns. See https://github.com/YSOVAR/YSOVAR/blob/master/docs/workflow.rst and http://docs.astropy.org/en/v0.2.1/_generated/astropy.io.ascii.latex.Latex.html for reference. """ table = astropy.table.Table() table.table_name = "Table 1" # Be careful about this. Make sure you don't get the order of the args confused. addc = lambda name, data: table.add_column( astropy.table.Column(name=name, data=data) ) sexagesimal_RA, sexagesimal_Dec = ( convert_decimal_degree_columns_to_sexagesimal( np.degrees(ukvar_spread.RA), np.degrees(ukvar_spread.DEC)) ) j_value_pm_error = join_columns_with_plusminus(ukvar_spread.j_median, ukvar_spread.j_err_median, precision=2) addc('ONCvar ID', ukvar_spread.UKvar_ID) addc('R.A.', sexagesimal_RA) addc('Decl.', sexagesimal_Dec) addc('Median J mag', j_value_pm_error) if write: filename = output_directory+"Table_test.tex" write_and_correct_latex_table(table, filename, "Basic Properties of Stars") return table
def calculate_fiber_acceptance_fraction(focal_x, focal_y, wavelength, source, atmosphere, instrument, source_types=None, source_fraction=None, source_half_light_radius=None, source_minor_major_axis_ratio=None, source_position_angle=None, oversampling=32, saved_images_file=None, saved_table_file=None): """Calculate the acceptance fraction for a single fiber. The behavior of this function is customized by the instrument.fiberloss configuration parameters. When instrument.fiberloss.method == 'table', pre-tabulated values are returned using source.type as the key and all other parameters to this function are ignored. When instrument.fiberloss.method == 'galsim', fiberloss is calculated on the fly using the GalSim package via :class:`GalsimFiberlossCalculator` to model the PSF components and source profile and perform the convolutions. To efficiently calculate fiberloss fractions for multiple sources with GalSim, use :class:`GalsimFiberlossCalculator` directly instead of repeatedly calling this method. See :mod:`specsim.quickfiberloss` for an example of this approach. Parameters ---------- focal_x : :class:`astropy.units.Quantity` X coordinate of the fiber center in the focal plane with length units. focal_y : :class:`astropy.units.Quantity` Y coordinate of the fiber center in the focal plane with length units. wavelength : :class:`astropy.units.Quantity` Array of simulation wavelengths (with length units) where the fiber acceptance fraction should be tabulated. source : :class:`specsim.source.Source` Source model to use for the calculation. atmosphere : :class:`specsim.atmosphere.Atmosphere` Atmosphere model to use for the calculation. instrument : :class:`specsim.instrument.Instrument` Instrument model to use for the calculation. source_types : array or None Array of source type names that identify which tabulated fiberloss fraction should be used for each fiber with the ``table`` method. Each name should already be defined as a key in the ``instruments.fiberloss.table.paths`` configuration. Ignored for the ``galsim`` method. source_fraction : array or None Array of shape (num_fibers, 2). See :meth:`GalsimFiberlossCalculator.create_source` for details. Ignored for the ``table`` method. source_half_light_radius : array or None Array of shape (num_fibers, 2). See :meth:`GalsimFiberlossCalculator.create_source` for details. Ignored for the ``table`` method. source_minor_major_axis_ratio : array or None Array of shape (num_fibers, 2). See :meth:`GalsimFiberlossCalculator.create_source` for details. Ignored for the ``table`` method. source_position_angle : array or None Array of shape (num_fibers, 2). See :meth:`GalsimFiberlossCalculator.create_source` for details. Ignored for the ``table`` method. oversampling : int Oversampling factor to use for anti-aliasing the fiber aperture. Ignored for the ``table`` method. saved_images_file : str or None See :meth:`GalsimFiberlossCalculator.calculate`. Ignored for the ``table`` method. saved_table_file : str or None Write a table of calculated values to a file with this name. The extension determines the file format, and .ecsv is recommended. The saved file can then be used as a pre-tabulated input with instrument.fiberloss.method = 'table'. Returns ------- numpy array Array of fiber acceptance fractions (dimensionless) at each of the input wavelengths. """ num_fibers = len(focal_x) if len(focal_y) != num_fibers: raise ValueError('Arrays focal_x and focal_y must have same length.') # Use pre-tabulated fiberloss fractions when requested. if instrument.fiberloss_method == 'table': if source_types is None: # Use same source type for all fibers. return instrument.fiber_acceptance_dict[source.type_name][ np.newaxis, :] elif len(source_types) != num_fibers: raise ValueError('Unexpected shape for source_types.') floss = np.empty((num_fibers, len(wavelength))) for i, type_name in enumerate(source_types): floss[i] = instrument.fiber_acceptance_dict[type_name] return floss # Otherwise, use GalSim or the fastfiberacceptance calibrated on galsim # to calculate fiberloss fractions on the fly... # Initialize the grid of wavelengths where the fiberloss will be # calculated. num_wlen = instrument.fiberloss_num_wlen wlen_unit = wavelength.unit wlen_grid = np.linspace(wavelength.value[0], wavelength.value[-1], num_wlen) * wlen_unit # Calculate the focal-plane optics at the fiber locations. scale, blur, offset = instrument.get_focal_plane_optics( focal_x, focal_y, wlen_grid) # Calculate the atmospheric seeing at each wavelength. seeing_fwhm = atmosphere.get_seeing_fwhm(wlen_grid).to(u.arcsec).value # Replicate source parameters from the source config if they are not # provided via args. If they are provided, check for the expected shape. if source_fraction is None: source_fraction = np.tile( [source.disk_fraction, source.bulge_fraction], [num_fibers, 1]) elif source_fraction.shape != (num_fibers, 2): raise ValueError('Unexpected shape for source_fraction.') if source_half_light_radius is None: source_half_light_radius = np.tile([ source.disk_shape.half_light_radius.to(u.arcsec).value, source.bulge_shape.half_light_radius.to(u.arcsec).value ], [num_fibers, 1]) elif source_half_light_radius.shape != (num_fibers, 2): raise ValueError('Unexpected shape for source_half_light_radius.') if source_minor_major_axis_ratio is None: source_minor_major_axis_ratio = np.tile([ source.disk_shape.minor_major_axis_ratio, source.bulge_shape.minor_major_axis_ratio ], [num_fibers, 1]) elif source_minor_major_axis_ratio.shape != (num_fibers, 2): raise ValueError('Unexpected shape for source_minor_major_axis_ratio.') if source_position_angle is None: source_position_angle = np.tile([ source.disk_shape.position_angle.to(u.deg).value, source.bulge_shape.position_angle.to(u.deg).value ], [num_fibers, 1]) elif source_position_angle.shape != (num_fibers, 2): raise ValueError('Unexpected shape for source_position_angle.') fiberloss_grid = None # choose here how to compute things if instrument.fiberloss_method == 'fastsim': scale_um_per_arcsec = scale.to(u.um / u.arcsec).value blur_um = blur.to(u.um).value sigma = np.zeros((offset.shape[0], offset.shape[1])) disk_half_light_radius = np.zeros(sigma.shape) bulge_half_light_radius = np.zeros(sigma.shape) disk_frac = np.zeros(sigma.shape) bulge_frac = np.zeros(sigma.shape) for i in range(offset.shape[0]): sigma[i] = np.sqrt((seeing_fwhm / 2.35482)**2 * scale_um_per_arcsec[i, 0] * scale_um_per_arcsec[i, 1] + blur_um[i]**2) disk_half_light_radius[i] = source_half_light_radius[ i, 0] * np.ones(offset.shape[1]) bulge_half_light_radius[i] = source_half_light_radius[ i, 1] * np.ones(offset.shape[1]) disk_frac[i] = source_fraction[i, 0] * np.ones(offset.shape[1]) bulge_frac[i] = source_fraction[i, 1] * np.ones(offset.shape[1]) point_frac = 1 - disk_frac - bulge_frac offset_um = offset.to(u.um).value delta = np.sqrt(offset_um[:, :, 0]**2 + offset_um[:, :, 1]**2) fiberloss_grid = np.zeros(sigma.shape) if np.sum(point_frac) > 0: fiberloss_grid += point_frac * instrument.fast_fiber_acceptance.value( "POINT", sigma, delta) if np.sum(disk_frac) > 0: fiberloss_grid += disk_frac * instrument.fast_fiber_acceptance.value( "DISK", sigma, delta, disk_half_light_radius) if np.sum(bulge_frac) > 0: fiberloss_grid += bulge_frac * instrument.fast_fiber_acceptance.value( "BULGE", sigma, delta, bulge_half_light_radius) else: # Initialize a new calculator. calc = GalsimFiberlossCalculator( instrument.fiber_diameter.to(u.um).value, wlen_grid.to(u.Angstrom).value, instrument.fiberloss_num_pixels, oversampling, atmosphere.seeing_moffat_beta) # Calculate fiberloss fractions. Note that the calculator expects arrays # with implicit units. fiberloss_grid = calc.calculate(seeing_fwhm, scale.to(u.um / u.arcsec).value, offset.to(u.um).value, blur.to(u.um).value, source_fraction, source_half_light_radius, source_minor_major_axis_ratio, source_position_angle, saved_images_file) # TODO: add support for saving table when num_fibers > 1. if saved_table_file and num_fibers == 1: meta = dict( description='Fiberloss fraction for source "{0}"'.format( source.name) + ' at focal (x,y) = ({0:.3f},{1:.3f})'.format(focal_x, focal_y)) table = astropy.table.Table(meta=meta) table.add_column( astropy.table.Column(name='Wavelength', data=wlen_grid.value, unit=wlen_grid.unit, description='Observed wavelength')) table.add_column( astropy.table.Column(name='FiberAcceptance', data=fiberloss_grid[0], description='Fiber acceptance fraction')) args = {} if saved_table_file.endswith('.ecsv'): args['format'] = 'ascii.ecsv' table.write(saved_table_file, **args) # Interpolate (linearly) to the simulation wavelength grid. # Use scipy.interpolate instead of np.interp here to avoid looping # over fibers. interpolator = scipy.interpolate.interp1d(wlen_grid.value, fiberloss_grid, kind='linear', axis=1, copy=False, assume_sorted=True) # Both wavelength grids have the same units, by construction, so no # conversion factor is required here. return interpolator(wavelength.value)
def __init__(self, config, num_fibers=2, camera_output=True, verbose=False, params=None): if specsim.config.is_string(config): config = specsim.config.load_config(config) config.verbose = verbose self.verbose = verbose # Initalize our component models. self.atmosphere = specsim.atmosphere.initialize(config) self.instrument = specsim.instrument.initialize(config, camera_output) self.source = specsim.source.initialize(config) self.observation = specsim.observation.initialize(config) self.telescope = specsim.telescope.initialize(config, params=params) self._num_fibers = int(num_fibers) if self._num_fibers < 1: raise ValueError('Must have num_fibers >= 1.') # Initialize our table of simulation results. self.camera_names = [] self.camera_slices = {} num_rows = len(config.wavelength) shape = (self.num_fibers, ) column_args = dict(dtype=float, length=num_rows, shape=shape) flux_unit = u.erg / (u.cm**2 * u.s * u.Angstrom) self._simulated = astropy.table.Table(meta=dict( description='Specsim simulation results')) self._simulated.add_column( astropy.table.Column(name='wavelength', data=config.wavelength)) self._simulated.add_column( astropy.table.Column(name='source_flux', unit=flux_unit, **column_args)) self._simulated.add_column( astropy.table.Column(name='fiberloss', **column_args)) self._simulated.add_column( astropy.table.Column(name='source_fiber_flux', unit=flux_unit, **column_args)) self._simulated.add_column( astropy.table.Column(name='sky_fiber_flux', unit=flux_unit, **column_args)) self._simulated.add_column( astropy.table.Column(name='num_source_photons', **column_args)) self._simulated.add_column( astropy.table.Column(name='num_sky_photons', **column_args)) for camera in self.instrument.cameras: name = camera.name self.camera_names.append(name) self.camera_slices[name] = camera.ccd_slice self._simulated.add_column( astropy.table.Column( name='num_source_electrons_{0}'.format(name), **column_args)) self._simulated.add_column( astropy.table.Column(name='num_sky_electrons_{0}'.format(name), **column_args)) self._simulated.add_column( astropy.table.Column( name='num_dark_electrons_{0}'.format(name), **column_args)) self._simulated.add_column( astropy.table.Column( name='read_noise_electrons_{0}'.format(name), **column_args)) # Count the number of bytes used in the simulated table. self.table_bytes = 0 for name in self._simulated.colnames: d = self._simulated[name].data self.table_bytes += np.prod(d.shape) * d.dtype.itemsize # Initialize each camera's table of results downsampled to # output pixels, if requested. self._camera_output = [] if camera_output: for camera in self.instrument.cameras: meta = dict(name=camera.name, num_fibers=self.num_fibers, pixel_size=camera.output_pixel_size) table = astropy.table.Table(meta=meta) column_args['length'] = len(camera.output_wavelength) table.add_column( astropy.table.Column(name='wavelength', data=camera.output_wavelength)) table.add_column( astropy.table.Column(name='num_source_electrons', **column_args)) table.add_column( astropy.table.Column(name='num_sky_electrons', **column_args)) table.add_column( astropy.table.Column(name='num_dark_electrons', **column_args)) table.add_column( astropy.table.Column(name='read_noise_electrons', **column_args)) table.add_column( astropy.table.Column(name='random_noise_electrons', **column_args)) table.add_column( astropy.table.Column(name='variance_electrons', **column_args)) table.add_column( astropy.table.Column(name='flux_calibration', **column_args)) table.add_column( astropy.table.Column(name='observed_flux', unit=flux_unit, **column_args)) table.add_column( astropy.table.Column(name='flux_inverse_variance', unit=flux_unit**-2, **column_args)) # Add bytes used in this table to our running total. for name in table.colnames: d = table[name].data self.table_bytes += np.prod(d.shape) * d.dtype.itemsize self._camera_output.append(table) if self.verbose: print('Allocated {0:.1f}Mb of table data.'.format( self.table_bytes / (2.**20)))
def __init__(self, config): if isinstance(config, basestring): config = specsim.config.load_config(config) # Initalize our component models. self.atmosphere = specsim.atmosphere.initialize(config) self.instrument = specsim.instrument.initialize(config) self.source = specsim.source.initialize(config) self.observation = specsim.observation.initialize(config) # Initialize our table of simulation results. self.camera_names = [] self.camera_slices = {} num_rows = len(config.wavelength) flux_unit = u.erg / (u.cm**2 * u.s * u.Angstrom) self._simulated = astropy.table.Table( meta=dict(description='Specsim simulation results')) self._simulated.add_column(astropy.table.Column( name='wavelength', data=config.wavelength)) self._simulated.add_column(astropy.table.Column( name='source_flux', dtype=float, length=num_rows, unit=flux_unit)) self._simulated.add_column(astropy.table.Column( name='source_fiber_flux', dtype=float, length=num_rows, unit=flux_unit)) self._simulated.add_column(astropy.table.Column( name='sky_fiber_flux', dtype=float, length=num_rows, unit=flux_unit)) self._simulated.add_column(astropy.table.Column( name='num_source_photons', dtype=float, length=num_rows)) self._simulated.add_column(astropy.table.Column( name='num_sky_photons', dtype=float, length=num_rows)) for camera in self.instrument.cameras: name = camera.name self.camera_names.append(name) self.camera_slices[name] = camera.ccd_slice self._simulated.add_column(astropy.table.Column( name='num_source_electrons_{0}'.format(name), dtype=float, length=num_rows)) self._simulated.add_column(astropy.table.Column( name='num_sky_electrons_{0}'.format(name), dtype=float, length=num_rows)) self._simulated.add_column(astropy.table.Column( name='num_dark_electrons_{0}'.format(name), dtype=float, length=num_rows)) self._simulated.add_column(astropy.table.Column( name='read_noise_electrons_{0}'.format(name), dtype=float, length=num_rows)) # Initialize each camera's table of results downsampled to # output pixels. self._camera_output = [] for camera in self.instrument.cameras: meta = dict( name=camera.name, pixel_size=camera.output_pixel_size) table = astropy.table.Table(meta=meta) num_rows = len(camera.output_wavelength) table.add_column(astropy.table.Column( name='wavelength', data=camera.output_wavelength)) table.add_column(astropy.table.Column( name='num_source_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='num_sky_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='num_dark_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='read_noise_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='random_noise_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='variance_electrons', dtype=float, length=num_rows)) table.add_column(astropy.table.Column( name='flux_calibration', dtype=float, length=num_rows, unit=flux_unit)) table.add_column(astropy.table.Column( name='observed_flux', dtype=float, length=num_rows, unit=flux_unit)) table.add_column(astropy.table.Column( name='flux_inverse_variance', dtype=float, length=num_rows, unit=flux_unit ** -2)) self._camera_output.append(table)
def extract(inputs, pixel_scale, filename, noisefile, outputfile, finalfits, num_sections, height, width, x, y): logger.info(f"Will source extract galaxies from noise file {noisefile}") # run sextractor on noise image. cmd = '/nfs/slac/g/ki/ki19/deuce/AEGIS/ismael/WLD/params/sextractor-2.25.0/src/sex {} -c {} -CATALOG_NAME {} ' \ '-PARAMETERS_NAME {} -FILTER_NAME {} -STARNNW_NAME {}'.format( noisefile, inputs['config_file'], outputfile, inputs['param_file'], inputs['filter_file'], inputs['starnnw_file']) logger.info(f"With cmd: {cmd}") subprocess.run(cmd, shell=True) logger.success(f"Successfully source extracted {noisefile}!") # read noise image to figure out image bounds. fits_section = fitsio.FITS(noisefile) stamp = fits_section[0].read() img_width = stamp.shape[0] # pixels img_height = stamp.shape[1] assert img_width == width / num_sections and img_height == height / num_sections, \ "Something is wrong with the heights specified." logger.info( f"The image width and height from the stamp are {img_width} and {img_height} respectively." ) # read results obtained (table obtained either from combining or from single.) cat = descwl.output.Reader(filename).results table = cat.table detected, matched, indices, distance = cat.match_sextractor(outputfile) logger.success( f"Successfully matched catalogue with source extractor from sextract output: {outputfile}" ) # convert to arcsecs and relative to this image's center (not to absolute, before w/ respect to corner.) detected['X_IMAGE'] = (detected['X_IMAGE'] - 0.5 * img_width - 0.5) * pixel_scale detected['Y_IMAGE'] = (detected['Y_IMAGE'] - 0.5 * img_height - 0.5) * pixel_scale # adjust to absolute image center if necessary, both for measured centers and catalogue centers. detected['X_IMAGE'] += x * (width * pixel_scale) # need to use arcsecs detected['Y_IMAGE'] += y * (height * pixel_scale) table['dx'] += x * (width * pixel_scale) table['dy'] += y * (height * pixel_scale) # also adjust the xmin,xmax, ymin, ymax bounding box edges, because why not? # remember these are in pixels; xmin, xmax relative to left edge; ymin,ymax relative to right edge. table['xmin'] += int(x * width + width / 2 - img_width / 2) table['xmax'] += int(x * width + width / 2 - img_width / 2) table['ymin'] += int(x * height + height / 2 - img_height / 2) table['ymax'] += int(x * height + height / 2 - img_height / 2) # convert second moments to arcsecs. # Not adjust relative to center, because only used for sigma calculation. detected['X2_IMAGE'] *= pixel_scale**2 detected['Y2_IMAGE'] *= pixel_scale**2 detected['XY_IMAGE'] *= pixel_scale**2 # calculate size from moments X2_IMAGE,Y2_IMAGE,XY_IMAGE -> remember in pixel**2 so have to convert to arcsecs. sigmas = [] for x2, y2, xy in zip(detected['X2_IMAGE'], detected['Y2_IMAGE'], detected['XY_IMAGE']): second_moments = np.array([[x2, xy], [xy, y2]]) sigma = np.linalg.det(second_moments)**(+1. / 4) # should be a PLUS. sigmas.append(sigma) SIGMA = astropy.table.Column(name='SIGMA', data=sigmas) detected.add_column(SIGMA) # find the indices of the ambiguous blends. logger.info("Finding indices/ids that are ambiguously blended") ambg_blends = detected_ambiguous_blends(table, indices, detected) logger.success("All indices have been found") logger.info( f"Adding column to original table and writing it to {finalfits}") ambiguous_blend_column = [] for i, gal_row in enumerate(table): if i in ambg_blends: ambiguous_blend_column.append(True) else: ambiguous_blend_column.append(False) column = astropy.table.Column(name='ambig_blend', data=ambiguous_blend_column) table.add_column(column) logger.debug( f"Number of galaxies in table from file {finalfits} is: {len(table)}") table.write(finalfits)