def combine_per_camera_catalogs(catalogs): # catalogs is the output of GFA_exposure's all_source_catalogs() method # which is a dictionary of astropy QTable's, with the keys # being the GFA camera extension names # want to add a column to each table giving the GFA camera name, then # append the all into one per-exposure table assert(type(catalogs).__name__ == 'dict') composite_list = [] for extname, tab in catalogs.items(): if tab is not None: tab['camera'] = extname tab['petal_loc'] = np.array([common.gfa_extname_to_gfa_number(extname) for extname in tab['camera']], dtype='uint8') composite_list.append(tab) # handle case of no sources in any image if len(composite_list) == 0: return None composite = vstack(composite_list) composite = strip_none_columns(composite) composite['extname'] = composite['camera'] return composite
def psf_image_header(self, hdu): hdu.header['EXTNAME'] = self.extname hdu.header['PETALLOC'] = common.gfa_extname_to_gfa_number(self.extname) hdu.header['NSTARS'] = self.nstars hdu.header['FIBFRAC'] = self.fiber_fracflux if np.isfinite(self.fiber_fracflux) else 0.0 # ?? hdu.header['EXPID'] = self.im_header['EXPID'] hdu.header['CBOX'] = self.cbox hdu.header['CFAILED'] = self.psf_centroiding_failed if self.cube_index is not None: hdu.header['CUBE_IND'] = self.cube_index # guide*.fits.fz GUIDE? extensions apparently don't have NIGHT # or any other date-related information available if 'NIGHT' in self.im_header: hdu.header['NIGHT'] = self.im_header['NIGHT']
def to_hdu(self, primary=False, flavor=''): # convert this image to an HDU # currently expect flavor to be one of # REDUCED - reduced image # BITMASK - data quality bitmask # INVVAR - inverse variance image # DETMAP - detection significance map # if no flavor is specified then assume ".image" attribute is desired # data for this HDU f = (fits.PrimaryHDU if primary else fits.ImageHDU) if (flavor == '') or (flavor == 'REDUCED'): hdu = f(self.image.astype('float32'), header=self.header) elif (flavor == 'BITMASK'): hdu = f(self.bitmask.astype('int'), header=self.header) hdu.header = dq_mask.add_dq_bitmask_header_cards(hdu.header) elif (flavor == 'INVVAR'): hdu = f(self.ivar_adu.astype('float32'), header=self.header) elif (flavor == 'DETMAP'): assert(self.detmap is not None) hdu = f(self.detmap.astype('float32'), header=self.header) hdu.header['FLAVOR'] = flavor gain = common.gfa_camera_gain(self.extname) hdu.header['GAINA'] = (gain, '[e-/ADU] assumed gain') hdu.header['BUNIT'] = common.reduced_flavor_to_bunit(flavor) petal_loc = common.gfa_extname_to_gfa_number(self.extname) hdu.header['PETALLOC'] = (petal_loc, 'petal number') return hdu
def assemble_ccds_table(tab, catalog, exp, outdir, proc_obj, cube_index=None, ps1=None, det_sn_thresh=5.0, sky_mags=True, minimal=False, mjdrange=None): nrows = len(tab) tab['extname'] = tab['camera'] tab['contrast'] = [exp.images[extname].header['CONTRAST'] for extname in tab['camera']] if minimal: return tab if sky_mags: tab['sky_mag_ab'] = [exp.images[extname].sky_mag for extname in tab['camera']] tab['sky_mag_ab_subregion'] = [exp.images[extname].sky_mag_upper for extname in tab['camera']] amps = common.valid_amps_list() if sky_mags: sky_mag_ab_per_amp = np.zeros((nrows, len(amps)), dtype='float32') # 4 amps for i, extname in enumerate(tab['camera']): for j in range(len(amps)): _mag = np.nan if exp.images[extname].sky_mag_per_amp is None else exp.images[extname].sky_mag_per_amp[j] sky_mag_ab_per_amp[i, j] = _mag tab['sky_mag_ab_per_amp'] = sky_mag_ab_per_amp tab['petal_loc'] = np.array([common.gfa_extname_to_gfa_number(extname) for extname in tab['camera']], dtype='uint8') tab['expid'] = [exp.images[extname].header['EXPID'] for extname in tab['camera']] # should work except if early versions of guide cubes lacked # MJD information... tab['mjd'] = [exp.images[extname].try_retrieve_meta_keyword('MJD-OBS', placeholder=0.0) for extname in tab['camera']] eph = util.load_lst() tab['lst_deg'] = [util.interp_ephemeris(t['mjd'], eph=eph) for t in tab] tab['moon_illumination'] = [util.interp_ephemeris(t['mjd'], eph=eph, colname='MPHASE') for t in tab] tab['program'] = [str(exp.images[extname].try_retrieve_meta_keyword('PROGRAM', placeholder='')) for extname in tab['camera']] tab['skyra'] = [exp.images[extname].try_retrieve_meta_keyword('SKYRA', placeholder=np.nan) for extname in tab['camera']] tab['skydec'] = [exp.images[extname].try_retrieve_meta_keyword('SKYDEC', placeholder=np.nan) for extname in tab['camera']] # zenith distance using approximate center of the field given by SKYRA, SKYDEC tab['zenith_dist_deg'] = [util._zenith_distance(t['skyra'], t['skydec'], t['lst_deg']) for t in tab] tab['domshutl'] = np.array(nrows*[exp.try_retrieve_header_card('DOMSHUTL', placeholder='')], dtype='U8') tab['domshutu'] = np.array(nrows*[exp.try_retrieve_header_card('DOMSHUTU', placeholder='')], dtype='U8') tab['pmcover'] = exp.try_retrieve_header_card('PMCOVER', placeholder='') tab['moonra'] = exp.try_retrieve_header_card('MOONRA', placeholder=np.nan) tab['moondec'] = exp.try_retrieve_header_card('MOONDEC', placeholder=np.nan) if np.isnan(tab['moonra'][0]): tab['moonra'] = util.interp_ephemeris(tab['mjd'][0], eph=eph, colname='MOONRA') if np.isnan(tab['moondec'][0]): tab['moondec'] = util.interp_ephemeris(tab['mjd'][0], eph=eph, colname='MOONDEC') tab['moon_zd_deg'] = util._zenith_distance(tab['moonra'][0], tab['moondec'][0], tab['lst_deg'][0]) tab['t_c_for_dark'] = [exp.images[extname].t_c_for_dark for extname in tab['camera']] tab['t_c_for_dark_is_guess'] = [int(exp.images[extname].t_c_for_dark_is_guess) for extname in tab['camera']] tab['time_s_for_dark'] = [exp.images[extname].time_s_for_dark for extname in tab['camera']] tab['night'] = exp.try_retrieve_header_card('NIGHT', placeholder='') tab['focus'] = exp.try_retrieve_header_card('FOCUS', placeholder='') tab['exptime'] = [exp.images[extname].try_retrieve_meta_keyword('EXPTIME', placeholder=np.nan) for extname in tab['camera']] # hack for acquisition images like guide-00074954-0000.fits.fz # to make sure their _ccds table ends up listing cube_index 0 # rather than NaN is_0000_acq_file = proc_obj.fname_in.find('-0000.fits.fz') != -1 if is_0000_acq_file: tab['cube_index'] = 0 else: tab['cube_index'] = np.nan if cube_index is None else int(cube_index) if cube_index == -1: tab['coadd_index_start'] = [exp.images[extname].coadd_index_range[0] for extname in tab['camera']] tab['coadd_index_end'] = [exp.images[extname].coadd_index_range[1] for extname in tab['camera']] tab['coadd_mjdobs_min'] = [exp.bintables[extname]['MJD-OBS'][ind] for extname, ind in zip(tab['camera'], tab['coadd_index_start'])] tab['coadd_mjdobs_max'] = [exp.bintables[extname]['MJD-OBS'][ind] for extname, ind in zip(tab['camera'], tab['coadd_index_end'])] tab['racen'] = np.zeros(len(tab), dtype=float) tab['deccen'] = np.zeros(len(tab), dtype=float) tab['fname_raw'] = proc_obj.fname_in tab['gitrev'] = proc_obj.gitrev tab['fiber_fracflux'] = [(exp.images[extname].psf.fiber_fracflux if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['fiber_fracflux_elg'] = [(exp.images[extname].psf.fiber_fracflux_elg if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['fiber_fracflux_bgs'] = [(exp.images[extname].psf.fiber_fracflux_bgs if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['n_sources_for_psf'] = [(exp.images[extname].psf.nstars if exp.images[extname].psf is not None else 0) for extname in tab['camera']] # this pertains to aperture _3 which is 1.5 asec radius tab['aper_corr_fac'] = [(exp.images[extname].psf.aper_corr_fac if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['xcentroid_psf'] = [(exp.images[extname].psf.xcen_flux_weighted if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['ycentroid_psf'] = [(exp.images[extname].psf.ycen_flux_weighted if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_fwhm_pix'] = [(exp.images[extname].psf.moffat_fwhm_pix if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_fwhm_asec'] = [(exp.images[extname].psf.moffat_fwhm_asec if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_centroid_cbox'] = [(float(exp.images[extname].psf.cbox) if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_centroid_failed'] = [(exp.images[extname].psf.psf_centroiding_failed if exp.images[extname].psf is not None else 0) for extname in tab['camera']] tab['radprof_fwhm_asec'] = [(exp.images[extname].psf.radprof_fwhm_asec if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] # is 0 the best placeholder value here when no PSF exists? tab['psf_centroiding_flag'] = [(exp.images[extname].psf.psf_centroiding_flag if exp.images[extname].psf is not None else 0) for extname in tab['camera']] tab['psf_asymmetry_ratio'] = [(exp.images[extname].psf.psf_asymmetry_ratio if exp.images[extname].psf is not None else np.float32(np.nan)) for extname in tab['camera']] tab['psf_asymmetry_numerator'] = [(exp.images[extname].psf.psf_asymmetry_numerator if exp.images[extname].psf is not None else np.float32(np.nan)) for extname in tab['camera']] tab['psf_asymmetry_denominator'] = [(exp.images[extname].psf.psf_asymmetry_denominator if exp.images[extname].psf is not None else np.float32(np.nan)) for extname in tab['camera']] tab['psf_total_flux'] = [(exp.images[extname].psf.psf_total_flux if exp.images[extname].psf is not None else np.float32(np.nan)) for extname in tab['camera']] radprof_ccds_table(tab, exp) for i, extname in enumerate(tab['camera']): racen, deccen = ccd_center_radec(exp.images[extname].wcs) tab['racen'][i] = racen tab['deccen'][i] = deccen tab['mountha_header'] = exp.try_retrieve_header_card('MOUNTHA', placeholder=np.nan) tab['mountdec_header'] = exp.try_retrieve_header_card('MOUNTDEC', placeholder=np.nan) tab['ha_deg'] = [util._get_ha(t['skyra'], t['lst_deg'], t['mountdec_header']) for t in tab] tab['ha_deg_per_gfa'] = [util._get_ha(t['racen'], t['lst_deg'], t['mountdec_header']) for t in tab] tab['moon_sep_deg'] = util.moon_separation(tab['moonra'], tab['moondec'], tab['racen'], tab['deccen']) # per-camera zenith distance -- will only be accurate to the extent that # each camera's WCS recalibration succeeded tab['zd_deg_per_gfa'] = [util._zenith_distance(t['racen'], t['deccen'], t['lst_deg']) for t in tab] tab['header_airmass'] = exp.try_retrieve_header_card('AIRMASS', placeholder=np.nan) # this should make the airmass properly evolve # with time for guide cube outputs tab['airmass'] = 1.0/np.cos(tab['zenith_dist_deg']/(180.0/np.pi)) # this per-camera version of airmass should also evolve # properly with time for guide cube outputs tab['airmass_per_gfa'] = 1.0/np.cos(tab['zd_deg_per_gfa']/(180.0/np.pi)) tab['zp_adu_per_s'] = [exp.images[extname].compute_zeropoint(ps1) for extname in tab['camera']] tab['n_stars_for_zp'] = [(np.sum(ps1['use_for_zp'] & (ps1['extname'] == extname)).astype(int) if 'use_for_zp' in ps1.colnames else 0) for extname in tab['camera']] tab['transparency'] = [util.transparency_from_zeropoint(tab[i]['zp_adu_per_s'], tab[i]['airmass_per_gfa'], tab[i]['camera']) for i in range(len(tab))] par = common.gfa_misc_params() tab['kterm'] = np.float32(par['kterm']) tab['fracflux_nominal_pointsource'] = np.float32(par['fracflux_nominal_pointsource']) tab['fracflux_nominal_elg'] = np.float32(par['fracflux_nominal_elg']) tab['fracflux_nominal_bgs'] = np.float32(par['fracflux_nominal_bgs']) tab['det_sn_thresh'] = det_sn_thresh prescan_overscan_ccds_table(tab, exp) high_level_ccds_metrics(tab, catalog, exp) astrom_ccds_table(tab, exp) dark_current_ccds_table(tab, exp) if mjdrange is not None: tab['req_mjd_min'] = mjdrange[0] tab['req_mjd_max'] = mjdrange[1] return tab
def assemble_ccds_table(tab, catalog, exp, outdir, proc_obj, cube_index=None, ps1=None, det_sn_thresh=5.0, sky_mags=True, minimal=False): nrows = len(tab) tab['extname'] = tab['camera'] tab['contrast'] = [ exp.images[extname].header['CONTRAST'] for extname in tab['camera'] ] if minimal: return tab if sky_mags: tab['sky_mag_ab'] = [ exp.images[extname].sky_mag for extname in tab['camera'] ] amps = common.valid_amps_list() if sky_mags: sky_mag_ab_per_amp = np.zeros((nrows, len(amps)), dtype='float32') # 4 amps for i, extname in enumerate(tab['camera']): for j in range(len(amps)): _mag = np.nan if exp.images[ extname].sky_mag_per_amp is None else exp.images[ extname].sky_mag_per_amp[j] sky_mag_ab_per_amp[i, j] = _mag tab['sky_mag_ab_per_amp'] = sky_mag_ab_per_amp tab['petal_loc'] = np.array([ common.gfa_extname_to_gfa_number(extname) for extname in tab['camera'] ], dtype='uint8') tab['expid'] = [ exp.images[extname].header['EXPID'] for extname in tab['camera'] ] # should work except if early versions of guide cubes lacked # MJD information... tab['mjd'] = [ exp.images[extname].try_retrieve_meta_keyword('MJD-OBS', placeholder=0.0) for extname in tab['camera'] ] eph = util.load_lst() tab['lst_deg'] = [util.interp_lst(t['mjd'], eph=eph) for t in tab] tab['program'] = [ str(exp.images[extname].try_retrieve_meta_keyword('PROGRAM', placeholder='')) for extname in tab['camera'] ] tab['skyra'] = [ exp.images[extname].try_retrieve_meta_keyword('SKYRA', placeholder=np.nan) for extname in tab['camera'] ] tab['skydec'] = [ exp.images[extname].try_retrieve_meta_keyword('SKYDEC', placeholder=np.nan) for extname in tab['camera'] ] # zenith distance using approximate center of the field given by SKYRA, SKYDEC tab['zenith_dist_deg'] = [ util._zenith_distance(t['skyra'], t['skydec'], t['lst_deg']) for t in tab ] tab['domshutl'] = np.array( nrows * [exp.try_retrieve_header_card('DOMSHUTL', placeholder='')], dtype='U8') tab['domshutu'] = np.array( nrows * [exp.try_retrieve_header_card('DOMSHUTU', placeholder='')], dtype='U8') tab['pmcover'] = exp.try_retrieve_header_card('PMCOVER', placeholder='') tab['moonra'] = exp.try_retrieve_header_card('MOONRA', placeholder=np.nan) tab['moondec'] = exp.try_retrieve_header_card('MOONDEC', placeholder=np.nan) tab['t_c_for_dark'] = [ exp.images[extname].t_c_for_dark for extname in tab['camera'] ] tab['t_c_for_dark_is_guess'] = [ int(exp.images[extname].t_c_for_dark_is_guess) for extname in tab['camera'] ] tab['time_s_for_dark'] = [ exp.images[extname].time_s_for_dark for extname in tab['camera'] ] tab['night'] = exp.try_retrieve_header_card('NIGHT', placeholder='') tab['focus'] = exp.try_retrieve_header_card('FOCUS', placeholder='') tab['exptime'] = [ exp.images[extname].try_retrieve_meta_keyword('EXPTIME', placeholder=np.nan) for extname in tab['camera'] ] tab['cube_index'] = np.nan if cube_index is None else int(cube_index) if cube_index == -1: tab['coadd_index_start'] = [ exp.images[extname].coadd_index_range[0] for extname in tab['camera'] ] tab['coadd_index_end'] = [ exp.images[extname].coadd_index_range[1] for extname in tab['camera'] ] tab['racen'] = np.zeros(len(tab), dtype=float) tab['deccen'] = np.zeros(len(tab), dtype=float) tab['fname_raw'] = proc_obj.fname_in tab['gitrev'] = proc_obj.gitrev tab['fiber_fracflux'] = [(exp.images[extname].psf.fiber_fracflux if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['n_sources_for_psf'] = [(exp.images[extname].psf.nstars if exp.images[extname].psf is not None else 0) for extname in tab['camera']] # this pertains to aperture _3 which is 1.5 asec radius tab['aper_corr_fac'] = [(exp.images[extname].psf.aper_corr_fac if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['xcentroid_psf'] = [(exp.images[extname].psf.xcen_flux_weighted if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['ycentroid_psf'] = [(exp.images[extname].psf.ycen_flux_weighted if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_fwhm_pix'] = [(exp.images[extname].psf.moffat_fwhm_pix if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_fwhm_asec'] = [(exp.images[extname].psf.moffat_fwhm_asec if exp.images[extname].psf is not None else np.nan) for extname in tab['camera']] tab['psf_centroid_cbox'] = [ (float(exp.images[extname].psf.cbox) if exp.images[extname].psf is not None else np.nan) for extname in tab['camera'] ] tab['psf_centroid_failed'] = [ (exp.images[extname].psf.psf_centroiding_failed if exp.images[extname].psf is not None else 0) for extname in tab['camera'] ] for i, extname in enumerate(tab['camera']): racen, deccen = ccd_center_radec(exp.images[extname].wcs) tab['racen'][i] = racen tab['deccen'][i] = deccen tab['mountha_header'] = exp.try_retrieve_header_card('MOUNTHA', placeholder=np.nan) tab['mountdec_header'] = exp.try_retrieve_header_card('MOUNTDEC', placeholder=np.nan) tab['ha_deg'] = [ util._get_ha(t['skyra'], t['lst_deg'], t['mountdec_header']) for t in tab ] tab['ha_deg_per_gfa'] = [ util._get_ha(t['racen'], t['lst_deg'], t['mountdec_header']) for t in tab ] tab['moon_sep_deg'] = util.moon_separation(tab['moonra'], tab['moondec'], tab['racen'], tab['deccen']) # per-camera zenith distance -- will only be accurate to the extent that # each camera's WCS recalibration succeeded tab['zd_deg_per_gfa'] = [ util._zenith_distance(t['racen'], t['deccen'], t['lst_deg']) for t in tab ] tab['header_airmass'] = exp.try_retrieve_header_card('AIRMASS', placeholder=np.nan) # this should make the airmass properly evolve # with time for guide cube outputs tab['airmass'] = 1.0 / np.cos(tab['zenith_dist_deg'] / (180.0 / np.pi)) # this per-camera version of airmass should also evolve # properly with time for guide cube outputs tab['airmass_per_gfa'] = 1.0 / np.cos(tab['zd_deg_per_gfa'] / (180.0 / np.pi)) tab['zp_adu_per_s'] = [ exp.images[extname].compute_zeropoint(ps1) for extname in tab['camera'] ] tab['transparency'] = [ util.transparency_from_zeropoint(tab[i]['zp_adu_per_s'], tab[i]['airmass_per_gfa'], tab[i]['camera']) for i in range(len(tab)) ] tab['det_sn_thresh'] = det_sn_thresh prescan_overscan_ccds_table(tab, exp) high_level_ccds_metrics(tab, catalog, exp) astrom_ccds_table(tab, exp) dark_current_ccds_table(tab, exp) return tab