def fit_fringes_single_integration(args): self = args["object"] slc = args["slc"] # indexes each slice of 3D stack of images id_tag = args["slc"] nrm = NRM_Model(mask=self.instrument_data.mask, pixscale=self.instrument_data.pscale_rad, holeshape=self.instrument_data.holeshape, affine2d=self.instrument_data.affine2d, over=self.oversample) # for image data from single filter, this is the filter bandpass. # otherwise it's the IFU wavelength slice. nrm.bandpass = self.instrument_data.wls[slc] if self.npix == 'default': self.npix = self.scidata[slc, :, :].shape[0] # New or modified in LG++ # center the image on its peak pixel: # AS subtract 1 from "r" below for testing >1/2 pixel offsets # AG 03-2019 -- is above comment still relevant? # Where appropriate, the slice under consideration is centered, and processed if self.instrument_data.arrname == "jwst_g7s6c": # get the cropped image and identically-cropped bad pixel data: self.ctrd, self.dqslice = utils.center_imagepeak( self.scidata[slc, :, :], dqm=self.dqmask[slc, :, :]) else: self.ctrd = utils.center_imagepeak(self.scidata[slc, :, :]) # store the 2D cropped image centered on the brightest pixel, # bad pixels smoothed over if self.psf_offset_ff is None: # returned values have offsets x-y flipped: # Finding centroids the Fourier way assumes no bad pixels case # - Fourier domain mean slope # offsets from brightest pixel ctr centroid = utils.find_centroid(self.ctrd, self.instrument_data.threshold) # use flipped centroids to update centroid of image for JWST # pixel coordinates: - note the flip of [0] and [1] to match DS9 view image_center = utils.centerpoint(self.ctrd.shape) + \ np.array((centroid[1], centroid[0])) # info only, unused nrm.xpos = centroid[1] # flip 0 and 1 to convert nrm.ypos = centroid[0] # flip 0 and 1 nrm.psf_offset = nrm.xpos, nrm.ypos # renamed .bestcenter to .psf_offset if self.debug: print( "nrm.core.fit_fringes_single_integration: utils.find_centroid() -> nrm.psf_offset" ) else: # user-provided psf_offset python-style offsets from array center are here. nrm.psf_offset = self.psf_offset_ff nrm.make_model(fov=self.ctrd.shape[0], bandpass=nrm.bandpass, over=self.oversample, psf_offset=nrm.psf_offset, pixscale=nrm.pixel) # again, fit just one slice... if self.instrument_data.arrname == "jwst_g7s6c": nrm.fit_image(self.ctrd, modelin=nrm.model, psf_offset=nrm.psf_offset, dqm=self.dqslice, weighted=self.weighted) else: nrm.fit_image(self.ctrd, modelin=nrm.model, psf_offset=nrm.psf_offset, weighted=self.weighted) """ Attributes now stored in nrm object: ----------------------------------------------------------------------------- soln --- resulting sin/cos coefficients from least squares fitting fringephase --- baseline phases in radians fringeamp --- baseline amplitudes (flux normalized) redundant_cps --- closure phases in radians redundant_cas --- closure amplitudes residual --- fit residuals [data - model solution] cond --- matrix condition for inversion fringepistons --- zero-mean piston opd in radians on each hole (eigenphases) ----------------------------------------------------------------------------- For jwst_g7s6 cropped-to-match-data bad pixel array 'ctrb' is also stored """ self.save_output(slc, nrm) # Please elucidate what this is for self.nrm = nrm # store extracted values here return None
def setUp(self): # setup parameters for simulation verbose = 1 overwrite = 1 monochromatic_wavelength_m = np.array([(1.0, 4.3e-6),]) mask = 'MASK_NRM' filter = 'F430M' pixelscale_arcsec = 0.0656 filter_name = 'Monochromatic '+np.str(monochromatic_wavelength_m) self.filter = filter self.filter_name = filter_name self.monochromatic_wavelength_m = monochromatic_wavelength_m # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__),'test_data/fringe_fitting') if not os.path.exists(data_dir): os.makedirs(data_dir) out_dir = data_dir name_seed = 'PSF_NIRISS_%s_%s'%(mask,filter) psf_image_name = name_seed + '_reference.fits' psf_image = os.path.join(data_dir,psf_image_name) psf_image_without_oversampling = os.path.join(data_dir,psf_image_name.replace('.fits','_without_oversampling.fits')) if (not os.path.isfile(psf_image_without_oversampling)) | (overwrite): from nrm_analysis.fringefitting.LG_Model import NRM_Model jw = NRM_Model(mask='jwst',holeshape="hex") jw.set_pixelscale(pixelscale_arcsec*arcsec2rad) jw.simulate(fov=n_image, bandpass=monochromatic_wavelength_m, over=oversample) print("FringeFittingTestCase.SetUp: simulation oversampling is", oversample) # optional writing of oversampled image if 0: fits.writeto(psf_image,jw.psf_over, clobber=True) header = fits.getheader(psf_image) header['PIXELSCL'] = pixelscale_arcsec/oversample header['FILTER'] = filter_name header['PUPIL'] = mask fits.update(psf_image,jw.psf_over/10000./28., header=header) # PSF without oversampling fits.writeto(psf_image_without_oversampling,jw.psf, clobber=True) header = fits.getheader(psf_image_without_oversampling) header['PIXELSCL'] = pixelscale_arcsec header['FILTER'] = filter_name header['PUPIL'] = mask fits.update(psf_image_without_oversampling,jw.psf, header=header) # list of files produced for target file_list = glob.glob(os.path.join(data_dir,'*%s*.fits' % 'without_oversampling' )); self.simulated_image = file_list[0] self.psf_image_without_oversampling = psf_image_without_oversampling
class Affine2dTestCase(unittest.TestCase): def setUp(self): # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__),'test_data/affine2d_rot_psf') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) self.fnfmt = data_dir+'/psf_nrm_{2:.1f}_{0}_{1}_{3:.0f}.fits' # expects strings of %(imsize,hole) self.fmt = " ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})" self.pixel = 0.0656 * u.arcsec.to(u.rad) self.npix = 87 self.wave = np.array([(1.0, 4.3e-6),]) # m self.over = 1 mx, my = 1.0, 1.0 sx, sy= 0.0, 0.0 xo, yo= 0.0, 0.0 affine_ideal = Affine2d(mx=mx,my=my, sx=sx,sy=sy, xo=xo,yo=yo, name="Ideal") for rot in (0,5,10,15,20,25,30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95): """ print(" rot degrees pre", rot, end='') diagnostic = rot/15.0 - int(rot/15.0) print(" diagnostic", diagnostic, end='') rot = avoidhexsingularity(rot) # in utils print(" rot degrees post", rot) """ rot = avoidhexsingularity(rot) # in utils affine_rot = Affine2d(rotradccw=np.pi*rot/180.0, name="{0:.0f}".format(rot)) # in utils aff = affine_rot # hexonly g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff) self.jw.set_pixelscale(self.pixel*arcsec2rad) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, rot) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw del aff del affine_rot def test_psf(self): """ Read in PSFs with 0, 90 degree affines, 5 and 95 degree affines, Rotate one set and subtract from the smaller rot PSF - should be zero if everything is correctly calculated. If we nudge the PSF centers to avoid the line singularity that hextransformEE will encounter if the psf is centrally placed in a pixel. The file names are hand-edited to reflect the oversampling and rotations, so this is more a sanity check and code development tool than a routine test. """ psf0 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 0)) psf90 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 90)) psf90r0 = np.rot90(psf90) psfdiff = psf0 - psf90r0 fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir+"/diff_90_0_off08_ov1.fits", overwrite=True) psf0 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 5)) psf90 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 95)) psf90r0 = np.rot90(psf90) psfdiff = psf0 - psf90r0 fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir+"/diff_95_5_off08_ov1.fits", overwrite=True) self.assertTrue(0.0 < 1e-15, 'error: test_affine2d failed')
def verify_pistons(arg): """ Create simulated data with pistons, 1. analyze the data by calling fit_image Do not use fringefitter since the data is perfecrly centered (the if loop). Check if input and output pistons match. 2. analyze the data by calling fit_image via fringefitter Fringefitter finds the bestcenter and makes model with bestcenter. Since the data is perfecrly centered fringefitter should not affect output pistons. Check if input and output pistons match. """ jw = NRM_Model(mask='jwst', holeshape="hex") pixelscale_as = 0.0656 arcsec2rad = u.arcsec.to(u.rad) jw.set_pixelscale(pixelscale_as * arcsec2rad) np.random.seed(100) #lambda/14 ~ 80% strehl ratio phi = np.random.normal(0, 1.0, 7) / 14.0 # waves print("phi", phi, "varphi", phi.var(), "waves") phi = phi - phi.mean() print("phi_nb stdev/w", phi.std()) print("phi_nb stdev/r", phi.std() * 2 * np.pi) print("phi_nb mean/r", phi.mean() * 2 * np.pi) pistons = phi * 4.3e-6 #OR print("/=====input pistons/m=======/\n", pistons) print("/=====input pistons/r=======/\n", pistons * (2 * np.pi) / 4.3e-6) jw.set_pistons(pistons) jw.simulate(fov=81, bandpass=4.3e-6, over=oversample) fits.PrimaryHDU(data=jw.psf).writeto( "implaneia_tests/perfect_wpistons.fits", overwrite=True) if arg == ("no_fringefitter"): jw.make_model(fov=81, bandpass=4.3e-6, over=oversample) jw.fit_image(jw.psf, modelin=jw.model) pos = np.get_printoptions() np.set_printoptions(precision=4, formatter={'float': lambda x: '{:+.4e}'.format(x)}, linewidth=80) print("Residual/psfpeak array center:", jw.psf.shape) print((jw.residual / jw.psf.max())[36:-36, 36:-36]) np.set_printoptions(pos) fits.PrimaryHDU(data=jw.residual).writeto( "residual_pistons_no_ff.fits", overwrite=True) #return jw #print("output pistons/r",jw.fringepistons) #print("output pistons/w",jw.fringepistons/(2*np.pi)) #print("output pistons/m",jw.fringepistons*4.3e-6/(2*np.pi)) #print("input pistons/m ",jw.phi) elif arg == ("use_fringefitter"): fits.PrimaryHDU(data=jw.psf).writeto(datadir + "/perfect_wpistons.fits", overwrite=True) amisim2mirage(datadir, ("perfect_wpistons", ), mirexample, filt) niriss = InstrumentData.NIRISS(filt) ff_t = nrm_core.FringeFitter(niriss, datadir=datadir, savedir=datadir, oversample=oversample, interactive=False) print(test_tar) ff_t.fit_fringes(test_tar) print("Residual:") #print(ff_t.nrm.residual) print("Residual/psfpeak array center:", ff_t.nrm.reference.shape) pos = np.get_printoptions() np.set_printoptions(precision=3, formatter={'float': lambda x: '{:+.3e}'.format(x)}, linewidth=80) print((ff_t.nrm.residual / jw.psf.max())[36:-36, 36:-36]) np.set_printoptions(pos) fits.PrimaryHDU(data=ff_t.nrm.residual).writeto(datadir+\ "/residual_pistons_with_ff.fits",overwrite=True) utils.compare_pistons(jw.phi * 2 * np.pi / 4.3e-6, ff_t.nrm.fringepistons, str="ff_t")
def setUp(self): # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data/psf_offset') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) self.pixel = 0.0656 * u.arcsec.to(u.rad) self.npix = 87 self.wave = 4.3e-6 # m self.over = 1 """ mx, my = 1.0, 1.0 sx, sy= 0.0, 0.0 xo, yo= 0.0, 0.0 affine_ideal = Affine2d(mx=mx,my=my, sx=sx,sy=sy, xo=xo,yo=yo, name="Ideal") """ invert = False # greyscale inversion (true/false) holeshape = "hex" pixel_as = 0.0656 / 1.3 # slightly finer-than-actual-detector sampling, for clearer images print( "\n\t*** Watch out *** if comparing to real data: slightly finer-than-actual-detector sampling used for clearer images\n" ) fov = 101 # 'detpix' but at finer sampling than actual over = 1 wav_m = 4.3e-6 filt = 'F430M' band = 'Monochromatic ' + np.str(wav_m) psf_offsets = ( (0, 0), (1.0, 0), ) psf_offsets = ((0, 0), ) psf_offsets = ((0, 0), (1.0, 0), (0, 1.0), (1.0, 1.0)) print((enumerate(psf_offsets))) psfs = np.zeros( (len(psf_offsets), fov, fov)) # for easy to understand movie print(('psfs.shape', psfs.shape)) fncube3 = data_dir + "/cube.fits" # Loop over psf_offsets for noff, psfo in enumerate(psf_offsets): jw3 = NRM_Model(mask='jwst', holeshape=holeshape, pixscale=arcsec2rad * pixel_as, datapath="", refdir="./refdir") #chooseholes=None) jw3.simulate(fov=fov, bandpass=wav_m, over=over, psf_offset=psfo) mnem = "imctr_%.1f_%.1f" % psfo fn3 = data_dir + "/" + mnem + '.fits' name_seed = mnem # PSF fits.writeto(fn3, jw3.psf, overwrite=True) header = fits.getheader(fn3) header['SEGNAMES'] = "asbuilt" header['PIXELSCL'] = pixel_as header['over'] = over header['FILTER'] = wav_m header['hole'] = holeshape header['PUPIL'] = 'asbuilt' header['psfoff0'] = (psfo[0], "ds9X / detector pixels") header['psfoff1'] = (psfo[1], "ds9Y / detector pixels") header['SRC'] = ("test_psf_offset.py", "generating code") header['author'] = ("*****@*****.**", "responsible person?") fits.update(fn3, jw3.psf, header=header) psfs[noff, :, :] = jw3.psf """ calls tkinter, needs $DISPLAY environment variable, breaks travis testing figname = UC.make_standard_image( fn3, image_title=name_seed, save_plot=1, plot_dir=data_dir, name_seed=name_seed, stretch='linear', x_axis_label=None, y_axis_label=None, invert=invert, add_grid=True) print(figname + " written to " + data_dir) """ del jw3 fits.PrimaryHDU(data=psfs).writeto(fncube3, overwrite=True) # good for movie """
def find_scale( imagedata, affine_best, # best current guess at data geometry cf analytical ideal scales, # scales are near-unity pixel, npix, bandpass, over, holeshape, outdir=None): # for nrm_model """ Preserve incoming "pixel" value, put the scale correction into the Affine2d object Is that kosher??? Should we change the pixel scale and leave affine2d the same? Affine2d can also incorporate unequal x and y scales, shears... For now place scale corrections into the Affine2d object Note - placing isotropic scale change into Affine2d is equivalent to changing the effective image distance in the optical train while insisting that the mask physical geometry does not change, and the wavelength is perfectly knowm AS 2018 10 """ affine_best.show("\tfind_scale") vprint("\tBefore Loop: ", scales) #Extend this name to include multi-paramater searches? psffmt = 'psf_nrm_{0:d}_{1:s}_{2:.3f}um_scl{3:.3f}.fits' # expect (npix, holeshape, bandpass/um, scl) if hasattr(scales, '__iter__') is False: scales = (scales, ) affine2d_list = create_afflist_scales(scales, affine_best.mx, affine_best.my, affine_best.sx, affine_best.sy, affine_best.xo, affine_best.yo) crosscorrs = [] for (scl, aff) in zip(scales, affine2d_list): vprint(aff.name + "...") jw = NRM_Model(mask='jwst', holeshape=holeshape, over=over, affine2d=aff) jw.set_pixelscale(pixel) jw.simulate(fov=npix, bandpass=bandpass, over=over) psffn = psffmt.format(npix, holeshape, bandpass / um, scl) if outdir: fits.PrimaryHDU(data=jw.psf).writeto(outdir + "/" + psffn, overwrite=True) fits.writeto(psffn, jw.psf, overwrite=True) header = fits.getheader(psffn) utils.affinepars2header(header, aff) fits.update(psffn, jw.psf, header=header) crosscorrs.append(utils.rcrosscorrelate(imagedata, jw.psf).max()) del jw vprint("\t*******************") vprint("\tDebug: crosscorrelations", crosscorrs) vprint("\tDebug: scales", scales) scl_measured, max_cor = utils.findpeak_1d(crosscorrs, scales) vprint("\tScale factor measured {0:.5f} Max correlation {1:.3e}".format( scl_measured, max_cor)) vprint("\tpixel pitch from header {0:.3f} mas".format(pixel * rad2mas)) vprint("\tpixel pitch {0:.3f} mas (implemented using affine2d)".format( scl_measured * pixel * rad2mas)) # return convenient affine2d return utils.Affine2d(affine_best.mx * scl_measured, affine_best.my * scl_measured, affine_best.sx * scl_measured, affine_best.sy * scl_measured, affine_best.xo * scl_measured, affine_best.yo * scl_measured, name="scale_{0:.4f}".format(scl))
def setUp(self): # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data/affine2d_xyscale_psf') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) self.fnfmt = data_dir + '/psf_nrm_{0:d}_{1:s}_{2:.3f}um_{3:s}.fits' # expects e.g. self.fnfmt.format(self.npix, 'hex', self.wave/um, aff.name) self.pixel = 0.0656 * u.arcsec.to(u.rad) self.npix = 87 self.wave = 4.3e-6 # m self.over = 1 ################ self.pointsfmt = " ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})" self.numtestfmt = " min: {0:+.1e}, max: {1:+.1e}, avg: {2:+.1e}, sig: {3:+.1e}" # min max avg stddev self.testpoints = (np.array((0, 0)), np.array((1, 0)), np.array( (0, 1)), np.array((1, 1))) xo, yo = 0.0, 0.0 # always set these for PSFs... mx, my = 1.0, 1.0 sx, sy = 0.0, 0.0 self.affine_ideal = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Ideal") mx, my = -1.0, 1.0 sx, sy = 0.0, 0.0 self.affine_xrev = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xreverse") mx, my = 2.0, 1.0 sx, sy = 0.0, 0.0 self.affine_xmag = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xmag") mx, my = 1.0, 1.0 sx, sy = 0.5, 0.0 self.affine_sigx = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xshear") for aff in (self.affine_ideal, self.affine_xrev, self.affine_xmag, self.affine_sigx): # circ g7s6 jwst created for info only self.jw = NRM_Model(mask='jwst', holeshape="circ", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'circ', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # circonly g7s6 jwst created for info only self.jw = NRM_Model(mask='jwst', holeshape="circonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'circonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # hex g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'hex', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # hexonly g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # fringeonly g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="fringeonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'fringeonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw del aff self.hextest = self.eval_psf_hex() self.fringeonlytest = self.eval_psf_fringeonly() self.hexonlytest = self.eval_psf_hexonly() self.evals = [self.hextest, self.fringeonlytest, self.hexonlytest] self.sigsum = self.hextest + self.fringeonlytest + self.hexonlytest
class Affine2dTestCase(unittest.TestCase): def setUp(self): # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data/affine2d_xyscale_psf') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) self.fnfmt = data_dir + '/psf_nrm_{0:d}_{1:s}_{2:.3f}um_{3:s}.fits' # expects e.g. self.fnfmt.format(self.npix, 'hex', self.wave/um, aff.name) self.pixel = 0.0656 * u.arcsec.to(u.rad) self.npix = 87 self.wave = 4.3e-6 # m self.over = 1 ################ self.pointsfmt = " ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})" self.numtestfmt = " min: {0:+.1e}, max: {1:+.1e}, avg: {2:+.1e}, sig: {3:+.1e}" # min max avg stddev self.testpoints = (np.array((0, 0)), np.array((1, 0)), np.array( (0, 1)), np.array((1, 1))) xo, yo = 0.0, 0.0 # always set these for PSFs... mx, my = 1.0, 1.0 sx, sy = 0.0, 0.0 self.affine_ideal = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Ideal") mx, my = -1.0, 1.0 sx, sy = 0.0, 0.0 self.affine_xrev = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xreverse") mx, my = 2.0, 1.0 sx, sy = 0.0, 0.0 self.affine_xmag = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xmag") mx, my = 1.0, 1.0 sx, sy = 0.5, 0.0 self.affine_sigx = Affine2d(mx=mx, my=my, sx=sx, sy=sy, xo=xo, yo=yo, name="Xshear") for aff in (self.affine_ideal, self.affine_xrev, self.affine_xmag, self.affine_sigx): # circ g7s6 jwst created for info only self.jw = NRM_Model(mask='jwst', holeshape="circ", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'circ', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # circonly g7s6 jwst created for info only self.jw = NRM_Model(mask='jwst', holeshape="circonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'circonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # hex g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'hex', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # hexonly g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw # fringeonly g7s6 jwst self.jw = NRM_Model(mask='jwst', holeshape="fringeonly", affine2d=aff) self.jw.set_pixelscale(self.pixel) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) psffn = self.fnfmt.format(self.npix, 'fringeonly', self.wave / um, aff.name) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) del self.jw del aff self.hextest = self.eval_psf_hex() self.fringeonlytest = self.eval_psf_fringeonly() self.hexonlytest = self.eval_psf_hexonly() self.evals = [self.hextest, self.fringeonlytest, self.hexonlytest] self.sigsum = self.hextest + self.fringeonlytest + self.hexonlytest """ Ideal and Xreverse_xflipped should be machine zero or close """ def eval_psf_hex(self): psfIdeal = fits.getdata( self.fnfmt.format(self.npix, 'hex', self.wave / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'hex', self.wave / um, "Xreverse")) psfdiff = psfIdeal - psfXrev[::-1, :] print(" Numerical Summary: hex psf: " +\ self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std())) print(" Numerical Summary: hex test: " +\ self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std())) fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir + "/diff_hex.fits", overwrite=True) return psfdiff.std() def eval_psf_fringeonly(self): psfIdeal = fits.getdata( self.fnfmt.format(self.npix, 'fringeonly', self.wave / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'fringeonly', self.wave / um, "Xreverse")) psfdiff = psfIdeal - psfXrev[::-1, :] print(" Numerical Summary: fringeonly psf: " +\ self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std())) print(" Numerical Summary: fringeonly test: " +\ self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std())) fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir + "/diff_fringeonly.fits", overwrite=True) return psfdiff.std() def eval_psf_hexonly(self): psfIdeal = fits.getdata( self.fnfmt.format(self.npix, 'hexonly', self.wave / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'hexonly', self.wave / um, "Xreverse")) psfdiff = psfIdeal - psfXrev[::-1, :] print(" Numerical Summary: hexonly psf: " +\ self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std())) print(" Numerical Summary: hexonly test: " +\ self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std())) fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir + "/diff_hexonly.fits", overwrite=True) return psfdiff.std() def test_psfs(self): print("Standard deviations of all three tests:", self.evals) self.assertTrue(self.sigsum < 1e-7, 'error: test_affine2d_xyscale_psf failed')
def setUp(self): # setup parameters for simulation, most are passed on to driver_scene verbose = 0 overwrite = 1 apply_dither = 0 apply_jitter = 0 include_detection_noise = 0 uniform_flatfield = 1 OVERSAMPLE = 11 monochromatic_wavelength_m = 4.3e-6 create_calibrator = 0 random_seed = 124 flip = False mask = 'MASK_NRM' filter = 'F430M' n_image = 77 filter_name = 'Monochromatic ' + np.str(monochromatic_wavelength_m) # directory containing the static test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data') # define output directory for dynamically generated data out_dir = os.path.join(os.path.dirname(__file__), 'tmp_data') if not os.path.exists(out_dir): os.makedirs(out_dir) name_seed = 'PSF_NIRISS_%s_%s' % (mask, filter) point_source_image_name = 'point_source_image.fits' point_source_image = os.path.join(out_dir, point_source_image_name) psf_image_name = name_seed + '_reference.fits' psf_image = os.path.join(data_dir, psf_image_name) psf_image_without_oversampling = os.path.join( data_dir, psf_image_name.replace('.fits', '_without_oversampling.fits')) # generate delta-function like image to feed as point-source into scene_sim n_image2 = n_image * OVERSAMPLE data = np.zeros((n_image2, n_image2)) bright_pixel_index = (np.int(np.floor(n_image2 / 2.)), np.int(np.floor(n_image2 / 2.))) data[bright_pixel_index] = 1. fits.writeto(point_source_image, data, clobber=True) # following code can be used to regenerate reference PSF file, but it depends on nrm_analysis if 0: from nrm_analysis.fringefitting.LG_Model import NRM_Model jw = NRM_Model(mask='jwst', holeshape="hex", flip=flip) jw.simulate(fov=n_image, bandpass=monochromatic_wavelength_m, over=OVERSAMPLE, pixel=mas2rad(PIXELSCL_arcsec * 1000)) fits.writeto(psf_image, jw.psf_over, clobber=True) header = fits.getheader(psf_image) header['PIXELSCL'] = PIXELSCL_arcsec / OVERSAMPLE header['FILTER'] = filter_name header['PUPIL'] = mask fits.update(psf_image, jw.psf_over / 10000. / 28., header=header) # PSF without oversampling fits.writeto(psf_image_without_oversampling, jw.psf, clobber=True) header = fits.getheader(psf_image_without_oversampling) header['PIXELSCL'] = PIXELSCL_arcsec header['FILTER'] = filter_name header['PUPIL'] = mask fits.update(psf_image_without_oversampling, jw.psf, header=header) NGROUP = 1 NINT = 1 COUNTRATE = 5e8 # run driver_scene to generate target and calibrator images driver_scene.main(['--output_absolute_path','%s'%out_dir,\ '--overwrite','%d'%overwrite,'-utr','0', '-f','%s'%filter,'-v','%d'%verbose,'--apply_dither','%d'%apply_dither,'--apply_jitter','%d'%apply_jitter,\ '-p',psf_image,'-s','%s'%point_source_image,'-os','%d'%OVERSAMPLE,'-cr','%e'%COUNTRATE,'--include_detection_noise','%d'%include_detection_noise,\ '-tag',('%3.2e_NGROUP%d'%(COUNTRATE,NGROUP)).replace('.','p'),'--uniform_flatfield','%d'%uniform_flatfield,'--random_seed','%d'%random_seed,\ '--create_calibrator','%d'%create_calibrator,'--nint','%d'%NINT,'--ngroups','%d'%NGROUP]) # directory where simulated data was written filter_dir = os.path.join(out_dir, filter) self.filter_dir = filter_dir # list of files produced for target file_list = glob.glob(os.path.join(filter_dir, '%s*.fits' % 't_')) self.simulated_image = file_list[0] self.psf_image_without_oversampling = psf_image_without_oversampling