def __init__(self): # CLEARP pupil info from: # MODIFIED CALIBRATION OPTIC HOLDER - NIRISS # DRAWING NO 196847 REV 0 COMDEV # Design file name 196847Rev0.pdf sent by Loic Albert # Properties: # 39 mm outer diam, corresponds to the circumscribing pupil of JWST # 2.0 mm vane width # 6.0 mm radius for central obstruction # Note the circumscribing pupil of JWST is 6603.464 mm in diameter # (Ball SER on geometric optics model: BALL-JWST-SYST-05-003) pupil_mag = 6.603464 / 39.0 poppy.CompoundAnalyticOptic.__init__( self, ( poppy.SecondaryObscuration( secondary_radius=6.0 * pupil_mag, support_width=2.0 * pupil_mag, n_supports=3, support_angle_offset=90 + 180), # align first support with +V2 axis # but invert to match OTE exit pupil poppy.CircularAperture(radius=39 * pupil_mag / 2)), name='CLEARP')
def test_inwave_fresnel(plot=False): '''Verify basic functionality of the inwave kwarg for a basic FresnelOpticalSystem()''' npix = 128 oversample = 2 # HST example - Following example in PROPER Manual V2.0 page 49. lambda_m = 0.5e-6 * u.m diam = 2.4 * u.m fl_pri = 5.52085 * u.m d_pri_sec = 4.907028205 * u.m fl_sec = -0.6790325 * u.m d_sec_to_focus = 6.3919974 * u.m m1 = poppy.QuadraticLens(fl_pri, name='Primary') m2 = poppy.QuadraticLens(fl_sec, name='Secondary') hst = poppy.FresnelOpticalSystem(pupil_diameter=diam, npix=npix, beam_ratio=1 / oversample) hst.add_optic(poppy.CircularAperture(radius=diam.value / 2)) hst.add_optic( poppy.SecondaryObscuration(secondary_radius=0.396, support_width=0.0264, support_angle_offset=45.0)) hst.add_optic(m1) hst.add_optic(m2, distance=d_pri_sec) hst.add_optic(poppy.ScalarTransmission( planetype=poppy_core.PlaneType.image, name='focus'), distance=d_sec_to_focus) if plot: plt.figure(figsize=(12, 8)) psf1, wfs1 = hst.calc_psf(wavelength=lambda_m, display_intermediates=plot, return_intermediates=True) # now test the system by inputting a wavefront first wfin = poppy.FresnelWavefront(beam_radius=diam / 2, wavelength=lambda_m, npix=npix, oversample=oversample) if plot: plt.figure(figsize=(12, 8)) psf2, wfs2 = hst.calc_psf(wavelength=lambda_m, display_intermediates=plot, return_intermediates=True, inwave=wfin) wf = wfs1[-1].wavefront wf_no_in = wfs2[-1].wavefront assert np.allclose( wf, wf_no_in ), 'Results differ unexpectedly when using inwave argument for FresnelOpticalSystem().'
def make_hawki_poppy_psf(): import poppy osys = poppy.OpticalSystem() m1 = poppy.CircularAperture(radius=4.1) spiders = poppy.SecondaryObscuration(secondary_radius=0.6, n_supports=4, support_width=0.1) vlt = poppy.CompoundAnalyticOptic(opticslist=[m1, spiders], name='VLT') psfs = [] seeing = 0.4 see_psf = simcado.psf.seeing_psf(fwhm=seeing, size=384, pix_res=0.106 / 2) for lam in [1.2, 1.6, 2.2]: osys = poppy.OpticalSystem() osys.add_pupil(vlt) osys.add_detector(pixelscale=0.106, fov_arcsec=0.106 * 192) diff_psf = osys.calc_psf(lam * 1e-6) tmp = deepcopy(diff_psf) tmp[0].data = fftconvolve(diff_psf[0].data, see_psf[0].data, mode="same") tmp[0].data /= np.sum(tmp[0].data) tmp[0].header["SEEING"] = seeing tmp[0].header["CDELT1"] = tmp[0].header["PIXELSCL"] tmp[0].header["CDELT2"] = tmp[0].header["PIXELSCL"] psfs += tmp hdus = fits.HDUList(psfs) for i in range(1, len(hdus)): hdus[i] = fits.ImageHDU(data=hdus[i].data, header=hdus[i].header) hdus.writeto("HAWK-I_config/PSF_HAWKI_poppy.fits", clobber=True) fname = "HAWK-I_config/PSF_HAWKI_poppy.fits" plt.figure(figsize=(15, 4)) for i in range(3): plt.subplot(1, 3, i + 1) poppy.display_PSF(fname, ext=i, title="HAWKI PSF lambda=" + str(fits.getheader(fname, ext=i)["WAVELEN"])) plt.show()
def test_inwave_fraunhofer(plot=False): '''Verify basic functionality of the inwave kwarg for a basic OpticalSystem()''' npix = 128 oversample = 2 diam = 2.4 * u.m lambda_m = 0.5e-6 * u.m # calculate the Fraunhofer diffraction pattern hst = poppy.OpticalSystem(pupil_diameter=diam, npix=npix, oversample=oversample) hst.add_pupil(poppy.CircularAperture(radius=diam.value / 2)) hst.add_pupil( poppy.SecondaryObscuration(secondary_radius=0.396, support_width=0.0264, support_angle_offset=45.0)) hst.add_image( poppy.ScalarTransmission(planetype=poppy_core.PlaneType.image, name='focus')) if plot: plt.figure(figsize=(9, 3)) psf1, wfs1 = hst.calc_psf(wavelength=lambda_m, display_intermediates=plot, return_intermediates=True) # now test the system by inputting a wavefront first wfin = poppy.Wavefront(wavelength=lambda_m, npix=npix, diam=diam, oversample=oversample) if plot: plt.figure(figsize=(9, 3)) psf2, wfs2 = hst.calc_psf(wavelength=lambda_m, display_intermediates=plot, return_intermediates=True, inwave=wfin) wf = wfs1[-1].wavefront wf_no_in = wfs2[-1].wavefront assert np.allclose( wf, wf_no_in ), 'Results differ unexpectedly when using inwave argument in OpticalSystem().'
def multi_hexagon(rings_number, sec_rad, side_dist = 1.0, segment_gap = 0.01): """ multi_hexagon(rings_number, sec_rad, side_dist = 1.0, segment_gap = 0.01) # rings : The number of rings of hexagons to include, not counting the central segment # side_dist : Distance between sides (flat-to-flat) of the hexagon, in meters. Default is 1.0 # segment_gap : Gap between adjacent segments, in meters. Default is 0.01 m = 1 cm # sec_rad : scondary obstacle radius """ ap = poppy.MultiHexagonAperture(name='ApertureHex', flattoflat = side_dist, gap = segment_gap,rings =rings_number) # 3 rings of 2 m segments yields 14.1 m circumscribed diameter sec = poppy.SecondaryObscuration(secondary_radius = float(sec_rad), n_supports = 4, support_width = 0.1) # secondary with spiders atlast = poppy.CompoundAnalyticOptic( opticslist=[ap, sec], name='Mock ATLAST') # combine into one optic plt.figure(figsize=(12,8)) atlast.display(npix=1024, colorbar_orientation='vertical') return atlast
import matplotlib.pyplot as plt import logging logging.basicConfig(level=logging.DEBUG) np.seterr(divide='ignore', invalid='ignore') osys = poppy.OpticalSystem() osys.add_pupil(poppy.CircularAperture(radius=3)) # pupil radius in meters osys.add_detector(pixelscale=0.010, fov_arcsec=5.0) plt.figure(figsize=(16, 12)) ap = poppy.MultiHexagonAperture( rings=3, flattoflat=2 ) # 3 rings of 2 m segments yields 14.1 m circumscribed diameter sec = poppy.SecondaryObscuration(secondary_radius=1.5, n_supports=4, support_width=0.1) # secondary with spiders atlast = poppy.CompoundAnalyticOptic( opticslist=[ap, sec], name='Mock ATLAST') # combine into one optic atlast.display(npix=1024, colorbar_orientation='vertical') plt.savefig('example_atlast_pupil.png', dpi=100) plt.figure(figsize=(8, 6)) osys = poppy.OpticalSystem() osys.add_pupil(atlast) osys.add_detector(pixelscale=0.010, fov_arcsec=2.0) psf = osys.calc_psf(1e-6) poppy.display_psf(psf, title="Mock ATLAST PSF")
def test_fresnel_noninteger_oversampling(display_intermediates=False): '''Test for noninteger oversampling for basic FresnelOpticalSystem() using HST example system''' lambda_m = 0.5e-6 * u.m # lambda_m = np.linspace(0.475e-6, 0.525e-6, 3) * u.m diam = 2.4 * u.m fl_pri = 5.52085 * u.m d_pri_sec = 4.907028205 * u.m fl_sec = -0.6790325 * u.m d_sec_to_focus = 6.3919974 * u.m m1 = poppy.QuadraticLens(fl_pri, name='Primary') m2 = poppy.QuadraticLens(fl_sec, name='Secondary') image_plane = poppy.ScalarTransmission( planetype=poppy_core.PlaneType.image, name='focus') npix = 128 oversample1 = 2 hst1 = poppy.FresnelOpticalSystem(pupil_diameter=diam, npix=npix, beam_ratio=1 / oversample1) hst1.add_optic(poppy.CircularAperture(radius=diam.value / 2)) hst1.add_optic( poppy.SecondaryObscuration(secondary_radius=0.396, support_width=0.0264, support_angle_offset=45.0)) hst1.add_optic(m1) hst1.add_optic(m2, distance=d_pri_sec) hst1.add_optic(image_plane, distance=d_sec_to_focus) if display_intermediates: plt.figure(figsize=(12, 8)) psf1 = hst1.calc_psf(wavelength=lambda_m, display_intermediates=display_intermediates) # now test the second system which has a different oversampling factor oversample2 = 2.0 hst2 = poppy.FresnelOpticalSystem(pupil_diameter=diam, npix=npix, beam_ratio=1 / oversample2) hst2.add_optic(poppy.CircularAperture(radius=diam.value / 2)) hst2.add_optic( poppy.SecondaryObscuration(secondary_radius=0.396, support_width=0.0264, support_angle_offset=45.0)) hst2.add_optic(m1) hst2.add_optic(m2, distance=d_pri_sec) hst2.add_optic(image_plane, distance=d_sec_to_focus) if display_intermediates: plt.figure(figsize=(12, 8)) psf2 = hst2.calc_psf(wavelength=lambda_m, display_intermediates=display_intermediates) # Now test a 3rd HST system with oversample of 2.5 and compare to hardcoded result oversample3 = 2.5 hst3 = poppy.FresnelOpticalSystem(pupil_diameter=diam, npix=npix, beam_ratio=1 / oversample3) hst3.add_optic(poppy.CircularAperture(radius=diam.value / 2)) hst3.add_optic( poppy.SecondaryObscuration(secondary_radius=0.396, support_width=0.0264, support_angle_offset=45.0)) hst3.add_optic(m1) hst3.add_optic(m2, distance=d_pri_sec) hst3.add_optic(image_plane, distance=d_sec_to_focus) if display_intermediates: plt.figure(figsize=(12, 8)) psf3 = hst3.calc_psf(wavelength=lambda_m, display_intermediates=display_intermediates) assert np.allclose( psf1[0].data, psf2[0].data ), 'PSFs with oversampling 2 and 2.0 are surprisingly different.' np.testing.assert_almost_equal( psf3[0].header['PIXELSCL'], 0.017188733797782272, decimal=7, err_msg= 'pixelscale for the PSF with oversample of 2.5 is surprisingly different from expected result.' )
0.8, 0.065, # 7.5 cm semimajor 0.5 # phase ) m1.name = 'TOLIMAN rosette primary mirror' toliman = poppy.FresnelOpticalSystem(name='TOLIMAN telescope', pupil_diameter=m1_rad, npix=1024, beam_ratio=0.5) # Secondary mirror obscuration & spider toliman.add_optic( poppy.SecondaryObscuration(name='Secondary mirror support', secondary_radius=m2_rad, n_supports=m2_supports, support_width=m2_strut_width, support_angle_offset=0 * u.deg), pupil_m2_dist) # Primary mirror # Rosette components toliman.add_optic(m1, m1_m2_dist) # Central aperture - treat as a secondary obscuration with no spider toliman.add_optic( poppy.SecondaryObscuration(name='Secondary mirror support', secondary_radius=m1_aperture_rad, n_supports=0), 0 * u.m) # actually should be a bit further along # Mirror component toliman.add_optic( poppy.fresnel.ConicLens(f_lens=m1_fl,
def make_coronagraph(wfe_coeffs,npix_pupil=512,npix_detector=128,wavelength=1e-6*u.m,oversample=4,pixelscale=0.01,sensor_defocus=0.5,vortex_charge=2,llowfs=False,mask_type='fqpm',obscuration=False,lyot_factor=0.9): #sensor_defocus: defocus of llowfs detector in waves peak-to-valley #these values are picked rather arbitrarily, but seem to work aperture_radius = 3*u.m #lyot_radius=2.6*u.m lyot_radius=lyot_factor*aperture_radius pupil_radius = 3*aperture_radius #create the optical system osys = poppy.OpticalSystem("LLOWFS", oversample=oversample, npix=npix_pupil, pupil_diameter=2*pupil_radius) ap = poppy.CircularAperture(radius=aperture_radius) if obscuration: obsc = poppy.SecondaryObscuration(secondary_radius=0.5*u.m, n_supports=0) osys.add_pupil(poppy.CompoundAnalyticOptic(opticslist=[ap,obsc])) #osys.add_pupil(poppy.AsymmetricSecondaryObscuration(secondary_radius=0.5,support_width=0.2*u.meter,support_angle=(0,120,240))) else: osys.add_pupil(ap) error = poppy.ZernikeWFE(radius=aperture_radius, coefficients=wfe_coeffs) osys.add_pupil(error) #inject wavefrotn error at the pupil #correct for fqpm (and vvc) alignment osys.add_pupil(poppy.FQPM_FFT_aligner()) osys.add_image() #helper for plotting intermediates #select mask type if mask_type is 'fqpm': cgph_mask = poppy.IdealFQPM(wavelength=wavelength,name='FQPM Mask') elif mask_type is 'vortex': cgph_mask = VortexMask(charge=vortex_charge,wavelength=wavelength,name='Vortex Mask') else: raise ValueError("mask_type must be 'fqpm' or 'vortex'") cgph_mask._wavefront_display_hint='phase' osys.add_image(cgph_mask) #correct alignment back the other way osys.add_pupil(poppy.FQPM_FFT_aligner(direction='backward')) #osys.add_pupil() lyot = poppy.CircularAperture(radius=lyot_radius,name='Lyot Stop') lyot._wavefront_display_hint='intensity' if obscuration: lyot_obsc = poppy.InverseTransmission(poppy.SquareAperture(size=1.4*u.m)) lyot = poppy.CompoundAnalyticOptic(opticslist=[lyot,lyot_obsc]) if llowfs: #take the rejected light for the LLOWFS lyot_reflection = poppy.InverseTransmission(lyot) lyot_extent = poppy.CircularAperture(radius=pupil_radius) lyot = poppy.CompoundAnalyticOptic(opticslist = [lyot_reflection,lyot_extent]) lyot._wavefront_display_hint='intensity' osys.add_pupil(lyot) #if obscuration: # obsc = poppy.InverseTransmission(obsc) # osys.add_pupil(obsc) #Add a defocus term to the sensor #Calc of peak-to-valley WFE: https://poppy-optics.readthedocs.io/en/stable/wfe.html defocus_coeff = sensor_defocus*wavelength.to(u.m).value sensor_defocus_wfe = poppy.ZernikeWFE(radius=pupil_radius,coefficients=[0,0,0,defocus_coeff]) osys.add_pupil(sensor_defocus_wfe) #osys.add_pupil() osys.add_detector(pixelscale=pixelscale, fov_pixels=npix_detector, oversample=1) else: #add lyot stop osys.add_pupil(lyot) osys.add_detector(pixelscale=pixelscale, fov_arcsec=1) return osys