def determine_center(self, centering): # mostly for internal use from fit_image... self.vprint(self, "\n **** LG_Model.NRM_Model.determine_center: centering {}".format(centering)) sys.exit(" **** LG_Model.NRM_Model.determine_center") # First find the fractional-pixel centering if centering== "auto": if hasattr(self.bandpass, "__iter__"): self.auto_find_center( "centermodel_poly_{0}mas.fits".format(utils.rad2mas(self.pixel))) else: self.auto_find_center( "centermodel_{0}m_{1}mas.fits".format(self.bandpass, \ utils.rad2mas(self.pixel))) self.bestcenter = 0.5-self.over*self.xpos, 0.5-self.over*self.ypos sys.exit(" **** NRM_Model.fit_image: {}".format(self.bestcenter)) else: self.bestcenter = centering
def auto_find_center(self, modelfitsname, overwrite=0): """ This is the major method in this driver to be called. It is basically Deepashri's cormat driver & peak finder. Takes an image at the detector pixel scale and a fits file name * tries to read in the fits file * if there's no file it will go on to generate an oversampled PSF * if the data is a cube it will generate a cube of oversampled PSFs * if not it will generate a single array of oversampled PSF * then calculates cormat & finds the peak. returns center location on the detector scale. ************************************************************* *** *** *** NOTE: to plug this centering back into NRM_Model: *** *** ( 0.5 - model_oversampling*ctr[0], *** *** 0.5 - model_oversampling*ctr[1] ) *** *** LG+ *** ************************************************************* This is different in LG++: In nrm_core.fit_fringes_single_integration() I experimented with: nrm.bestcenter = 0.5-nrm.over*nrm.xpos, 0.5-nrm.over*nrm.ypos ################ AS LG+ nrm.bestcenter = -nrm.over*nrm.xpos, -nrm.over*nrm.ypos ################ AS try in LG++ nrm.bestcenter = nrm.xpos, nrm.ypos ################ AS try in LG++ Works! ************************************************************* """ self.pscale_rad = self.pixel self.pscale_mas = utils.rad2mas(self.pscale_rad) _npix = self.reference.shape[1] + 2 if ((not os.path.isfile(modelfitsname)) or (overwrite == 1)): # Creates a new oversampled model, default is pixel-centered self.simulate(fov=_npix, over=self.over, bandpass=self.bandpass) hdulist = fits.PrimaryHDU(data=self.psf_over) hdulist.header[""] = ("", "Written from auto_find_center method") #hdulist.header.update() hdulist.writeto(self.datapath + modelfitsname, clobber=True) else: # Looks for this file to read in if it's already been written and overwrite flag not set try: self.read_model(modelfitsname) except: self.psf_over = 0 if self.psf_over.shape[0] == self.reference.shape[0]: pass else: # if overwrite flag not set, but read model doesn't match, just make a new one self.simulate(fov=_npix, over=self.over, bandpass=self.bandpass) # finds correlation matrix between oversampled and detector psf self.cormat = utils.crosscorrelatePSFs(self.reference, self.psf_over, self.over) self.find_location_of_peak()
def save(nrmobj, outputname, savdir=""): """ Probably don't need to use this unless have run a fit. This is only to save fitting parameters and results right now. """ import json class savobj: def __init__(self): return None savobj.test = 1 with open(r"{0}.ffo".format(savdir, outputname), "wb") as output_file: json.dump(savobj, output_file) print("success!") # init stuff savobj.pscale_rad, savobj.pscale_mas = nrmobj.pixel, utils.rad2mas( nrmobj.pixel) savobj.holeshape, savobj.ctrs, savobj.d, savobj.D, savobj.N, \ savobj.datapath, savobj.refdir = nrmobj.holeshape, nrmobj.ctrs, nrmobj.d, \ nrmobj.D, nrmobj.N, nrmobj.datapath, nrmobj.refdir if hasattr(nrmobj, "refpsf"): savobj.refpsf, savobj.rot_best = nrmobj.refpsf, nrmobj.rot_measured if hasattr(nrmobj, "fittingmodel"): # details savobj.weighted, savobj.pixweight, savobj.bestcenter, \ savobj.bandpass, savobj.modelctrs, savobj.over,\ savobj.modelpix = nrmobj.weighted, nrmobj.pixweight, nrmobj.bestcenter, \ nrmobj.bandpass, nrmobj.modelctrs, nrmobj.over, nrmobj.modelpix # resulting arrays savobj.modelmat, savobj.soln, \ savobj.residual, savobj.cond, \ savobj.rawDC, savobj.flux, \ savobj.fringeamp, savobj.fringephase,\ savobj.cps, savobj.cas = nrmobj.fittingmodel, nrmobj.soln, nrmobj.residual, \ nrmobj.cond, nrmobj.rawDC, nrmobj.flux, nrmobj.fringeamp, \ nrmobj.fringephase, nrmobj.redundant_cps, nrmobj.redundant_cas if not hasattr(nrmobj, "modelpsf"): nrmobj.plot_model() savobj.modelpsf = nrmobj.modelpsf with open(r"{0}.ffo".format(savdir, outputname), "wb") as output_file: pickle.dump(savobj, output_file)
def fit_image(self, image, reference=None, pixguess=None, rotguess=0, psf_offset=(0,0), modelin=None, savepsfs=False, dqm=None, weighted=False): """ This works on 2D "centered" images fed to it. dqm is optional 2D bad pixel bool array, same size as image. self.maskname is a maskdef object with property self.maskname.mask a string 2021 """ self.vprint(self, "\n **** LG_Model.NRM_Model.fit_image: psf_offset {}".format(psf_offset)) if hasattr(modelin, 'shape'): self.vprint(self, " **** LG_Model.NRM_Model.fit_image modelin passed in") else: self.vprint(self, " **** LG_Model.NRM_Model.fit_image: modelin is None\n") """ fit_image will run a least-squares fit on an input image. Specifying a model is optional. If a model is not specified then this method will find the appropriate wavelength scale, rotation (and hopefully centering as well -- This is not written into the object yet, but should be soon). Without specifying a model, fit_image can take a reference image (a cropped deNaNed version of the data) to run correlations. It is recommended that the symmetric part of the data be used to avoid piston confusion in scaling. Good luck! """ self.model_in = modelin self.weighted = weighted self.saveval = savepsfs if modelin is None: self.vprint(self, " LG_Model.NRM_Model.fit_image: fittingmodel no modelin") # No model provided - now perform a set of automatic routines # A Cleaned up version of your image to enable Fourier fitting for # centering crosscorrelation with FindCentering() and # magnification and rotation via new_and_better_scaling_routine(). if reference==None: self.reference = image if np.isnan(image.any()): raise ValueError("Must have non-NaN image to "+\ "crosscorrelate for scale. Reference "+\ "image should also be centered. Get to it.") else: self.reference=reference # IMAGE CENTERING """ moved original ~12 lines code to determine_center routine... """ determine_center(self, centering) # populates self.best_center self.new_and_better_scaling_routine(self.reference, scaleguess=self.pixel, rotstart=rotguess, centering=self.bestcenter, fitswrite=self.saveval) self.pixscale_measured=self.pixel self.vprint(self, "pixel scale (mas):", utils.rad2mas(self.pixel)) self.fov=image.shape[0] self.fittingmodel=self.make_model(self.fov, bandpass=self.bandpass, over=self.over, rotate=True, psf_offset=self.bestcenter, pixscale=self.pixel) else: # This is the standard implaneia path on JWST NIRISS slice data # self.vprint(self, " **** LG_Model.NRM_Model.fit_image: fittingmodel=modelin") self.fittingmodel = modelin # working code 2022 next line... #self.soln, self.residual, self.cond,self.linfit_result = \ # leastsqnrm.matrix_operations(image, self.fittingmodel, verbose=False, dqm=dqm) #######################################################33 very old snippet below #######################################################33 very old snippet below if self.weighted is False: self.soln, self.residual, self.cond, self.linfit_result = \ leastsqnrm.matrix_operations(image, self.fittingmodel, verbose=False, dqm=dqm) else: self.soln, self.residual, self.cond, self.singvals = leastsqnrm.weighted_operations(image, \ self.fittingmodel, verbose=False, dqm=dqm) #######################################################33 inew code line above self.vprint(self, "NRM_Model Raw Soln:") self.vprint(self, self.soln) self.rawDC = self.soln[-1] self.flux = self.soln[0] self.soln = self.soln/self.soln[0] # fringephase now in radians self.fringeamp, self.fringephase = leastsqnrm.tan2visibilities(self.soln) self.fringepistons = utils.fringes2pistons(self.fringephase, len(self.ctrs)) self.redundant_cps = leastsqnrm.redundant_cps(self.fringephase, N=self.N) self.redundant_cas = leastsqnrm.return_CAs(self.fringeamp, N=self.N)
def new_and_better_scaling_routine(self, img, scaleguess=None, rotstart=0.0, datapath="", centering='PIXELCENTERED', fitswrite=True): """ returns pixel scale factor, rotation in addition to guess, and a goodness of fit parameter than can be compared in multiple iterations. correlations are calculated in the image plane, in anticipation of data with many bad pixels. """ if not hasattr(self, 'datapath'): self.datapath = datapath if not hasattr(self, 'bandpass'): raise ValueError( "This object has no specified bandpass/wavelength") reffov = img.shape[0] scal_corrlist = np.zeros((len(self.scallist), reffov, reffov)) pixscl_corrlist = scal_corrlist.copy() scal_corr = np.zeros(len(self.scallist)) self.pixscl_corr = scal_corr.copy() if fitswrite: pixfiles = [ f for f in os.listdir(self.datapath + self.refdir) if 'refpsf_pixscl' in f ] else: pixfiles = [] # --------------------------------- # user can specify a reference set of phases (m) at an earlier point so that # all PSFs are simulated with those phase pistons (e.g. measured from data at # an earlier iteration if not hasattr(self, 'refphi'): self.refphi = np.zeros(len(self.ctrs)) else: pass # --------------------------------- # --------------------------------- if len(pixfiles) > 4: vprint("reading in existing reference files...") vprint('in directory {0}'.format(self.datapath + self.refdir)) vprint(pixfiles) self.pixscales = np.zeros(len(pixfiles)) pixscl_corrlist = np.zeros((len(pixfiles), reffov, reffov)) for q, scalfile in enumerate(pixfiles): vprint(q) f = fits.open(self.datapath + self.refdir + pixfiles[q]) psf, filehdr = f[0].data, f[0].header self.test_pixscale = filehdr['PIXSCL'] self.pixscales[q] = self.test_pixscale f.close() pixscl_corrlist[q, :, :] = run_data_correlate(img, psf) self.pixscl_corr[q] = np.max(pixscl_corrlist[q]) vprint('max correlation', self.pixscl_corr[q]) if True in np.isnan(self.pixscl_corr): raise ValueError("Correlation produced NaNs,"\ " please check your work!") else: vprint('creating new reference files...') vprint('in directory {0}'.format(self.datapath + self.refdir)) self.pixscales = np.zeros(len(self.scallist)) for q, scal in enumerate(self.scallist): vprint(q) self.test_pixscale = self.pixel * scal self.pixscales[q] = self.test_pixscale psf = self.simulate( bandpass=self.bandpass, fov=reffov, pixel=self.test_pixscale, centering=centering ) #, phi=self.refphi) #Removed phi from call to simulate. DT, AS Feb 2016 # ------------------------------- if fitswrite: temphdu = fits.PrimaryHDU(data=psf, header=self.simhdr) temphdu.header["pixscale"] = (self.test_pixscale, "pixel scale (rad)") temphdu.writeto(self.datapath+self.refdir+\ "refpsf_pixscl{0}.fits".format(self.test_pixscale), clobber=True) # ------------------------------- pixscl_corrlist[q, :, :] = run_data_correlate(img, psf) self.pixscl_corr[q] = np.max(pixscl_corrlist[q]) if True in np.isnan(self.pixscl_corr): raise ValueError("Correlation produced NaNs,"\ " please check your work!") np.savetxt(self.datapath + self.refdir + "pix_correlationvalues.txt", self.pixscl_corr) np.savetxt(self.datapath + self.refdir + "pixelscalestested_rad.txt", self.pixscales) np.savetxt(self.datapath + self.refdir + "pixscalestested_val.txt", self.scallist) self.pixscale_optimal, scal_maxy = utils.findmax(mag=self.pixscales, vals=self.pixscl_corr) self.pixscale_factor = self.pixscale_optimal / self.pixel closestpixscale = self.pixscales[self.pixscl_corr == self.pixscl_corr.max()][0] vprint('PIXSCALE DEBUG') vprint(closestpixscale) vprint('NRM_Model pixel scale:', self.pixscale_optimal) vprint('fraction of guess:', self.pixscale_factor) radlist = self.rotlist_rad #DT, AS Jan 2016 corrlist = np.zeros((len(radlist), reffov, reffov)) self.corrs = np.zeros(len(radlist)) if fitswrite: rotfiles = [ f for f in os.listdir(self.datapath + self.refdir) if 'refpsf_rot' in f ] else: rotfiles = [] if len(rotfiles) > 4: vprint("reading from file") self.rots = np.zeros(len(rotfiles)) for q, rotfilefile in enumerate(rotfiles): f = fits.open(self.datapath + self.refdir + rotfile) vprint(self.datapath + self.refdir + rotfile, end=' ') vprint("rotfile", rotfile) psf, filehdr = f[0].data, f[0].header self.rots[q] = filehdr['ROTRAD'] f.close() corrlist[q, :, :] = run_data_correlate(psf, img) self.corrs[q] = np.max(corrlist[q]) vprint('max rot correlation: ', self.corrs[q]) self.corrs = self.corrs[np.argsort(self.rots)] self.rots = self.rots[np.argsort(self.rots)] else: self.rots = radlist for q, rad in enumerate(radlist): vprint('no rotation files found, creating new...') psf = self.simulate( bandpass=self.bandpass, fov=reffov, #pixel = closestpixscale, rotate=rad, pixel=self.pixscale_optimal, rotate=rad, centering=centering) # ------------------------------- if fitswrite: temphdu = fits.PrimaryHDU(data=psf, header=self.simhdr) temphdu.header["pixscale"] = (self.pixscale_optimal, \ "pixel scale (rad)") temphdu.writeto(self.datapath+self.refdir+\ "refpsf_rot{0}_pixel{1}.fits".format(rad, closestpixscale),clobber=True) # ------------------------------- corrlist[q, :, :] = run_data_correlate(psf, img) self.corrs[q] = np.max(corrlist[q]) np.savetxt(self.datapath + self.refdir + "rot_correlationvalues.txt", self.corrs) np.savetxt(self.datapath + self.refdir + "rotationstested_rad.txt", self.rots) np.savetxt(self.datapath + self.refdir + "rotationstested_deg.txt", self.rots * 180.0 / np.pi, fmt=self.fmt) #DT nov 20 self.rot_measured, maxy, = utils.findmax(mag=self.rots, vals=self.corrs) self.refpsf = self.simulate(bandpass=self.bandpass, pixel=self.pixscale_factor * self.pixel, fov=reffov, rotate=self.rot_measured, centering=centering) vprint( '--------------- WHAT THE MATCHING ROUTINE FOUND ---------------') vprint('scaling factor:', self.pixscale_factor) vprint('pixel scale (mas):', utils.rad2mas(self.pixscale_optimal)) vprint('rotation (rad):', self.rot_measured) vprint('--------------- -------------- ---------------') try: self.gof = goodness_of_fit(img, self.refpsf) except: vprint("rewrite goodness_of_fit, it failed.") self.gof = False return self.pixscale_factor, self.rot_measured, self.gof