def get_wf(wavelength, gridsize, PASSVALUE={}): diam = PASSVALUE.get('diam', 0.3) # telescope diameter in meters m1_fl = PASSVALUE.get('m1_fl', 0.5717255) # primary focal length (m) #beam_ratio = PASSVALUE.get('beam_ratio',0.99) # initial beam width/grid width tilt_x = PASSVALUE.get('tilt_x', 0.) # Tilt angle along x (arc seconds) tilt_y = PASSVALUE.get('tilt_y', 0.) # Tilt angle along y (arc seconds) beam_ratio = 0.99 # Define the wavefront wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # Point off-axis prop_tilt(wfo, tilt_x, tilt_y) # Input aperture proper.prop_circular_aperture(wfo, diam / 2.) # Define entrance proper.prop_define_entrance(wfo) proper.prop_lens(wfo, m1_fl, "primary") opd1_func = PASSVALUE['opd_func'] def build_m1_opd(): return gen_opdmap(opd1_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo)) wfo.wfarr *= build_phase_map( wfo, load_cacheable_grid(opd1_func.__name__, wfo, build_m1_opd, False)) wf = proper.prop_get_wavefront(wfo) return wf
def detector(wfo, conf): f_lens = conf['F_LENS'] nd = conf['N_D'] mode = conf['MODE'] prefix = conf['PREFIX'] Debug = conf['DEBUG'] n = proper.prop_get_gridsize(wfo) if (n >= nd): proper.prop_propagate(wfo, f_lens, "to reimaging lens") proper.prop_lens(wfo, f_lens, "apply reimaging lens") proper.prop_propagate(wfo, f_lens, "final focus") (wfo, sampling) = proper.prop_end( wfo, NOABS=False ) # conclude the simulation --> noabs= the wavefront array will be complex else: print('Error: final image is bigger than initial grid size') psf = wfo[int(n / 2 - nd / 2):int(n / 2 + nd / 2), int(n / 2 - nd / 2):int(n / 2 + nd / 2)] out_dir = str('./output_files/') if (Debug == True): fits.writeto(out_dir + prefix + '_' + mode + '_PSF' + '.fits', psf, overwrite=True) return psf
def simple_telescope(wavelength, gridsize): d_objective = 0.060 fl_objective = 15.0 * d_objective fl_eyepiece = 0.021 fl_eye = 0.022 beam_ratio = 0.5 wfo = proper.propbegin(d_objective, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wfo, d_objective / 2) proper.prop_define_entrance(wfo) proper.prop_lens(wfo, fl_objective, "objective") proper.prop_propagate(wfo, fl_objective + fl_eyepiece, "eyepiece") proper.prop_lens(wfo, fl_eyepiece, "eyepiece") exit_pupil_distance = fl_eyepiece / (1 - fl_eyepiece / (fl_objective + fl_eyepiece)) proper.prop_propagate(wfo, exit_pupil_distance, "exit pupil at eye lens:") proper.prop_lenx(wfo, fl_eye, "eye") proper.prop_propagate(wfo, fl_eye, "retina") (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
def lens(wf, focal=660, offset_before=0, offset_after=0, **conf): # propagation before lens proper.prop_propagate(wf, focal + offset_before) # Fourier transform of an image using a lens proper.prop_lens(wf, focal) # propagation after lens proper.prop_propagate(wf, focal + offset_after)
def add_zern_ab(wfo, f_lens): proper.prop_zernikes(wfo, [4, 11], np.array([500, 500]) * 1.0e-6) # [2,3], [0.5,0.5]*1.0e-6 # FPWFS.quicklook_wf(wfo) proper.prop_lens(wfo, f_lens, "objective") #propagate through focus to pupil proper.prop_propagate(wfo, f_lens * 2, "telescope pupil imaging lens") proper.prop_lens(wfo, f_lens, "telescope pupil imaging lens") proper.prop_propagate(wfo, f_lens, "DM")
def prop_pass_lens(wf, fl_lens, dist): """ pass the wavefront through a lens then propagate to the next surface :param wf: single wavefront of shape=(sp.grid_sz, sp.grid_sz) :param fl_lens: focal length in m :param dist: distance in m """ proper.prop_lens(wf, fl_lens) proper.prop_propagate(wf, dist)
def prop_mid_optics(wfo, f_lens): # proper.prop_propagate(wfo, f_lens) # quicklook_wf(wfo) proper.prop_lens(wfo, f_lens) # print 'here' # quicklook_wf(wfo) # propagate through focus to pupil # proper.prop_propagate(wfo, f_lens*2) # proper.prop_lens(wfo, f_lens) proper.prop_propagate(wfo, f_lens)
def lens(wf, focal=660, lens_method='proper', offset_before=0, offset_after=0, **conf): # propagation before lens proper.prop_propagate(wf, focal + offset_before) # Fourier transform of an image using a lens if lens_method == 'proper': proper.prop_lens(wf, focal) elif lens_method == 'numpy': wf._wfarr = fft.fft2(wf._wfarr)/wf._ngrid elif lens_method == 'pyfftw': wf._wfarr = fftw.fft2(wf._wfarr)/wf._ngrid # propagation after lens proper.prop_propagate(wf, focal + offset_after)
def prefocal_image(wavelength, gridsize, PASSVAL): diam = PASSVAL['diam'] focal_length = PASSVAL['focal_length'] beam_ratio = PASSVAL['beam_ratio'] wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wfo, diam/2) proper.prop_define_entrance(wfo) proper.prop_zernikes(wfo, [i+1 for i in range(len(PASSVAL['ZERN']))], PASSVAL['ZERN']) #print(proper.prop_get_phase(wfo)[gridsize//2,:]) proper.prop_lens(wfo, focal_length) proper.prop_propagate(wfo, focal_length - PASSVAL['DEFOCUS'], TO_PLANE=False) (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
def simple_telescope(wavelength, gridsize): diam = 1.0 focal_ratio = 15.0 focal_length = diam * focal_ratio beam_ratio = 0.5 wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wfo, diam / 2) proper.prop_zernikes(wfo, [5], [1e-6]) proper.prop_define_entrance(wfo) proper.prop_lens(wfo, focal_length * 0.98) proper.prop_propagate(wfo, focal_length) (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
def detector(wfo, f_lens, nd, coronagraph_type, prefix, Debug=False): n = proper.prop_get_gridsize(wfo) if (n >= nd): proper.prop_propagate(wfo, f_lens, "to reimaging lens") proper.prop_lens(wfo, f_lens, "apply reimaging lens") proper.prop_propagate(wfo, f_lens, "final focus") (wfo, sampling) = proper.prop_end( wfo, NOABS=False ) # conclude the simulation --> noabs= the wavefront array will be complex else: print('Error: final image is bigger than initial grid size') psf = wfo[int(n / 2 - nd / 2):int(n / 2 + nd / 2), int(n / 2 - nd / 2):int(n / 2 + nd / 2)] out_dir = str('./output_files/') if (Debug == True): fits.writeto(out_dir + prefix + '_' + coronagraph_type + '_PSF' + '.fits', psf, overwrite=True) return psf
def lens(wf, focal=660, offset_before=0, offset_after=0, offset_light_trap=0, diam_light_trap=0, **conf): # propagation before lens proper.prop_propagate(wf, focal + offset_before) # Fourier transform of an image using a lens proper.prop_lens(wf, focal) # check for light trap if offset_light_trap == 0 and diam_light_trap == 0: # propagation after lens proper.prop_propagate(wf, focal + offset_after) else: # add light trap proper.prop_propagate(wf, focal - offset_light_trap) proper.prop_circular_aperture(wf, diam_light_trap, 0, 0, NORM=True) proper.prop_propagate(wf, offset_light_trap + offset_after)
def coronagraph(wfo, f_lens, occulter_type, diam): proper.prop_lens(wfo, f_lens, "coronagraph imaging lens") proper.prop_propagate(wfo, f_lens, "occulter") # occulter sizes are specified here in units of lambda/diameter; # convert lambda/diam to radians then to meters lamda = proper.prop_get_wavelength(wfo) occrad = 4. # occulter radius in lam/D occrad_rad = occrad * lamda / diam # occulter radius in radians dx_m = proper.prop_get_sampling(wfo) dx_rad = proper.prop_get_sampling_radians(wfo) occrad_m = occrad_rad * dx_m / dx_rad # occulter radius in meters plt.figure(figsize=(12,8)) if occulter_type == "GAUSSIAN": r = proper.prop_radius(wfo) h = np.sqrt(-0.5 * occrad_m**2 / np.log(1 - np.sqrt(0.5))) gauss_spot = 1 - np.exp(-0.5 * (r/h)**2) proper.prop_multiply(wfo, gauss_spot) plt.suptitle("Gaussian spot", fontsize = 18) elif occulter_type == "SOLID": proper.prop_circular_obscuration(wfo, occrad_m) plt.suptitle("Solid spot", fontsize = 18) elif occulter_type == "8TH_ORDER": proper.prop_8th_order_mask(wfo, occrad, CIRCULAR = True) plt.suptitle("8th order band limited spot", fontsize = 18) # After occulter plt.subplot(1,2,1) plt.imshow(np.sqrt(proper.prop_get_amplitude(wfo)), origin = "lower", cmap = plt.cm.gray) plt.text(200, 10, "After Occulter", color = "w") proper.prop_propagate(wfo, f_lens, "pupil reimaging lens") proper.prop_lens(wfo, f_lens, "pupil reimaging lens") proper.prop_propagate(wfo, 2*f_lens, "lyot stop") plt.subplot(1,2,2) plt.imshow(proper.prop_get_amplitude(wfo)**0.2, origin = "lower", cmap = plt.cm.gray) plt.text(200, 10, "Before Lyot Stop", color = "w") plt.show() if occulter_type == "GAUSSIAN": proper.prop_circular_aperture(wfo, 0.25, NORM = True) elif occulter_type == "SOLID": proper.prop_circular_aperture(wfo, 0.84, NORM = True) elif occulter_type == "8TH_ORDER": proper.prop_circular_aperture(wfo, 0.50, NORM = True) proper.prop_propagate(wfo, f_lens, "reimaging lens") proper.prop_lens(wfo, f_lens, "reimaging lens") proper.prop_propagate(wfo, f_lens, "final focus") return
def prescription_quad_tiltafter(wavelength, gridsize, PASSVALUE = {'diam': 0.3, 'm1_fl': 0.5717255, 'beam_ratio': 0.2, 'tilt_x': 0.0, 'tilt_y': 0.0 }): diam = PASSVALUE['diam'] # telescope diameter in meters m1_fl = PASSVALUE['m1_fl'] # primary focal length (m) beam_ratio = PASSVALUE['beam_ratio'] # initial beam width/grid width tilt_x = PASSVALUE['tilt_x'] # Tilt angle along x (arc seconds) tilt_y = PASSVALUE['tilt_y'] # Tilt angle along y (arc seconds) # Define the wavefront wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # Input aperture proper.prop_circular_aperture(wfo, diam/2) # Define entrance proper.prop_define_entrance(wfo) # Primary mirror (treat as quadratic lens) proper.prop_lens(wfo, m1_fl, "primary") # Point off-axis prop_tilt(wfo, tilt_x, tilt_y) # Focus proper.prop_propagate(wfo, m1_fl, "focus", TO_PLANE=True) # End (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
def prescription_rc_quad(wavelength, gridsize, PASSVALUE = {}): # Assign parameters from PASSVALUE struct or use defaults diam = PASSVALUE.get('diam',0.3) # telescope diameter in meters m1_fl = PASSVALUE.get('m1_fl',0.5717255) # primary focal length (m) m1_hole_rad = PASSVALUE.get('m1_hole_rad',0.035) # Radius of hole in primary (m) m1_m2_sep = PASSVALUE.get('m1_m2_sep',0.549337630333726) # primary to secondary separation (m) m2_fl = PASSVALUE.get('m2_fl',-0.023378959) # secondary focal length (m) bfl = PASSVALUE.get('bfl',0.528110658881) # nominal distance from secondary to focus (m) beam_ratio = PASSVALUE.get('beam_ratio',0.2) # initial beam width/grid width m2_rad = PASSVALUE.get('m2_rad',0.059) # Secondary half-diameter (m) m2_strut_width = PASSVALUE.get('m2_strut_width',0.01) # Width of struts supporting M2 (m) m2_supports = PASSVALUE.get('m2_supports',5) # Number of support structs (assumed equally spaced) tilt_x = PASSVALUE.get('tilt_x',0.) # Tilt angle along x (arc seconds) tilt_y = PASSVALUE.get('tilt_y',0.) # Tilt angle along y (arc seconds) noabs = PASSVALUE.get('noabs',False) # Output complex amplitude? use_caching = PASSVALUE.get('use_caching',False) # Use cached files if available? get_wf = PASSVALUE.get('get_wf',False) # Return wavefront # Can also specify a opd_func function with signature opd_func(r, phi) if 'phase_func' in PASSVALUE: print('DEPRECATED setting "phase_func": use "opd_func" instead') if 'opd_func' not in PASSVALUE: PASSVALUE['opd_func'] = PASSVALUE['phase_func'] if 'phase_func_sec' in PASSVALUE: print('DEPRECATED setting "phase_func_sec": use "opd_func_sec" instead') if 'opd_func_sec' not in PASSVALUE: PASSVALUE['opd_func_sec'] = PASSVALUE['phase_func_sec'] def build_m2_obs(): # Input aperture grid = build_prop_circular_aperture(wfo, diam/2) # Secondary and structs obscuration grid *= build_prop_circular_obscuration(wfo, m2_rad) # secondary mirror obscuration # Spider struts/vanes, arranged evenly radiating out from secondary strut_length = diam/2 - m2_rad strut_step = 360/m2_supports strut_centre = m2_rad + strut_length/2 for i in range(0, m2_supports): angle = i*strut_step radians = math.radians(angle) xoff = math.cos(radians)*strut_centre yoff = math.sin(radians)*strut_centre grid *= build_prop_rectangular_obscuration(wfo, m2_strut_width, strut_length, xoff, yoff, ROTATION = angle + 90) return grid # Define the wavefront wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # Point off-axis prop_tilt(wfo, tilt_x, tilt_y) wfo.wfarr *= load_cacheable_grid('m2_obs', wfo, build_m2_obs, use_caching) # Normalize wavefront proper.prop_define_entrance(wfo) #if get_wf: # wf = proper.prop_get_wavefront(wfo) # print('Got wavefront') proper.prop_propagate(wfo, m1_m2_sep, "primary") # Primary mirror if 'opd_func' in PASSVALUE: opd1_func = PASSVALUE['opd_func'] def build_m1_opd(): return gen_opdmap(opd1_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo)) wfo.wfarr *= build_phase_map(wfo, load_cacheable_grid(opd1_func.__name__, wfo, build_m1_opd, use_caching)) if get_wf: wf = proper.prop_get_wavefront(wfo) print('Got wavefront') if 'm1_conic' in PASSVALUE: prop_conic(wfo, m1_fl, PASSVALUE['m1_conic'], "conic primary") else: proper.prop_lens(wfo, m1_fl, "primary") wfo.wfarr *= build_prop_circular_obscuration(wfo, m1_hole_rad) # Secondary mirror proper.prop_propagate(wfo, m1_m2_sep, "secondary") if 'opd_func_sec' in PASSVALUE: opd2_func = PASSVALUE['opd_func_sec'] def build_m2_opd(): return gen_opdmap(opd2_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo)) wfo.wfarr *= build_phase_map(wfo, load_cacheable_grid(opd2_func.__name__, wfo, build_m2_opd, use_caching)) if 'm1_conic' in PASSVALUE: prop_conic(wfo, m2_fl, PASSVALUE['m2_conic'], "conic secondary") else: proper.prop_lens(wfo, m2_fl, "secondary") def build_m2_ap(): return build_prop_circular_aperture(wfo, m2_rad) wfo.wfarr *= load_cacheable_grid('m2_ap', wfo, build_m2_ap) # proper.prop_state(wfo) # Hole through primary if m1_m2_sep<bfl: proper.prop_propagate(wfo, m1_m2_sep, "M1 hole") def build_m1_hole(): return build_prop_circular_aperture(wfo, m1_hole_rad) wfo.wfarr *= load_cacheable_grid('m1_hole', wfo, build_m1_hole) # Focus - bfl can be varied between runs if m1_m2_sep<bfl: proper.prop_propagate(wfo, bfl-m1_m2_sep, "focus", TO_PLANE=True) else: proper.prop_propagate(wfo, bfl, "focus", TO_PLANE=True) # # End # return proper.prop_end(wfo, NOABS = noabs) # End (wfo, sampling) = proper.prop_end(wfo) if get_wf: return (wfo, wf, sampling) else: return (wfo, sampling)
def vortex(wfo, charge, f_lens, diam, pixelsize, Debug_print=False): n = int(proper.prop_get_gridsize(wfo)) ofst = 0 # no offset ramp_sign = 1 #sign of charge is positive ramp_oversamp = 11. # vortex is oversampled for a better discretization if charge != 0: wavelength = proper.prop_get_wavelength(wfo) gridsize = proper.prop_get_gridsize(wfo) beam_ratio = pixelsize * 4.85e-9 / (wavelength / diam) calib = str(charge) + str('_') + str(int( beam_ratio * 100)) + str('_') + str(gridsize) my_file = str(tmp_dir + 'zz_perf_' + calib + '_r.fits') proper.prop_propagate(wfo, f_lens, 'inizio') # propagate wavefront proper.prop_lens(wfo, f_lens, 'focusing lens vortex') # propagate through a lens proper.prop_propagate(wfo, f_lens, 'VC') # propagate wavefront if (os.path.isfile(my_file) == True): if (Debug_print == True): print("Charge ", charge) vvc = readfield(tmp_dir, 'zz_vvc_' + calib) # read the theoretical vortex field vvc = proper.prop_shift_center(vvc) scale_psf = wfo._wfarr[0, 0] psf_num = readfield(tmp_dir, 'zz_psf_' + calib) # read the pre-vortex field psf0 = psf_num[0, 0] psf_num = psf_num / psf0 * scale_psf perf_num = readfield(tmp_dir, 'zz_perf_' + calib) # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wfo._wfarr = ( wfo._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field else: # CAL==1: # create the vortex for a perfectly circular pupil if (Debug_print == True): print("Charge ", charge) wfo1 = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wfo1, diam / 2) proper.prop_define_entrance(wfo1) proper.prop_propagate(wfo1, f_lens, 'inizio') # propagate wavefront proper.prop_lens( wfo1, f_lens, 'focusing lens vortex') # propagate through a lens proper.prop_propagate(wfo1, f_lens, 'VC') # propagate wavefront writefield(tmp_dir, 'zz_psf_' + calib, wfo1.wfarr) # write the pre-vortex field nramp = int(n * ramp_oversamp) #oversamp # create the vortex by creating a matrix (theta) representing the ramp (created by atan 2 gradually varying matrix, x and y) y1 = np.ones((nramp, ), dtype=np.int) y2 = np.arange(0, nramp, 1.) - (nramp / 2) - int(ramp_oversamp) / 2 y = np.outer(y2, y1) x = np.transpose(y) theta = np.arctan2(y, x) x = 0 y = 0 vvc_tmp = np.exp(1j * (ofst + ramp_sign * charge * theta)) theta = 0 vvc_real_resampled = cv2.resize( vvc_tmp.real, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc_imag_resampled = cv2.resize( vvc_tmp.imag, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc = np.array(vvc_real_resampled, dtype=complex) vvc.imag = vvc_imag_resampled vvcphase = np.arctan2(vvc.imag, vvc.real) # create the vortex phase vvc_complex = np.array(np.zeros((n, n)), dtype=complex) vvc_complex.imag = vvcphase vvc = np.exp(vvc_complex) vvc_tmp = 0. writefield(tmp_dir, 'zz_vvc_' + calib, vvc) # write the theoretical vortex field proper.prop_multiply(wfo1, vvc) proper.prop_propagate(wfo1, f_lens, 'OAP2') proper.prop_lens(wfo1, f_lens) proper.prop_propagate(wfo1, f_lens, 'forward to Lyot Stop') proper.prop_circular_obscuration( wfo1, 1., NORM=True) # null the amplitude iside the Lyot Stop proper.prop_propagate(wfo1, -f_lens) # back-propagation proper.prop_lens(wfo1, -f_lens) proper.prop_propagate(wfo1, -f_lens) writefield(tmp_dir, 'zz_perf_' + calib, wfo1.wfarr) # write the perfect-result vortex field vvc = readfield(tmp_dir, 'zz_vvc_' + calib) vvc = proper.prop_shift_center(vvc) scale_psf = wfo._wfarr[0, 0] psf_num = readfield(tmp_dir, 'zz_psf_' + calib) # read the pre-vortex field psf0 = psf_num[0, 0] psf_num = psf_num / psf0 * scale_psf perf_num = readfield(tmp_dir, 'zz_perf_' + calib) # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wfo._wfarr = ( wfo._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field proper.prop_propagate(wfo, f_lens, "propagate to pupil reimaging lens") proper.prop_lens(wfo, f_lens, "apply pupil reimaging lens") proper.prop_propagate(wfo, f_lens, "lyot stop") return wfo
def scexao_model(lmda, grid_size, kwargs): """ propagates instantaneous complex E-field thru Subaru from the DM through SCExAO uses PyPROPER3 to generate the complex E-field at the pupil plane, then propagates it through SCExAO 50x50 DM, then coronagraph, to the focal plane :returns spectral cube at instantaneous time in the focal_plane() """ # print("Propagating Broadband Wavefront Through Subaru") # Initialize the Wavefront in Proper wfo = proper.prop_begin(entrance_d, lmda, grid_size, beam_ratio) # Defines aperture (baffle-before primary) proper.prop_circular_aperture(wfo, entrance_d / 2) proper.prop_define_entrance(wfo) # normalizes abs intensity # Test Sampling if kwargs['verbose'] and kwargs['ix'] == 0: check1 = proper.prop_get_sampling(wfo) print( f"\n\tDM Pupil Plane\n" f"sampling at aperture is {check1 * 1e3:.4f} mm\n" f"Total Sim is {check1 * 1e3 * grid_size:.2f}x{check1 * 1e3 * grid_size:.2f} mm\n" f"Diameter of beam is {check1 * 1e3 * grid_size * beam_ratio:.4f} mm over {grid_size * beam_ratio} pix" ) # SCExAO Reimaging 1 proper.prop_lens( wfo, fl_SxOAPG) # produces f#14 beam (approx exit beam of AO188) proper.prop_propagate(wfo, fl_SxOAPG * 2) # move to second pupil if kwargs['verbose'] and kwargs['ix'] == 0: print(f"initial f# is {proper.prop_get_fratio(wfo):.2f}\n") ######################################## # Import/Apply Actual DM Map # ####################################### plot_flag = False if kwargs['verbose'] and kwargs['ix'] == 0: plot_flag = True dm_map = kwargs['map'] errormap(wfo, dm_map, SAMPLING=dm_pitch, MIRROR_SURFACE=True, MASKING=True, BR=beam_ratio, PLOT=plot_flag) # MICRONS=True if kwargs['verbose'] and kwargs['ix'] == 0: fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5)) ax1, ax2 = subplot.flatten() fig.suptitle('SCExAO Model WFO after errormap', fontweight='bold', fontsize=14) ax1.imshow(proper.prop_get_amplitude(wfo), interpolation='none' ) # np.abs(proper.prop_shift_center(wfo.wfarr))**2 ax1.set_title('Amplitude') ax2.imshow( proper.prop_get_phase(wfo), interpolation= 'none', # np.angle(proper.prop_shift_center(wfo.wfarr)) vmin=-1 * np.pi, vmax=1 * np.pi, cmap='hsv') # , cmap='hsv' ax2.set_title('Phase') # ------------------------------------------------ # SCExAO Reimaging 2 proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG) # focus at exit of DM telescope system proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG) # focus at exit of DM telescope system # # Coronagraph SubaruPupil(wfo) # focal plane mask # if kwargs['verbose'] and kwargs['ix']==0: # fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5)) # ax1, ax2 = subplot.flatten() # fig.suptitle('SCExAO Model WFO after FPM', fontweight='bold', fontsize=14) # # ax.imshow(dm_map, interpolation='none') # ax1.imshow(np.abs(proper.prop_shift_center(wfo.wfarr))**2, interpolation='none', norm=LogNorm(vmin=1e-7,vmax=1e-2)) # ax1.set_title('Amplitude') # ax2.imshow(np.angle(proper.prop_shift_center(wfo.wfarr)), interpolation='none', # vmin=-2*np.pi, vmax=2*np.pi, cmap='hsv') # , cmap='hsv' # ax2.set_title('Phase') proper.prop_propagate(wfo, fl_SxOAPG) proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG) # middle of 2f system proper.prop_circular_aperture(wfo, lyot_size, NORM=True) # lyot stop proper.prop_propagate(wfo, fl_SxOAPG) # proper.prop_lens(wfo, fl_SxOAPG) # exit lens of gaussian telescope proper.prop_propagate(wfo, fl_SxOAPG) # to focus # MEC Pickoff reimager. proper.prop_propagate(wfo, mec_parax_fl) # to another pupil proper.prop_lens( wfo, mec_parax_fl) # collimating lens, pupil size should be 8 mm proper.prop_propagate(wfo, mec1_fl + .0142557) # mec1_fl .054 mec1_fl+.0101057 # if kwargs['verbose'] and kwargs['ix']==0: # current = proper.prop_get_beamradius(wfo) # print(f'Beam Radius after SCExAO exit (at MEC foreoptics entrance) is {current*1e3:.3f} mm\n' # f'current f# is {proper.prop_get_fratio(wfo):.2f}\n') # ################################## # MEC Optics Box # ################################### proper.prop_circular_aperture(wfo, 0.00866) # reading off the zemax diameter proper.prop_lens(wfo, mec1_fl) # MEC lens 1 proper.prop_propagate(wfo, mec_l1_l2) # there is a image plane at z=mec1_fl proper.prop_lens(wfo, mec2_fl) # MEC lens 2 (tiny lens) proper.prop_propagate(wfo, mec_l2_l3) proper.prop_lens(wfo, mec3_fl) # MEC lens 3 proper.prop_propagate(wfo, mec3_fl, TO_PLANE=False) # , TO_PLANE=True mec_l3_focus # ####################################### # Focal Plane # ####################################### # Check Sampling in focal plane # shifts wfo from Fourier Space (origin==lower left corner) to object space (origin==center) # wf, samp = proper.prop_end(wfo, NoAbs=True) wf = proper.prop_shift_center(wfo.wfarr) wf = extract_center(wf, new_size=np.array(kwargs['psf_size'])) samp = proper.prop_get_sampling(wfo) smp_asec = proper.prop_get_sampling_arcsec(wfo) if kwargs['verbose'] and kwargs['ix'] == 0: fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5)) fig.subplots_adjust(left=0.08, hspace=.4, wspace=0.2) ax1, ax2 = subplot.flatten() fig.suptitle('SCExAO Model Focal Plane', fontweight='bold', fontsize=14) tic_spacing, tic_labels, axlabel = scale_lD( wfo, newsize=kwargs['psf_size'][0]) tic_spacing[0] = tic_spacing[0] + 1 # hack for edge effects tic_spacing[-1] = tic_spacing[-1] - 1 # hack for edge effects im = ax1.imshow( np.abs(wf)**2, interpolation='none', norm=LogNorm( vmin=1e-7, vmax=1e-2)) # np.abs(proper.prop_shift_center(wfo.wfarr))**2 ax1.set_xticks(tic_spacing) ax1.set_xticklabels(tic_labels) ax1.set_yticks(tic_spacing) ax1.set_yticklabels(tic_labels) ax1.set_ylabel(axlabel, fontsize=8) add_colorbar(im) im = ax2.imshow(np.angle(wf), interpolation='none', vmin=-np.pi, vmax=np.pi, cmap='hsv') ax2.set_xticks(tic_spacing) ax2.set_xticklabels(tic_labels) ax2.set_yticks(tic_spacing) ax2.set_yticklabels(tic_labels) ax2.set_ylabel(axlabel, fontsize=8) add_colorbar(im) if kwargs['verbose'] and kwargs['ix'] == 0: print( f"\nFocal Plane\n" f"sampling at focal plane is {samp*1e6:.1f} um ~= {smp_asec * 1e3:.4f} mas\n" f"\tfull FOV is {samp * kwargs['psf_size'][0] * 1e3:.2f} x {samp * kwargs['psf_size'][1] * 1e3:.2f} mm " ) # s_rad = proper.prop_get_sampling_radians(wfo) # print(f"sampling at focal plane is {s_rad * 1e6:.6f} urad") print(f'final focal ratio is {proper.prop_get_fratio(wfo)}') print(f"Finished simulation") return wf, samp
def add_aber(wfo, f_lens, aber_params, aber_vals, step=0, Loc='CPA'): if aber_params['QuasiStatic'] == False: step = 0 # print aber_params if aber_params['Phase']: for surf in range(aber_params['n_surfs']): filename = '%s%s_Phase%f_v%i.fits' % (iop.aberdir, Loc, step * cp.frame_time, surf) # print filename rms_error = np.random.normal(aber_vals['a'][0], aber_vals['a'][1]) # print rms_error c_freq = np.random.normal( aber_vals['b'][0], aber_vals['b'][1]) # correlation frequency (cycles/meter) # print c_freq high_power = np.random.normal( aber_vals['c'][0], aber_vals['c'][1]) # high frewquency falloff (r^-high_power) # print high_power # quicklook_wf(wfo) if aber_params['OOPP']: proper.prop_lens(wfo, f_lens, "OOPP") proper.prop_propagate(wfo, f_lens / aber_params['OOPP'][surf]) # quicklook_wf(wfo) prim_map = proper.prop_psd_errormap(wfo, rms_error, c_freq, high_power, FILE=filename, TPF=True) if aber_params['OOPP']: proper.prop_propagate( wfo, f_lens + f_lens * (1 - 1. / aber_params['OOPP'][surf])) proper.prop_lens(wfo, f_lens, "OOPP") # quicklook_wf(wfo) # quicklook_im(prim_map*1e9, logAmp=False, colormap="jet", show=True, axis=None, title='nm', pupil=True) if aber_params['Amp']: # filename = '%s%s_Amp%f.fits' % (iop.aberdir, Loc, step * cp.frame_time) for surf in range(aber_params['n_surfs']): filename = '%s%s_Amp%f_v%i.fits' % (iop.aberdir, Loc, step * cp.frame_time, surf) # print filename rms_error = np.random.normal(aber_vals['a_amp'][0], aber_vals['a_amp'][1]) # print rms_error c_freq = np.random.normal( aber_vals['b'][0], aber_vals['b'][1]) # correlation frequency (cycles/meter) # print c_freq high_power = np.random.normal( aber_vals['c'][0], aber_vals['c'][1]) # high frewquency falloff (r^-high_power) # print high_power prim_map = proper.prop_psd_errormap(wfo, rms_error, c_freq, high_power, FILE=filename, AMPLITUDE=1.0)
def occulter(self, wf): n = int(proper.prop_get_gridsize(wf)) ofst = 0 # no offset ramp_sign = 1 # sign of charge is positive ramp_oversamp = 11. # vortex is oversampled for a better discretization # f_lens = tp.f_lens #conf['F_LENS'] # diam = tp.diam#conf['DIAM'] charge = 2 #conf['CHARGE'] pixelsize = 5 #conf['PIXEL_SCALE'] Debug_print = False #conf['DEBUG_PRINT'] coron_temp = os.path.join(iop.testdir, 'coron_maps/') if not os.path.exists(coron_temp): os.mkdir(coron_temp) if charge != 0: wavelength = proper.prop_get_wavelength(wf) gridsize = proper.prop_get_gridsize(wf) beam_ratio = pixelsize * 4.85e-9 / (wavelength / tp.entrance_d) # dprint((wavelength,gridsize,beam_ratio)) calib = str(charge) + str('_') + str(int( beam_ratio * 100)) + str('_') + str(gridsize) my_file = str(coron_temp + 'zz_perf_' + calib + '_r.fits') if (os.path.isfile(my_file) == True): if (Debug_print == True): print("Charge ", charge) vvc = self.readfield( coron_temp, 'zz_vvc_' + calib) # read the theoretical vortex field vvc = proper.prop_shift_center(vvc) scale_psf = wf._wfarr[0, 0] psf_num = self.readfield(coron_temp, 'zz_psf_' + calib) # read the pre-vortex field psf0 = psf_num[0, 0] psf_num = psf_num / psf0 * scale_psf perf_num = self.readfield( coron_temp, 'zz_perf_' + calib) # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wf._wfarr = ( wf._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field else: # CAL==1: # create the vortex for a perfectly circular pupil if (Debug_print == True): dprint(f"Vortex Charge= {charge}") f_lens = 200.0 * tp.entrance_d wf1 = proper.prop_begin(tp.entrance_d, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wf1, tp.entrance_d / 2) proper.prop_define_entrance(wf1) proper.prop_propagate(wf1, f_lens, 'inizio') # propagate wavefront proper.prop_lens( wf1, f_lens, 'focusing lens vortex') # propagate through a lens proper.prop_propagate(wf1, f_lens, 'VC') # propagate wavefront self.writefield(coron_temp, 'zz_psf_' + calib, wf1.wfarr) # write the pre-vortex field nramp = int(n * ramp_oversamp) # oversamp # create the vortex by creating a matrix (theta) representing the ramp (created by atan 2 gradually varying matrix, x and y) y1 = np.ones((nramp, ), dtype=np.int) y2 = np.arange(0, nramp, 1.) - (nramp / 2) - int(ramp_oversamp) / 2 y = np.outer(y2, y1) x = np.transpose(y) theta = np.arctan2(y, x) x = 0 y = 0 vvc_tmp = np.exp(1j * (ofst + ramp_sign * charge * theta)) theta = 0 vvc_real_resampled = cv2.resize( vvc_tmp.real, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc_imag_resampled = cv2.resize( vvc_tmp.imag, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc = np.array(vvc_real_resampled, dtype=complex) vvc.imag = vvc_imag_resampled vvcphase = np.arctan2(vvc.imag, vvc.real) # create the vortex phase vvc_complex = np.array(np.zeros((n, n)), dtype=complex) vvc_complex.imag = vvcphase vvc = np.exp(vvc_complex) vvc_tmp = 0. self.writefield(coron_temp, 'zz_vvc_' + calib, vvc) # write the theoretical vortex field proper.prop_multiply(wf1, vvc) proper.prop_propagate(wf1, f_lens, 'OAP2') proper.prop_lens(wf1, f_lens) proper.prop_propagate(wf1, f_lens, 'forward to Lyot Stop') proper.prop_circular_obscuration( wf1, 1., NORM=True) # null the amplitude iside the Lyot Stop proper.prop_propagate(wf1, -f_lens) # back-propagation proper.prop_lens(wf1, -f_lens) proper.prop_propagate(wf1, -f_lens) self.writefield( coron_temp, 'zz_perf_' + calib, wf1.wfarr) # write the perfect-result vortex field vvc = self.readfield(coron_temp, 'zz_vvc_' + calib) vvc = proper.prop_shift_center(vvc) scale_psf = wf._wfarr[0, 0] psf_num = self.readfield(coron_temp, 'zz_psf_' + calib) # read the pre-vortex field psf0 = psf_num[0, 0] psf_num = psf_num / psf0 * scale_psf perf_num = self.readfield( coron_temp, 'zz_perf_' + calib) # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wf._wfarr = ( wf._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field return wf
def wfirst_phaseb(lambda_m, output_dim0, PASSVALUE={'dummy': 0}): # "output_dim" is used to specify the output dimension in pixels at the final image plane. # Computational grid sizes are hardcoded for each coronagraph. # Based on Zemax prescription "WFIRST_CGI_DI_LOWFS_Sep24_2018.zmx" by Hong Tang. data_dir = wfirst_phaseb_proper.data_dir if 'PASSVALUE' in locals(): if 'data_dir' in PASSVALUE: data_dir = PASSVALUE['data_dir'] map_dir = data_dir + wfirst_phaseb_proper.map_dir polfile = data_dir + wfirst_phaseb_proper.polfile cor_type = 'hlc' # coronagraph type ('hlc', 'spc', 'none') source_x_offset_mas = 0 # source offset in mas (tilt applied at primary) source_y_offset_mas = 0 source_x_offset = 0 # source offset in lambda0_m/D radians (tilt applied at primary) source_y_offset = 0 polaxis = 0 # polarization axis aberrations: # -2 = -45d in, Y out # -1 = -45d in, X out # 1 = +45d in, X out # 2 = +45d in, Y out # 5 = mean of modes -1 & +1 (X channel polarizer) # 6 = mean of modes -2 & +2 (Y channel polarizer) # 10 = mean of all modes (no polarization filtering) use_errors = 1 # use optical surface phase errors? 1 or 0 zindex = np.array([0, 0]) # array of Zernike polynomial indices zval_m = np.array([0, 0]) # array of Zernike coefficients (meters RMS WFE) use_aperture = 0 # use apertures on all optics? 1 or 0 cgi_x_shift_pupdiam = 0 # X,Y shear of wavefront at FSM (bulk displacement of CGI); normalized relative to pupil diameter cgi_y_shift_pupdiam = 0 cgi_x_shift_m = 0 # X,Y shear of wavefront at FSM (bulk displacement of CGI) in meters cgi_y_shift_m = 0 fsm_x_offset_mas = 0 # offset in focal plane caused by tilt of FSM in mas fsm_y_offset_mas = 0 fsm_x_offset = 0 # offset in focal plane caused by tilt of FSM in lambda0/D fsm_y_offset = 0 end_at_fsm = 0 # end propagation after propagating to FSM (no FSM errors) focm_z_shift_m = 0 # offset (meters) of focus correction mirror (+ increases path length) use_hlc_dm_patterns = 0 # use Dwight's HLC default DM wavefront patterns? 1 or 0 use_dm1 = 0 # use DM1? 1 or 0 use_dm2 = 0 # use DM2? 1 or 0 dm_sampling_m = 0.9906e-3 # actuator spacing in meters dm1_xc_act = 23.5 # for 48x48 DM, wavefront centered at actuator intersections: (0,0) = 1st actuator center dm1_yc_act = 23.5 dm1_xtilt_deg = 0 # tilt around X axis (deg) dm1_ytilt_deg = 5.7 # effective DM tilt in deg including 9.65 deg actual tilt and pupil ellipticity dm1_ztilt_deg = 0 # rotation of DM about optical axis (deg) dm2_xc_act = 23.5 # for 48x48 DM, wavefront centered at actuator intersections: (0,0) = 1st actuator center dm2_yc_act = 23.5 dm2_xtilt_deg = 0 # tilt around X axis (deg) dm2_ytilt_deg = 5.7 # effective DM tilt in deg including 9.65 deg actual tilt and pupil ellipticity dm2_ztilt_deg = 0 # rotation of DM about optical axis (deg) use_pupil_mask = 1 # SPC only: use SPC pupil mask (0 or 1) mask_x_shift_pupdiam = 0 # X,Y shear of shaped pupil mask; normalized relative to pupil diameter mask_y_shift_pupdiam = 0 mask_x_shift_m = 0 # X,Y shear of shaped pupil mask in meters mask_y_shift_m = 0 use_fpm = 1 # use occulter? 1 or 0 fpm_x_offset = 0 # FPM x,y offset in lambda0/D fpm_y_offset = 0 fpm_x_offset_m = 0 # FPM x,y offset in meters fpm_y_offset_m = 0 fpm_z_shift_m = 0 # occulter offset in meters along optical axis (+ = away from prior optics) pinhole_diam_m = 0 # FPM pinhole diameter in meters end_at_fpm_exit_pupil = 0 # return field at FPM exit pupil? output_field_rootname = '' # rootname of FPM exit pupil field file (must set end_at_fpm_exit_pupil=1) use_lyot_stop = 1 # use Lyot stop? 1 or 0 lyot_x_shift_pupdiam = 0 # X,Y shear of Lyot stop mask; normalized relative to pupil diameter lyot_y_shift_pupdiam = 0 lyot_x_shift_m = 0 # X,Y shear of Lyot stop mask in meters lyot_y_shift_m = 0 use_field_stop = 1 # use field stop (HLC)? 1 or 0 field_stop_radius_lam0 = 0 # field stop radius in lambda0/D (HLC or SPC-wide mask only) field_stop_x_offset = 0 # field stop offset in lambda0/D field_stop_y_offset = 0 field_stop_x_offset_m = 0 # field stop offset in meters field_stop_y_offset_m = 0 use_pupil_lens = 0 # use pupil imaging lens? 0 or 1 use_defocus_lens = 0 # use defocusing lens? Options are 1, 2, 3, 4, corresponding to +18.0, +9.0, -4.0, -8.0 waves P-V @ 550 nm defocus = 0 # instead of specific lens, defocus in waves P-V @ 550 nm (-8.7 to 42.0 waves) final_sampling_m = 0 # final sampling in meters (overrides final_sampling_lam0) final_sampling_lam0 = 0 # final sampling in lambda0/D output_dim = output_dim0 # dimension of output in pixels (overrides output_dim0) if 'PASSVALUE' in locals(): if 'use_fpm' in PASSVALUE: use_fpm = PASSVALUE['use_fpm'] if 'cor_type' in PASSVALUE: cor_type = PASSVALUE['cor_type'] is_spc = False is_hlc = False if cor_type == 'hlc': is_hlc = True file_directory = data_dir + '/hlc_20190210/' # must have trailing "/" prefix = file_directory + 'run461_' pupil_diam_pix = 309.0 pupil_file = prefix + 'pupil_rotated.fits' lyot_stop_file = prefix + 'lyot.fits' lambda0_m = 0.575e-6 lam_occ = [ 5.4625e-07, 5.49444444444e-07, 5.52638888889e-07, 5.534375e-07, 5.55833333333e-07, 5.59027777778e-07, 5.60625e-07, 5.62222222222e-07, 5.65416666667e-07, 5.678125e-07, 5.68611111111e-07, 5.71805555556e-07, 5.75e-07, 5.78194444444e-07, 5.81388888889e-07, 5.821875e-07, 5.84583333333e-07, 5.87777777778e-07, 5.89375e-07, 5.90972222222e-07, 5.94166666667e-07, 5.965625e-07, 5.97361111111e-07, 6.00555555556e-07, 6.0375e-07 ] lam_occs = [ '5.4625e-07', '5.49444444444e-07', '5.52638888889e-07', '5.534375e-07', '5.55833333333e-07', '5.59027777778e-07', '5.60625e-07', '5.62222222222e-07', '5.65416666667e-07', '5.678125e-07', '5.68611111111e-07', '5.71805555556e-07', '5.75e-07', '5.78194444444e-07', '5.81388888889e-07', '5.821875e-07', '5.84583333333e-07', '5.87777777778e-07', '5.89375e-07', '5.90972222222e-07', '5.94166666667e-07', '5.965625e-07', '5.97361111111e-07', '6.00555555556e-07', '6.0375e-07' ] lam_occs = [ prefix + 'occ_lam' + s + 'theta6.69polp_' for s in lam_occs ] # find nearest matching FPM wavelength wlam = (np.abs(lambda_m - np.array(lam_occ))).argmin() occulter_file_r = lam_occs[wlam] + 'real.fits' occulter_file_i = lam_occs[wlam] + 'imag.fits' n_default = 1024 # gridsize in non-critical areas if use_fpm == 1: n_to_fpm = 2048 else: n_to_fpm = 1024 n_from_lyotstop = 1024 field_stop_radius_lam0 = 9.0 elif cor_type == 'hlc_erkin': is_hlc = True file_directory = data_dir + '/hlc_20190206_v3/' # must have trailing "/" prefix = file_directory + 'dsn17d_run2_pup310_fpm2048_' pupil_diam_pix = 310.0 pupil_file = prefix + 'pupil.fits' lyot_stop_file = prefix + 'lyot.fits' lambda0_m = 0.575e-6 lam_occ = [ 5.4625e-07, 5.4944e-07, 5.5264e-07, 5.5583e-07, 5.5903e-07, 5.6222e-07, 5.6542e-07, 5.6861e-07, 5.7181e-07, 5.75e-07, 5.7819e-07, 5.8139e-07, 5.8458e-07, 5.8778e-07, 5.9097e-07, 5.9417e-07, 5.9736e-07, 6.0056e-07, 6.0375e-07 ] lam_occs = [ '5.4625e-07', '5.4944e-07', '5.5264e-07', '5.5583e-07', '5.5903e-07', '5.6222e-07', '5.6542e-07', '5.6861e-07', '5.7181e-07', '5.75e-07', '5.7819e-07', '5.8139e-07', '5.8458e-07', '5.8778e-07', '5.9097e-07', '5.9417e-07', '5.9736e-07', '6.0056e-07', '6.0375e-07' ] lam_occs = [ prefix + 'occ_lam' + s + 'theta6.69pols_' for s in lam_occs ] # find nearest matching FPM wavelength wlam = (np.abs(lambda_m - np.array(lam_occ))).argmin() occulter_file_r = lam_occs[wlam] + 'real_rotated.fits' occulter_file_i = lam_occs[wlam] + 'imag_rotated.fits' n_default = 1024 # gridsize in non-critical areas if use_fpm == 1: n_to_fpm = 2048 else: n_to_fpm = 1024 n_from_lyotstop = 1024 field_stop_radius_lam0 = 9.0 elif cor_type == 'spc-ifs_short' or cor_type == 'spc-ifs_long' or cor_type == 'spc-spec_short' or cor_type == 'spc-spec_long': is_spc = True file_dir = data_dir + '/spc_20190130/' # must have trailing "/" pupil_diam_pix = 1000.0 pupil_file = file_dir + 'pupil_SPC-20190130_rotated.fits' pupil_mask_file = file_dir + 'SPM_SPC-20190130.fits' fpm_file = file_dir + 'fpm_0.05lamdivD.fits' fpm_sampling = 0.05 # sampling in fpm_sampling_lambda_m/D of FPM mask if cor_type == 'spc-ifs_short' or cor_type == 'spc-spec_short': fpm_sampling_lambda_m = 0.66e-6 lambda0_m = 0.66e-6 else: fpm_sampling_lambda_m = 0.73e-6 lambda0_m = 0.73e-6 # FPM scaled for this central wavelength lyot_stop_file = file_dir + 'LS_SPC-20190130.fits' n_default = 2048 # gridsize in non-critical areas n_to_fpm = 2048 # gridsize to/from FPM n_mft = 1400 # gridsize to FPM (propagation to/from FPM handled by MFT) n_from_lyotstop = 4096 elif cor_type == 'spc-wide': is_spc = True file_dir = data_dir + '/spc_20181220/' # must have trailing "/" pupil_diam_pix = 1000.0 pupil_file = file_dir + 'pupil_SPC-20181220_1k_rotated.fits' pupil_mask_file = file_dir + 'SPM_SPC-20181220_1000_rounded9_gray.fits' fpm_file = file_dir + 'fpm_0.05lamdivD.fits' fpm_sampling = 0.05 # sampling in lambda0/D of FPM mask fpm_sampling_lambda_m = 0.825e-6 lambda0_m = 0.825e-6 # FPM scaled for this central wavelength lyot_stop_file = file_dir + 'LS_SPC-20181220_1k.fits' n_default = 2048 # gridsize in non-critical areas n_to_fpm = 2048 # gridsize to/from FPM n_mft = 1400 n_from_lyotstop = 4096 elif cor_type == 'none': file_directory = data_dir + '/hlc_20190210/' # must have trailing "/" prefix = file_directory + 'run461_' pupil_diam_pix = 309.0 pupil_file = prefix + 'pupil_rotated.fits' lambda0_m = 0.575e-6 use_fpm = 0 use_lyot_stop = 0 use_field_stop = 0 n_default = 1024 n_to_fpm = 1024 n_from_lyotstop = 1024 else: raise Exception('ERROR: Unsupported cor_type: ' + cor_type) if 'PASSVALUE' in locals(): if 'lam0' in PASSVALUE: lamba0_m = PASSVALUE['lam0'] * 1.0e-6 if 'lambda0_m' in PASSVALUE: lambda0_m = PASSVALUE['lambda0_m'] mas_per_lamD = lambda0_m * 360.0 * 3600.0 / ( 2 * np.pi * 2.363) * 1000 # mas per lambda0/D if 'source_x_offset' in PASSVALUE: source_x_offset = PASSVALUE['source_x_offset'] if 'source_y_offset' in PASSVALUE: source_y_offset = PASSVALUE['source_y_offset'] if 'source_x_offset_mas' in PASSVALUE: source_x_offset = PASSVALUE['source_x_offset_mas'] / mas_per_lamD if 'source_y_offset_mas' in PASSVALUE: source_y_offset = PASSVALUE['source_y_offset_mas'] / mas_per_lamD if 'use_errors' in PASSVALUE: use_errors = PASSVALUE['use_errors'] if 'polaxis' in PASSVALUE: polaxis = PASSVALUE['polaxis'] if 'zindex' in PASSVALUE: zindex = np.array(PASSVALUE['zindex']) if 'zval_m' in PASSVALUE: zval_m = np.array(PASSVALUE['zval_m']) if 'end_at_fsm' in PASSVALUE: end_at_fsm = PASSVALUE['end_at_fsm'] if 'cgi_x_shift_pupdiam' in PASSVALUE: cgi_x_shift_pupdiam = PASSVALUE['cgi_x_shift_pupdiam'] if 'cgi_y_shift_pupdiam' in PASSVALUE: cgi_y_shift_pupdiam = PASSVALUE['cgi_y_shift_pupdiam'] if 'cgi_x_shift_m' in PASSVALUE: cgi_x_shift_m = PASSVALUE['cgi_x_shift_m'] if 'cgi_y_shift_m' in PASSVALUE: cgi_y_shift_m = PASSVALUE['cgi_y_shift_m'] if 'fsm_x_offset' in PASSVALUE: fsm_x_offset = PASSVALUE['fsm_x_offset'] if 'fsm_y_offset' in PASSVALUE: fsm_y_offset = PASSVALUE['fsm_y_offset'] if 'fsm_x_offset_mas' in PASSVALUE: fsm_x_offset = PASSVALUE['fsm_x_offset_mas'] / mas_per_lamD if 'fsm_y_offset_mas' in PASSVALUE: fsm_y_offset = PASSVALUE['fsm_y_offset_mas'] / mas_per_lamD if 'focm_z_shift_m' in PASSVALUE: focm_z_shift_m = PASSVALUE['focm_z_shift_m'] if 'use_hlc_dm_patterns' in PASSVALUE: use_hlc_dm_patterns = PASSVALUE['use_hlc_dm_patterns'] if 'use_dm1' in PASSVALUE: use_dm1 = PASSVALUE['use_dm1'] if 'dm1_m' in PASSVALUE: dm1_m = PASSVALUE['dm1_m'] if 'dm1_xc_act' in PASSVALUE: dm1_xc_act = PASSVALUE['dm1_xc_act'] if 'dm1_yc_act' in PASSVALUE: dm1_yc_act = PASSVALUE['dm1_yc_act'] if 'dm1_xtilt_deg' in PASSVALUE: dm1_xtilt_deg = PASSVALUE['dm1_xtilt_deg'] if 'dm1_ytilt_deg' in PASSVALUE: dm1_ytilt_deg = PASSVALUE['dm1_ytilt_deg'] if 'dm1_ztilt_deg' in PASSVALUE: dm1_ztilt_deg = PASSVALUE['dm1_ztilt_deg'] if 'use_dm2' in PASSVALUE: use_dm2 = PASSVALUE['use_dm2'] if 'dm2_m' in PASSVALUE: dm2_m = PASSVALUE['dm2_m'] if 'dm2_xc_act' in PASSVALUE: dm2_xc_act = PASSVALUE['dm2_xc_act'] if 'dm2_yc_act' in PASSVALUE: dm2_yc_act = PASSVALUE['dm2_yc_act'] if 'dm2_xtilt_deg' in PASSVALUE: dm2_xtilt_deg = PASSVALUE['dm2_xtilt_deg'] if 'dm2_ytilt_deg' in PASSVALUE: dm2_ytilt_deg = PASSVALUE['dm2_ytilt_deg'] if 'dm2_ztilt_deg' in PASSVALUE: dm2_ztilt_deg = PASSVALUE['dm2_ztilt_deg'] if 'use_pupil_mask' in PASSVALUE: use_pupil_mask = PASSVALUE['use_pupil_mask'] if 'mask_x_shift_pupdiam' in PASSVALUE: mask_x_shift_pupdiam = PASSVALUE['mask_x_shift_pupdiam'] if 'mask_y_shift_pupdiam' in PASSVALUE: mask_y_shift_pupdiam = PASSVALUE['mask_y_shift_pupdiam'] if 'mask_x_shift_m' in PASSVALUE: mask_x_shift_m = PASSVALUE['mask_x_shift_m'] if 'mask_y_shift_m' in PASSVALUE: mask_y_shift_m = PASSVALUE['mask_y_shift_m'] if 'fpm_x_offset' in PASSVALUE: fpm_x_offset = PASSVALUE['fpm_x_offset'] if 'fpm_y_offset' in PASSVALUE: fpm_y_offset = PASSVALUE['fpm_y_offset'] if 'fpm_x_offset_m' in PASSVALUE: fpm_x_offset_m = PASSVALUE['fpm_x_offset_m'] if 'fpm_y_offset_m' in PASSVALUE: fpm_y_offset_m = PASSVALUE['fpm_y_offset_m'] if 'fpm_z_shift_m' in PASSVALUE: fpm_z_shift_m = PASSVALUE['fpm_z_shift_m'] if 'pinhole_diam_m' in PASSVALUE: pinhole_diam_m = PASSVALUE['pinhole_diam_m'] if 'end_at_fpm_exit_pupil' in PASSVALUE: end_at_fpm_exit_pupil = PASSVALUE['end_at_fpm_exit_pupil'] if 'output_field_rootname' in PASSVALUE: output_field_rootname = PASSVALUE['output_field_rootname'] if 'use_lyot_stop' in PASSVALUE: use_lyot_stop = PASSVALUE['use_lyot_stop'] if 'lyot_x_shift_pupdiam' in PASSVALUE: lyot_x_shift_pupdiam = PASSVALUE['lyot_x_shift_pupdiam'] if 'lyot_y_shift_pupdiam' in PASSVALUE: lyot_y_shift_pupdiam = PASSVALUE['lyot_y_shift_pupdiam'] if 'lyot_x_shift_m' in PASSVALUE: lyot_x_shift_m = PASSVALUE['lyot_x_shift_m'] if 'lyot_y_shift_m' in PASSVALUE: lyot_y_shift_m = PASSVALUE['lyot_y_shift_m'] if 'use_field_stop' in PASSVALUE: use_field_stop = PASSVALUE['use_field_stop'] if 'field_stop_x_offset' in PASSVALUE: field_stop_x_offset = PASSVALUE['field_stop_x_offset'] if 'field_stop_y_offset' in PASSVALUE: field_stop_y_offset = PASSVALUE['field_stop_y_offset'] if 'field_stop_x_offset_m' in PASSVALUE: field_stop_x_offset_m = PASSVALUE['field_stop_x_offset_m'] if 'field_stop_y_offset_m' in PASSVALUE: field_stop_y_offset_m = PASSVALUE['field_stop_y_offset_m'] if 'use_pupil_lens' in PASSVALUE: use_pupil_lens = PASSVALUE['use_pupil_lens'] if 'use_defocus_lens' in PASSVALUE: use_defocus_lens = PASSVALUE['use_defocus_lens'] if 'defocus' in PASSVALUE: defocus = PASSVALUE['defocus'] if 'output_dim' in PASSVALUE: output_dim = PASSVALUE['output_dim'] if 'final_sampling_m' in PASSVALUE: final_sampling_m = PASSVALUE['final_sampling_m'] if 'final_sampling_lam0' in PASSVALUE: final_sampling_lam0 = PASSVALUE['final_sampling_lam0'] diam = 2.3633372 fl_pri = 2.83459423440 * 1.0013 d_pri_sec = 2.285150515460035 d_focus_sec = d_pri_sec - fl_pri fl_sec = -0.653933011 * 1.0004095 d_sec_focus = 3.580188916677103 diam_sec = 0.58166 d_sec_fold1 = 2.993753476654728 d_fold1_focus = 0.586435440022375 diam_fold1 = 0.09 d_fold1_m3 = 1.680935841598811 fl_m3 = 0.430216463069001 d_focus_m3 = 1.094500401576436 d_m3_pupil = 0.469156807701977 d_m3_focus = 0.708841602661368 diam_m3 = 0.2 d_m3_m4 = 0.943514749358944 fl_m4 = 0.116239114833590 d_focus_m4 = 0.234673014520402 d_m4_pupil = 0.474357941656967 d_m4_focus = 0.230324117970585 diam_m4 = 0.07 d_m4_m5 = 0.429145636743193 d_m5_focus = 0.198821518772608 fl_m5 = 0.198821518772608 d_m5_pupil = 0.716529242882632 diam_m5 = 0.07 d_m5_fold2 = 0.351125431220770 diam_fold2 = 0.06 d_fold2_fsm = 0.365403811661862 d_fsm_oap1 = 0.354826767220001 fl_oap1 = 0.503331895563883 diam_oap1 = 0.06 d_oap1_focm = 0.768005607094041 d_focm_oap2 = 0.314483210543378 fl_oap2 = 0.579156922073536 diam_oap2 = 0.06 d_oap2_dm1 = 0.775775726154228 d_dm1_dm2 = 1.0 d_dm2_oap3 = 0.394833855161549 fl_oap3 = 1.217276467668519 diam_oap3 = 0.06 d_oap3_fold3 = 0.505329955078121 diam_fold3 = 0.06 d_fold3_oap4 = 1.158897671642761 fl_oap4 = 0.446951159052363 diam_oap4 = 0.06 d_oap4_pupilmask = 0.423013568764728 d_pupilmask_oap5 = 0.408810648253099 fl_oap5 = 0.548189351937178 diam_oap5 = 0.06 d_oap5_fpm = 0.548189083164429 d_fpm_oap6 = 0.548189083164429 fl_oap6 = 0.548189083164429 diam_oap6 = 0.06 d_oap6_lyotstop = 0.687567667550736 d_lyotstop_oap7 = 0.401748843470518 fl_oap7 = 0.708251083480054 diam_oap7 = 0.06 d_oap7_fieldstop = 0.708251083480054 d_fieldstop_oap8 = 0.210985967281651 fl_oap8 = 0.210985967281651 diam_oap8 = 0.06 d_oap8_pupil = 0.238185804200797 d_oap8_filter = 0.368452268225530 diam_filter = 0.01 d_filter_lens = 0.170799548215162 fl_lens = 0.246017378417573 + 0.050001306014153 diam_lens = 0.01 d_lens_fold4 = 0.246017378417573 diam_fold4 = 0.02 d_fold4_image = 0.050001578514650 fl_pupillens = 0.149260576823040 n = n_default # start off with less padding wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n) pupil = proper.prop_fits_read(pupil_file) proper.prop_multiply(wavefront, trim(pupil, n)) pupil = 0 if polaxis != 0: polmap(wavefront, polfile, pupil_diam_pix, polaxis) proper.prop_define_entrance(wavefront) proper.prop_lens(wavefront, fl_pri) if source_x_offset != 0 or source_y_offset != 0: # compute tilted wavefront to offset source by xoffset,yoffset lambda0_m/D xtilt_lam = -source_x_offset * lambda0_m / lambda_m ytilt_lam = -source_y_offset * lambda0_m / lambda_m x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) proper.prop_multiply( wavefront, np.exp(complex(0, 1) * np.pi * (xtilt_lam * x + ytilt_lam * y))) x = 0 y = 0 if zindex[0] != 0: proper.prop_zernikes(wavefront, zindex, zval_m) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_PRIMARY_phase_error_V1.0.fits', WAVEFRONT=True) proper.prop_errormap( wavefront, map_dir + 'wfirst_phaseb_GROUND_TO_ORBIT_4.2X_phase_error_V1.0.fits', WAVEFRONT=True) proper.prop_propagate(wavefront, d_pri_sec, 'secondary') proper.prop_lens(wavefront, fl_sec) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_SECONDARY_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_sec / 2.0) proper.prop_propagate(wavefront, d_sec_fold1, 'FOLD_1') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FOLD1_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_fold1 / 2.0) proper.prop_propagate(wavefront, d_fold1_m3, 'M3') proper.prop_lens(wavefront, fl_m3) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_M3_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_m3 / 2.0) proper.prop_propagate(wavefront, d_m3_m4, 'M4') proper.prop_lens(wavefront, fl_m4) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_M4_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_m4 / 2.0) proper.prop_propagate(wavefront, d_m4_m5, 'M5') proper.prop_lens(wavefront, fl_m5) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_M5_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_m5 / 2.0) proper.prop_propagate(wavefront, d_m5_fold2, 'FOLD_2') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FOLD2_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_fold2 / 2.0) proper.prop_propagate(wavefront, d_fold2_fsm, 'FSM') if end_at_fsm == 1: (wavefront, sampling_m) = proper.prop_end(wavefront, NOABS=True) wavefront = trim(wavefront, n) return wavefront, sampling_m if cgi_x_shift_pupdiam != 0 or cgi_y_shift_pupdiam != 0 or cgi_x_shift_m != 0 or cgi_y_shift_m != 0: # bulk coronagraph pupil shear # FFT the field, apply a tilt, FFT back if cgi_x_shift_pupdiam != 0 or cgi_y_shift_pupdiam != 0: # offsets are normalized to pupil diameter xt = -cgi_x_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n yt = -cgi_y_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n else: # offsets are meters d_m = proper.prop_get_sampling(wavefront) xt = -cgi_x_shift_m / d_m * float(pupil_diam_pix) / n yt = -cgi_y_shift_m / d_m * float(pupil_diam_pix) / n x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) tilt = complex(0, 1) * np.pi * (x * xt + y * yt) x = 0 y = 0 wavefront0 = proper.prop_get_wavefront(wavefront) wavefront0 = ffts(wavefront0, -1) wavefront0 *= np.exp(tilt) wavefront0 = ffts(wavefront0, 1) tilt = 0 wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FSM_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_fsm / 2.0) if (fsm_x_offset != 0.0 or fsm_y_offset != 0.0): # compute tilted wavefront to offset source by fsm_x_offset,fsm_y_offset lambda0_m/D xtilt_lam = fsm_x_offset * lambda0_m / lambda_m ytilt_lam = fsm_y_offset * lambda0_m / lambda_m x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) proper.prop_multiply( wavefront, np.exp(complex(0, 1) * np.pi * (xtilt_lam * x + ytilt_lam * y))) x = 0 y = 0 proper.prop_propagate(wavefront, d_fsm_oap1, 'OAP1') proper.prop_lens(wavefront, fl_oap1) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP1_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap1 / 2.0) proper.prop_propagate(wavefront, d_oap1_focm + focm_z_shift_m, 'FOCM') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FOCM_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_focm / 2.0) proper.prop_propagate(wavefront, d_focm_oap2 + focm_z_shift_m, 'OAP2') proper.prop_lens(wavefront, fl_oap2) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP2_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap2 / 2.0) proper.prop_propagate(wavefront, d_oap2_dm1, 'DM1') if use_dm1 != 0: proper.prop_dm(wavefront, dm1_m, dm1_xc_act, dm1_yc_act, dm_sampling_m, XTILT=dm1_xtilt_deg, YTILT=dm1_ytilt_deg, ZTILT=dm1_ztilt_deg) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_DM1_phase_error_V1.0.fits', WAVEFRONT=True) if is_hlc == True and use_hlc_dm_patterns == 1: dm1wfe = proper.prop_fits_read(prefix + 'dm1wfe.fits') proper.prop_add_phase(wavefront, trim(dm1wfe, n)) dm1wfe = 0 proper.prop_propagate(wavefront, d_dm1_dm2, 'DM2') if use_dm2 == 1: proper.prop_dm(wavefront, dm2_m, dm2_xc_act, dm2_yc_act, dm_sampling_m, XTILT=dm2_xtilt_deg, YTILT=dm2_ytilt_deg, ZTILT=dm2_ztilt_deg) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_DM2_phase_error_V1.0.fits', WAVEFRONT=True) if is_hlc == True: if use_hlc_dm_patterns == 1: dm2wfe = proper.prop_fits_read(prefix + 'dm2wfe.fits') proper.prop_add_phase(wavefront, trim(dm2wfe, n)) dm2wfe = 0 dm2mask = proper.prop_fits_read(prefix + 'dm2mask.fits') proper.prop_multiply(wavefront, trim(dm2mask, n)) dm2mask = 0 proper.prop_propagate(wavefront, d_dm2_oap3, 'OAP3') proper.prop_lens(wavefront, fl_oap3) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP3_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap3 / 2.0) proper.prop_propagate(wavefront, d_oap3_fold3, 'FOLD_3') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FOLD3_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_fold3 / 2.0) proper.prop_propagate(wavefront, d_fold3_oap4, 'OAP4') proper.prop_lens(wavefront, fl_oap4) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP4_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap4 / 2.0) proper.prop_propagate(wavefront, d_oap4_pupilmask, 'PUPIL_MASK') # flat/reflective shaped pupil if is_spc == True and use_pupil_mask != 0: pupil_mask = proper.prop_fits_read(pupil_mask_file) pupil_mask = trim(pupil_mask, n) if mask_x_shift_pupdiam != 0 or mask_y_shift_pupdiam != 0 or mask_x_shift_m != 0 or mask_y_shift_m != 0: # shift SP mask by FFTing it, applying tilt, and FFTing back if mask_x_shift_pupdiam != 0 or mask_y_shift_pupdiam != 0: # offsets are normalized to pupil diameter xt = -mask_x_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n yt = -mask_y_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n else: d_m = proper.prop_get_sampling(wavefront) xt = -mask_x_shift_m / d_m * float(pupil_diam_pix) / n yt = -mask_y_shift_m / d_m * float(pupil_diam_pix) / n x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) tilt = complex(0, 1) * np.pi * (x * xt + y * yt) x = 0 y = 0 pupil_mask = ffts(pupil_mask, -1) pupil_mask *= np.exp(tilt) pupil_mask = ffts(pupil_mask, 1) pupil_mask = pupil_mask.real tilt = 0 proper.prop_multiply(wavefront, pupil_mask) pupil_mask = 0 if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_PUPILMASK_phase_error_V1.0.fits', WAVEFRONT=True) # while at a pupil, use more padding to provide 2x better sampling at FPM diam = 2 * proper.prop_get_beamradius(wavefront) (wavefront, dx) = proper.prop_end(wavefront, NOABS=True) n = n_to_fpm wavefront0 = trim(wavefront, n) wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n) wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 proper.prop_propagate(wavefront, d_pupilmask_oap5, 'OAP5') proper.prop_lens(wavefront, fl_oap5) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP5_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap5 / 2.0) proper.prop_propagate(wavefront, d_oap5_fpm + fpm_z_shift_m, 'FPM', TO_PLANE=True) if use_fpm == 1: if fpm_x_offset != 0 or fpm_y_offset != 0 or fpm_x_offset_m != 0 or fpm_y_offset_m != 0: # To shift FPM, FFT field to pupil, apply tilt, FFT back to focus, # apply FPM, FFT to pupil, take out tilt, FFT back to focus if fpm_x_offset != 0 or fpm_y_offset != 0: # shifts are specified in lambda0/D x_offset_lamD = fpm_x_offset * lambda0_m / lambda_m y_offset_lamD = fpm_y_offset * lambda0_m / lambda_m else: d_m = proper.prop_get_sampling(wavefront) x_offset_lamD = fpm_x_offset_m / d_m * float( pupil_diam_pix) / n y_offset_lamD = fpm_y_offset_m / d_m * float( pupil_diam_pix) / n x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) tilt = complex(0, 1) * np.pi * (x * x_offset_lamD + y * y_offset_lamD) x = 0 y = 0 wavefront0 = proper.prop_get_wavefront(wavefront) wavefront0 = ffts(wavefront0, -1) wavefront0 *= np.exp(tilt) wavefront0 = ffts(wavefront0, 1) wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 if is_hlc == True: occ_r = proper.prop_fits_read(occulter_file_r) occ_i = proper.prop_fits_read(occulter_file_i) occ = np.array(occ_r + 1j * occ_i, dtype=np.complex128) proper.prop_multiply(wavefront, trim(occ, n)) occ_r = 0 occ_i = 0 occ = 0 elif is_spc == True: # super-sample FPM wavefront0 = proper.prop_get_wavefront(wavefront) wavefront0 = ffts(wavefront0, 1) # to virtual pupil wavefront0 = trim(wavefront0, n_mft) fpm = proper.prop_fits_read(fpm_file) nfpm = fpm.shape[1] fpm_sampling_lam = fpm_sampling * fpm_sampling_lambda_m / lambda_m wavefront0 = mft2(wavefront0, fpm_sampling_lam, pupil_diam_pix, nfpm, -1) # MFT to highly-sampled focal plane wavefront0 *= fpm fpm = 0 wavefront0 = mft2(wavefront0, fpm_sampling_lam, pupil_diam_pix, n, +1) # MFT to virtual pupil wavefront0 = ffts(wavefront0, -1) # back to normally-sampled focal plane wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 if fpm_x_offset != 0 or fpm_y_offset != 0 or fpm_x_offset_m != 0 or fpm_y_offset_m != 0: wavefront0 = proper.prop_get_wavefront(wavefront) wavefront0 = ffts(wavefront0, -1) wavefront0 *= np.exp(-tilt) wavefront0 = ffts(wavefront0, 1) wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 tilt = 0 if pinhole_diam_m != 0: # "pinhole_diam_m" is pinhole diameter in meters dx_m = proper.prop_get_sampling(wavefront) dx_pinhole_diam_m = pinhole_diam_m / 101.0 # 101 samples across pinhole n_out = 105 m_per_lamD = dx_m * n / float( pupil_diam_pix) # current focal plane sampling in lambda_m/D dx_pinhole_lamD = dx_pinhole_diam_m / m_per_lamD # pinhole sampling in lambda_m/D n_in = int(round(pupil_diam_pix * 1.2)) wavefront0 = proper.prop_get_wavefront(wavefront) wavefront0 = ffts(wavefront0, +1) # to virtual pupil wavefront0 = trim(wavefront0, n_in) m = dx_pinhole_lamD * n_in * float(n_out) / pupil_diam_pix wavefront0 = mft2(wavefront0, dx_pinhole_lamD, pupil_diam_pix, n_out, -1) # MFT to highly-sampled focal plane p = (radius(n_out) * dx_pinhole_diam_m) <= (pinhole_diam_m / 2.0) p = p.astype(np.int) wavefront0 *= p p = 0 wavefront0 = mft2(wavefront0, dx_pinhole_lamD, pupil_diam_pix, n, +1) # MFT back to virtual pupil wavefront0 = ffts(wavefront0, -1) # back to normally-sampled focal plane wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 proper.prop_propagate(wavefront, d_fpm_oap6 - fpm_z_shift_m, 'OAP6') proper.prop_lens(wavefront, fl_oap6) if use_errors != 0 and end_at_fpm_exit_pupil == 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP6_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap6 / 2.0) proper.prop_propagate(wavefront, d_oap6_lyotstop, 'LYOT_STOP') # while at a pupil, switch back to less padding diam = 2 * proper.prop_get_beamradius(wavefront) (wavefront, dx) = proper.prop_end(wavefront, NOABS=True) n = n_from_lyotstop wavefront = trim(wavefront, n) if output_field_rootname != '': lams = format(lambda_m * 1e6, "6.4f") pols = format(int(round(polaxis))) hdu = pyfits.PrimaryHDU() hdu.data = np.real(wavefront) hdu.writeto(output_field_rootname + '_' + lams + 'um_' + pols + '_real.fits', overwrite=True) hdu = pyfits.PrimaryHDU() hdu.data = np.imag(wavefront) hdu.writeto(output_field_rootname + '_' + lams + 'um_' + pols + '_imag.fits', overwrite=True) if end_at_fpm_exit_pupil == 1: return wavefront, dx wavefront0 = wavefront.copy() wavefront = 0 wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n) wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0) wavefront0 = 0 if use_lyot_stop != 0: lyot = proper.prop_fits_read(lyot_stop_file) lyot = trim(lyot, n) if lyot_x_shift_pupdiam != 0 or lyot_y_shift_pupdiam != 0 or lyot_x_shift_m != 0 or lyot_y_shift_m != 0: # apply shift to lyot stop by FFTing the stop, applying a tilt, and FFTing back if lyot_x_shift_pupdiam != 0 or lyot_y_shift_pupdiam != 0: # offsets are normalized to pupil diameter xt = -lyot_x_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n yt = -lyot_y_shift_pupdiam * pupil_diam_pix * float( pupil_diam_pix) / n else: d_m = proper.prop_get_sampling(wavefront) xt = -lyot_x_shift_m / d_m * float(pupil_diam_pix) / n yt = -lyot_y_shift_m / d_m * float(pupil_diam_pix) / n x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1)) y = np.transpose(x) tilt = complex(0, 1) * np.pi * (x * xt + y * yt) x = 0 y = 0 lyot = ffts(lyot, -1) lyot *= np.exp(tilt) lyot = ffts(lyot, 1) lyot = lyot.real tilt = 0 proper.prop_multiply(wavefront, lyot) lyot = 0 if use_pupil_lens != 0 or pinhole_diam_m != 0: proper.prop_circular_aperture(wavefront, 1.1, NORM=True) proper.prop_propagate(wavefront, d_lyotstop_oap7, 'OAP7') proper.prop_lens(wavefront, fl_oap7) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP7_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap7 / 2.0) proper.prop_propagate(wavefront, d_oap7_fieldstop, 'FIELD_STOP') if use_field_stop != 0 and (cor_type == 'hlc' or cor_type == 'hlc_erkin'): sampling_lamD = float( pupil_diam_pix) / n # sampling at focus in lambda_m/D stop_radius = field_stop_radius_lam0 / sampling_lamD * ( lambda0_m / lambda_m) * proper.prop_get_sampling(wavefront) if field_stop_x_offset != 0 or field_stop_y_offset != 0: # convert offsets in lambda0/D to meters x_offset_lamD = field_stop_x_offset * lambda0_m / lambda_m y_offset_lamD = field_stop_y_offset * lambda0_m / lambda_m pupil_ratio = float(pupil_diam_pix) / n field_stop_x_offset_m = x_offset_lamD / pupil_ratio * proper.prop_get_sampling( wavefront) field_stop_y_offset_m = y_offset_lamD / pupil_ratio * proper.prop_get_sampling( wavefront) proper.prop_circular_aperture(wavefront, stop_radius, -field_stop_x_offset_m, -field_stop_y_offset_m) proper.prop_propagate(wavefront, d_fieldstop_oap8, 'OAP8') proper.prop_lens(wavefront, fl_oap8) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_OAP8_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_oap8 / 2.0) proper.prop_propagate(wavefront, d_oap8_filter, 'filter') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FILTER_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_filter / 2.0) proper.prop_propagate(wavefront, d_filter_lens, 'LENS') if use_pupil_lens == 0 and use_defocus_lens == 0 and defocus == 0: # use imaging lens to create normal focus proper.prop_lens(wavefront, fl_lens) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_LENS_phase_error_V1.0.fits', WAVEFRONT=True) elif use_pupil_lens != 0: # use pupil imaging lens proper.prop_lens(wavefront, fl_pupillens) if use_errors != 0: proper.prop_errormap( wavefront, map_dir + 'wfirst_phaseb_PUPILLENS_phase_error_V1.0.fits', WAVEFRONT=True) else: # table is waves P-V @ 575 nm z4_pv_waves = np.array([ -9.0545, -8.5543, -8.3550, -8.0300, -7.54500, -7.03350, -6.03300, -5.03300, -4.02000, -2.51980, 0.00000000, 3.028000, 4.95000, 6.353600, 8.030000, 10.10500, 12.06000, 14.06000, 20.26000, 28.34000, 40.77500, 56.65700 ]) fl_defocus_lens = np.array([ 5.09118, 1.89323, 1.54206, 1.21198, 0.914799, 0.743569, 0.567599, 0.470213, 0.406973, 0.350755, 0.29601868, 0.260092, 0.24516, 0.236606, 0.228181, 0.219748, 0.213278, 0.207816, 0.195536, 0.185600, 0.176629, 0.169984 ]) # subtract ad-hoc function to make z4 vs f_length more accurately spline interpolatible f = fl_defocus_lens / 0.005 f0 = 59.203738 z4t = z4_pv_waves - (0.005 * (f0 - f - 40)) / f**2 / 0.575e-6 if use_defocus_lens != 0: # use one of 4 defocusing lenses defocus = np.array([18.0, 9.0, -4.0, -8.0]) # waves P-V @ 575 nm f = interp1d(z4_pv_waves, z4t, kind='cubic') z4x = f(defocus) f = interp1d(z4t, fl_defocus_lens, kind='cubic') lens_fl = f(z4x) proper.prop_lens(wavefront, lens_fl[use_defocus_lens - 1]) if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_DEFOCUSLENS' + str(use_defocus_lens) + '_phase_error_V1.0.fits', WAVEFRONT=True) defocus = defocus[use_defocus_lens - 1] else: # specify amount of defocus (P-V waves @ 575 nm) f = interp1d(z4_pv_waves, z4t, kind='cubic') z4x = f(defocus) f = interp1d(z4t, fl_defocus_lens, kind='cubic') lens_fl = f(z4x) proper.prop_lens(wavefront, lens_fl) if use_errors != 0: proper.prop_errormap( wavefront, map_dir + 'wfirst_phaseb_DEFOCUSLENS1_phase_error_V1.0.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_lens / 2.0) proper.prop_propagate(wavefront, d_lens_fold4, 'FOLD_4') if use_errors != 0: proper.prop_errormap(wavefront, map_dir + 'wfirst_phaseb_FOLD4_phase_error_V1.1.fits', WAVEFRONT=True) if use_aperture != 0: proper.prop_circular_aperture(wavefront, diam_fold4 / 2.0) if defocus != 0 or use_defocus_lens != 0: if np.abs(defocus) <= 4: proper.prop_propagate(wavefront, d_fold4_image, 'IMAGE', TO_PLANE=True) else: proper.prop_propagate(wavefront, d_fold4_image, 'IMAGE') else: proper.prop_propagate(wavefront, d_fold4_image, 'IMAGE') (wavefront, sampling_m) = proper.prop_end(wavefront, NOABS=True) if final_sampling_lam0 != 0 or final_sampling_m != 0: if final_sampling_m != 0: mag = sampling_m / final_sampling_m sampling_m = final_sampling_m else: mag = (float(pupil_diam_pix) / n) / final_sampling_lam0 * (lambda_m / lambda0_m) sampling_m = sampling_m / mag wavefront = proper.prop_magnify(wavefront, mag, output_dim, AMP_CONSERVE=True) else: wavefront = trim(wavefront, output_dim) return wavefront, sampling_m
def dummy_telescope(lmda, grid_size, kwargs): """ propagates instantaneous complex E-field thru Subaru from the DM through SCExAO uses PyPROPER3 to generate the complex E-field at the pupil plane, then propagates it through SCExAO 50x50 DM, then coronagraph, to the focal plane :returns spectral cube at instantaneous time in the focal_plane() """ # print("Propagating Broadband Wavefront Through Subaru") # Initialize the Wavefront in Proper wfo = proper.prop_begin(entrance_d, lmda, grid_size, beam_ratio) # Defines aperture (baffle-before primary) proper.prop_circular_aperture(wfo, entrance_d / 2) proper.prop_define_entrance(wfo) # normalizes abs intensity # SCExAO Reimaging 1 proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG * 2) # move to second pupil ######################################## # Import/Apply Actual DM Map # ####################################### plot_flag = False if kwargs['verbose'] and kwargs['ix'] == 0: plot_flag = True dm_map = kwargs['map'] # flat = proper.prop_zernikes(wfo, [2, 3], np.array([5, 1])) # zernike[2,3] = x,y tilt # adding a tilt for shits and giggles # proper.prop_propagate(wfo, fl_SxOAPG) # from tweeter-DM to OAP2 errormap(wfo, dm_map, SAMPLING=dm_pitch, MIRROR_SURFACE=True, MICRONS=True, BR=beam_ratio, PLOT=plot_flag) # WAVEFRONT=True # errormap(wfo, dm_map, SAMPLING=dm_pitch, AMPLITUDE=True, BR=beam_ratio, PLOT=plot_flag) # WAVEFRONT=True # proper.prop_circular_aperture(wfo, entrance_d/2) if kwargs['verbose'] and kwargs['ix'] == 0: fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5)) ax1, ax2 = subplot.flatten() fig.suptitle('SCExAO Model WFO after errormap', fontweight='bold', fontsize=14) # ax.imshow(dm_map, interpolation='none') ax1.imshow(np.abs(proper.prop_shift_center(wfo.wfarr))**2, interpolation='none') ax1.set_title('Amplitude') ax2.imshow(np.angle(proper.prop_shift_center(wfo.wfarr)), interpolation='none', vmin=-2 * np.pi, vmax=2 * np.pi) # , cmap='hsv' ax2.set_title('Phase') # ------------------------------------------------ # proper.prop_propagate(wfo, fl_SxOAPG) # from tweeter-DM to OAP2 # SCExAO Reimaging 2 proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG) # focus at exit of DM telescope system proper.prop_lens(wfo, fl_SxOAPG) proper.prop_propagate(wfo, fl_SxOAPG) # focus at exit of DM telescope system # ######################################## # # Focal Plane # # ####################################### # Check Sampling in focal plane # shifts wfo from Fourier Space (origin==lower left corner) to object space (origin==center) # proper.prop_shift_center(wfo.wfarr) # wf, samp = proper.prop_end(wfo, NoAbs=True) wf = proper.prop_shift_center(wfo.wfarr) samp = proper.prop_get_sampling(wfo) # smp_asec = proper.prop_get_sampling_arcsec(wfo) if kwargs['verbose'] and kwargs['ix'] == 0: fig, ax = plt.subplots(nrows=1, ncols=1) fig.suptitle('SCExAO Model Focal Plane', fontweight='bold', fontsize=14) ax.imshow( np.abs(wf)**2, interpolation='none', norm=LogNorm( vmin=1e-7, vmax=1e-2)) # np.abs(proper.prop_shift_center(wfo.wfarr))**2 # # if kwargs['verbose'] and kwargs['ix']==0: # print(f"\n\tFocal Plane\n" # f"sampling at focal plane is {smp_asec * 1e3:.4f} mas\n" # f"\tfull FOV is {smp_asec * grid_size * 1e3:.2f} mas") # s_rad = proper.prop_get_sampling_radians(wfo) # print(f"sampling at focal plane is {s_rad * 1e6:.6f} urad") # print(f"Finished simulation") return wf, samp
def prescription_quad(wavelength, gridsize, PASSVALUE={}): # Assign parameters from PASSVALUE struct or use defaults diam = PASSVALUE.get('diam', 0.3) # telescope diameter in meters m1_fl = PASSVALUE.get('m1_fl', 0.5717255) # primary focal length (m) beam_ratio = PASSVALUE.get('beam_ratio', 0.2) # initial beam width/grid width tilt_x = PASSVALUE.get('tilt_x', 0.) # Tilt angle along x (arc seconds) tilt_y = PASSVALUE.get('tilt_y', 0.) # Tilt angle along y (arc seconds) noabs = PASSVALUE.get('noabs', False) # Output complex amplitude? m1_hole_rad = PASSVALUE.get('m1_hole_rad', None) # Inner hole diameter use_caching = PASSVALUE.get('use_caching', False) # Use cached files if available? get_wf = PASSVALUE.get('get_wf', False) # Return wavefront """ Prescription for a single quad lens system """ if 'phase_func' in PASSVALUE: print('DEPRECATED setting "phase_func": use "opd_func" instead') if 'opd_func' not in PASSVALUE: PASSVALUE['opd_func'] = PASSVALUE['phase_func'] elif 'opd_func' not in PASSVALUE: print("no phase function") if 'phase_func_sec' in PASSVALUE: print( 'DEPRECATED setting "phase_func_sec": use "opd_func_sec" instead') if 'opd_func_sec' not in PASSVALUE: PASSVALUE['opd_func_sec'] = PASSVALUE['phase_func_sec'] # Define the wavefront wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # Point off-axis prop_tilt(wfo, tilt_x, tilt_y) ### # Change to build ciruclar aperture?? # Input aperture proper.prop_circular_aperture(wfo, diam / 2.) ### # Define entrance proper.prop_define_entrance(wfo) proper.prop_lens(wfo, m1_fl, "primary") if 'opd_func' in PASSVALUE: opd1_func = PASSVALUE['opd_func'] def build_m1_opd(): return gen_opdmap(opd1_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo)) wfo.wfarr *= build_phase_map( wfo, load_cacheable_grid(opd1_func.__name__, wfo, build_m1_opd, use_caching)) if get_wf: wf = proper.prop_get_wavefront(wfo) print('Got wavefront') if m1_hole_rad is not None: proper.prop_circular_obscuration(wfo, m1_hole_rad) #if get_wf: # wf = proper.prop_get_wavefront(wfo) # print('Got wavefront') # Focus proper.prop_propagate(wfo, m1_fl, "focus", TO_PLANE=True) # End (wfo, sampling) = proper.prop_end(wfo) if get_wf: return (wfo, wf, sampling) else: return (wfo, sampling)
def telescope( wavelength, gridsize, PASSVALUE={ 'prefix': 'prova', 'path': os.path.abspath(os.path.join(__file__, os.pardir)), 'charge': 0, 'CAL': 0, 'diam': 37., 'spiders_width': 0.60, 'spiders_angle': [0., 60., 120.], 'beam_ratio': 0.25, 'f_lens': 658.6, 'npupil': 243, 'r_obstr': 0.3, 'pupil_file': 0, 'phase_apodizer_file': 0, 'amplitude_apodizer_file': 0, 'TILT': [0., 0.], 'LS': False, 'RAVC': False, 'LS_phase_apodizer_file': 0, 'LS_amplitude_apodizer_file': 0, 'LS_parameters': [0.0, 0.0, 0.0], 'atm_screen': 0, 'missing_segments_number': 0, 'apodizer_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'LS_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'Island_Piston': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'NCPA': 0, 'Debug_print': False, 'Debug': False }): ## call all the vues passed via passvalue prefix = PASSVALUE['prefix'] path = PASSVALUE['path'] charge = PASSVALUE['charge'] CAL = PASSVALUE['CAL'] diam = PASSVALUE['diam'] spiders_width = PASSVALUE['spiders_width'] spiders_angle = PASSVALUE['spiders_angle'] beam_ratio = PASSVALUE['beam_ratio'] f_lens = PASSVALUE['f_lens'] npupil = PASSVALUE['npupil'] r_obstr = PASSVALUE['r_obstr'] pupil_file = PASSVALUE['pupil_file'] phase_apodizer_file = PASSVALUE['phase_apodizer_file'] amplitude_apodizer_file = PASSVALUE['amplitude_apodizer_file'] TILT = PASSVALUE['TILT'] LS = PASSVALUE['LS'] RAVC = PASSVALUE['RAVC'] LS_phase_apodizer_file = PASSVALUE['LS_phase_apodizer_file'] LS_amplitude_apodizer_file = PASSVALUE['LS_amplitude_apodizer_file'] LS_parameters = PASSVALUE['LS_parameters'] atm_screen = PASSVALUE['atm_screen'] missing_segments_number = PASSVALUE['missing_segments_number'] apodizer_misalignment = PASSVALUE['apodizer_misalignment'] LS_misalignment = PASSVALUE['LS_misalignment'] Island_Piston = PASSVALUE['Island_Piston'] NCPA = PASSVALUE['NCPA'] Debug_print = PASSVALUE['Debug_print'] Debug = PASSVALUE['Debug'] TILT = np.array(TILT) apodizer_misalignment = np.array(apodizer_misalignment) LS_misalignment = np.array(LS_misalignment) Island_Piston = np.array(Island_Piston) ## call the size of the grid n = int(gridsize) wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # define the simualtion pupil lamda = proper.prop_get_wavelength( wfo) #save the wavelength value [m] into lamda if (Debug_print == True): print("lambda: ", lamda) pupil(wfo, CAL, npupil, diam, r_obstr, spiders_width, spiders_angle, pupil_file, missing_segments_number, Debug, Debug_print) if (Debug == True): fits.writeto( path + prefix + '_pupil_pre_define.fits', proper.prop_get_amplitude(wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) proper.prop_define_entrance(wfo) #define the entrance wavefront #wfo.wfarr *= 1./np.amax(wfo._wfarr) # max(amplitude)=1 if (isinstance(atm_screen, (list, tuple, np.ndarray)) == True) and ( atm_screen.ndim >= 2): # when the atmosphere is present print('atmosphere') atmosphere(wfo, npupil, atm_screen, Debug_print, Debug) if (isinstance(NCPA, (list, tuple, np.ndarray)) == True) and (NCPA.ndim >= 2): # when the atmosphere is present NCPA_application(wfo, npupil, NCPA, path, Debug_print, Debug) if (RAVC == True) or (isinstance(phase_apodizer_file, (list, tuple, np.ndarray)) == True) or (isinstance(amplitude_apodizer_file, (list, tuple, np.ndarray)) == True): # when tha apodizer is present apodization(wfo, r_obstr, npupil, RAVC, phase_apodizer_file, amplitude_apodizer_file, apodizer_misalignment, Debug_print, Debug) if (all(v == 0 for v in Island_Piston) == False): # when the piston is present island_effect_piston(wfo, npupil, Island_Piston, path, Debug_print, Debug) if (TILT.any != 0.): # when tip/tilt if (Debug_print == True): print("TILT: ", TILT) print("lamda: ", lamda) tiptilt = (np.multiply( TILT, lamda )) / 4 # translate the tip/tilt from lambda/D into RMS phase errors proper.prop_zernikes(wfo, [2, 3], tiptilt) # 2-->xtilt, 3-->ytilt if (Debug == True): if CAL == 1: fits.writeto(path + prefix + '_pupil_amplitude_CAL1.fits', proper.prop_get_amplitude(wfo) [int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) fits.writeto( path + prefix + '_pupil_phase_CAL1.fits', proper.prop_get_phase(wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) else: fits.writeto( path + prefix + '_pupil_amplitude_CAL0_RA' + str(int(RAVC)) + '_charge' + str(charge) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_amplitude( wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) fits.writeto( path + prefix + '_pupil_phase_CAL0_RA' + str(int(RAVC)) + '_charge' + str(charge) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_phase(wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) proper.prop_propagate(wfo, f_lens, 'inizio') # propagate wavefront proper.prop_lens(wfo, f_lens, 'focusing lens vortex') # propagate through a lens proper.prop_propagate(wfo, f_lens, 'VC') # propagate wavefront vortex(wfo, CAL, charge, f_lens, path, Debug_print) if (Debug == True): if CAL == 1: fits.writeto(path + prefix + '_afterVortex_CAL1.fits', proper.prop_get_amplitude(wfo) [int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) fits.writeto( path + prefix + '_afterVortex_CAL1_phase.fits', proper.prop_get_phase(wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) else: print( 'ATM: ', str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True))) if ((((int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)))) == 1): print('atm_screen: ', atm_screen.shape) print( 'ATM: ', int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) fits.writeto( path + prefix + '_afterVortex_CAL0_RA' + str(int(RAVC)) + '_charge' + str(charge) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_amplitude( wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) fits.writeto( path + prefix + '_afterVortex_phase_CAL0_RA' + str(int(RAVC)) + '_charge' + str(charge) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_phase(wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) proper.prop_propagate(wfo, f_lens, 'Lyot Collimetor') # propagate wavefront proper.prop_lens(wfo, f_lens, 'Lyot Collimetor') # propagate wavefront through a lens proper.prop_propagate(wfo, f_lens, 'Lyot Stop') # propagate wavefront if (Debug == True): if CAL == 1: fits.writeto(path + prefix + '_beforeLS_CAL1.fits', proper.prop_get_amplitude(wfo) [int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) else: fits.writeto( path + prefix + '_beforeLS_CAL0_charge' + str(charge) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_amplitude( wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) lyotstop(wfo, diam, r_obstr, npupil, RAVC, LS, LS_parameters, spiders_angle, LS_phase_apodizer_file, LS_amplitude_apodizer_file, LS_misalignment, path, Debug_print, Debug) if (Debug == True): if CAL == 1: fits.writeto(path + prefix + '_afterLS_CAL1.fits', proper.prop_get_amplitude(wfo) [int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) else: fits.writeto( path + prefix + '_afterLS_CAL0_charge' + str(charge) + '_LS' + str(int(LS)) + '_RA' + str(int(RAVC)) + '_ATM' + str( int( isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) + '.fits', proper.prop_get_amplitude( wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50), int(n / 2) - int(npupil / 2 + 50):int(n / 2) + int(npupil / 2 + 50)], overwrite=True) proper.prop_propagate(wfo, f_lens) # propagate wavefront proper.prop_lens(wfo, f_lens) # propagate wavefront through a lens proper.prop_propagate(wfo, f_lens) # propagate wavefront (wfo, sampling) = proper.prop_end( wfo, NOABS=True ) # conclude the simulation --> noabs= the wavefront array will be complex return (wfo, sampling) # return the wavefront
def toliman_prescription_simple(wavelength, gridsize): # Values from Eduardo's RC Toliman system diam = 0.3 # telescope diameter in meters fl_pri = 0.5 * 1.143451 # primary focal length (m) # BN 20180208 d_pri_sec = 0.549337630333726 # primary to secondary separation (m) # d_pri_sec = 0.559337630333726 # primary to secondary separation (m) fl_sec = -0.5 * 0.0467579189727913 # secondary focal length (m) d_sec_to_focus = 0.528110658881 # nominal distance from secondary to focus (from eqn) # d_sec_to_focus = 0.589999999989853 # nominal distance from secondary to focus beam_ratio = 0.2 # initial beam width/grid width m2_rad = 0.059 # Secondary half-diameter (m) m2_strut_width = 0.01 # Width of struts supporting M2 (m) m2_supports = 5 # Define the wavefront wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) # Input aperture proper.prop_circular_aperture(wfo, diam / 2) # NOTE: could prop_propagate() here if some baffling included # Secondary and structs obscuration proper.prop_circular_obscuration(wfo, m2_rad) # secondary mirror obscuration # Spider struts/vanes, arranged evenly radiating out from secondary strut_length = diam / 2 - m2_rad strut_step = 360 / m2_supports strut_centre = m2_rad + strut_length / 2 for i in range(0, m2_supports): angle = i * strut_step radians = math.radians(angle) xoff = math.cos(radians) * strut_centre yoff = math.sin(radians) * strut_centre proper.prop_rectangular_obscuration(wfo, m2_strut_width, strut_length, xoff, yoff, ROTATION=angle + 90) # Define entrance proper.prop_define_entrance(wfo) # Primary mirror (treat as quadratic lens) proper.prop_lens(wfo, fl_pri, "primary") # Propagate the wavefront proper.prop_propagate(wfo, d_pri_sec, "secondary") # Secondary mirror (another quadratic lens) proper.prop_lens(wfo, fl_sec, "secondary") # NOTE: hole through primary? # Focus # BN 20180208 - Need TO_PLANE=True if you want an intermediate plane proper.prop_propagate(wfo, d_sec_to_focus, "focus", TO_PLANE=True) # proper.prop_propagate(wfo, d_sec_to_focus, "focus", TO_PLANE = False) # End (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
def lens(wfo, f_lens): proper.prop_propagate(wfo, f_lens) proper.prop_lens(wfo, f_lens) proper.prop_propagate(wfo, f_lens)
def simple_telescope(wavelength, gridsize): # Define entrance aperture diameter and other quantities d_objective = 5.0 # objective diameter in meters fl_objective = 20.0 * d_objective # objective focal length in meters fl_eyepiece = 0.021 # eyepiece focal length fl_eye = 0.022 # human eye focal length beam_ratio = 0.3 # initial beam width/grid width # Define the wavefront wfo = proper.prop_begin(d_objective, wavelength, gridsize, beam_ratio) # print d_objective, wavelength, gridsize, beam_ratio # Define a circular aperture proper.prop_circular_aperture(wfo, d_objective / 2) # proper.prop_propagate(wfo, fl_objective) # proper.prop_propagate(wfo, fl_objective) # proper.prop_propagate(wfo, fl_objective) # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # Define entrance proper.prop_define_entrance(wfo) # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # proper.prop_propagate(wfo, fl_objective+fl_eyepiece, "eyepiece") # # plt.imshow(proper.prop_get_amplitude(wfo)) # # plt.show() # # proper.prop_propagate(wfo, fl_objective+fl_eyepiece, "eyepiece") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # # proper.prop_propagate(wfo, fl_objective+fl_eyepiece, "eyepiece") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # Define a lens proper.prop_lens(wfo, fl_objective, "objective") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # Propagate the wavefront proper.prop_propagate(wfo, fl_objective + fl_eyepiece, "eyepiece") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() # Define another lens proper.prop_lens(wfo, fl_eyepiece, "eyepiece") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() exit_pupil_distance = fl_eyepiece / (1 - fl_eyepiece / (fl_objective + fl_eyepiece)) proper.prop_propagate(wfo, exit_pupil_distance, "exit pupil at eye lens") # quicklook_wf(wfo) # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() proper.prop_lens(wfo, fl_eye, "eye") proper.prop_propagate(wfo, fl_eye, "retina") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() quicklook_wf(wfo) phase_map = proper.prop_get_phase(wfo) amp_map = proper.prop_get_amplitude(wfo) # quicklook_im(phase_map) amp_map[80:100, 80:100] = 0 quicklook_im(amp_map, logAmp=True) import numpy as np wfo.wfarr = proper.prop_shift_center(amp_map * np.cos(phase_map) + 1j * amp_map * np.sin(phase_map)) # quicklook_wf(wf_array[iw,0]) proper.prop_propagate(wfo, fl_eye, "retina") proper.prop_lens(wfo, fl_eye, "eye") quicklook_wf(wfo) # End (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling)
calib) # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wfo._wfarr = ( wfo._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field quicklook_wf(wfo) proper.prop_propagate(wfo, f_lens, "propagate to pupil reimaging lens") proper.prop_lens(wfo, f_lens, "apply pupil reimaging lens") proper.prop_propagate(wfo, f_lens, "lyot stop") quicklook_wf(wfo) return wfo wfo = proper.prop_begin(tp.diam, tp.band[0], tp.grid_size, tp.beam_ratio) proper.prop_circular_aperture(wfo, tp.diam / 2) proper.prop_define_entrance(wfo) # proper.prop_zernikes(wfo, [2, 3], np.array([3,3])*1e-6) vortex(wfo) # quicklook_wf(wfo) proper.prop_circular_aperture(wfo, 0.75, NORM=True) quicklook_wf(wfo) proper.prop_propagate(wfo, tp.f_lens) proper.prop_lens(wfo, tp.f_lens) # quicklook_wf(wfo) (wframe, sampling) = proper.prop_end(wfo) print np.sum(phot.aper_phot(wframe, 0, 5, plot=True)) quicklook_im(wframe, logAmp=True) quicklook_im(phot.aper_phot(wframe, 0, 5))
def coronagraph(wfo, f_lens, occulter_type, occult_loc, diam): # proper.prop_lens(wfo, f_lens, "coronagraph imaging lens") # proper.prop_propagate(wfo, f_lens, "occulter") # quicklook_wf(wfo) # occulter sizes are specified here in units of lambda/diameter; # convert lambda/diam to radians then to meters lamda = proper.prop_get_wavelength(wfo) # print lamda occrad = 3 # occulter radius in lam/D occrad_rad = occrad * lamda / diam # occulter radius in radians dx_m = proper.prop_get_sampling(wfo) dx_rad = proper.prop_get_sampling_radians(wfo) occrad_m = occrad_rad * dx_m / dx_rad # occulter radius in meters # print occrad_m, occulter_type # print 'line 22.', occulter_type #plt.figure(figsize=(12,8)) # quicklook_wf(wfo) if occulter_type == "Gaussian": r = proper.prop_radius(wfo) h = np.sqrt(-0.5 * occrad_m**2 / np.log(1 - np.sqrt(0.5))) #*0.8 gauss_spot = 1 - np.exp(-0.5 * (r / h)**2) # print occult_loc # gauss_spot = np.roll(gauss_spot,occult_loc,(0,1)) gauss_spot = shift(gauss_spot, shift=occult_loc, mode='wrap') proper.prop_multiply(wfo, gauss_spot) # quicklook_wf(wfo) #plt.suptitle("Gaussian spot", fontsize = 18) elif occulter_type == "Solid": proper.prop_circular_obscuration(wfo, occrad_m * 4. / 3) #plt.suptitle("Solid spot", fontsize = 18) # quicklook_wf(wfo) elif occulter_type == "8th_Order": proper.prop_8th_order_mask(wfo, occrad * 3. / 4., CIRCULAR=True) # quicklook_wf(wfo) elif occulter_type == 'Vortex': # print('lol') # apodization(wfo, True) vortex(wfo) # lyotstop(wfo, True) #plt.suptitle("8th order band limited spot", fontsize = 18) # quicklook_wf(wfo, logAmp=False, show=True) # After occulter # plt.subplot(1,2,1) # plt.imshow(np.sqrt(proper.prop_get_amplitude(wfo)), origin = "lower", cmap = plt.cm.gray) # plt.text(200, 10, "After Occulter", color = "w") # plt.show() # quicklook_wf(wfo) proper.prop_propagate(wfo, f_lens, "pupil reimaging lens") # quicklook_wf(wfo) proper.prop_lens(wfo, f_lens, "pupil reimaging lens") # quicklook_wf(wfo) proper.prop_propagate(wfo, 2 * f_lens, "lyot stop") # quicklook_wf(wfo) # from numpy.fft import fft2, ifft2 # wfo.wfarr = fft2(wfo.wfarr) #/ np.size(wfo.wfarr) # quicklook_wf(wfo) # plt.subplot(1,2,2) # plt.imshow(proper.prop_get_amplitude(wfo)**0.2, origin = "lower", cmap = plt.cm.gray) # plt.text(200, 10, "Before Lyot Stop", color = "w") # plt.show() # quicklook_wf(wfo,logAmp=False, show=True) if occulter_type == "Gaussian": # quicklook_wf(wfo) proper.prop_circular_aperture(wfo, 0.75, NORM=True) elif occulter_type == "Solid": # quicklook_wf(wfo) proper.prop_circular_aperture(wfo, 0.84, NORM=True) elif occulter_type == "8th_Order": # quicklook_wf(wfo) proper.prop_circular_aperture(wfo, 0.75, NORM=True) #0.5 elif occulter_type == "Vortex": # proper.prop_circular_aperture(wfo, 0.98, NORM = True) #0.5 lyotstop(wfo, True) # quicklook_wf(wfo) elif occulter_type == "None (Lyot Stop)": proper.prop_circular_aperture(wfo, 0.8, NORM=True) proper.prop_propagate(wfo, f_lens, "reimaging lens") # errs = np.sqrt(proper.prop_get_amplitude(wfo)) # # plt.figure() # # plt.imshow(errs) # # plt.show() # quicklook_wf(wfo) proper.prop_lens(wfo, f_lens, "reimaging lens") # quicklook_wf(wfo) proper.prop_propagate(wfo, f_lens, "final focus") # from numpy.fft import fft2, ifft2 # wfo.wfarr = fft2(wfo.wfarr) / np.size(wfo.wfarr) # quicklook_wf(wfo) return
def vortex(wfo, CAL, charge, f_lens, path, Debug_print): n = int(proper.prop_get_gridsize(wfo)) ofst = 0 # no offset ramp_sign = 1 #sign of charge is positive #sampling = n ramp_oversamp = 11. # vortex is oversampled for a better discretization if charge != 0: if CAL == 1: # create the vortex for a perfectly circular pupil if (Debug_print == True): print("CAL:1, charge ", charge) writefield(path, 'zz_psf', wfo.wfarr) # write the pre-vortex field nramp = int(n * ramp_oversamp) #oversamp # create the vortex by creating a matrix (theta) representing the ramp (created by atan 2 gradually varying matrix, x and y) y1 = np.ones((nramp, ), dtype=np.int) y2 = np.arange(0, nramp, 1.) - (nramp / 2) - int(ramp_oversamp) / 2 y = np.outer(y2, y1) x = np.transpose(y) theta = np.arctan2(y, x) x = 0 y = 0 #vvc_tmp_complex = np.array(np.zeros((nramp,nramp)), dtype=complex) #vvc_tmp_complex.imag = ofst + ramp_sign*charge*theta #vvc_tmp = np.exp(vvc_tmp_complex) vvc_tmp = np.exp(1j * (ofst + ramp_sign * charge * theta)) theta = 0 vvc_real_resampled = cv2.resize( vvc_tmp.real, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc_imag_resampled = cv2.resize( vvc_tmp.imag, (0, 0), fx=1 / ramp_oversamp, fy=1 / ramp_oversamp, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions vvc = np.array(vvc_real_resampled, dtype=complex) vvc.imag = vvc_imag_resampled vvcphase = np.arctan2(vvc.imag, vvc.real) # create the vortex phase vvc_complex = np.array(np.zeros((n, n)), dtype=complex) vvc_complex.imag = vvcphase vvc = np.exp(vvc_complex) vvc_tmp = 0. writefield(path, 'zz_vvc', vvc) # write the theoretical vortex field wfo0 = wfo proper.prop_multiply(wfo, vvc) proper.prop_propagate(wfo, f_lens, 'OAP2') proper.prop_lens(wfo, f_lens) proper.prop_propagate(wfo, f_lens, 'forward to Lyot Stop') proper.prop_circular_obscuration( wfo, 1., NORM=True) # null the amplitude iside the Lyot Stop proper.prop_propagate(wfo, -f_lens) # back-propagation proper.prop_lens(wfo, -f_lens) proper.prop_propagate(wfo, -f_lens) writefield(path, 'zz_perf', wfo.wfarr) # write the perfect-result vortex field wfo = wfo0 else: if (Debug_print == True): print("CAL:0, charge ", charge) vvc = readfield(path, 'zz_vvc') # read the theoretical vortex field vvc = proper.prop_shift_center(vvc) scale_psf = wfo._wfarr[0, 0] psf_num = readfield(path, 'zz_psf') # read the pre-vortex field psf0 = psf_num[0, 0] psf_num = psf_num / psf0 * scale_psf perf_num = readfield( path, 'zz_perf') # read the perfect-result vortex field perf_num = perf_num / psf0 * scale_psf wfo._wfarr = ( wfo._wfarr - psf_num ) * vvc + perf_num # the wavefront takes into account the real pupil with the perfect-result vortex field return