def simarc(arcdata, nspec=5000, nonuniform=False, testslit=False): ''' Simulates an arc lamp exposure (CCD pixel to wavelength calibration). Args: arcdata: Table with columns VACUUM_WAVE and ELECTRONS Options: nspec: (int) number of spectra to simulate nonuniform: (bool) include calibration screen non-uniformity Returns: (wave, phot, fibermap) wave: 1D[nwave] wavelengths in Angstroms phot: 2D[nspec, nwave] photons observed by CCD (i.e. electrons) fibermap: fibermap Table Note: this bypasses specsim since we don't have an arclamp model in surface brightness units; we only have electrons on the CCD. But it does include the effect of varying fiber sizes. TODO: * add exptime support * update inputs to surface brightness and DESI lamp lines (DESI-2674) ''' wave = arcdata['VACUUM_WAVE'] phot = arcdata['ELECTRONS'] if testslit: fibermap = astropy.table.Table(testslit_fibermap()[0:nspec]) else: fibermap = astropy.table.Table(desispec.io.empty_fibermap(nspec)) fibermap.meta['FLAVOR'] = 'arc' fibermap['OBJTYPE'] = 'ARC' x = fibermap['X_TARGET'] y = fibermap['Y_TARGET'] r = np.sqrt(x**2 + y**2) #- Determine ratio of fiber sizes relative to largest fiber fiber_area = fiber_area_arcsec2(fibermap['X_TARGET'], fibermap['Y_TARGET']) size_ratio = fiber_area / np.max(fiber_area) #- Correct photons for fiber size phot = np.tile(phot, nspec).reshape(nspec, len(wave)) phot = (phot.T * size_ratio).T #- Apply calibration screen non-uniformity if nonuniform: ratio = _calib_screen_uniformity(radius=r) assert np.all(ratio <= 1) and np.all(ratio > 0.99) phot = (phot.T * ratio).T return wave, phot, fibermap
def exposure_fiberflat(channel, expid, metric, outfile=None): """ Generate an Exposure level plot of a FiberFlat metric Args: channel: str, e.g. 'b', 'r', 'z' expid: int metric: str, allowed entires are: ['meanflux'] Returns: """ from desispec.io.meta import find_exposure_night, findfile from desispec.io.frame import read_meta_frame, read_frame from desispec.io.fiberflat import read_fiberflat from desimodel.focalplane import fiber_area_arcsec2 log = get_logger() # Find exposure night = find_exposure_night(expid) # Search for frames with the input channel frame0 = findfile('frame', camera=channel+'0', night=night, expid=expid) if not os.path.exists(frame0): log.fatal("No Frame 0 for channel={:s} and expid={:d}".format(channel, expid)) # Confirm frame is a Flat fmeta = read_meta_frame(frame0) assert fmeta['FLAVOR'].strip() == 'flat' # Load up all the frames x,y,metrics = [],[],[] for wedge in range(10): # Load frame_file = findfile('frame', camera=channel+'{:d}'.format(wedge), night=night, expid=expid) fiber_file = findfile('fiberflat', camera=channel+'{:d}'.format(wedge), night=night, expid=expid) try: frame = read_frame(frame_file) except: continue else: fiberflat = read_fiberflat(fiber_file) fibermap = frame.fibermap gdp = fiberflat.mask == 0 # X,Y x.append([fibermap['X_TARGET']]) y.append([fibermap['Y_TARGET']]) area = fiber_area_arcsec2(x[-1], y[-1]) mean_area = np.mean(area) # Metric if metric == 'meanflux': mean_norm = np.mean(fiberflat.fiberflat*gdp,axis=1) / (area / mean_area) metrics.append([mean_norm]) # Cocatenate x = np.concatenate(x) y = np.concatenate(y) metrics = np.concatenate(metrics) # Plot if outfile is None: outfile='qa_{:08d}_{:s}_fiberflat.png'.format(expid, channel) exposure_map(x,y,metrics, mlbl='Mean Flux', title='Mean Flux for Exposure {:08d}, Channel {:s}'.format(expid, channel), outfile=outfile)
def qa_fiberflat(param, frame, fiberflat): """ Calculate QA on FiberFlat object Args: param: dict of QA parameters frame: Frame fiberflat: FiberFlat Returns: qadict: dict of QA outputs Need to record simple Python objects for yaml (str, float, int) """ from desimodel.focalplane import fiber_area_arcsec2 log = get_logger() # x, y, area fibermap = frame.fibermap x = fibermap['X_TARGET'] y = fibermap['Y_TARGET'] area = fiber_area_arcsec2(x, y) mean_area = np.mean(area) norm_area = area / mean_area npix = fiberflat.fiberflat.shape[1] # Normalize norm_flat = fiberflat.fiberflat / np.outer(norm_area, np.ones(npix)) # Output dict qadict = {} # Check amplitude of the meanspectrum qadict['MAX_MEANSPEC'] = float(np.max(fiberflat.meanspec)) if qadict['MAX_MEANSPEC'] < 100000: log.warning("Low counts in meanspec = {:g}".format( qadict['MAX_MEANSPEC'])) # Record chi2pdf try: qadict['CHI2PDF'] = float(fiberflat.chi2pdf) except TypeError: qadict['CHI2PDF'] = 0. # N mask qadict['N_MASK'] = int(np.sum(fiberflat.mask > 0)) if qadict['N_MASK'] > param['MAX_N_MASK']: # Arbitrary log.warning("High rejection rate: {:d}".format(qadict['N_MASK'])) # Scale (search for low/high throughput) gdp = fiberflat.mask == 0 rtio = (frame.flux / np.outer(norm_area, np.ones(npix))) / np.outer( np.ones(fiberflat.nspec), fiberflat.meanspec) scale = np.median(rtio * gdp, axis=1) MAX_SCALE_OFF = float(np.max(np.abs(scale - 1.))) fiber = int(np.argmax(np.abs(scale - 1.))) qadict['MAX_SCALE_OFF'] = [MAX_SCALE_OFF, fiber] if qadict['MAX_SCALE_OFF'][0] > param['MAX_SCALE_OFF']: log.warning("Discrepant flux in fiberflat: {:g}, {:d}".format( qadict['MAX_SCALE_OFF'][0], qadict['MAX_SCALE_OFF'][1])) # Offset in fiberflat qadict['MAX_OFF'] = float(np.max(np.abs(norm_flat - 1.))) if qadict['MAX_OFF'] > param['MAX_OFF']: log.warning("Large offset in fiberflat: {:g}".format( qadict['MAX_OFF'])) # Offset in mean of fiberflat #mean = np.mean(fiberflat.fiberflat*gdp,axis=1) mean = np.mean(norm_flat * gdp, axis=1) fiber = int(np.argmax(np.abs(mean - 1.))) qadict['MAX_MEAN_OFF'] = [float(np.max(np.abs(mean - 1.))), fiber] if qadict['MAX_MEAN_OFF'][0] > param['MAX_MEAN_OFF']: log.warning("Discrepant mean in fiberflat: {:g}, {:d}".format( qadict['MAX_MEAN_OFF'][0], qadict['MAX_MEAN_OFF'][1])) # RMS in individual fibers rms = np.std(gdp * (norm_flat - np.outer(mean, np.ones(fiberflat.nwave))), axis=1) #rms = np.std(gdp*(fiberflat.fiberflat- # np.outer(mean, np.ones(fiberflat.nwave))),axis=1) fiber = int(np.argmax(rms)) qadict['MAX_RMS'] = [float(np.max(rms)), fiber] if qadict['MAX_RMS'][0] > param['MAX_RMS']: log.warning("Large RMS in fiberflat: {:g}, {:d}".format( qadict['MAX_RMS'][0], qadict['MAX_RMS'][1])) # Return return qadict
def qa_fiberflat(param, frame, fiberflat): """ Calculate QA on FiberFlat object Args: param: dict of QA parameters frame: Frame fiberflat: FiberFlat Returns: qadict: dict of QA outputs Need to record simple Python objects for yaml (str, float, int) """ from desimodel.focalplane import fiber_area_arcsec2 log = get_logger() # x, y, area fibermap = frame.fibermap x = fibermap['DESIGN_X'] y = fibermap['DESIGN_Y'] area = fiber_area_arcsec2(x, y) mean_area = np.mean(area) norm_area = area / mean_area npix = fiberflat.fiberflat.shape[1] # Normalize norm_flat = fiberflat.fiberflat / np.outer(norm_area, np.ones(npix)) # Output dict qadict = {} # Check amplitude of the meanspectrum qadict['MAX_MEANSPEC'] = float(np.max(fiberflat.meanspec)) if qadict['MAX_MEANSPEC'] < 100000: log.warning("Low counts in meanspec = {:g}".format(qadict['MAX_MEANSPEC'])) # Record chi2pdf try: qadict['CHI2PDF'] = float(fiberflat.chi2pdf) except TypeError: qadict['CHI2PDF'] = 0. # N mask qadict['N_MASK'] = int(np.sum(fiberflat.mask > 0)) if qadict['N_MASK'] > param['MAX_N_MASK']: # Arbitrary log.warning("High rejection rate: {:d}".format(qadict['N_MASK'])) # Scale (search for low/high throughput) gdp = fiberflat.mask == 0 rtio = (frame.flux / np.outer(norm_area, np.ones(npix))) / np.outer(np.ones(fiberflat.nspec),fiberflat.meanspec) scale = np.median(rtio*gdp,axis=1) MAX_SCALE_OFF = float(np.max(np.abs(scale-1.))) fiber = int(np.argmax(np.abs(scale-1.))) qadict['MAX_SCALE_OFF'] = [MAX_SCALE_OFF, fiber] if qadict['MAX_SCALE_OFF'][0] > param['MAX_SCALE_OFF']: log.warning("Discrepant flux in fiberflat: {:g}, {:d}".format( qadict['MAX_SCALE_OFF'][0], qadict['MAX_SCALE_OFF'][1])) # Offset in fiberflat qadict['MAX_OFF'] = float(np.max(np.abs(norm_flat-1.))) if qadict['MAX_OFF'] > param['MAX_OFF']: log.warning("Large offset in fiberflat: {:g}".format(qadict['MAX_OFF'])) # Offset in mean of fiberflat #mean = np.mean(fiberflat.fiberflat*gdp,axis=1) mean = np.mean(norm_flat*gdp,axis=1) fiber = int(np.argmax(np.abs(mean-1.))) qadict['MAX_MEAN_OFF'] = [float(np.max(np.abs(mean-1.))), fiber] if qadict['MAX_MEAN_OFF'][0] > param['MAX_MEAN_OFF']: log.warning("Discrepant mean in fiberflat: {:g}, {:d}".format( qadict['MAX_MEAN_OFF'][0], qadict['MAX_MEAN_OFF'][1])) # RMS in individual fibers rms = np.std(gdp*(norm_flat - np.outer(mean, np.ones(fiberflat.nwave))),axis=1) #rms = np.std(gdp*(fiberflat.fiberflat- # np.outer(mean, np.ones(fiberflat.nwave))),axis=1) fiber = int(np.argmax(rms)) qadict['MAX_RMS'] = [float(np.max(rms)), fiber] if qadict['MAX_RMS'][0] > param['MAX_RMS']: log.warning("Large RMS in fiberflat: {:g}, {:d}".format( qadict['MAX_RMS'][0], qadict['MAX_RMS'][1])) # Return return qadict
def frame_fiberflat(outfil, qaframe, frame, fiberflat): """ QA plots for fiber flat Args: outfil: qaframe: frame: fiberflat: Returns: Stuff? """ from desimodel.focalplane import fiber_area_arcsec2 # Setup fibermap = frame.fibermap gdp = fiberflat.mask == 0 nfiber = len(frame.fibers) xfiber = np.zeros(nfiber) yfiber = np.zeros(nfiber) for ii,fiber in enumerate(frame.fibers): mt = np.where(fiber == fibermap['FIBER'])[0] xfiber[ii] = fibermap['X_TARGET'][mt] yfiber[ii] = fibermap['Y_TARGET'][mt] area = fiber_area_arcsec2(xfiber,yfiber) mean_area = np.mean(area) jet = cm = plt.get_cmap('jet') # Tile plot(s) fig = plt.figure(figsize=(8, 5.0)) gs = gridspec.GridSpec(2,2) # Mean Flatfield flux in each fiber ax = plt.subplot(gs[0,0]) ax.xaxis.set_major_locator(plt.MultipleLocator(100.)) mean_flux = np.mean(frame.flux*gdp, axis=1) / fiber_area_arcsec2(xfiber,yfiber) rms_mean = np.std(mean_flux) med_mean = np.median(mean_flux) #from xastropy.xutils import xdebug as xdb #pdb.set_trace() mplt = ax.scatter(xfiber, yfiber, marker='o', s=9., c=mean_flux, cmap=jet) mplt.set_clim(vmin=med_mean-2*rms_mean, vmax=med_mean+2*rms_mean) cb = fig.colorbar(mplt) cb.set_label('Mean Flux') # Mean ax = plt.subplot(gs[0,1]) ax.xaxis.set_major_locator(plt.MultipleLocator(100.)) mean_norm = np.mean(fiberflat.fiberflat*gdp,axis=1) / (area/mean_area) m2plt = ax.scatter(xfiber, yfiber, marker='o', s=9., c=mean_norm, cmap=jet) #m2plt.set_clim(vmin=0.98, vmax=1.02) cb = fig.colorbar(m2plt) cb.set_label('Mean of Fiberflat') # RMS ax = plt.subplot(gs[1,0]) ax.xaxis.set_major_locator(plt.MultipleLocator(100.)) rms = np.std(gdp*(fiberflat.fiberflat- np.outer(mean_norm, np.ones(fiberflat.nwave))),axis=1) rplt = ax.scatter(xfiber, yfiber, marker='o', s=9., c=rms, cmap=jet) #rplt.set_clim(vmin=0.98, vmax=1.02) cb = fig.colorbar(rplt) cb.set_label('RMS in Fiberflat') # Meta text ax2 = plt.subplot(gs[1,1]) ax2.set_axis_off() show_meta(ax2, qaframe, 'FIBERFLAT', outfil) """ xlbl = 0.05 ylbl = 0.85 i0 = outfil.rfind('/') ax2.text(xlbl, ylbl, outfil[i0+1:], color='black', transform=ax2.transAxes, ha='left') yoff=0.10 for key in sorted(qaframe.data['FIBERFLAT']['METRICS'].keys()): if key in ['QA_FIG']: continue # Show ylbl -= yoff ax2.text(xlbl+0.05, ylbl, key+': '+str(qaframe.data['FIBERFLAT']['METRICS'][key]), transform=ax2.transAxes, ha='left', fontsize='x-small') """ # Finish plt.tight_layout(pad=0.1,h_pad=0.0,w_pad=0.0) _ = makepath(outfil) plt.savefig(outfil) plt.close() print('Wrote QA SkyRes file: {:s}'.format(outfil))