def run_pa(self, input_frame, psfbootfile, outfile, usesigma, linelist=None, npoly=2, nbins=2, domain=None): from desispec.quicklook.arcprocess import process_arc, write_psffile from desispec.quicklook.palib import get_resolution from desispec.psf import PSF wcoeffs = process_arc(input_frame, linelist=linelist, npoly=npoly, nbins=nbins, domain=domain) #- write out the psf outfile wstep = input_frame.meta["WAVESTEP"] write_psffile(psfbootfile, wcoeffs, outfile, wavestepsize=wstep) log.debug("Wrote psf file {}".format(outfile)) #- update the arc frame resolution from new coeffs newpsf = PSF(outfile) input_frame.resolution_data = get_resolution(input_frame.wave, input_frame.nspec, newpsf, usesigma=usesigma) return input_frame
def do_boxcar(image, psf, outwave, boxwidth=2.5, nspec=500, maskFile=None, usesigma=False): """Extracts spectra row by row, given the centroids Args: image : desispec.image object psf: desispec.psf.PSF like object Or do we just parse the traces here and write a separate wrapper to handle this? Leaving psf in the input argument now. outwave: wavelength array for the final spectra output boxwidth: HW box size in pixels usesigma: if True, use sigma from psfboot file(xsigma) or psf file (wsigma) to calculate resolution data. Returns flux, ivar, resolution """ import math from desispec.frame import Frame #wavelength=psf.wavelength() # (nspec,npix_y) def calcMask(psf): wmin = psf.wmin wmax = psf.wmax waves = np.arange(wmin, wmax, 0.25) xs = psf.x(None, waves) #- xtraces # doing the full image here. ys = psf.y(None, waves) #- ytraces camera = image.camera spectrograph = int(camera[1:]) #- first char is "r", "b", or "z" imshape = image.pix.shape mask = np.zeros((imshape[1], imshape[0])) maxx, maxy = mask.shape maxx = maxx - 1 maxy = maxy - 1 ranges = np.zeros((mask.shape[1], xs.shape[0] + 1), dtype=int) for bin in range(0, len(waves)): ixmaxold = 0 for spec in range(0, xs.shape[0]): xpos = xs[spec][bin] ypos = int(ys[spec][bin]) if xpos < 0 or xpos > maxx or ypos < 0 or ypos > maxy: continue xmin = xpos - boxwidth xmax = xpos + boxwidth ixmin = int(math.floor(xmin)) ixmax = int(math.floor(xmax)) if ixmin <= ixmaxold: print("Error Box width overlaps,", xpos, ypos, ixmin, ixmaxold) return None, None ixmaxold = ixmax if mask[int(xpos)][ypos] > 0: continue # boxing in x vals if ixmin < 0: #int value is less than 0 ixmin = 0 rxmin = 1.0 else: # take part of the bin depending on real xmin rxmin = 1.0 - xmin + ixmin if ixmax > maxx: # xmax is bigger than the image ixmax = maxx rxmax = 1.0 else: # take the part of the bin depending on real xmax rxmax = xmax - ixmax ranges[ypos][spec + 1] = math.ceil(xmax) #end at next column if ranges[ypos][spec] == 0: ranges[ypos][spec] = ixmin mask[ixmin][ypos] = rxmin for x in range(ixmin + 1, ixmax): mask[x][ypos] = 1.0 mask[ixmax][ypos] = rxmax for ypos in range(ranges.shape[0]): lastval = ranges[ypos][0] for sp in range(1, ranges.shape[1]): if ranges[ypos][sp] == 0: ranges[ypos][sp] = lastval lastval = ranges[ypos][sp] return mask, ranges if maskFile is not None: import os if os.path.exists(maskFile) and os.path.isfile(maskFile): f = open(maskFile, 'rb') npf = np.load(f) mask = npf['mask'] ranges = npf['ranges'] print("Loading mask from file %s" % maskFile) else: print( "Mask file is given but doesn't exist. Generating mask and saving to file %s" % maskFile) mask, ranges = calcMask(psf) try: f = open(maskFile, 'wb') np.savez(f, mask=mask, ranges=ranges) except: pass else: mask, ranges = calcMask(psf) maskedimg = (image.pix * mask.T) maskedvar = (1 / image.ivar.clip(0) * mask.T) flux = np.zeros((maskedimg.shape[0], ranges.shape[1] - 1)) ivar = np.zeros((maskedimg.shape[0], ranges.shape[1] - 1)) for r in range(flux.shape[0]): row = np.add.reduceat(maskedimg[r], ranges[r])[:-1] flux[r] = row vrow = np.add.reduceat(maskedvar[r], ranges[r])[:-1] ivar[r] = 1 / vrow wtarget = outwave #- limit nspec to psf.nspec max if nspec > psf.nspec: nspec = psf.nspec print("Warning! Extracting only {} spectra".format(psf.nspec)) fflux = np.zeros((nspec, len(wtarget))) iivar = np.zeros((nspec, len(wtarget))) #- convert to per angstrom first and then resample to desired wave length grid. for spec in range(nspec): ww = psf.wavelength(spec) dwave = np.gradient(ww) flux[:, spec] /= dwave ivar[:, spec] *= dwave**2 fflux[spec, :], iivar[spec, :] = resample_spec(ww, flux[:, spec], wtarget, ivar[:, spec]) #- Get resolution from the psf resolution = get_resolution(wtarget, nspec, psf, usesigma=usesigma) return fflux, iivar, resolution
def do_boxcar(image,tset,outwave,boxwidth=2.5,nspec=500,maskFile=None,usesigma=False, quick_resolution=False): """Extracts spectra row by row, given the centroids Args: image : desispec.image object tset: desispec.xytraceset like object outwave: wavelength array for the final spectra output boxwidth: HW box size in pixels usesigma: if True, use sigma from psf file (ysigma) to calculate resolution data. quick_resolution: whether to calculate the resolution matrix or use QuickResolution object Returns flux, ivar, resolution """ import math from desispec.frame import Frame #wavelength=psf.wavelength() # (nspec,npix_y) def calcMask(tset): wmin=tset.wavemin wmax=tset.wavemax waves=np.arange(wmin,wmax,0.25) xs=tset.x_vs_wave(np.arange(tset.nspec),waves) #- xtraces # doing the full image here. ys=tset.y_vs_wave(np.arange(tset.nspec),waves) #- ytraces camera=image.camera spectrograph=int(camera[1:]) #- first char is "r", "b", or "z" imshape=image.pix.shape mask=np.zeros((imshape[1],imshape[0])) maxx,maxy=mask.shape maxx=maxx-1 maxy=maxy-1 ranges=np.zeros((mask.shape[1],xs.shape[0]+1),dtype=int) for bin in range(0,len(waves)): ixmaxold=0 for spec in range(0,xs.shape[0]): xpos=xs[spec][bin] ypos=int(ys[spec][bin]) if xpos<0 or xpos>maxx or ypos<0 or ypos>maxy : continue xmin=xpos-boxwidth xmax=xpos+boxwidth ixmin=int(math.floor(xmin)) ixmax=int(math.floor(xmax)) if ixmin <= ixmaxold: print("Error Box width overlaps,",xpos,ypos,ixmin,ixmaxold) return None,None ixmaxold=ixmax if mask[int(xpos)][ypos]>0 : continue # boxing in x vals if ixmin < 0: #int value is less than 0 ixmin=0 rxmin=1.0 else:# take part of the bin depending on real xmin rxmin=1.0-xmin+ixmin if ixmax>maxx:# xmax is bigger than the image ixmax=maxx rxmax=1.0 else: # take the part of the bin depending on real xmax rxmax=xmax-ixmax ranges[ypos][spec+1]=math.ceil(xmax)#end at next column if ranges[ypos][spec]==0: ranges[ypos][spec]=ixmin mask[ixmin][ypos]=rxmin for x in range(ixmin+1,ixmax): mask[x][ypos]=1.0 mask[ixmax][ypos]=rxmax for ypos in range(ranges.shape[0]): lastval=ranges[ypos][0] for sp in range(1,ranges.shape[1]): if ranges[ypos][sp]==0: ranges[ypos][sp]=lastval lastval=ranges[ypos][sp] return mask,ranges if maskFile is not None: import os if os.path.exists(maskFile) and os.path.isfile(maskFile): f=open(maskFile,'rb') npf=np.load(f) mask=npf['mask'] ranges=npf['ranges'] print("Loading mask from file %s"%maskFile) else: print("Mask file is given but doesn't exist. Generating mask and saving to file %s"%maskFile) mask,ranges=calcMask(tset) try: f=open(maskFile,'wb') np.savez(f,mask=mask,ranges=ranges) except: pass else: mask,ranges=calcMask(tset) Tmask=mask.T maskedimg=(image.pix*Tmask) maskedvar=(Tmask/image.ivar.clip(1e-8)) flux=np.zeros((maskedimg.shape[0],ranges.shape[1]-1)) ivar=np.zeros((maskedimg.shape[0],ranges.shape[1]-1)) for r in range(flux.shape[0]): row=np.add.reduceat(maskedimg[r],ranges[r])[:-1] flux[r]=row vrow=np.add.reduceat(maskedvar[r],ranges[r])[:-1] ivar[r]=1/vrow wtarget=outwave #- limit nspec to tset.nspec max if nspec > tset.nspec: nspec=tset.nspec print("Warning! Extracting only {} spectra".format(tset.nspec)) fflux=np.zeros((nspec,len(wtarget))) iivar=np.zeros((nspec,len(wtarget))) #- convert to per angstrom first and then resample to desired wave length grid. for spec in range(nspec): ww=tset.wave_vs_y(spec,np.arange(0,tset.npix_y)) dwave=np.gradient(ww) flux[:,spec]/=dwave ivar[:,spec]*=dwave**2 fflux[spec,:],iivar[spec,:]=resample_spec(ww,flux[:,spec],wtarget,ivar[:,spec]) #- Get resolution from the psf resolution=get_resolution(wtarget,nspec,tset,usesigma=usesigma) return fflux,iivar,resolution