def test_compare_specter(self): #- specter version psf = specter.psf.load_psf(self.psffile) for ispec in np.linspace(0, 499, 20).astype(int): spots, corners, psfparams = get_spots(ispec, 1, self.wavelengths, self.psfdata) xc, yc = corners ny, nx = spots.shape[2:4] for iwave, w in enumerate(self.wavelengths): xslice, yslice, pix = psf.xypix(ispec, w) self.assertEqual(pix.shape, (ny, nx)) self.assertEqual(xc[0, iwave], xslice.start) self.assertEqual(yc[0, iwave], yslice.start) self.assertTrue(np.allclose(spots[0, iwave], pix))
def compute_fiber_bundle_trace_shifts_using_psf(fibers, line, psf, image, maxshift=2.): """ Computes trace shifts along x and y from a preprocessed image, a PSF (with trace coords), and a given emission line, by doing a forward model of the image. Args: fibers : 1D array with list of fibers line : float, wavelength of an emission line (in Angstrom) psf : specter psf object image : DESI preprocessed image object Optional: maxshift : float maximum shift in pixels for 2D chi2 scan Returns: x : 1D array of x coordinates on CCD (axis=1 in numpy image array, AXIS=0 in FITS, cross-dispersion axis = fiber number direction) y : 1D array of y coordinates on CCD (axis=0 in numpy image array, AXIS=1 in FITS, wavelength dispersion axis) dx : 1D array of shifts along x coordinates on CCD dy : 1D array of shifts along y coordinates on CCD sx : 1D array of uncertainties on dx sy : 1D array of uncertainties on dy """ log = get_logger() #log.info("compute_fiber_bundle_offsets fibers={} line={}".format(fibers,line)) # get central coordinates of bundle for interpolation of offsets on CCD x, y = psf.xy([ int(np.median(fibers)), ], line) try: nfibers = len(fibers) # compute stamp coordinates xstart = None xstop = None ystart = None ystop = None xs = [] ys = [] pix = [] xx = [] yy = [] for fiber in fibers: txs, tys, tpix = psf.xypix(fiber, line) xs.append(txs) ys.append(tys) pix.append(tpix) if xstart is None: xstart = txs.start xstop = txs.stop ystart = tys.start ystop = tys.stop else: xstart = min(xstart, txs.start) xstop = max(xstop, txs.stop) ystart = min(ystart, tys.start) ystop = max(ystop, tys.stop) # load stamp data, with margins to avoid problems with shifted psf margin = int(maxshift) + 1 stamp = np.zeros( (ystop - ystart + 2 * margin, xstop - xstart + 2 * margin)) stampivar = np.zeros(stamp.shape) stamp[margin:-margin, margin:-margin] = image.pix[ystart:ystop, xstart:xstop] stampivar[margin:-margin, margin:-margin] = image.ivar[ystart:ystop, xstart:xstop] # will use a fixed footprint despite changes of psf stamps # so that chi2 always based on same data set footprint = np.zeros(stamp.shape) for i in range(nfibers): footprint[margin - ystart + ys[i].start:margin - ystart + ys[i].stop, margin - xstart + xs[i].start:margin - xstart + xs[i].stop] = 1 #plt.imshow(footprint) ; plt.show() ; sys.exit(12) # define grid of shifts to test res = 0.5 nshift = int(maxshift / res) dx = res * np.tile( np.arange(2 * nshift + 1) - nshift, (2 * nshift + 1, 1)) dy = dx.T original_shape = dx.shape dx = dx.ravel() dy = dy.ravel() chi2 = np.zeros(dx.shape) A = np.zeros((nfibers, nfibers)) B = np.zeros((nfibers)) mods = np.zeros(np.zeros(nfibers).shape + stamp.shape) debugging = False if debugging: # FOR DEBUGGING KEEP MODELS models = [] # loop on possible shifts # refit fluxes and compute chi2 for d in range(len(dx)): # print(d,dx[d],dy[d]) A *= 0 B *= 0 mods *= 0 for i, fiber in enumerate(fibers): # apply the PSF shift psf._cache = {} # reset cache !! psf.coeff['X']._coeff[fiber][0] += dx[d] psf.coeff['Y']._coeff[fiber][0] += dy[d] # compute pix and paste on stamp frame xx, yy, pix = psf.xypix(fiber, line) mods[i][margin - ystart + yy.start:margin - ystart + yy.stop, margin - xstart + xx.start:margin - xstart + xx.stop] = pix # undo the PSF shift psf.coeff['X']._coeff[fiber][0] -= dx[d] psf.coeff['Y']._coeff[fiber][0] -= dy[d] B[i] = np.sum(stampivar * stamp * mods[i]) for j in range(i + 1): A[i, j] = np.sum(stampivar * mods[i] * mods[j]) if j != i: A[j, i] = A[i, j] Ai = np.linalg.inv(A) flux = Ai.dot(B) model = np.zeros(stamp.shape) for i in range(nfibers): model += flux[i] * mods[i] chi2[d] = np.sum(stampivar * (stamp - model)**2) if debugging: models.append(model) if debugging: schi2 = chi2.reshape(original_shape).copy() # FOR DEBUGGING sdx = dx.copy() sdy = dy.copy() # find minimum chi2 grid point k = chi2.argmin() j, i = np.unravel_index(k, ((2 * nshift + 1), (2 * nshift + 1))) #print("node dx,dy=",dx.reshape(original_shape)[j,i],dy.reshape(original_shape)[j,i]) # cut a region around minimum delta = 1 istart = max(0, i - delta) istop = min(2 * nshift + 1, i + delta + 1) jstart = max(0, j - delta) jstop = min(2 * nshift + 1, j + delta + 1) chi2 = chi2.reshape(original_shape)[jstart:jstop, istart:istop].ravel() dx = dx.reshape(original_shape)[jstart:jstop, istart:istop].ravel() dy = dy.reshape(original_shape)[jstart:jstop, istart:istop].ravel() # fit 2D polynomial of deg2 m = np.array([dx * 0 + 1, dx, dy, dx**2, dy**2, dx * dy]).T c, r, rank, s = np.linalg.lstsq(m, chi2) if c[3] > 0 and c[4] > 0: # get minimum # dchi2/dx=0 : c[1]+2*c[3]*dx+c[5]*dy = 0 # dchi2/dy=0 : c[2]+2*c[4]*dy+c[5]*dx = 0 a = np.array([[2 * c[3], c[5]], [c[5], 2 * c[4]]]) b = np.array([c[1], c[2]]) t = -np.linalg.inv(a).dot(b) dx = t[0] dy = t[1] sx = 1. / np.sqrt(c[3]) sy = 1. / np.sqrt(c[4]) #print("interp dx,dy=",dx,dy) if debugging: # FOR DEBUGGING import matplotlib.pyplot as plt plt.figure() plt.subplot(2, 2, 1, title="chi2") plt.imshow(schi2, extent=(-nshift * res, nshift * res, -nshift * res, nshift * res), origin=0, interpolation="nearest") plt.plot(dx, dy, "+", color="white", ms=20) plt.xlabel("x") plt.ylabel("y") plt.subplot(2, 2, 2, title="data") plt.imshow(stamp * footprint, origin=0, interpolation="nearest") plt.grid() k0 = np.argmin(sdx**2 + sdy**2) plt.subplot(2, 2, 3, title="original psf") plt.imshow(models[k0], origin=0, interpolation="nearest") plt.grid() plt.subplot(2, 2, 4, title="shifted psf") plt.imshow(models[k], origin=0, interpolation="nearest") plt.grid() plt.show() else: log.warning( "fit failed (bad chi2 surf.) for fibers [%d:%d] line=%dA" % (fibers[0], fibers[-1] + 1, int(line))) dx = 0. dy = 0. sx = 10. sy = 10. except LinAlgError: log.warning( "fit failed (masked or missing data) for fibers [%d:%d] line=%dA" % (fibers[0], fibers[-1] + 1, int(line))) dx = 0. dy = 0. sx = 10. sy = 10. return x, y, dx, dy, sx, sy
elif cam == "z": camid = 2 expnum = int(os.path.basename(filename).split("-")[2].replace(".fits", "")) for fiber in fibers: tx = psf.x(fiber, args.wave) ty = psf.y(fiber, args.wave) dtx = tx - reftx[fiber] dty = ty - refty[fiber] psf._cache = {} # reset cache !! psf.coeff['X']._coeff[fiber][0] -= dtx psf.coeff['Y']._coeff[fiber][0] -= dty xx, yy, img = psf.xypix(fiber, args.wave) cx = np.sum(xpix * img) / np.sum(img) cy = np.sum(ypix * img) / np.sum(img) sx = np.sqrt(np.sum((xpix - cx)**2 * img) / np.sum(img)) sy = np.sqrt(np.sum((ypix - cy)**2 * img) / np.sum(img)) ebias = np.sum(refimage[fiber] * img) / np.sum(img**2) - 1. line = "%d %d %d %d" % (expnum, camid, fiber, args.wave) line += " %f %f %f %f %f %f %f" % (dtx, dty, cx, cy, sx, sy, ebias) #print(line) sys.stdout.flush() ofile.write("%s\n" % line) ofile.close()
def compute_fiber_bundle_trace_shifts_using_psf(fibers,line,psf,image,maxshift=2.) : """ Computes trace shifts along x and y from a preprocessed image, a PSF (with trace coords), and a given emission line, by doing a forward model of the image. Args: fibers : 1D array with list of fibers line : float, wavelength of an emission line (in Angstrom) psf : specter psf object image : DESI preprocessed image object Optional: maxshift : float maximum shift in pixels for 2D chi2 scan Returns: x : 1D array of x coordinates on CCD (axis=1 in numpy image array, AXIS=0 in FITS, cross-dispersion axis = fiber number direction) y : 1D array of y coordinates on CCD (axis=0 in numpy image array, AXIS=1 in FITS, wavelength dispersion axis) dx : 1D array of shifts along x coordinates on CCD dy : 1D array of shifts along y coordinates on CCD sx : 1D array of uncertainties on dx sy : 1D array of uncertainties on dy """ log=get_logger() #log.info("compute_fiber_bundle_offsets fibers={} line={}".format(fibers,line)) # get central coordinates of bundle for interpolation of offsets on CCD x,y = psf.xy([int(np.median(fibers)),],line) try : nfibers=len(fibers) # compute stamp coordinates xstart=None xstop=None ystart=None ystop=None xs=[] ys=[] pix=[] xx=[] yy=[] for fiber in fibers : txs,tys,tpix = psf.xypix(fiber,line) xs.append(txs) ys.append(tys) pix.append(tpix) if xstart is None : xstart =txs.start xstop =txs.stop ystart =tys.start ystop =tys.stop else : xstart =min(xstart,txs.start) xstop =max(xstop,txs.stop) ystart =min(ystart,tys.start) ystop =max(ystop,tys.stop) # load stamp data, with margins to avoid problems with shifted psf margin=int(maxshift)+1 stamp=np.zeros((ystop-ystart+2*margin,xstop-xstart+2*margin)) stampivar=np.zeros(stamp.shape) stamp[margin:-margin,margin:-margin]=image.pix[ystart:ystop,xstart:xstop] stampivar[margin:-margin,margin:-margin]=image.ivar[ystart:ystop,xstart:xstop] # will use a fixed footprint despite changes of psf stamps # so that chi2 always based on same data set footprint=np.zeros(stamp.shape) for i in range(nfibers) : footprint[margin-ystart+ys[i].start:margin-ystart+ys[i].stop,margin-xstart+xs[i].start:margin-xstart+xs[i].stop]=1 #plt.imshow(footprint) ; plt.show() ; sys.exit(12) # define grid of shifts to test res=0.5 nshift=int(maxshift/res) dx=res*np.tile(np.arange(2*nshift+1)-nshift,(2*nshift+1,1)) dy=dx.T original_shape=dx.shape dx=dx.ravel() dy=dy.ravel() chi2=np.zeros(dx.shape) A=np.zeros((nfibers,nfibers)) B=np.zeros((nfibers)) mods=np.zeros(np.zeros(nfibers).shape+stamp.shape) debugging=False if debugging : # FOR DEBUGGING KEEP MODELS models=[] # loop on possible shifts # refit fluxes and compute chi2 for d in range(len(dx)) : # print(d,dx[d],dy[d]) A *= 0 B *= 0 mods *= 0 for i,fiber in enumerate(fibers) : # apply the PSF shift psf._cache={} # reset cache !! psf.coeff['X']._coeff[fiber][0] += dx[d] psf.coeff['Y']._coeff[fiber][0] += dy[d] # compute pix and paste on stamp frame xx, yy, pix = psf.xypix(fiber,line) mods[i][margin-ystart+yy.start:margin-ystart+yy.stop,margin-xstart+xx.start:margin-xstart+xx.stop]=pix # undo the PSF shift psf.coeff['X']._coeff[fiber][0] -= dx[d] psf.coeff['Y']._coeff[fiber][0] -= dy[d] B[i] = np.sum(stampivar*stamp*mods[i]) for j in range(i+1) : A[i,j] = np.sum(stampivar*mods[i]*mods[j]) if j!=i : A[j,i] = A[i,j] Ai=np.linalg.inv(A) flux=Ai.dot(B) model=np.zeros(stamp.shape) for i in range(nfibers) : model += flux[i]*mods[i] chi2[d]=np.sum(stampivar*(stamp-model)**2) if debugging : models.append(model) if debugging : schi2=chi2.reshape(original_shape).copy() # FOR DEBUGGING sdx=dx.copy() sdy=dy.copy() # find minimum chi2 grid point k = chi2.argmin() j,i = np.unravel_index(k, ((2*nshift+1),(2*nshift+1))) #print("node dx,dy=",dx.reshape(original_shape)[j,i],dy.reshape(original_shape)[j,i]) # cut a region around minimum delta=1 istart=max(0,i-delta) istop=min(2*nshift+1,i+delta+1) jstart=max(0,j-delta) jstop=min(2*nshift+1,j+delta+1) chi2=chi2.reshape(original_shape)[jstart:jstop,istart:istop].ravel() dx=dx.reshape(original_shape)[jstart:jstop,istart:istop].ravel() dy=dy.reshape(original_shape)[jstart:jstop,istart:istop].ravel() # fit 2D polynomial of deg2 m = np.array([dx*0+1, dx, dy, dx**2, dy**2, dx*dy ]).T c, r, rank, s = np.linalg.lstsq(m, chi2) if c[3]>0 and c[4]>0 : # get minimum # dchi2/dx=0 : c[1]+2*c[3]*dx+c[5]*dy = 0 # dchi2/dy=0 : c[2]+2*c[4]*dy+c[5]*dx = 0 a=np.array([[2*c[3],c[5]],[c[5],2*c[4]]]) b=np.array([c[1],c[2]]) t=-np.linalg.inv(a).dot(b) dx=t[0] dy=t[1] sx=1./np.sqrt(c[3]) sy=1./np.sqrt(c[4]) #print("interp dx,dy=",dx,dy) if debugging : # FOR DEBUGGING import matplotlib.pyplot as plt plt.figure() plt.subplot(2,2,1,title="chi2") plt.imshow(schi2,extent=(-nshift*res,nshift*res,-nshift*res,nshift*res),origin=0,interpolation="nearest") plt.plot(dx,dy,"+",color="white",ms=20) plt.xlabel("x") plt.ylabel("y") plt.subplot(2,2,2,title="data") plt.imshow(stamp*footprint,origin=0,interpolation="nearest") plt.grid() k0=np.argmin(sdx**2+sdy**2) plt.subplot(2,2,3,title="original psf") plt.imshow(models[k0],origin=0,interpolation="nearest") plt.grid() plt.subplot(2,2,4,title="shifted psf") plt.imshow(models[k],origin=0,interpolation="nearest") plt.grid() plt.show() else : log.warning("fit failed (bad chi2 surf.) for fibers [%d:%d] line=%dA"%(fibers[0],fibers[-1]+1,int(line))) dx=0. dy=0. sx=10. sy=10. except LinAlgError : log.warning("fit failed (masked or missing data) for fibers [%d:%d] line=%dA"%(fibers[0],fibers[-1]+1,int(line))) dx=0. dy=0. sx=10. sy=10. return x,y,dx,dy,sx,sy
res_fiber=[] res_wave=[] res_x_rms=[] res_y_rms=[] use_trace = True for fiber in fibers : for wave in waves : images = [] i0 = [] i1 = [] xc = [] yc = [] for psf in psfs : xx, yy, ccdpix = psf.xypix(fiber,wave) xc.append(psf.x(fiber,wave)) yc.append(psf.y(fiber,wave)) #print("fiber,wave",fiber,wave) #print("xx",xx) #print("yy",yy) #plt.imshow(ccdpix) #plt.show() images.append(ccdpix) i1.append(xx.start) i0.append(yy.start)
default=None, required=False, help='path to output image (png) file') args = parser.parse_args() psf = specter.psf.GaussHermitePSF(args.psf) wave = np.linspace(psf.wmin + 200, psf.wmax - 200, 15) zoom = 18 image = np.zeros((psf.npix_y / zoom, psf.npix_x / zoom)) for fiber in range(psf.nspec): for wavelength in wave: print(fiber, wavelength) x, y = psf.xy(fiber, wavelength) xslice, yslice, pix = psf.xypix(fiber, wavelength) xslice = slice(xslice.start + int(x / zoom - x), xslice.stop + int(x / zoom - x)) yslice = slice(yslice.start + int(y / zoom - y), yslice.stop + int(y / zoom - y)) try: image[yslice, xslice] += pix except ValueError: print("failed for fiber wave=", fiber, wavelength) pass fig = pylab.figure() pylab.imshow(image, origin=0, interpolation="nearest",
psf=specter.psf.GaussHermitePSF(args.psf) wmin=max(3650,psf.wmin+500) wmax=min(10200,psf.wmax-500) wave=np.linspace(wmin,wmax,15) zoom_out=32 image=np.zeros((psf.npix_y//zoom_out,psf.npix_x//zoom_out)) fibers=10+20*np.arange(25) for fiber in fibers : for wavelength in wave : print(fiber,wavelength) x,y = psf.xy(fiber,wavelength) xslice,yslice,pix = psf.xypix(fiber,wavelength) #dx=xslice.stop-xslice.start #dy=yslice.stop-yslice.start dx=(x/zoom_out-x) dy=(y/zoom_out-y) idx=int(dx+0.5) idy=int(dy+0.5) ipix=np.zeros(pix.shape) x=np.arange(xslice.start,xslice.stop)+idx y=np.arange(yslice.start,yslice.stop)+idy f=scipy.interpolate.interp2d(x,y,pix) ipix = f(x+(idx-dx), y+(idy-dy)) xslice = slice(xslice.start+idx,xslice.stop+idx) yslice = slice(yslice.start+idy,yslice.stop+idy)
res_fiber = [] res_wave = [] res_x_rms = [] res_y_rms = [] use_trace = True for fiber in fibers: for wave in waves: images = [] i0 = [] i1 = [] xc = [] yc = [] for psf in psfs: xx, yy, ccdpix = psf.xypix(fiber, wave) xc.append(psf.x(fiber, wave)) yc.append(psf.y(fiber, wave)) #print("fiber,wave",fiber,wave) #print("xx",xx) #print("yy",yy) #plt.imshow(ccdpix) #plt.show() images.append(ccdpix) i1.append(xx.start) i0.append(yy.start) mi0 = int(np.min(i0)) mi1 = int(np.min(i1))