def create_data(imdir, rot, ov): """ imdir: directory for simulated fits image data rot: pupil rotation in degrees ov: oversample for simulation Writes sim data to fitsimdir """ npix = 81 wave = 4.3e-6 # SI fnfmt = '/psf_nrm_{2:.1f}_{0}_{1}_rot{3:.3f}d.fits' # expects strings of %(npix, holeshape, wave/um, rot_d) rot = utils.avoidhexsingularity(rot) # in utils affine_rot = utils.Affine2d(rotradccw=np.pi*rot/180.0, name="rot{0:.3f}d".format(rot)) # in utils jw = NRM_Model(mask='jwst', holeshape='hex', affine2d=affine_rot) jw.set_pixelscale(PIXELSCALE_r) jw.simulate(fov=81, bandpass=MONOF430M, over=ov) psffn = fnfmt.format(npix, 'hex', wave/um, rot) fits.writeto(imdir+psffn, jw.psf, overwrite=True) header = fits.getheader(imdir+psffn) header = utils.affinepars2header(header, affine_rot) fits.update(imdir+psffn, jw.psf, header=header) del jw return psffn # filename only, not full path
def setUp(self): self.holeshape = "hex" # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data/find_affine2d_parameters') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) pixel = 0.0656 * u.arcsec.to(u.rad) npix = 87 wave = np.array([ (1.0, 4.3e-6), ]) # m over = 3 holeshape = 'hex' rotd_true = 9.25 rotdegs = (8.0, 9.0, 10.0, 11.0, 12.0 ) # search in this range of rotation (degrees) # store the real affine to be uased to create test data self.affine = utils.Affine2d( rotradccw=np.pi * utils.avoidhexsingularity(rotd_true) / 180.0, name="{0:.4}".format(float(rotd_true))) self.affine.show(label="Creating affine2d for PSF data") # create image data to find its rotation, as a sample test... imagefn = data_dir + "/imagedata.fits" jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=self.affine) jw.set_pixelscale(pixel) jw.simulate(fov=npix, bandpass=wave, over=over) fits.writeto(imagefn, jw.psf, overwrite=True) imagedata = jw.psf.copy() del jw fits.getdata(imagefn) psf_offset = (0.0, 0.0) print("driver:", rotdegs) mx, my, sx, sy, xo, yo, = (1.0, 1.0, 0.0, 0.0, 0.0, 0.0) aff_best_rot = FAP.find_rotation(imagedata, psf_offset, rotdegs, mx, my, sx, sy, xo, yo, pixel, npix, wave, over, holeshape, outdir=data_dir) print(aff_best_rot) self.aff_best_rot = aff_best_rot
def test_offset_residuals(): """ Use same affine object for simulation and analysis """ pixelscale_as = 0.0656 arcsec2rad = u.arcsec.to(u.rad) #psf_offsets = ((0,0), (1.0,0), ) #psf_offsets = ((0,0), (1.0,0), (0, 1.0), (1.0,1.0)) bandpass = np.array([ (1.0, 4.3e-6), ]) # Loop over psf_offsets jw = NRM_Model(mask='jwst', holeshape='hex') jw.set_pixelscale(pixelscale_as * arcsec2rad) jw.simulate(fov=35, bandpass=bandpass, over=oversample, psf_offset=psf_offsets) fits.writeto(fitsimdir + "offset_data.fits", jw.psf, overwrite=True) jw.make_model(fov=35, bandpass=bandpass, over=oversample, psf_offset=psf_offsets) jw.fit_image(jw.psf, modelin=jw.model) fits.writeto(fitsimdir + "residual_offset.fits", jw.residual, overwrite=True)
def find_rotation( imagedata, rotdegs, mx, my, sx, sy, xo, yo, # for Affine2d pixel, npix, bandpass, over, holeshape, outdir=None): # for nrm_model """ AS AZG 2018 08 Ann Arbor Develop the rotation loop first """ vprint("Before Loop: ", rotdegs) #Extend this name to include multi-paramater searches? psffmt = 'psf_nrm_{0:d}_{1:s}_{2:.3f}um_r{3:.3f}deg.fits' # expect (npix, holeshape, bandpass/um, scl) if hasattr(rotdegs, '__iter__') is False: rotdegs = (rotdegs, ) affine2d_list = create_afflist_rot(rotdegs, mx, my, sx, sy, xo, yo) crosscorr_rots = [] for (rot, aff) in zip(rotdegs, 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, rot) 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) crosscorr_rots.append(utils.rcrosscorrelate(imagedata, jw.psf).max()) del jw vprint("Debug: ", crosscorr_rots, rotdegs) rot_measured_d, max_cor = utils.findpeak_1d(crosscorr_rots, rotdegs) vprint("Rotation measured: max correlation {1:.3e}", rot_measured_d, max_cor) # return convenient affine2d return utils.Affine2d(rotradccw=np.pi * rot_measured_d / 180.0, name="{0:.4f}".format(rot_measured_d))
def simulate_data(affine2d=None, psf_offset_det=None, pistons_w=None): np.set_printoptions(precision=4, formatter={'float': lambda x: '{:+.1e}'.format(x)}, linewidth=80) default_printoptions() #***********ADD EFFECTS TO SIMULATE******************* jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=affine2d) jw.set_pixelscale(pixelscale_as*arcsec2rad) jw.simulate(fov=fov, bandpass=bandpass, over=oversample) fits.PrimaryHDU(data=jw.psf).writeto(fitsimdir+"all_effects_data.fits",overwrite=True) #**********Convert simulated data to mirage format.******* utils.amisim2mirage(fitsimdir, ("all_effects_data",), mirexample, filt)
def simulate_data(affine2d=None, psf_offset_det=None, pistons_w=None): print(" simulate_data: ", affine2d.name) #************ADD PISTONS TO PERFECT DATA****************** pistons_w = pistons_w - pistons_w.mean() pistons_m = pistons_w * lamc pistons_r = pistons_w * 2.0 * np.pi utils.show_pistons_w(pistons_w, str="simulate_data: input pistons") np.set_printoptions(precision=4, formatter={'float': lambda x: '{:+.1e}'.format(x)}, linewidth=80) print(" simulate_data: pistons_um", pistons_m / 1e-6) print(" simulate_data: pistons_r", pistons_r) print(" simulate_data: pistons_w stdev/w", round(pistons_w.std(), 4)) print(" simulate_data: pistons_w stdev/r", round(pistons_w.std() * 2 * np.pi, 4)) print(" simulate_data: pistons_w mean/r", round(pistons_w.mean() * 2 * np.pi, 4)) default_printoptions() #***********ADD EFFECTS TO SIMULATE******************* jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=affine2d) jw.set_pixelscale(pixelscale_as * arcsec2rad) jw.set_pistons(pistons_m) print(" simulate: ", psf_offset_det, type(psf_offset_det)) jw.simulate(fov=fov, bandpass=bandpass, over=oversample, psf_offset=psf_offset_det) fits.PrimaryHDU(data=jw.psf).writeto(fitsimdir + "all_effects_data.fits", overwrite=True) #**********Convert simulated data to mirage format.******* utils.amisim2mirage(fitsimdir, ("all_effects_data", ), mirexample, filt)
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[:, 1][0] / 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("\tfind_affine2d_parameters: crosscorrelations", crosscorrs) vprint("\tfind_affine2d_parameters: scales", scales) scl_measured, max_cor = utils.findpeak_1d(crosscorrs, scales) vprint( "\tfind_affine2d_parameters factor measured {0:.5f} Max correlation {1:.3e}" .format(scl_measured, max_cor)) vprint("\tfind_affine2d_parameters pitch from header {0:.3f} mas".format( pixel * rad2mas)) vprint( "\tfind_affine2d_parameters 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))
class Affine2dMakeModelRotTestCase(unittest.TestCase): def setUp(self): allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6') b4, c2, b5, b2, c1, b6, c6 = allholes self.hc = (b2, b6, b5) # holechoices self.hstr = holes2string(self.hc) self.holeshape = "hex" # directory containing the test data data_dir = os.path.join(os.path.dirname(__file__), 'test_data/affine2d_makemodel_rot') self.data_dir = data_dir print(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) # expects strings of % (self.npix, self.holeshape, self.wave/um, rot, self.hstr) self.fnfmt = data_dir + '/psf_nrm_{2:.1f}_{0}_{1}_{3:.0f}_{4:s}.fits' self.fmt = " ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})" self.pixel = 0.0656 self.npix = 87 self.wave = 4.3e-6 # m self.over = 11 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") rots = (0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95) rots = ( 0.000, 10.000, ) for rot in rots: rot = avoidhexsingularity(rot) # in utils affine_rot = Affine2d(rotradccw=np.pi * rot / 180.0, name="{0:.0f}".format(rot)) # in utils aff = affine_rot # holeshape is hex or circ g7s6 jwst # because model_array requires # a primary beam for one slice of the model self.jw = NRM_Model( mask='jwst', holeshape=self.holeshape, #chooseholes=self.hc, affine2d=aff) self.jw.set_pixelscale(self.pixel * arcsec2rad) self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over) # write psf psffn = self.fnfmt.format(self.npix, self.holeshape, self.wave / um, rot, self.hstr) fits.writeto(psffn, self.jw.psf, overwrite=True) header = fits.getheader(psffn) header = affinepars2header(header, aff) fits.update(psffn, self.jw.psf, header=header) print("test: psf shape", self.jw.psf.shape) modelslices = self.jw.make_model(fov=self.npix, bandpass=self.wave, over=self.over) print("test: modelslices type", type(modelslices)) print("test: modelslices shape", modelslices.shape) modelfn = psffn.replace("psf_nrm", "model") # write model model_for_fitsfile = np.zeros( (modelslices.shape[2], modelslices.shape[0], modelslices.shape[1])) for sl in range(modelslices.shape[2]): model_for_fitsfile[sl, :, :] = modelslices[:, :, sl] print("test: model_for_fitsfile type", type(model_for_fitsfile)) print("test: model_for_fitsfile shape", model_for_fitsfile.shape) fits.writeto(modelfn, model_for_fitsfile[6, :, :], overwrite=True) header = fits.getheader(modelfn) header = affinepars2header(header, aff) fits.update(modelfn, model_for_fitsfile[6, :, :], header=header) del self.jw del aff del affine_rot def test_psf(self): """ sanity check and code development tool than a routine test. """ self.assertTrue(0.0 < 1e-15, 'error: test_affine2d failed')
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' pixel = 0.0656 # arcsec 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 datadir = os.path.join(os.path.dirname(__file__), 'test_data/find_pass_affine') if not os.path.exists(datadir): os.makedirs(datadir) self.datadir = datadir # file containing the test data imagefn = datadir + "/simulated_image.fits" # use millidegrees and integers imagefn = imagefn.replace( ".fits", "_truerotmd{0:+05d}.fits".format(int(1000.0 * float(rotd_true)))) self.imagefn = imagefn # savedir for reduced quantities self.savedir = imagefn.replace( ".fits", "_truerotmd{0:+05d}.fits".format(int(1000.0 * float(rotd_true)))) self.savedir = self.datadir + '/' print('\n') print(' >> >> >> >> set-up self.imagefn %s' % self.imagefn) print(' >> >> >> >> set-up self.datadir %s' % self.datadir) print(' >> >> >> >> set-up self.savedir %s' % self.savedir) # Create test data on disk print("avoidhexsingularity: ", utils.avoidhexsingularity(rotd_true)) affine = utils.Affine2d(rotradccw=np.pi * utils.avoidhexsingularity(rotd_true) / 180.0, name="{0:.3}".format(float(rotd_true))) affine.show(label="Creating PSF data with Affine2d") # from nrm_analysis.fringefitting.LG_Model import NRM_Model jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=affine) jw.set_pixelscale(pixel * arcsec2rad) jw.simulate(fov=n_image, bandpass=monochromatic_wavelength_m, over=oversample) # PSF without oversampling fits.writeto(imagefn, jw.psf, overwrite=True) header = fits.getheader(imagefn) header['PIXELSCL'] = (pixel, "arcseconds") header['FILTER'] = filter_name header['PUPIL'] = mask header = utils.affinepars2header(header, affine) fits.update(imagefn, jw.psf, header=header) self.simulated_image = jw.psf.copy() self.affine = affine # Affine2d parameters used to create test simulated_image ("true" value) del jw del affine
def psf(filt, fbp, cw, ew, beta, data_dir, oversample = 11, n_image = 81, pixelscale_as=0.0656, f2f = 0.82, saveover=False): arcsec2rad = u.arcsec.to(u.rad) WGHT = fbp[:,0] WAVE = fbp[:,1] # setup parameters for simulation verbose = 1 overwrite = 1 mask = 'MASK_NRM' # directory containing the test data if not os.path.exists(data_dir): os.makedirs(data_dir) name_seed = 'PSF_%s_%s_x%d_%.2f'%(mask,filt,oversample,f2f) # original # only det sampling needed here... name_seed = '%s_%d_%s_det.fits'%(filt, n_image, "A0V") # for ami_sim input photometry in NIRISSami_apt_calcPSF name_seed = '%s_%d_%s_x%d.fits'%(filt, n_image, "flat", oversample) # for ami_sim PSF to give to driver_scene name_seed_det = '%s_%d_%s_det.fits'%(filt, n_image, "flat") # for ami_sim PSF for examining by eye print(name_seed) psf_image = os.path.join(data_dir,name_seed) psf_image_without_oversampling = os.path.join(data_dir, name_seed_det) from nrm_analysis.fringefitting.LG_Model import NRM_Model jw = NRM_Model(mask='jwst',holeshape="hex") jw.set_pixelscale(pixelscale_as*arcsec2rad) jw.simulate(fov=n_image, bandpass=fbp, over=oversample) print("simulateG7S6psf: simulation oversampling is", oversample) (year, month, day, hour, minute, second, weekday, DOY, DST) = time.gmtime() # oversampled psf is used as the fine psf to create jitter and dither errors. # ami_sim driver scene expects ODD numbers of pixels to a side. # We oversize to 81 x 81 pixels here. # When adding mirage headers to ami_sim 'data' we should trim to 80x80. # oversampled psf is used as the fine psf to create jitter and dither errors. if saveover: # oversampled psf is used as the fine psf to createjitter and dither errors. # PSF on oversampled pixels psf_over_n = filt_psftot[filt] * jw.psf_over/jw.psf_over.sum() # wp psf total ~15% fits.writeto(psf_image, psf_over_n, overwrite=True) header = fits.getheader(psf_image) header['PIXELSCL'] = pixelscale_as/oversample, "arcsec per pixel" header['FILTER'] = filt header['PUPIL'] = mask header["OVER"] = ( oversample, "oversample") header["SPTYPE"] = "FLAT", "source spectral type unspecified" header["NWAVES"] = fbp.shape[0] header["WAVELEN"] = cw, "Weighted mean wavelength in meters " header["FILT_EW"] = ew, "Filter equiv width" header["FILT_BP"] = beta, "Fractional bandpass = WL/EqW" for i in range(len(WAVE)): header["WAVE%d"%i] = WAVE[i], "Wavelength %d"%i header["WGHT%d"%i] = WGHT[i], "Wavelength weight %d"%i header["FT"] = ( "analytical", "hexee * fringes") header['NRM_GEOM'] = 'G7S6', 'Beaulieu, PGT, AS, active ctrs' header['F2F'] = jw.d, "flat2flat hole size m" header['NRM_X_A1'] = jw.ctrs[0,0], 'X coordinate (m) of NRM sub-aperture 0' header['NRM_Y_A1'] = jw.ctrs[0,1], 'Y coordinate (m) of NRM sub-aperture 0' header['NRM_X_A2'] = jw.ctrs[1,0], 'X coordinate (m) of NRM sub-aperture 1' header['NRM_Y_A2'] = jw.ctrs[1,1], 'Y coordinate (m) of NRM sub-aperture 1' header['NRM_X_A3'] = jw.ctrs[2,0], 'X coordinate (m) of NRM sub-aperture 2' header['NRM_Y_A3'] = jw.ctrs[2,1], 'Y coordinate (m) of NRM sub-aperture 2' header['NRM_X_A4'] = jw.ctrs[3,0], 'X coordinate (m) of NRM sub-aperture 3' header['NRM_Y_A4'] = jw.ctrs[3,1], 'Y coordinate (m) of NRM sub-aperture 3' header['NRM_X_A5'] = jw.ctrs[4,0], 'X coordinate (m) of NRM sub-aperture 4' header['NRM_Y_A5'] = jw.ctrs[4,1], 'Y coordinate (m) of NRM sub-aperture 4' header['NRM_X_A6'] = jw.ctrs[5,0], 'X coordinate (m) of NRM sub-aperture 5' header['NRM_Y_A6'] = jw.ctrs[5,1], 'Y coordinate (m) of NRM sub-aperture 5' header['NRM_X_A7'] = jw.ctrs[6,0], 'X coordinate (m) of NRM sub-aperture 6' header['NRM_Y_A7'] = jw.ctrs[6,1], 'Y coordinate (m) of NRM sub-aperture 6' header['NORMALIZ'] = 'first', 'PM psf.sum=1, this.sum = mask throughput' header['PSFTOT'] = filt_psftot[filt], "sum of webbpsf sim done at 11x over" header['PSFPEAK'] = psf_over_n.max() header["SRC"] = ( "simulateG7S6psf.py", "ImplaneIA/notebooks/") header['AUTHOR'] = '%s@%s' % (os.getenv('USER'), os.getenv('HOST')), 'username@host for calculation' header['DATE'] = '%4d-%02d-%02dT%02d:%02d:%02d' % (year, month, day, hour, minute, second), 'Date of calculation' header['F2F'] = (0.82, "flat2flat hole size m") fits.update(psf_image, psf_over_n, header=header) # PSF on detector pixels psf_det_n = filt_psftot[filt] * jw.psf/jw.psf.sum() fits.writeto(psf_image_without_oversampling, psf_det_n, overwrite=True) header = fits.getheader(psf_image_without_oversampling) header['PIXELSCL'] = pixelscale_as, "arcsec per pixel" header['FILTER'] = filt header['PUPIL'] = mask header["OVER"] = ( oversample, "oversample pre-rebin") header["SPTYPE"] = "FLAT", "source spectral type" header["NWAVES"] = fbp.shape[0] header["WAVELEN"] = cw, "Weighted mean wavelength in meters " header["FILT_EW"] = ew, "Filter equiv width" header["FILT_BP"] = beta, "Fractional bandpass = WL/EqW" for i in range(len(WAVE)): header["WAVE%d"%i] = WAVE[i], "Wavelength %d"%i header["WGHT%d"%i] = WGHT[i], "Wavelength weight %d"%i header["FT"] = ( "analytical", "hexee * fringes") header['NRM_GEOM'] = 'G7S6', 'Beaulieu, PGT, AS active ctrs' header['F2F'] = jw.d, "flat2flat hole size m" header['NRM_X_A1'] = jw.ctrs[0,0], 'X coordinate (m) of NRM sub-aperture 0' header['NRM_Y_A1'] = jw.ctrs[0,1], 'Y coordinate (m) of NRM sub-aperture 0' header['NRM_X_A2'] = jw.ctrs[1,0], 'X coordinate (m) of NRM sub-aperture 1' header['NRM_Y_A2'] = jw.ctrs[1,1], 'Y coordinate (m) of NRM sub-aperture 1' header['NRM_X_A3'] = jw.ctrs[2,0], 'X coordinate (m) of NRM sub-aperture 2' header['NRM_Y_A3'] = jw.ctrs[2,1], 'Y coordinate (m) of NRM sub-aperture 2' header['NRM_X_A4'] = jw.ctrs[3,0], 'X coordinate (m) of NRM sub-aperture 3' header['NRM_Y_A4'] = jw.ctrs[3,1], 'Y coordinate (m) of NRM sub-aperture 3' header['NRM_X_A5'] = jw.ctrs[4,0], 'X coordinate (m) of NRM sub-aperture 4' header['NRM_Y_A5'] = jw.ctrs[4,1], 'Y coordinate (m) of NRM sub-aperture 4' header['NRM_X_A6'] = jw.ctrs[5,0], 'X coordinate (m) of NRM sub-aperture 5' header['NRM_Y_A6'] = jw.ctrs[5,1], 'Y coordinate (m) of NRM sub-aperture 5' header['NRM_X_A7'] = jw.ctrs[6,0], 'X coordinate (m) of NRM sub-aperture 6' header['NRM_Y_A7'] = jw.ctrs[6,1], 'Y coordinate (m) of NRM sub-aperture 6' header['NORMALIZ'] = 'first', 'PM psf.sum=1, this.sum = mask throughput' header['PSFTOT'] = psf_det_n.sum() header['PSFPEAK'] = psf_det_n.max() header['CPF'] = psf_det_n.max() / psf_det_n.sum(), 'Central pixel fraction' header["SRC"] = ( "simulateG7S6psf_for_ami_sim.py", "ImplaneIA/notebooks/") header['AUTHOR'] = '%s@%s' % (os.getenv('USER'), os.getenv('HOST')), 'username@host for calculation' header['DATE'] = '%4d-%02d-%02dT%02d:%02d:%02d' % (year, month, day, hour, minute, second), 'Date of calculation' fits.update(psf_image_without_oversampling, psf_det_n, header=header)
def psf(filt, fbp, cw, ew, beta, data_dir, oversample = 11, n_image = 81, pixelscale_as=0.0656, f2f = 0.82, saveover = True): arcsec2rad = u.arcsec.to(u.rad) WGHT = fbp[:,0] WAVE = fbp[:,1] # setup parameters for simulation verbose = 1 overwrite = 1 mask = 'MASK_NRM' # directory containing the test data if not os.path.exists(data_dir): os.makedirs(data_dir) name_seed = 'PSF_%s_%s_x%d_%.2f'%(mask,filt,oversample,f2f) psf_image_name = name_seed + '_ref.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','_det.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_as*arcsec2rad) jw.simulate(fov=n_image, bandpass=fbp, over=oversample) print("simulateG7S6psf: simulation oversampling is", oversample) (year, month, day, hour, minute, second, weekday, DOY, DST) = time.gmtime() # optional writing of oversampled image if saveover: psf_over_n = jw.psf_over[:80*oversample,:80*oversample]/jw.psf_over[:80*oversample,:80*oversample].sum() psf_over_n = psf_over_n * filt_psftot[filt] # "sum of webbpsf sim done at 11x over" fits.writeto(psf_image, psf_over_n, overwrite=True) header = fits.getheader(psf_image) header['PIXELSCL'] = pixelscale_as/oversample, "arcsec per pixel" header['FILTER'] = filt header['PUPIL'] = mask header["OVER"] = ( oversample, "oversample") header["SPTYPE"] = "FLAT", "source spectral type unspecified" header["NWAVES"] = fbp.shape[0] header["WAVELEN"] = cw, "Weighted mean wavelength in meters " header["FILT_EW"] = ew, "Filter equiv width" header["FILT_BP"] = beta, "Fractional bandpass = WL/EqW" for i in range(len(WAVE)): header["WAVE%d"%i] = WAVE[i], "Wavelength %d"%i header["WGHT%d"%i] = WGHT[i], "Wavelength weight %d"%i header["FT"] = ( "analytical", "hexee * fringes") header['NRM_GEOM'] = 'G7S6', 'Beaulieu, PGT, AS, active ctrs' header['F2F'] = jw.d, "flat2flat hole size m" header['NRM_X_A1'] = jw.ctrs[0,0], 'X coordinate (m) of NRM sub-aperture 0' header['NRM_Y_A1'] = jw.ctrs[0,1], 'Y coordinate (m) of NRM sub-aperture 0' header['NRM_X_A2'] = jw.ctrs[1,0], 'X coordinate (m) of NRM sub-aperture 1' header['NRM_Y_A2'] = jw.ctrs[1,1], 'Y coordinate (m) of NRM sub-aperture 1' header['NRM_X_A3'] = jw.ctrs[2,0], 'X coordinate (m) of NRM sub-aperture 2' header['NRM_Y_A3'] = jw.ctrs[2,1], 'Y coordinate (m) of NRM sub-aperture 2' header['NRM_X_A4'] = jw.ctrs[3,0], 'X coordinate (m) of NRM sub-aperture 3' header['NRM_Y_A4'] = jw.ctrs[3,1], 'Y coordinate (m) of NRM sub-aperture 3' header['NRM_X_A5'] = jw.ctrs[4,0], 'X coordinate (m) of NRM sub-aperture 4' header['NRM_Y_A5'] = jw.ctrs[4,1], 'Y coordinate (m) of NRM sub-aperture 4' header['NRM_X_A6'] = jw.ctrs[5,0], 'X coordinate (m) of NRM sub-aperture 5' header['NRM_Y_A6'] = jw.ctrs[5,1], 'Y coordinate (m) of NRM sub-aperture 5' header['NRM_X_A7'] = jw.ctrs[6,0], 'X coordinate (m) of NRM sub-aperture 6' header['NRM_Y_A7'] = jw.ctrs[6,1], 'Y coordinate (m) of NRM sub-aperture 6' header['PSFTOT'] = filt_psftot[filt], "sum of webbpsf sim done at 11x over" header['PSFPEAK'] = psf_over_n.max() header["SRC"] = ( "simulateG7S6psf.py", "ImplaneIA/notebooks/") header['AUTHOR'] = '%s@%s' % (os.getenv('USER'), os.getenv('HOST')), 'username@host for calculation' header['DATE'] = '%4d-%02d-%02dT%02d:%02d:%02d' % (year, month, day, hour, minute, second), 'Date of calculation' header['F2F'] = (0.82, "flat2flat hole size m") fits.update(psf_image, psf_over_n, header=header) # PSF without oversampling psf_det_n = jw.psf[:80,:80]/jw.psf[:80,:80].sum() # we can delete this line but I'm in a hurry... webbpsfnorm = filt_cpf[filt] / psf_det_n.max() psf_det_n = psf_det_n * webbpsfnorm # forces central pixel values to agree ^see above fits.writeto(psf_image_without_oversampling, psf_det_n, overwrite=True) header = fits.getheader(psf_image_without_oversampling) header['PIXELSCL'] = pixelscale_as, "arcsec per pixel" header['FILTER'] = filt header['PUPIL'] = mask header["OVER"] = ( oversample, "oversample pre-rebin") header["SPTYPE"] = "FLAT", "source spectral type unspecified" header["NWAVES"] = fbp.shape[0] header["WAVELEN"] = cw, "Weighted mean wavelength in meters " header["FILT_EW"] = ew, "Filter equiv width" header["FILT_BP"] = beta, "Fractional bandpass = WL/EqW" for i in range(len(WAVE)): header["WAVE%d"%i] = WAVE[i], "Wavelength %d"%i header["WGHT%d"%i] = WGHT[i], "Wavelength weight %d"%i header["FT"] = ( "analytical", "hexee * fringes") header['NRM_GEOM'] = 'G7S6', 'Beaulieu, PGT, AS active ctrs' header['F2F'] = jw.d, "flat2flat hole size m" header['NRM_X_A1'] = jw.ctrs[0,0], 'X coordinate (m) of NRM sub-aperture 0' header['NRM_Y_A1'] = jw.ctrs[0,1], 'Y coordinate (m) of NRM sub-aperture 0' header['NRM_X_A2'] = jw.ctrs[1,0], 'X coordinate (m) of NRM sub-aperture 1' header['NRM_Y_A2'] = jw.ctrs[1,1], 'Y coordinate (m) of NRM sub-aperture 1' header['NRM_X_A3'] = jw.ctrs[2,0], 'X coordinate (m) of NRM sub-aperture 2' header['NRM_Y_A3'] = jw.ctrs[2,1], 'Y coordinate (m) of NRM sub-aperture 2' header['NRM_X_A4'] = jw.ctrs[3,0], 'X coordinate (m) of NRM sub-aperture 3' header['NRM_Y_A4'] = jw.ctrs[3,1], 'Y coordinate (m) of NRM sub-aperture 3' header['NRM_X_A5'] = jw.ctrs[4,0], 'X coordinate (m) of NRM sub-aperture 4' header['NRM_Y_A5'] = jw.ctrs[4,1], 'Y coordinate (m) of NRM sub-aperture 4' header['NRM_X_A6'] = jw.ctrs[5,0], 'X coordinate (m) of NRM sub-aperture 5' header['NRM_Y_A6'] = jw.ctrs[5,1], 'Y coordinate (m) of NRM sub-aperture 5' header['NRM_X_A7'] = jw.ctrs[6,0], 'X coordinate (m) of NRM sub-aperture 6' header['NRM_Y_A7'] = jw.ctrs[6,1], 'Y coordinate (m) of NRM sub-aperture 6' header['PSFTOT'] = psf_det_n.sum() header['PSFPEAK'] = psf_det_n.max() header['CPF'] = filt_cpf[filt] header["SRC"] = ( "simulateG7S6psf.py", "ImplaneIA/notebooks/") header['AUTHOR'] = '%s@%s' % (os.getenv('USER'), os.getenv('HOST')), 'username@host for calculation' header['DATE'] = '%4d-%02d-%02dT%02d:%02d:%02d' % (year, month, day, hour, minute, second), 'Date of calculation' fits.update(psf_image_without_oversampling, psf_det_n, header=header)
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 = np.array([ (1.0, 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[:, 1][0] / 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[:, 1][0] / 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[:, 1][0] / 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[:, 1][0] / 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[:, 1][0] / 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[:, 1][0] / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'hex', self.wave[:, 1][0] / 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[:, 1][0] / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'fringeonly', self.wave[:, 1][0] / 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[:, 1][0] / um, "Ideal")) psfXrev = fits.getdata( self.fnfmt.format(self.npix, 'hexonly', self.wave[:, 1][0] / 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 test_offset_residuals_with_offset_measured(): """ Simulate data with known offsets, analyze data using fringefitter. """ pixelscale_as = 0.0656 arcsec2rad = u.arcsec.to(u.rad) PIXELSCALE_r = pixelscale_as * arcsec2rad jw0 = NRM_Model(mask='jwst', holeshape="hex") jw0.set_pixelscale(pixelscale_as * arcsec2rad) jw0.simulate(fov=35, bandpass=bandpass, over=oversample, psf_offset=(0.0, 0.0)) fits.PrimaryHDU(data=jw0.psf).writeto(fitsimdir + "no_offset_data.fits", overwrite=True) jw = NRM_Model(mask='jwst', holeshape="hex") jw.set_pixelscale(pixelscale_as * arcsec2rad) jw.simulate(fov=35, bandpass=bandpass, over=oversample, psf_offset=psf_offsets) fits.PrimaryHDU(data=jw.psf).writeto(fitsimdir + "offset_data.fits", overwrite=True) fits.PrimaryHDU(data=(jw.psf - jw0.psf) / jw0.psf.max()).writeto( fitsimdir + "diff_from_center.fits", overwrite=True) amisim2mirage(fitsimdir, ("offset_data", ), mirexample, filt) niriss = InstrumentData.NIRISS(filt, bandpass=bandpass) ff_t = nrm_core.FringeFitter(niriss, datadir=fitsimdir, savedir=fitsimdir, oversample=oversample, interactive=False) print(test_tar) ff_t.fit_fringes(test_tar) jw_m = NRM_Model(mask='jwst', holeshape="hex") jw_m.set_pixelscale(pixelscale_as * arcsec2rad) #Look at measured offsets in the screen output and feed them to simulate to compare with simulated data created with input offsets. #nrm.bestcenter (0.4799802988666451, 6.984734412937637e-05) nrm.xpos 0.4799802988666451 nrm.ypos 6.984734412937637e-05 jw_m.simulate(fov=35, bandpass=bandpass, over=oversample, psf_offset=(ff_t.nrm.xpos, ff_t.nrm.ypos)) fits.PrimaryHDU(data=jw_m.psf).writeto(fitsimdir + "m_offset_data.fits", overwrite=True) fits.PrimaryHDU(data=(jw.psf - jw_m.psf) / jw0.psf.max()).writeto( fitsimdir + "m_diff_of_offsets.fits", overwrite=True) 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(fitsimdir+\ "residual_offsets_with_ff.fits",overwrite=True)
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
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")
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')