def exer4(odir): """ Precise control of image positioning using phase slopes? """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 100 radius = 20.0 fp_size_reselt = 100 pupil = utils.makedisk(npup, radius=radius) tilts = ((0,0), (0*np.pi/npup, 0), (1*np.pi/npup, 0), (2*np.pi/npup, 0), (3*np.pi/npup, 0), (4*np.pi/npup, 0), (95*np.pi/npup, 0), (npup*np.pi/npup, 0)) phases = utils.phasearrays(npup, tilts) for nt, ph in enumerate(phases): pupilarray = pupil * np.exp(1j * ph) imagefield = ft.perform(pupilarray, fp_size_reselt, npup) image_intensity = (imagefield*imagefield.conj()).real psf = image_intensity / image_intensity.max() # peak intensity unity fits.PrimaryHDU(psf).writeto( odir+"/ex4_tiltPi_a_{0:.3f}_b_{1:.3f}.fits".format(tilts[nt][0],tilts[nt][1]), overwrite=True)
def exer5(odir): """ Create ripples of phase aberration in the pupil to simulate the Ruffles Potato Chip Telescope (RPCT) """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 100 radius = 20.0 fp_size_reselt = 100 pupil = utils.makedisk(npup, radius=radius) number_of_waves_across = (2,3,4,5,6) peaks = (0.0, 0.1, 0.3, 1.0, 3.0) # radians, amplitude of phase ripple arrayshape = (npup, npup) diam_pupil = radius*2 # pixels center = (arrayshape[0]/2, arrayshape[1]/2) for nwaves in number_of_waves_across: for peak in peaks: for offset in (0, ): for angle in (0, ): spatialwavelen = diam_pupil / nwaves offset = offset * np.pi/180.0 khat = np.array((np.sin(angle*np.pi/180.0), np.cos(angle*np.pi/180.0))) # unit vector kwavedata = np.fromfunction(utils.kwave2d, arrayshape, spatialwavelen=spatialwavelen, center=center, offset=offset, khat=khat) pupilarray = pupil * np.exp(1j * peak * kwavedata) imagefield = ft.perform(pupilarray, fp_size_reselt, npup) image_intensity = (imagefield*imagefield.conj()).real psf = image_intensity / image_intensity.max() # peak intensity unity fits.PrimaryHDU(peak*kwavedata).writeto( odir+"/ex5_pupilarrayripple_{0:d}acrossD_peak_{1:.1f}.fits".format(nwaves,peak), overwrite=True)
def create_input_datafiles(rfn=None): """ Pupil and image data, true (zero mean) phase map (rad) No de-tilting of the thase done. Didactic case, no input parameters: create the pupil & monochromatic image on appropriate pixel scales. Pupil and image arrays of same size, ready to FT into each other losslessly. For real data you'll need to worry about adjusting sizes to satify this sampling relation between the two planes. For finite bandwidth data image simulation will loop over wavelengths. For coarsely sampled pixels image simulation will need to use finer sampling and rebin to detector pixel sizes. [email protected] Jan 2019 """ pupil0 = utils.makedisk(250, radius=50) # D=100 pix, array 250 pix pupil1 = (pupil0 - utils.makedisk(250, radius=15, ctr=(125.0, 75.0))) * pupil0 pupil2 = (pupil1 - utils.makedisk(250, radius=15, ctr=(90.0, 90.0))) * pupil0 pupil3 = (pupil2 - utils.makedisk(250, radius=15, ctr=(75.0, 125.0))) * pupil0 fits.writeto(rfn + "0__input_pup.fits", pupil0, overwrite=True) fits.writeto(rfn + "1__input_pup.fits", pupil1, overwrite=True) fits.writeto(rfn + "2__input_pup.fits", pupil2, overwrite=True) fits.writeto(rfn + "3__input_pup.fits", pupil3, overwrite=True) for pnum in (0, 1, 2, 3): pupil = fits.getdata(rfn + "{:1d}__input_pup.fits".format(pnum)) offctrbump = (pupil.shape[0] / 2.0 + 30, pupil.shape[1] / 2.0 + 20.0 ) # off-center bump ctrbump = (pupil.shape[0] / 2.0, pupil.shape[1] / 2.0) # central bump #quarter wave phase bump, off center phase = (2.0 * np.pi / 4.0) * utils.makegauss( pupil.shape[0], ctr=offctrbump, sigma=10.0) * pupil phase = de_mean(phase, pupil) # zero mean phase - doesn't change image fits.writeto(rfn + "{:1d}__input_truepha.fits".format(pnum), phase, overwrite=True) mft = matrixDFT.MatrixFourierTransform() imagefield = mft.perform(pupil * np.exp(1j * phase), pupil.shape[0], pupil.shape[0]) image = (imagefield * imagefield.conj()).real fits.writeto(rfn + "{:1d}__input_img.fits".format(pnum), image / image.sum(), overwrite=True) del mft
def exer2(odir): """ Are you simulating samples or pixels? Image plane sampling effect """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 100 radius = 20.0 fp_size_reselts = 10 fp_npixels = (4, 8, 16, 32) pupil = utils.makedisk(npup, radius=radius) fits.PrimaryHDU(pupil).writeto(odir+"/ex2_pupil.fits", overwrite=True) # write pupil file for fpnpix in fp_npixels: imagefield = ft.perform(pupil, fp_size_reselts, fpnpix) imageintensity = (imagefield*imagefield.conj()).real psf = imageintensity / imageintensity.max() # normalize to peak intensity unity zpsf = scipy.ndimage.zoom(psf, 32//fpnpix, order=0) fits.PrimaryHDU(zpsf).writeto(odir+"/ex2_nfppix{}_zoom{}.fits".format(fpnpix,32//fpnpix), overwrite=True)
def exer3(odir): """ What do phase slopes - tilts - in the pupil plane do? """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 100 radius = 20.0 fp_size_reselt = 100 pupil = utils.makedisk(npup, radius=radius) tilts = ((0,0), (0.3,0), (1.0,0), (3.0,0)) phases = utils.phasearrays(npup, tilts) for nt, ph in enumerate(phases): pupilarray = pupil * np.exp(1j * ph) imagefield = ft.perform(pupilarray, fp_size_reselt, npup) image_intensity = (imagefield*imagefield.conj()).real psf = image_intensity / image_intensity.max() # peak intensity unity fits.PrimaryHDU(psf).writeto( odir+"/ex3_tilt_a_{0:.3f}_b_{1:.3f}.fits".format(tilts[nt][0],tilts[nt][1]), overwrite=True)
def exer1(odir): """ Let's get something for nothing if we can!!! """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 100 radius = 20.0 fp_size_reselts = (100, 200, 300, 400) fp_npixels = (100, 200, 300, 400) pupil = utils.makedisk(npup, radius=radius) fits.PrimaryHDU(pupil).writeto(odir+"/ex1_pupil.fits", overwrite=True) # write pupil file for (fpr,fpnpix) in zip(fp_npixels,fp_size_reselts): imagearray = np.zeros((400,400)) # create same-sized array for all 4 FOV's we calculate. imagefield = ft.perform(pupil, fpr, fpnpix) imageintensity = (imagefield*imagefield.conj()).real psf = imageintensity / imageintensity.max() # normalize to peak intensity unity imagearray[200-fpnpix//2:200+fpnpix//2,200-fpnpix//2:200+fpnpix//2] = psf # center image in largest array size fits.PrimaryHDU(imagearray).writeto(odir+"/ex1_nfppix{}_fpsize{}.fits".format(fpnpix,fpr), overwrite=True)
def create_input_datafiles_bumps(rfn=None): """ returns: list of mgsdtasets Didactic case, no input parameters: create the pupil & monochromatic image on appropriate pixel scales. Pupil and image arrays of same size, ready to FT into each other losslessly. For real data you'll need to worry about adjusting sizes to satify this sampling relation between the two planes. For finite bandwidth data image simulation will loop over wavelengths. For coarsely sampled pixels image simulation will need to use finer sampling and rebin to detector pixel sizes. [email protected] Jan 2019 """ mft = matrixDFT.MatrixFourierTransform() pupilradius = 50 pupil = utils.makedisk(250, radius=pupilradius) # D=100 pix, array 250 pix pupilindex = np.where(pupil >= 1) pupilfn = rfn + "__input_pup.fits" fits.writeto(pupilfn, pupil, overwrite=True) mgsdatasets = [] defocus_list = (-12.0, 12.0, -10.0, 10.0, -8.0, 8.0, -6.0, 6.0, -4.0, 4.0, -2.0, 2.0) print(defocus_list) number_of_d_across_D = range( 1, 16) # different aberrations - dia of bump in pupil rippleamp = 1.0 # radians, 1/6.3 waves, about 340nm at 2.12 micron Bump height. bad var name # for a variety of bumps across the pupil: for nwaves in number_of_d_across_D: # preserve var name nwaves from ripple case - bad varname here. pupil = fits.getdata(pupilfn) mgsdataset = [pupilfn] # an mgsdataset starts with the pupil file... rbump = 4.0 * float( pupilradius) / nwaves # sigma of gaussian bump in pupil #print("{:.1e}".format(rbump)) bump = utils.makegauss(250, ctr=(145.0, 145.0), sigma=rbump) # D=100 pix, array 250 pix rbump = 0.5 * float(pupilradius) / nwaves # rad of disk bump in pupil #print("{:.1e}".format(rbump)) bump = utils.makedisk(250, radius=rbump, ctr=(145.0, 145.0)) # D=100 pix, array 250 pix bump = (1.0 / np.sqrt(2)) * bump / bump[pupilindex].std( ) # 0.5 variance aberration, same SR hit ripplephase = rippleamp * bump # bad var name phasefn = rfn + "bump_{0:d}acrossD_peak_{1:.1f}_pha.fits".format( int(nwaves), rippleamp) fits.PrimaryHDU(ripplephase).writeto(phasefn, overwrite=True) mgsdataset.append( phasefn) # an mgsdataset now pupil file, phase abberration file, # Now create images for each defocus in the list # # First a utility array, parabola P2V unity over pupil, zero outside pupil prad = pupilradius # for parabola=unity at edge of active pupil 2% < unity center = utils.centerpoint(pupil.shape[0]) unityP2Vparabola = np.fromfunction( utils.parabola2d, pupil.shape, cx=center[0], cy=center[1]) / (prad * prad) * pupil fits.writeto(rfn + "unityP2Vparabola.fits", unityP2Vparabola, overwrite=True) # sanity check - write it out for defoc in defocus_list: # defoc units are waves, Peak-to-Valley defocusphase = unityP2Vparabola * 2 * np.pi * defoc aberfn = "pup__bump_defoc_{:.1f}wav.fits".format(defoc) fits.writeto(rfn + aberfn, defocusphase, overwrite=True) aberfn = rfn + "pup_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) aber = defocusphase + ripplephase fits.writeto(aberfn, aber, overwrite=True) imagefield = mft.perform(pupil * np.exp(1j * aber), pupil.shape[0], pupil.shape[0]) image = (imagefield * imagefield.conj()).real fits.writeto(imagfn, image / image.sum(), overwrite=True) mgsdataset.append((defoc, imagfn, aberfn)) mgsdatasets.append(mgsdataset) # Prepare a quicklook at signal in the pairs of defocussed images: side = 2.0 # inches, quicklook at curvatue signal imshow ndefoc = len(defocus_list) // 2 nspatfreq = len(number_of_d_across_D) magnif = 2.0 fig = plt.figure(1, (nspatfreq * magnif, ndefoc * magnif)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(ndefoc, nspatfreq), # creates 2x2 grid of axes axes_pad=0.02, # pad between axes in inch. ) i = 0 iwav = 0 for nwaves in number_of_d_across_D: ifoc = 0 maxlist = [] for defoc in defocus_list: # defoc units are waves, Peak-to-Valley if defoc > 0: imagfn_pos = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn_neg = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, -defoc) datapos = fits.getdata(imagfn_pos).flatten() dataneg = fits.getdata(imagfn_neg).flatten() quicklook = (datapos - dataneg[::-1]).reshape((250, 250)) * ( defoc * defoc) # normalize to equal brightness signal maxlist.append(quicklook.max()) print("max {:.1e}".format(quicklook.max()) ) # print me out and fix the limits for imshow by hand. #fits.writeto(imagfn_pos.replace("img","qlk"), quicklook, overwrite=True) i = iwav + (ndefoc - ifoc - 1) * nspatfreq grid[i].imshow( quicklook, origin='lower', cmap=plt.get_cmap( 'ocean'), # RdBu, gist_rainbow, ocean, none vmin=-3.0e-3, vmax=3.0e-3) # The AxesGrid object work as a list of axes. grid[i].set_xticks([]) grid[i].set_yticks([]) grid[i].text(20, 220, "D/{:d} dia bump".format(int(nwaves + 1)), color='y', weight='bold') grid[i].text(20, 20, "+/-{:d}w PV".format(int(defoc)), color='w', weight='bold') #print('iwav', iwav, 'ifoc', ifoc, 'i:', i) ifoc += 1 iwav += 1 strtop = "Wavefront signal from piston phase bumps of different diameters vs. defocus either side of focus" strbot = "Anand S. 2019, after Dean & Bowers, JOSA A 2003 (figs. 4 & 7)" fig.text(0.02, 0.94, strtop, fontsize=18, weight='bold') fig.text(0.02, 0.05, strbot, fontsize=14) plt.tight_layout() plt.savefig("DeanBowers2003_signal_vs_defocus_bump.png", dpi=150, pad_inches=1.0) plt.show() #print("Unity P-V parabola:", arraystats(unityP2Vparabola)) """ for dataset in mgsdatasets: print("MGS data set: pupilfn, aber, (defoc/PVwaves, imagefn, defoc+aber), (repeats)") for thing in dataset: print("\t", thing) print("") """ return mgsdatasets
def create_input_datafiles(rfn=None): """ returns: list of mgsdtasets pupilfn: name of pupil file Pupil and image data, true (zero mean) phase map (rad) No de-tilting of the thase done. Didactic case, no input parameters: create the pupil & monochromatic image on appropriate pixel scales. Pupil and image arrays of same size, ready to FT into each other losslessly. For real data you'll need to worry about adjusting sizes to satify this sampling relation between the two planes. For finite bandwidth data image simulation will loop over wavelengths. For coarsely sampled pixels image simulation will need to use finer sampling and rebin to detector pixel sizes. [email protected] Jan 2019 """ mft = matrixDFT.MatrixFourierTransform() pupilradius = 50 pupil = utils.makedisk(250, radius=pupilradius) # D=100 pix, array 250 pix pupilfn = rfn + "__input_pup.fits" fits.writeto(pupilfn, pupil, overwrite=True) mgsdatasets = [] dfoc_max = 12 nfoci = 8 # number of defocus steps, in geo prog ffac = pow(10, np.log10(dfoc_max) / nfoci) defocus_list = [] for i in range(nfoci): defocus_list.append(ffac) defocus_list.append(-ffac) ffac *= pow(10, np.log10(dfoc_max) / nfoci) defocus_list.reverse() defocus_list = (-12.0, 12.0, -10.0, 10.0, -8.0, 8.0, -6.0, 6.0, -4.0, 4.0, -2.0, 2.0) print(defocus_list) number_of_waves_across_D = range( 1, 16) # different aberrations - number of waves across pupil print(number_of_waves_across_D) rippleamp = 1.0 # radians, 1/6.3 waves, about 340nm at 2.12 micron ripplepha = 30.0 # degrees, just for fun rippleangle = 15.0 # degrees # for a variety of ripples across the pupil: for nwaves in number_of_waves_across_D: pupil = fits.getdata(pupilfn) mgsdataset = [pupilfn] # an mgsdataset starts with the pupil file... spatialwavelen = 2.0 * pupilradius / nwaves khat = np.array((np.sin(rippleangle * np.pi / 180.0), np.cos(rippleangle * np.pi / 180.0))) # unit vector kwavedata = np.fromfunction(utils.kwave2d, pupil.shape, spatialwavelen=spatialwavelen, center=utils.centerpoint(pupil.shape[0]), offset=ripplepha, khat=khat) ripplephase = pupil * rippleamp * kwavedata #imagefield = ft.perform(pupilarray, fp_size_reselt, npup) # remove this #image_intensity = (imagefield*imagefield.conj()).real # remove this #psf = image_intensity / image_intensity.sum() # total intensity unity # remove this phasefn = rfn + "ripple_{0:d}acrossD_peak_{1:.1f}_pha.fits".format( int(nwaves), rippleamp) fits.PrimaryHDU(ripplephase).writeto(phasefn, overwrite=True) mgsdataset.append( phasefn) # an mgsdataset now pupil file, phase abberration file, # Now create images for each defocus in the list # # First a utility array, parabola P2V unity over pupil, zero outside pupil prad = pupilradius # for parabola=unity at edge of active pupil 2% < unity center = utils.centerpoint(pupil.shape[0]) unityP2Vparabola = np.fromfunction( utils.parabola2d, pupil.shape, cx=center[0], cy=center[1]) / (prad * prad) * pupil fits.writeto(rfn + "unityP2Vparabola.fits", unityP2Vparabola, overwrite=True) # sanity check - write it out for defoc in defocus_list: # defoc units are waves, Peak-to-Valley defocusphase = unityP2Vparabola * 2 * np.pi * defoc aberfn = "pup_defoc_{:.1f}wav.fits".format(defoc) fits.writeto(rfn + aberfn, defocusphase, overwrite=True) aberfn = rfn + "pup_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) aber = defocusphase + ripplephase #fits.writeto(aberfn, aber, overwrite=True) imagefield = mft.perform(pupil * np.exp(1j * aber), pupil.shape[0], pupil.shape[0]) image = (imagefield * imagefield.conj()).real fits.writeto(imagfn, image / image.sum(), overwrite=True) mgsdataset.append((defoc, imagfn, aberfn)) mgsdatasets.append(mgsdataset) """ phase = de_mean(phase, pupil) # zero mean phase - doesn't change image fits.writeto(rfn+"{:1d}__input_truepha.fits".format(pnum), phase, overwrite=True) mft = matrixDFT.MatrixFourierTransform() imagefield = mft.perform(pupil * np.exp(1j*phase), pupil.shape[0], pupil.shape[0]) image = (imagefield*imagefield.conj()).real fits.writeto(rfn+"{:1d}__input_img.fits".format(pnum), image/image.sum(), overwrite=True) del mft """ # Prepare a quicklook at signal in the pairs of defocussed images: side = 2.0 # inches, quicklook at curvatue signal imshow ndefoc = len(defocus_list) // 2 nspatfreq = len(number_of_waves_across_D) magnif = 2.0 fig = plt.figure(1, (nspatfreq * magnif, ndefoc * magnif)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(ndefoc, nspatfreq), # creates 2x2 grid of axes axes_pad=0.02, # pad between axes in inch. ) i = 0 iwav = 0 for nwaves in number_of_waves_across_D: ifoc = 0 maxlist = [] for defoc in defocus_list: # defoc units are waves, Peak-to-Valley if defoc > 0: imagfn_pos = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn_neg = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, -defoc) datapos = fits.getdata(imagfn_pos).flatten() dataneg = fits.getdata(imagfn_neg).flatten() quicklook = (datapos - dataneg[::-1]).reshape((250, 250)) * ( defoc * defoc) # normalize to equal brightness signal maxlist.append(quicklook.max()) #print("max {:.1e}".format(quicklook.max())) #fits.writeto(imagfn_pos.replace("img","qlk"), quicklook, overwrite=True) i = iwav + (ndefoc - ifoc - 1) * nspatfreq grid[i].imshow( quicklook, origin='lower', cmap=plt.get_cmap( 'ocean'), # RdBu, gist_rainbow, ocean, none vmin=-1.3e-2, vmax=1.3e-2) # The AxesGrid object work as a list of axes. grid[i].set_xticks([]) grid[i].set_yticks([]) grid[i].text(20, 220, "{:d} ripples ax D".format(int(nwaves)), color='y', weight='bold') grid[i].text(20, 20, "+/-{:d}w PV".format(int(defoc)), color='w', weight='bold') ifoc += 1 iwav += 1 strtop = "Wavefront signal from phase ripples across the pupil vs. defocus either side of focus" strbot = "Anand S. 2019, illustrating Dean & Bowers, JOSA A 2003 (figs. 4 & 7)" fig.text(0.02, 0.94, strtop, fontsize=18, weight='bold') fig.text(0.02, 0.05, strbot, fontsize=14) plt.tight_layout() plt.savefig("DeanBowers2003_signal_vs_defocus_ripple.pdf", dpi=150, pad_inches=1.0) plt.show() #print("Unity P-V parabola:", arraystats(unityP2Vparabola)) """ for dataset in mgsdatasets: print("MGS data set: pupilfn, aber, (defoc/PVwaves, imagefn, defoc+aber), (repeats)") for thing in dataset: print("\t", thing) print("") """ return mgsdatasets
def exer6(odir): """ Coronagraph train, no optimization for speed. 2nd order BLC, didactic example, fftlike """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 250 # Size of all arrays radius = 50.0 # Numerical reselts in DFT setup cf telescope reselts: # reselts of telescope - here its 0.4 reselts per DFT output image pixel if npup=250,radius=50. dftpixel = 2.0 * radius / npup # Jinc first zero in reselts of telescope... firstzero_optical_reselts = 10.0 firstzero_numericalpixels = firstzero_optical_reselts / dftpixel print("Jinc firstzero_numericalpixels", firstzero_numericalpixels) jinc = np.fromfunction(utils.Jinc, (npup,npup), c=utils.centerpoint(npup), scale=firstzero_numericalpixels) fpm_blc2ndorder = 1 - jinc*jinc print("Jinc fpm min = ", fpm_blc2ndorder.min(), "Jinc fpm max = ", fpm_blc2ndorder.max()) # Pupil, Pupilphase, Apodizer, FP intensity, Intensity after FPM, # Lyot intensity, Lyot Stop, Post-Lyot Stop Intensity, Final image. # # Set up optical train for a typical Lyot style or phase mask coronagraph: Cordict = { "Pupil": utils.makedisk(npup, radius=radius), "Pupilphase": None, "Apodizer": None, "FPintensity": None, "FPM": fpm_blc2ndorder, "LyotIntensity": None, "LyotStop": utils.makedisk(npup, radius=41), "PostLyotStopIntensity": None, "FinalImage": None, "ContrastImage": None} # Propagate through the coronagraph train... # Start with perfect incoming plane wave, no aberrations efield = Cordict["Pupil"] # Put in phase aberrations: if Cordict["Pupilphase"] is not None: efield *= np.exp(1j*Cordict["Pupilphase"]) # Apodize the entrance pupil: if Cordict["Apodizer"] is not None: efield *= Cordict["Apodizer"] # PROPAGATE TO FIRST FOCAL PLANE: efield = ft.perform(efield, npup, npup) # Store FPM intensity: Cordict["FPintensity"] = (efield * efield.conj()).real # Save no-Cor efield for normalization of cor image by peak of no-FPM image efield_NC = efield.copy() # Multiply by FPM transmission function # Lyot style - zero in center, phase mask style: zero integral over domain efield *= Cordict["FPM"] # PROPAGATE TO LYOT PLANE: efield_NC = ft.perform(efield_NC, npup, npup) efield = ft.perform(efield, npup, npup) # Save Cor Lyot intensity; Cordict["LyotIntensity"] = (efield * efield.conj()).real # Apply Lyot stop: if Cordict["LyotStop"] is not None: efield_NC *= Cordict["LyotStop"] if Cordict["LyotStop"] is not None: efield *= Cordict["LyotStop"] # Save Cor Lyot intensity after applying Lyot stop; Cordict["PostLyotStopIntensity"] = (efield * efield.conj()).real # PROPAGATE TO FINAL IMAGE PLANE: efield_NC = ft.perform(efield_NC, npup, npup) efield = ft.perform(efield, npup, npup) final_image_intensity_NC = (efield_NC * efield_NC.conj()).real final_image_intensity = (efield * efield.conj()).real Cordict["FinalImage"] = (efield * efield.conj()).real Cordict["ContrastImage"] = (efield * efield.conj()).real / final_image_intensity_NC.max() # Write our coronagraph planes: planenames, cube = corcube(Cordict) # write planemames as fits keywords print(odir+"/ex6_BLC_2ndOrder.fits") fits.PrimaryHDU(cube).writeto(odir+"/ex6_BLC_2ndOrder.fits", overwrite=True) fobj = fits.open(odir+"/ex6_BLC_2ndOrder.fits") fobj[0].header["Pupil"] = 1 fobj[0].header["FPI"] = (2, "focal plane Intensity") fobj[0].header["FPM"] = (3, "focal plane mask") fobj[0].header["LyotIntn"] = (4, "Lyot Intensity") fobj[0].header["LyotStop"] = 5 fobj[0].header["PostLyot"] = (6, "Post Lyot Stop Intensity") fobj[0].header["CorIm"] = (7, "Raw cor image") fobj[0].header["Contrast"] = (8, "Cor image in contrast units") fobj.writeto(odir+"/ex6_BLC_2ndOrder.fits", overwrite=True)