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 # 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) hdu.header['FLAVOR'] = flavor ci_extname = self.header['EXTNAME'] gain = common.ci_camera_gain(ci_extname) hdu.header['GAINA'] = (gain, '[e-/ADU] assumed gain') hdu.header['BUNIT'] = common.reduced_flavor_to_bunit(flavor) ci_num = common.ci_extname_to_ci_number(ci_extname) hdu.header['CINUM'] = (ci_num, 'CI# number from DESI-3347') return hdu
def calc_variance_adu(self, flatfield): assert (self.flatfielded) ci_extname = self.header['EXTNAME'] gain = common.ci_camera_gain(ci_extname) variance_adu_sq = self.var_e_sq / (gain**2) del self.var_e_sq self.var_e_sq = None variance_adu_sq *= (flatfield**2) assert (np.sum(variance_adu_sq <= 0) == 0) # note that I'm not currently taking into account uncertainty due # to the uncertainty on the flatfield; not sure if doing so would # be desirable eventually ivar_adu = 1.0 / variance_adu_sq assert (self.bitmask is not None) # zero out inverse variance of pixels with anything flagged in # data quality bitmask ivar_adu *= (self.bitmask == 0) self.ivar_adu = ivar_adu
def countrate_1flat(fname): # compute the count rate for one flat field image and also # the corresponding inverse variance # flat is already bias-subtracted flat, header = read_1flat(fname) t = header['ACTTIME'] # ADU/s countrate = flat / t gain = common.ci_camera_gain(ci_extname) # should probably also include a term for the random noise in the # master bias, which currently isn't all that small because only # 4 bias frames are available flat_var_adu_sq = (common.ci_camera_readnoise(ci_extname)**2 + \ flat*gain)/(gain**2) # make countrate_var a scalar to avoid per-pixel uncertainties that # would be biased high (low) for pixels that randomly scattered high (low) countrate_var = np.median(flat_var_adu_sq) / (t**2) countrate_ivar = 1.0 / countrate_var return countrate, countrate_ivar
def create_satmask(im, extname): # im is just a 2D array of pixels, not a CI_image object par = common.ci_misc_params() gain = common.ci_camera_gain(extname) sat_thresh = par['full_well_electrons'] / gain satmask = (im >= sat_thresh) return satmask
def calc_variance_e_squared(self): # at this stage the image ought to have been bias subtracted # but not flatfielded or dark subtracted assert (self.bias_subtracted) assert ((not self.dark_subtracted) and (not self.flatfielded)) ci_extname = self.header['EXTNAME'] gain = common.ci_camera_gain(ci_extname) var_e_sq = (common.ci_camera_readnoise(ci_extname)**2 + \ self.image*(self.image >= 0)*gain) assert (np.sum(var_e_sq <= 0) == 0) self.var_e_sq = var_e_sq
def total_dark_current_adu(ci_extname, acttime, t_celsius): """ accttime - actual exposure time in seconds t_celsius - temperature in deg celsius output is in ADU/pix """ assert (common.is_valid_image_extname(ci_extname)) assert (acttime >= 0) gain = common.ci_camera_gain(ci_extname) dark_e_per_pix = total_dark_current_electrons(acttime, t_celsius) dark_adu_per_pix = dark_e_per_pix / gain return dark_adu_per_pix
def adu_to_surface_brightness(sky_adu_1pixel, acttime, extname): """ convert from ADU (per pixel) to mag per square asec (AB) note that this is meant to be applied to an average sky value across an entire CI camera; this function does not take into account platescale variations within a camera """ if (sky_adu_1pixel <= 0) or (acttime <= 0): return np.nan par = common.ci_misc_params() pixel_area_sq_asec = util.nominal_pixel_area_sq_asec(extname) sky_adu_per_sq_asec = sky_adu_1pixel / pixel_area_sq_asec sky_adu_per_sec_sq_asec = sky_adu_per_sq_asec / acttime sky_e_per_sec_sq_asec = sky_adu_per_sec_sq_asec * common.ci_camera_gain( extname) return (par['nominal_zeropoint'] - 2.5 * np.log10(sky_e_per_sec_sq_asec))