def cdriver(method, data, guess, trim, radius, size, mask=None, uncd=None, fitbg=1, maskstar=True, expand=5.0, psf=None, psfctr=None): # Default mask: all good if mask is None: mask = np.ones(np.shape(data)) # Default uncertainties: flat image if uncd is None: uncd = np.ones(np.shape(data)) # Trim the image if requested if trim != 0: # Integer part of center cen = np.rint(guess) # Center in the trimed image loc = (trim, trim) # Do the trim: img, msk, err = ie.trimimage(data, cen, loc, mask=mask, uncd=uncd) else: cen = np.array([0,0]) loc = np.rint(guess) img, msk, err = data, mask, uncd # If all data is bad: if not np.any(msk): raise Exception('Bad Frame Exception!') weights = 1.0/np.abs(err) # Get the center with one of the methods: if method == 'fgc': foo, bar = g.fitgaussian(img, yxguess=loc, mask=msk, weights=weights, fitbg=fitbg, maskg=maskstar) #print(foo, bar) y, x = foo[2:4] yerr, xerr = bar[2:4] # Make trimming correction and return return ((y, x) + cen - trim), (yerr, xerr)
def centerdriver(method, data, guess, trim, radius, size, mask=None, uncd=None, fitbg=1, maskstar=True, expand=5.0, psf=None, psfctr=None): """ Use the center method to find the center of a star in data, starting from position guess. Parameters: ----------- method: string Name of the centering method to use. data: 2D ndarray Array containing the star image. guess: 2 elements 1D array y, x initial guess position of the target. trim: integer Semi-length of the box around the target that will be trimmed. radius: float least asymmetry parameter. See err_fasym_c. size: float least asymmetry parameter. See err_fasym_c. mask: 2D ndarray A mask array of bad pixels. Same shape of data. uncd: 2D ndarray An array containing the uncertainty values of data. Same shape of data. Returns: -------- A y,x tuple (scalars) with the coordinates of center of the target in data. Example: -------- nica Modification History: --------------------- 23-11-2010 patricio Written by Patricio Cubillos [email protected] """ # Default mask: all good if mask is None: mask = np.ones(np.shape(data)) # Default uncertainties: flat image if uncd is None: uncd = np.ones(np.shape(data)) # Trim the image if requested if trim != 0: # Integer part of center cen = np.rint(guess) # Center in the trimed image loc = (trim, trim) # Do the trim: img, msk, err = ie.trimimage(data, cen, loc, mask=mask, uncd=uncd) else: cen = np.array([0, 0]) loc = np.rint(guess) img, msk, err = data, mask, uncd # If all data is bad: if not np.any(msk): raise Exception('Bad Frame Exception!') weights = 1.0 / np.abs(err) extra = [] # Get the center with one of the methods: if method == 'fgc': sy, sx, y, x = g.fitgaussian(img, yxguess=loc, mask=msk, weights=weights, fitbg=fitbg, maskg=maskstar)[0][0:4] extra = sy, sx #Gaussian 1-sigma half-widths elif method == 'col': y, x = ctr.col(img) elif method == 'lag': [y, x], asym = la.actr(img, loc, asym_rad=radius, asym_size=size, method='gaus') #y, x = ctr.actr(img, loc, asym_rad=radius, # asym_size=size, method='gaus') elif method == 'lac': [y, x], asym = la.actr(img, loc, asym_rad=radius, asym_size=size, method='col') elif method == 'bpf' or method == 'ipf': y, x, flux, sky = pf.spitzer_fit(img, msk, weights, psf, psfctr, expand, method) extra = flux, sky # Make trimming correction and return return ((y, x) + cen - trim), extra
def centerdriver(method, data, guess, trim, radius, size, mask=None, uncd=None, fitbg=1, maskstar=True, expand=5.0, psf=None, psfctr=None, noisepix=False, npskyrad=(0, 0)): """ Use the center method to find the center of a star in data, starting from position guess. Parameters: ----------- method: string Name of the centering method to use. data: 2D ndarray Array containing the star image. guess: 2 element 1D array y, x initial guess position of the target. trim: integer Semi-length of the box around the target that will be trimmed. radius: float Least-asymmetry parameter. See err_fasym_c. size: float Least-asymmetry parameter. See err_fasym_c. mask: 2D ndarray A mask array of bad pixels. Same shape as data. uncd: 2D ndarray An array containing the uncertainty values of data. Same shape as data. noisepix: bool Boolean flag to calculate and return noise pixels. npskyrad: 2 element iterable Radius of sky annuli used in noise pixel calculation Returns: -------- A y,x tuple (scalars) with the coordinates of center of the target in data. Example: -------- nica Modification History: --------------------- 2010-11-23 patricio Written by Patricio Cubillos [email protected] 2016-12-11 jh Fixed None comparisons. Cleaned up docstring. 2018-01-05 zacchaeus updated for python3 [email protected] """ # Default mask: all good if type(mask) == type(None): mask = np.ones(np.shape(data)) # Default uncertainties: flat image if type(uncd) == type(None): uncd = np.ones(np.shape(data)) # Trim the image if requested if trim != 0: # Integer part of center cen = np.rint(guess) # Center in the trimed image loc = (trim, trim) # Do the trim: img, msk, err = ie.trimimage(data, cen[0], cen[1], loc[0], loc[1], mask=mask, uncd=uncd) else: cen = np.array([0, 0]) loc = np.rint(guess) img, msk, err = data, mask, uncd # If all data is bad: if not np.any(msk): raise Exception('Bad Frame Exception!') weights = 1.0 / np.abs(err) extra = [] # Get the center with one of the methods: if method == 'fgc': par, err = g.fitgaussian(img, yxguess=loc, mask=msk, weights=weights, fitbg=fitbg, maskg=maskstar) y, x = par[2:4] #print('y: {:.3f}\tx: {:.3f}'.format(y, x)) # array([yerr, xerr, ywidth, xwidth]) extra = np.concatenate((err[2:4], par[0:2])) elif method == 'rfgc': par, err = g.rotfitgaussian(img, yxguess=loc, mask=msk, weights=weights, fitbg=fitbg, maskg=maskstar) y, x = par[2:4] #print('y: {:.3f}\tx: {:.3f}'.format(y, x)) # array([yerr, xerr, ywidth, xwidth, rot]) extra = np.concatenate((err[2:4], par[0:2], [par[5]])) elif method == 'col': y, x = cenlight.col(img, loc, npskyrad, mask=msk) # print(y, x) elif method == 'ccl': y, x = cenlight.ccl(img, trim, loc, npskyrad, mask=msk) elif method == 'lag': pos, asymarr = ctr.actr(img, loc, asym_rad=radius, asym_size=size, method='gaus') y = pos[0] x = pos[1] elif method == 'lac': pos, asymarr = ctr.actr(img, loc, asym_rad=radius, asym_size=size, method='col') y = pos[0] x = pos[1] elif method == 'bpf' or method == 'ipf': y, x, flux, sky = pf.spitzer_fit(img, msk, weights, psf, psfctr, expand, method) extra = flux, sky # Make trimming correction and return if noisepix == True: N = calcnoisepix(img, y, x, npskyrad, mask=msk) return ((y, x) + cen - trim), extra, N else: return ((y, x) + cen - trim), extra
def photometry(event, pcf, photdir, mute, owd): tini = time.time() # Create photometry log logname = event.logname log = le.Logedit(photdir + "/" + logname, logname) log.writelog("\nStart " + photdir + " photometry: " + time.ctime()) parentdir = os.getcwd() + "/" os.chdir(photdir) # Parse the attributes from the control file to the event: attrib = vars(pcf) keys = attrib.keys() for key in keys: setattr(event, key, attrib.get(key)) maxnimpos, npos = event.maxnimpos, event.npos # allocating frame parameters: event.fp.aplev = np.zeros((npos, maxnimpos)) event.fp.aperr = np.zeros((npos, maxnimpos)) event.fp.nappix = np.zeros((npos, maxnimpos)) event.fp.skylev = np.zeros((npos, maxnimpos)) event.fp.skyerr = np.zeros((npos, maxnimpos)) event.fp.nskypix = np.zeros((npos, maxnimpos)) event.fp.nskyideal = np.zeros((npos, maxnimpos)) event.fp.status = np.zeros((npos, maxnimpos)) event.fp.good = np.zeros((npos, maxnimpos)) # For interpolated aperture photometry, we need to "interpolate" the # mask, which requires float values. Thus, we convert the mask to # floats (this needs to be done before processes are spawned or memory # usage balloons). if event.mask.dtype != float: event.mask = event.mask.astype(float) # Aperture photometry: if event.phottype == "aper": # not event.dooptimal or event.from_aper is None: # Multy Process set up: # Shared memory arrays allow only 1D Arrays :( aplev = Array("d", np.zeros(npos * maxnimpos)) # aperture flux aperr = Array("d", np.zeros(npos * maxnimpos)) # aperture error nappix = Array("d", np.zeros(npos * maxnimpos)) # number of aperture pixels skylev = Array("d", np.zeros(npos * maxnimpos)) # sky level skyerr = Array("d", np.zeros(npos * maxnimpos)) # sky error nskypix = Array("d", np.zeros(npos * maxnimpos)) # number of sky pixels nskyideal = Array("d", np.zeros( npos * maxnimpos)) # ideal number of sky pixels status = Array("d", np.zeros(npos * maxnimpos)) # apphot return status good = Array("d", np.zeros(npos * maxnimpos)) # good flag # Size of chunk of data each core will process: chunksize = maxnimpos // event.ncores + 1 event.aparr = np.ones(npos * maxnimpos) * event.photap + event.offset print("Number of cores: " + str(event.ncores)) # Start Muti Procecess: processes = [] for nc in range(event.ncores): start = nc * chunksize # Starting index to process end = (nc + 1) * chunksize # Ending index to process proc = Process(target=do_aphot, args=(start, end, event, log, mute, aplev, aperr, nappix, skylev, skyerr, nskypix, nskyideal, status, good, 0)) processes.append(proc) proc.start() # Make sure all processes finish their work: for nc in range(event.ncores): processes[nc].join() # Put the results in the event. I need to reshape them: event.fp.aplev = np.asarray(aplev).reshape(npos, maxnimpos) event.fp.aperr = np.asarray(aperr).reshape(npos, maxnimpos) event.fp.nappix = np.asarray(nappix).reshape(npos, maxnimpos) event.fp.skylev = np.asarray(skylev).reshape(npos, maxnimpos) event.fp.skyerr = np.asarray(skyerr).reshape(npos, maxnimpos) event.fp.nskypix = np.asarray(nskypix).reshape(npos, maxnimpos) event.fp.nskyideal = np.asarray(nskyideal).reshape(npos, maxnimpos) event.fp.status = np.asarray(status).reshape(npos, maxnimpos) event.fp.good = np.asarray(good).reshape(npos, maxnimpos) # raw photometry (no sky subtraction): event.fp.apraw = (event.fp.aplev + (event.fp.skylev * event.fp.nappix)) # Print results into the log if it wasn't done before: for pos in range(npos): for i in range(event.nimpos[pos]): log.writelog( '\nframe =%7d ' % i + 'pos =%5d ' % pos + 'y =%7.3f ' % event.fp.y[pos, i] + 'x =%7.3f' % event.fp.x[pos, i] + '\n' + 'aplev =%11.3f ' % event.fp.aplev[pos, i] + 'aperr =%9.3f ' % event.fp.aperr[pos, i] + 'nappix =%6.2f' % event.fp.nappix[pos, i] + '\n' + 'skylev=%11.3f ' % event.fp.skylev[pos, i] + 'skyerr=%9.3f ' % event.fp.skyerr[pos, i] + 'nskypix=%6.2f ' % event.fp.nskypix[pos, i] + 'nskyideal=%6.2f' % event.fp.nskyideal[pos, i] + '\n' + 'status=%7d ' % event.fp.status[pos, i] + 'good =%5d' % event.fp.good[pos, i], mute=True) elif event.phottype == "var": # variable aperture radius # Multy Process set up: # Shared memory arrays allow only 1D Arrays :( aplev = Array("d", np.zeros(npos * maxnimpos)) # aperture flux aperr = Array("d", np.zeros(npos * maxnimpos)) # aperture error nappix = Array("d", np.zeros(npos * maxnimpos)) # number of aperture pixels skylev = Array("d", np.zeros(npos * maxnimpos)) # sky level skyerr = Array("d", np.zeros(npos * maxnimpos)) # sky error nskypix = Array("d", np.zeros(npos * maxnimpos)) # number of sky pixels nskyideal = Array("d", np.zeros( npos * maxnimpos)) # ideal number of sky pixels status = Array("d", np.zeros(npos * maxnimpos)) # apphot return status good = Array("d", np.zeros(npos * maxnimpos)) # good flag # Size of chunk of data each core will process: chunksize = maxnimpos // event.ncores + 1 event.aparr = event.fp.noisepix[0]**.5 * event.photap + event.offset print("Number of cores: " + str(event.ncores)) # Start Muti Procecess: processes = [] for nc in range(event.ncores): start = nc * chunksize # Starting index to process end = (nc + 1) * chunksize # Ending index to process proc = Process(target=do_aphot, args=(start, end, event, log, mute, aplev, aperr, nappix, skylev, skyerr, nskypix, nskyideal, status, good, 0)) processes.append(proc) proc.start() # Make sure all processes finish their work: for nc in range(event.ncores): processes[nc].join() # Put the results in the event. I need to reshape them: event.fp.aplev = np.asarray(aplev).reshape(npos, maxnimpos) event.fp.aperr = np.asarray(aperr).reshape(npos, maxnimpos) event.fp.nappix = np.asarray(nappix).reshape(npos, maxnimpos) event.fp.skylev = np.asarray(skylev).reshape(npos, maxnimpos) event.fp.skyerr = np.asarray(skyerr).reshape(npos, maxnimpos) event.fp.nskypix = np.asarray(nskypix).reshape(npos, maxnimpos) event.fp.nskyideal = np.asarray(nskyideal).reshape(npos, maxnimpos) event.fp.status = np.asarray(status).reshape(npos, maxnimpos) event.fp.good = np.asarray(good).reshape(npos, maxnimpos) # raw photometry (no sky subtraction): event.fp.apraw = (event.fp.aplev + (event.fp.skylev * event.fp.nappix)) # Print results into the log if it wasn't done before: for pos in range(npos): for i in range(event.nimpos[pos]): log.writelog( '\nframe =%7d ' % i + 'pos =%5d ' % pos + 'y =%7.3f ' % event.fp.y[pos, i] + 'x =%7.3f' % event.fp.x[pos, i] + '\n' + 'aplev =%11.3f ' % event.fp.aplev[pos, i] + 'aperr =%9.3f ' % event.fp.aperr[pos, i] + 'nappix =%6.2f' % event.fp.nappix[pos, i] + '\n' + 'skylev=%11.3f ' % event.fp.skylev[pos, i] + 'skyerr=%9.3f ' % event.fp.skyerr[pos, i] + 'nskypix=%6.2f ' % event.fp.nskypix[pos, i] + 'nskyideal=%6.2f' % event.fp.nskyideal[pos, i] + '\n' + 'status=%7d ' % event.fp.status[pos, i] + 'good =%5d' % event.fp.good[pos, i], mute=True) elif event.phottype == "ell": # elliptical # Multy Process set up: # Shared memory arrays allow only 1D Arrays :( aplev = Array("d", np.zeros(npos * maxnimpos)) # aperture flux aperr = Array("d", np.zeros(npos * maxnimpos)) # aperture error nappix = Array("d", np.zeros(npos * maxnimpos)) # number of aperture pixels skylev = Array("d", np.zeros(npos * maxnimpos)) # sky level skyerr = Array("d", np.zeros(npos * maxnimpos)) # sky error nskypix = Array("d", np.zeros(npos * maxnimpos)) # number of sky pixels nskyideal = Array("d", np.zeros( npos * maxnimpos)) # ideal number of sky pixels status = Array("d", np.zeros(npos * maxnimpos)) # apphot return status good = Array("d", np.zeros(npos * maxnimpos)) # good flag # Size of chunk of data each core will process: chunksize = maxnimpos // event.ncores + 1 print("Number of cores: " + str(event.ncores)) # Start Muti Procecess: processes = [] for nc in range(event.ncores): start = nc * chunksize # Starting index to process end = (nc + 1) * chunksize # Ending index to process proc = Process(target=do_aphot, args=(start, end, event, log, mute, aplev, aperr, nappix, skylev, skyerr, nskypix, nskyideal, status, good, 0)) processes.append(proc) proc.start() # Make sure all processes finish their work: for nc in range(event.ncores): processes[nc].join() # Put the results in the event. I need to reshape them: event.fp.aplev = np.asarray(aplev).reshape(npos, maxnimpos) event.fp.aperr = np.asarray(aperr).reshape(npos, maxnimpos) event.fp.nappix = np.asarray(nappix).reshape(npos, maxnimpos) event.fp.skylev = np.asarray(skylev).reshape(npos, maxnimpos) event.fp.skyerr = np.asarray(skyerr).reshape(npos, maxnimpos) event.fp.nskypix = np.asarray(nskypix).reshape(npos, maxnimpos) event.fp.nskyideal = np.asarray(nskyideal).reshape(npos, maxnimpos) event.fp.status = np.asarray(status).reshape(npos, maxnimpos) event.fp.good = np.asarray(good).reshape(npos, maxnimpos) # raw photometry (no sky subtraction): event.fp.apraw = (event.fp.aplev + (event.fp.skylev * event.fp.nappix)) # Print results into the log if it wasn't done before: for pos in range(npos): for i in range(event.nimpos[pos]): log.writelog( '\nframe =%7d ' % i + 'pos =%5d ' % pos + 'y =%7.3f ' % event.fp.y[pos, i] + 'x =%7.3f' % event.fp.x[pos, i] + '\n' + 'aplev =%11.3f ' % event.fp.aplev[pos, i] + 'aperr =%9.3f ' % event.fp.aperr[pos, i] + 'nappix =%6.2f' % event.fp.nappix[pos, i] + '\n' + 'skylev=%11.3f ' % event.fp.skylev[pos, i] + 'skyerr=%9.3f ' % event.fp.skyerr[pos, i] + 'nskypix=%6.2f ' % event.fp.nskypix[pos, i] + 'nskyideal=%6.2f' % event.fp.nskyideal[pos, i] + '\n' + 'status=%7d ' % event.fp.status[pos, i] + 'good =%5d' % event.fp.good[pos, i], mute=True) elif event.phottype == "psffit": event.fp.aplev = event.fp.flux event.fp.skylev = event.fp.psfsky event.fp.good = np.zeros((event.npos, event.maxnimpos)) for pos in range(event.npos): event.fp.good[pos, 0:event.nimpos[pos]] = 1 elif event.phottype == "optimal": # utils for profile construction: pshape = np.array([2 * event.otrim + 1, 2 * event.otrim + 1]) subpsf = np.zeros(np.asarray(pshape, int) * event.expand) x = np.indices(pshape) clock = t.Timer(np.sum(event.nimpos), progress=np.array([0.05, 0.1, 0.25, 0.5, 0.75, 1.1])) for pos in range(npos): for i in range(event.nimpos[pos]): # Integer part of center of subimage: cen = np.rint([event.fp.y[pos, i], event.fp.x[pos, i]]) # Center in the trimed image: loc = (event.otrim, event.otrim) # Do the trim: img, msk, err = ie.trimimage(event.data[i, :, :, pos], *cen, *loc, mask=event.mask[i, :, :, pos], uncd=event.uncd[i, :, :, pos]) # Center of star in the subimage: ctr = (event.fp.y[pos, i] - cen[0] + event.otrim, event.fp.x[pos, i] - cen[1] + event.otrim) # Make profile: # Index of the position in the supersampled PSF: pix = pf.pos2index(ctr, event.expand) profile, pctr = pf.make_psf_binning(event.psfim, pshape, event.expand, [pix[0], pix[1], 1.0, 0.0], event.psfctr, subpsf) #subtract the sky level: img -= event.fp.psfsky[pos, i] # optimal photometry calculation: immean, uncert, good = op.optphot(img, profile, var=err**2.0, mask=msk) event.fp.aplev[pos, i] = immean event.fp.aperr[pos, i] = uncert event.fp.skylev[pos, i] = event.fp.psfsky[pos, i] event.fp.good[pos, i] = good # Report progress: clock.check(np.sum(event.nimpos[0:pos]) + i, name=event.centerdir) # START PREFLASH EDIT ::::::::::::::::::::::::::::::::::::: # Do aperture on preflash data: if event.havepreflash: print("\nStart preflash photometry:") premaxnimpos = event.premaxnimpos preaplev = Array("d", np.zeros(npos * premaxnimpos)) preaperr = Array("d", np.zeros(npos * premaxnimpos)) prenappix = Array("d", np.zeros(npos * premaxnimpos)) preskylev = Array("d", np.zeros(npos * premaxnimpos)) preskyerr = Array("d", np.zeros(npos * premaxnimpos)) preskynpix = Array("d", np.zeros(npos * premaxnimpos)) preskyideal = Array("d", np.zeros(npos * premaxnimpos)) prestatus = Array("d", np.zeros(npos * premaxnimpos)) pregood = Array("d", np.zeros(npos * premaxnimpos)) # Start Procecess: mute = False proc = Process(target=do_aphot, args=(0, event.prenimpos[0], event, log, mute, preaplev, preaperr, prenappix, preskylev, preskyerr, preskynpix, preskyideal, prestatus, pregood, 1)) proc.start() proc.join() # Put the results in the event. I need to reshape them: event.prefp.aplev = np.asarray(preaplev).reshape(npos, premaxnimpos) event.prefp.aperr = np.asarray(preaperr).reshape(npos, premaxnimpos) event.prefp.nappix = np.asarray(prenappix).reshape(npos, premaxnimpos) event.prefp.status = np.asarray(prestatus).reshape(npos, premaxnimpos) event.prefp.skylev = np.asarray(preskylev).reshape(npos, premaxnimpos) event.prefp.good = np.asarray(pregood).reshape(npos, premaxnimpos) # raw photometry (no sky subtraction): event.prefp.aplev = (event.prefp.aplev + (event.prefp.skylev * event.prefp.nappix)) # END PREFLASH EDIT ::::::::::::::::::::::::::::::::::::::: if event.method in ["bpf"]: event.ispsf = False # PSF aperture correction: if event.ispsf and event.phottype == "aper": log.writelog('Calculating PSF aperture:') event.psfim = event.psfim.astype(np.float64) imerr = np.ones(np.shape(event.psfim)) imask = np.ones(np.shape(event.psfim)) skyfrac = 0.1 event.aperfrac, ape, event.psfnappix, event.psfskylev, sle, \ event.psfnskypix, event.psfnskyideal, event.psfstatus \ = ap.apphot_c(event.psfim, imerr, imask, event.psfctr[0], event.psfctr[1], event.photap * event.psfexpand, event.skyin * event.psfexpand, event.skyout * event.psfexpand, skyfrac, event.apscale, event.skymed) event.aperfrac += event.psfskylev * event.psfnappix event.fp.aplev /= event.aperfrac event.fp.aperr /= event.aperfrac log.writelog('Aperture contains %f of PSF.' % event.aperfrac) if event.ispsf and event.phottype == "var": log.writelog('Calculating PSF aperture:') event.psfim = event.psfim.astype(np.float64) imerr = np.ones(np.shape(event.psfim)) imask = np.ones(np.shape(event.psfim)) skyfrac = 0.1 avgap = np.mean(event.aparr) event.aperfrac, ape, event.psfnappix, event.psfskylev, sle, \ event.psfnskypix, event.psfnskyideal, event.psfstatus \ = ap.apphot_c(event.psfim, imerr, imask, event.psfctr[0], event.psfctr[1], avgap * event.psfexpand, event.skyin * event.psfexpand, event.skyout * event.psfexpand, skyfrac, event.apscale, event.skymed) event.aperfrac += event.psfskylev * event.psfnappix event.fp.aplev /= event.aperfrac event.fp.aperr /= event.aperfrac log.writelog('Aperture contains %f of PSF.' % event.aperfrac) if event.ispsf and event.phottype == "ell": log.writelog('Calculating PSF aperture:') event.psfim = event.psfim.astype(np.float64) imerr = np.ones(np.shape(event.psfim)) imask = np.ones(np.shape(event.psfim)) skyfrac = 0.1 avgxwid = np.mean(event.fp.xsig * event.photap) avgywid = np.mean(event.fp.ysig * event.photap) avgrot = np.mean(event.fp.rot) event.aperfrac, ape, event.psfnappix, event.psfskylev, sle, \ event.psfnskypix, event.psfnskyideal, event.psfstatus \ = ap.elphot_c(event.psfim, imerr, imask, event.psfctr[0], event.psfctr[1], avgxwid * event.psfexpand, avgywid * event.psfexpand, avgrot, event.skyin * event.psfexpand, event.skyout * event.psfexpand, skyfrac, event.apscale, event.skymed) event.aperfrac += event.psfskylev * event.psfnappix event.fp.aplev /= event.aperfrac event.fp.aperr /= event.aperfrac log.writelog('Aperture contains %f of PSF.' % event.aperfrac) # Sadly we must do photometry for every aperture used # Possibly use a range and interpolate? Might be an option # for the future to speed this up. # This is commented out, as it seems to just remove the corrections # made by variable or elliptical photometry # if event.ispsf and (event.phottype == "var" or event.phottype == "ell"): # log.writelog('Calculating PSF aperture. This may take some time.') # event.psfim = event.psfim.astype(np.float64) # imerr = np.ones(np.shape(event.psfim)) # imask = np.ones(np.shape(event.psfim)) # skyfrac = 0.1 # aperfrac = Array("d", np.zeros(npos*maxnimpos))# psf flux # aperfracerr = Array("d", np.zeros(npos*maxnimpos))# psf flux error # psfnappix = Array("d", np.zeros(npos*maxnimpos))# psf aperture pix num # psfsky = Array("d", np.zeros(npos*maxnimpos))# psf sky level # psfskyerr = Array("d", np.zeros(npos*maxnimpos))# psf sky error # psfnskypix = Array("d", np.zeros(npos*maxnimpos))# psf sky pix num # psfnskyideal = Array("d", np.zeros(npos*maxnimpos))# psf ideal sky pix num # psfstatus = Array("d", np.zeros(npos*maxnimpos))# psf return status # psfgood = Array("d", np.zeros(npos*maxnimpos))# psf good flag # processes=[] # for nc in range(event.ncores): # start = nc * chunksize # end = (nc+1) * chunksize # proc = Process(target=do_aphot_psf, args=(start, end, event, log, mute, # aperfrac, aperfracerr, # psfnappix, # psfsky, psfskyerr, # psfnskypix, psfnskyideal, # psfstatus, psfgood)) # processes.append(proc) # proc.start() # for nc in range(event.ncores): # processes[nc].join() # # Reshape # event.aperfrac = np.asarray(aperfrac ).reshape(npos,maxnimpos) # event.aperfracerr = np.asarray(aperfracerr ).reshape(npos,maxnimpos) # event.psfnappix = np.asarray(psfnappix ).reshape(npos,maxnimpos) # event.psfsky = np.asarray(psfsky ).reshape(npos,maxnimpos) # event.psfskyerr = np.asarray(psfskyerr ).reshape(npos,maxnimpos) # event.psfnskypix = np.asarray(psfnskypix ).reshape(npos,maxnimpos) # event.psfnskyideal = np.asarray(psfnskyideal).reshape(npos,maxnimpos) # event.psfstatus = np.asarray(psfstatus ).reshape(npos,maxnimpos) # event.psfgood = np.asarray(psfgood ).reshape(npos,maxnimpos) # event.aperfrac += event.psfsky * event.psfnappix # event.fp.aplev /= event.aperfrac # event.fp.aperr /= event.aperfrac # log.writelog('Aperture contains average %f of PSF.'%np.mean(event.aperfrac)) # save print("\nSaving ...") # denoised data: if event.denphot: killdata = 'dendata' else: killdata = 'data' me.saveevent(event, event.eventname + "_pht", delete=[killdata, 'uncd', 'mask']) # Print time elapsed and close log: cwd = os.getcwd() + "/" log.writelog("Output files (" + event.photdir + "):") log.writelog("Data:") log.writelog(" " + cwd + event.eventname + "_pht.dat") log.writelog("Log:") log.writelog(" " + cwd + logname) dt = t.hms_time(time.time() - tini) log.writeclose("\nEnd Photometry. Time (h:m:s): %s " % dt + " (" + photdir + ")") print("-------------- ------------\n") os.chdir(owd) if event.runp5: os.system("python3 poet.py p5 %s/%s" % (event.centerdir, event.photdir))
def dooptphot(data, uncd, mask, fp, center, nimpos, rejlim=[1.45, 1, 0.005], itmax=20, trim=10, order=1, ftol=1e-8, resize=30, norm=1, log=None, psf=None): """ Perform optimal photometry on a set of images. Parameters ---------- data: 4D array_like image array (im, x, y, pos) uncd: 4D array_like Array containing pixel uncertainties (same shape as data) mask: Array of same dimensions as data containing the bad pixel masks to be used in optimal photometry. sratio: array_like Pixel scale ratios for each position in x and y. The array should have shape: (2, npos) psf: Passed directly into CURVEFIT the psfdata image (handed through to CF_MIPS1_PSFCTR unmodified) rejlim: A 3-element array containing the cutoff values for chi square, sky-median(sky)(median taken per position), and sky error(above minimum sky error for that position). Images that produce values outside the cutoff range will be marked as such in IOSTATUS. The default values for these parameters are: rejlim = [1.45, 1, 0.005] ftol: Relative error desired in the sum of squares. Passed to scipy.optimize.leastsq. res: passed into CURVEFIT trim: Define half-width of sub-image Returns: ------- Array containing a whole bunch of information. OPTIONAL OUTPUTS: OSTATUS: An array that labels bad images (according to the criterion above- see REJLIM).An image that fails based on a high chi-square is labeled with a -1. A high or low sky level is labeled with a -10, and a high sky error is labeled with a -100. SIDE EFFECTS: This function defines pos, nx, maxnim, and nimpos if they arent already defined. Examples -------- ofp = do.dooptphot(data, uncd, mask, fp, center, nimpos, rejlim=[10.45, 10, 1.5], itmax=20, order=1, resize=30, norm=1) pos = 0 plt.clf() plt.plot(ofp.time[pos, 0:nimpos[pos]], fp.oskylev [pos, 0:nimpos[pos]], '+') plt.plot(ofp.time[pos, 0:nimpos[pos]], fp.ophotlev[pos, 0:nimpos[pos]], '+') Revisions: --------- Written by Statia June 20, 2005 2005-06-21 Statia Added image rejection part. 2005-07-14 Added sclpar keyword. 2005-07-15 Distprf keyword. 2008-03-07 Changed parinfo to fix xctr, yctr (to use values from apphot). 2008-06-03 Emily Rewriting to use curvefit instead of mpfit, as was done in mips1-3b-optphot.pro 2008-06-05 Emily (sloppy) MIPS correction for sky median rejection test 2009-05-18 Kevin Allowed curvefit to use subimages of data. 2010-06-24 Patricio Converted to python. """ tini = time.time() # pieces of apphot needed (from fp): x, y, aplev, skylev # Sizes maxnimpos, ny, nx, npos = np.shape(data) # initialize skyint and skyslope (used in calculating status and # returned if keywords set) skyint = np.zeros(npos) skyslope = np.zeros(npos) # Allocate space for the results fp.oxx = np.zeros((npos, maxnimpos)) # X position fp.oyy = np.zeros((npos, maxnimpos)) # Y position fp.oxerr = np.zeros((npos, maxnimpos)) # error in X position fp.oyerr = np.zeros((npos, maxnimpos)) # error in Y position fp.optlev = np.zeros((npos, maxnimpos)) # flux from curvefit fp.opterr = np.zeros((npos, maxnimpos)) # flux error curvefit fp.oskylev = np.zeros((npos, maxnimpos)) # sky level fp.oskyerr = np.zeros((npos, maxnimpos)) # sky error fp.ophotlev = np.zeros((npos, maxnimpos)) # flux from optphot fp.ophoterr = np.zeros((npos, maxnimpos)) # flux error from optphot fp.oniter = np.zeros((npos, maxnimpos)) # iteration number for curvefit fp.ofitstatus = np.zeros((npos, maxnimpos)) # status output from mpfiot fp.ocspdof = np.zeros((npos, maxnimpos)) # chi squared per dof # according to curvefit fp.ostatus = np.zeros((npos, maxnimpos)) # optphot return status # (formally reject) fp.ogood = np.zeros((npos, maxnimpos)) # good flag fp.orad = np.zeros((npos, maxnimpos)) # distance from nearest pix center # Get the PSF: if psf == None: psf = pb.psfbuild(data, mask, fp, center, nimpos, resize=resize, trim=trim) # Do photometry # The parameters to fit: # pars = [Y position, X position, aperture flux, sky flux level] pars = np.zeros(4) # Pixels of the centers yr, xr = center[0::2], center[1::2] # integer values yoff = yr - trim xoff = xr - trim # Coordinates of the center of the psf in the subimage: psfyc, psfxc = fp.y[:, 0] - yoff, fp.x[:, 0] - xoff le.writelog('\nOptimal Photometry\n', log) # pos = 0 # if True: for pos in np.arange(0, npos): for im in np.arange(0, nimpos[pos]): # calculate shifted, scaled PSF # should sky really be a free parameter at this point? # sub-image, sub-mask, sub-uncd subim, subma, subun = ie.trimimage(data[im, :, :, pos], (yr[pos], xr[pos]), (trim, trim), mask[im, :, :, pos], uncd[im, :, :, pos]) weights = 1.0 / subun**2.0 # weights = 0.0 if uncd is huge, give points tiny value weights[np.where(weights == 0)] = np.mean(weights) / 100.0 # The parameters to fit: pars[0] = fp.y[pos, im] - yoff[pos] # Y position in the sub-image pars[1] = fp.x[pos, im] - xoff[pos] # X position pars[2] = fp.aplev[pos, im] # aperture flux pars[3] = fp.skylev[pos, im] # sky flux level # center of the psf psfc = psfyc[pos], psfxc[pos] # Fit the PSF position, sky, and aperture flux level to the frame. fit, err, niter, csqpdof, stat = pf.psffit(subim, weights, psf[:, :, pos], pars, psfc, order=order, norm=norm) # Save the results of the fit fp.oyy[pos, im] = fit[0] + yoff[pos] fp.oyerr[pos, im] = err[0] fp.oxx[pos, im] = fit[1] + xoff[pos] fp.oxerr[pos, im] = err[1] fp.optlev[pos, im] = fit[2] fp.opterr[pos, im] = err[2] fp.oskylev[pos, im] = fit[3] fp.oskyerr[pos, im] = err[3] fp.oniter[pos, im] = niter fp.ocspdof[pos, im] = csqpdof fp.ofitstatus[pos, im] = stat subimpsf = pf.scalepsf(psf[:, :, pos], fit, np.shape(subim), psfc, order, norm) impsf = np.zeros((ny, nx)) impsf = ie.pasteimage(impsf, (subimpsf - fp.oskylev[pos, im]) / fp.optlev[pos, im], (yr[pos], xr[pos])) # save yerror appropriately, # documentation for curvefit says yerror is "standard error between # yfit and y", what is this, really? fp.ophotlev[pos,im], fp.ophoterr[pos, im], profile, wght = \ op.optphot(data[im,:,:,pos] - fp.oskylev[pos,im], impsf, var=uncd[im,:,:,pos]**2 + fp.oskyerr[pos,im]**2, mask=mask[im,:,:,pos]) le.writelog( '\n' + 'frame =%4d ' % im + 'pos =%3d ' % pos + 'ocspdof =%11.3f ' % fp.ocspdof[pos, im] + 'niter =%5d ' % fp.oniter[pos, im] + '\n' + 'y =%8.3f ' % fp.oyy[pos, im] + 'yerr =%7.4f ' % fp.oyerr[pos, im] + 'flux =%11.3f ' % fp.ophotlev[pos, im] + 'fluxerr =%9.3f ' % fp.ophoterr[pos, im] + '\n' + 'x =%8.3f ' % fp.oxx[pos, im] + 'xerr =%7.4f ' % fp.oxerr[pos, im] + 'skylev =%11.3f ' % fp.oskylev[pos, im] + 'skyerr =%9.3f ' % fp.oskyerr[pos, im], log) # Finding Bad Frames # Make rejection mask: # 0 = good; # 1 = chisq too high; # 10 = sky-median(sky) too high; # 100 = skyerror too high # It makes more sense if a bitmask, I don't know how to do that just now. # HIGH CHISQ loc = np.where(fp.ocspdof[pos, 0:nimpos[pos]] >= rejlim[0]) if np.size(loc) != 0: fp.ostatus[pos, :][loc] -= 1 le.writelog( str(np.size(loc)) + ' frames rejected for high chisq', log) # HIGH/LOW SKY RELATIVE TO SLOPE SUBTRACTED MEDIAN #FINDME: for MIPS, ignore first frames (code this more cleanly later) if (pos == 0) or (pos == 7): frames = np.where((np.arange(nimpos[pos]) % 6) != 0) else: frames = np.where((np.arange(nimpos[pos]) % 5) != 0) # Do a linear fit to the sky level as function of time. test = np.polyfit((fp.time[pos, 0:nimpos[pos]])[frames], (fp.oskylev[pos, 0:nimpos[pos]])[frames], 1) skyint[pos] = test[1] skyslope[pos] = test[0] line = test[1] + test[0] * fp.time[pos, 0:nimpos[pos]] skydiff = np.abs(fp.oskylev[pos, 0:nimpos[pos]] - line) # print( skyint[pos], skyslope[pos] ) # print( 'skylev', fp[ioskylev, 0:nimpos[pos]-1,pos] print('skydiff med: ' + str(np.median(skydiff)) + ', std: ' + str(np.std(skydiff))) loc = np.where(skydiff >= rejlim[1]) if np.size(loc) != 0: fp.ostatus[pos, :][loc] -= 10 le.writelog( str(np.size(loc)) + ' frames rejected for high/low sky level', log) # HIGH SKY ERROR y = fp.oskyerr[pos, 0:nimpos[pos]] loc = np.where(y >= rejlim[2] + np.amin(y)) if np.size(loc) != 0: fp.ostatus[pos, :][loc] -= 100 le.writelog( str(np.size(loc)) + ' frames rejected for sky error', log) print('rejection complete') fp.ogood[np.where(fp.ostatus == 0)] = 1 # pixel R position fp.orad = np.sqrt((fp.oxx % 1.0 - 0.5)**2.0 + (fp.oyy % 1.0 - 0.5)**2.0) #le.writelog('optimal photometry time: %f minutes'%((time.time()-tini)/60), log) return fp, psf
def psfbuild(data, mask, fp, center, nimpos, resize=30, trim=10): """ The resampling uses scipy.ndimage.interpolation.zoom, the size of the result will have size = resize*size, the value of the corners coincide in both arrays. Work plan: + trim the images to a rectangular area around the star + bilinear interpolate images and masks + clip mask interpolation so that any mask value < 1 becomes 0 + get centers from frameparameters (= from aperture photometry) + shift each image to align with center of first image + shift mask likewise + sum images + sum masks + multiply images by masks + psf = sum(image) / sum(mask) (pixel-wise sum) + psf = psf - np.median(psf) (to subtract sky) import sys sys.path.append('/home/patricio/ast/esp01/convert/lib/python') import psfbuild as pb import event as ev from loadevent import loadEvent event = loadEvent('hd209bs51_ctr', load=['data','uncd','mask','event']) psf = pb.psfbuild(event.data, event.mask, event.fp, event.srcest, event.nimpos, resize=20, trim=10) fig = plt.figure(11) plt.clf() plt.imshow(psf[:,:,0], interpolation='nearest', origin='ll') #plt.xlim(200,400) #plt.ylim(200,400) plt.colorbar() """ tini = time.time() print('\nPSF Building:') mnpos, ny, nx, npos = np.shape(data) # Extract only a rectangular area around the star: subdata = np.zeros((mnpos, 2*trim+1, 2*trim+1, npos)) submask = np.zeros((mnpos, 2*trim+1, 2*trim+1, npos)) # Get shape of the sub-images sny, snx = np.shape(subdata[0,:,:,0]) # Coordinates of the centers yc, xc = center[0::2], center[1::2] # Trim the image: for pos in np.arange(npos): for i in np.arange(mnpos): subdata[i,:,:,pos], submask[i,:,:,pos] = \ ie.trimimage( data[i,:,:,pos], (yc[pos],xc[pos]), (trim, trim), mask=mask[i,:,:,pos] ) # Shape of resampled images: coory = zoom(np.arange(sny)*1.0, resize, order=1) coorx = zoom(np.arange(snx)*1.0, resize, order=1) rny, rnx = np.size(coory), np.size(coorx) # Get shifts according to centering: shifty = fp.y - fp.y[:,0:1] shiftx = fp.x - fp.x[:,0:1] # Amount by which the images should be rolled to align them expandy = (rny-1.0)/(sny-1.0) expandx = (rnx-1.0)/(snx-1.0) rolly = -np.round(shifty*expandy) rollx = -np.round(shiftx*expandx) # Stupid python gets confused with -0 values! rolly[np.where(rolly==0)] = 0 rollx[np.where(rollx==0)] = 0 verbose = False if verbose: # Rounded shifts roundsy = -rolly/expandy roundsx = -rollx/expandx plt.figure(1,(10,5)) plt.clf() plt.plot(shifty [3,:], 'r') plt.plot(roundsy[3,:], 'b') ''' im = 0 pos = 0 resize = 25 z = zoom(subdata[i,:,:,pos], resize, order=1) z = zoom(subdata[i,:,:,pos], 501.0/sny, order=1) rny, rnx = (np.array([sny, snx]) - 1) * resize + 1 print(np.shape(z)) print(rny) q = zoom(z, 1./resize, order=1) resize=3 z = zoom(x, 51./3, order=1) q = zoom(z, 1./resize, order=1) q rny, rnx = (np.array([3, 3]) - 1) * (resize) + 1 np.linspace(0, 3-1, rny) np.size(np.linspace(0, 3-1, rny)) i2d.interp2d(x, expand=resize+1, order=0) coor = zoom(np.arange(sny)*1.0, resize, order=1) ''' verbose = False if verbose: fig = plt.figure(5) plt.clf() plt.imshow(subdata[ 0,:,:,3], interpolation='nearest', origin='ll') plt.colorbar() fig = plt.figure(6) plt.clf() plt.imshow(subdata[36,:,:,3], interpolation='nearest', origin='ll') plt.colorbar() nfig = 7 # Allocate space for the resampled data rsdata = np.zeros((mnpos, rny, rnx, npos)) rsmask = np.zeros((mnpos, rny, rnx, npos)) # for i in np.arange(mnpos): # for pos in np.arange(npos): # Resample and align: for pos in np.arange(npos): for i in np.arange(nimpos[pos]): # Resample using linear interpolation: rsdata[i,:,:,pos] = zoom(subdata[i,:,:,pos], resize, order=1) rsmask[i,:,:,pos] = zoom(submask[i,:,:,pos], resize, order=1) rsmask[i,:,:,pos] = (rsmask[i,:,:,pos] == 1) # rsdata[i,:,:,pos] = i2d.interp2d(subdata[i,:,:,pos], expand=resize, # y=y, x=x, yi=yi, xi=xi) # rsmask[i,:,:,pos] = i2d.interp2d(submask[i,:,:,pos], expand=resize, # y=y, x=x, yi=yi, xi=xi) # fig = plt.figure(nfig) # nfig += 1 # plt.clf() # plt.imshow(rsdata[i,:,:,pos], interpolation='nearest', origin='ll') # plt.xlim(250,350) # plt.ylim(250,350) # plt.colorbar() # Align the data using roll: rsdata[i,:,:,pos] = np.roll(np.roll(rsdata[i,:,:,pos], int(rolly[pos,i]),axis=0), int(rollx[pos,i]),axis=1) rsmask[i,:,:,pos] = np.roll(np.roll(rsmask[i,:,:,pos], int(rolly[pos,i]),axis=0), int(rollx[pos,i]),axis=1) # if i%15 == 0: # progress # print(i) print('resizing time: %f seconds'%(time.time()-tini)) verbose = False if verbose: fig = plt.figure(2) plt.clf() plt.imshow(rsmask[0,:,:,3], interpolation='nearest', origin='ll') plt.colorbar() fig = plt.figure(3) plt.clf() plt.imshow(rsmask[36,:,:,3], interpolation='nearest', origin='ll') # plt.xlim(250,350) # plt.ylim(250,350) plt.colorbar() verbose = False if verbose: fig = plt.figure(9) plt.clf() plt.imshow(rsdata[36,:,:,3], interpolation='nearest', origin='ll') #plt.xlim(250,350) #plt.ylim(250,350) plt.colorbar() # Multiply images by masks rsdata *= rsmask # Number of good values in each pixel ngood = np.sum(rsmask, axis=0) # Avoid dividing by 0 loc = np.where(ngood == 0) ngood[loc] = 1.0 # The PSF psf = np.sum(rsdata, axis=0) / ngood # Subtract the sky level: psf -= np.median(psf) # Fix bad pixels psf[loc] = 0.0 # Normalize to sum(psf) = 1.0 # psf /= np.sum(psf) # Plots: # plot(shifty[3,:]) # resize = 30 return psf