def lyot_stop(wf, mode='RAVC', ravc_r=0.6, ls_dRext=0.03, ls_dRint=0.05, ls_dRspi=0.04, spi_width=0.5, spi_angles=[0,60,120], diam_ext=37, diam_int=11, ls_misalign=None, file_app_phase='', file_app_amp='', ngrid=1024, npupil=285, margin=50, get_amp=False, get_phase=False, verbose=False, **conf): """Add a Lyot stop, or an APP.""" # case 1: Lyot stop if mode in ['CVC', 'RAVC']: # LS parameters r_obstr = ravc_r if mode in ['RAVC'] else diam_int/diam_ext ls_int = r_obstr + ls_dRint ls_ext = 1 - ls_dRext ls_spi = spi_width/diam_ext + ls_dRspi # LS misalignments ls_misalign = [0,0,0,0,0,0] if ls_misalign is None else list(ls_misalign) dx_amp, dy_amp, dz_amp = ls_misalign[0:3] dx_phase, dy_phase, dz_phase = ls_misalign[3:6] # create Lyot stop proper.prop_circular_aperture(wf, ls_ext, dx_amp, dy_amp, NORM=True) if diam_int > 0: proper.prop_circular_obscuration(wf, ls_int, dx_amp, dy_amp, NORM=True) if spi_width > 0: for angle in spi_angles: proper.prop_rectangular_obscuration(wf, ls_spi, 2, \ dx_amp, dy_amp, ROTATION=angle, NORM=True) if verbose is True: print('Create Lyot stop') print(' ls_int=%3.4f, ls_ext=%3.4f, ls_spi=%3.4f'\ %(ls_int, ls_ext, ls_spi)) print('') # case 2: APP elif mode in ['APP']: if verbose is True: print('Load APP from files\n') # get amplitude and phase data APP_amp = fits.getdata(file_app_amp) if os.path.isfile(file_app_amp) \ else np.ones((npupil, npupil)) APP_phase = fits.getdata(file_app_phase) if os.path.isfile(file_app_phase) \ else np.zeros((npupil, npupil)) # resize to npupil APP_amp = impro.resize_img(APP_amp, npupil) APP_phase = impro.resize_img(APP_phase, npupil) # pad with zeros to match PROPER ngrid APP_amp = impro.pad_img(APP_amp, ngrid, 1) APP_phase = impro.pad_img(APP_phase, ngrid, 0) # multiply the loaded APP proper.prop_multiply(wf, APP_amp*np.exp(1j*APP_phase)) # get the LS amplitude and phase for output LS_amp = impro.crop_img(proper.prop_get_amplitude(wf), npupil, margin)\ if get_amp is True else None LS_phase = impro.crop_img(proper.prop_get_phase(wf), npupil, margin)\ if get_phase is True else None return wf, LS_amp, LS_phase
def add_spiders(wfo, diam): # print 'Including Spiders' proper.prop_circular_obscuration(wfo, (diam / 3) / 2.5) proper.prop_rectangular_obscuration(wfo, 0.05 * diam, diam * 1.3, ROTATION=10) proper.prop_rectangular_obscuration(wfo, diam * 1.3, 0.05 * diam, ROTATION=10)
def SubaruPupil(wf): """ adds Subaru pupil mask to the optical train :param wf: 2D proper wavefront :return: acts upon wfo, applies a spatial mask of s=circular secondary obscuration and possibly spider legs """ # dprint('Applying Subaru Pupil') # M2 shadow proper.prop_circular_obscuration(wf, 14 / 46, NORM=True) # Legs proper.prop_rectangular_obscuration(wf, 1.2, 2 / 46, .5, -.375, ROTATION=-50, NORM=True) proper.prop_rectangular_obscuration(wf, 1.2, 2 / 46, .5, .375, ROTATION=50, NORM=True) proper.prop_rectangular_obscuration(wf, 1.2, 2 / 46, -.5, -.375, ROTATION=50, NORM=True) proper.prop_rectangular_obscuration(wf, 1.2, 2 / 46, -.5, .375, ROTATION=-50, NORM=True) proper.prop_rectangular_obscuration(wf, 1, 1 / 46, .05, .45, ROTATION=-50, NORM=True) # Misc Spots proper.prop_circular_obscuration(wf, .075, -.1, 0.6, NORM=True) proper.prop_circular_obscuration(wf, .075, .5, -.375, NORM=True)
def lyot_stop(wf, mode='RAVC', ravc_r=0.6, ls_dRext=0.03, ls_dRint=0.05, ls_dRspi=0.04, spi_width=0.5, spi_angles=[0,60,120], diam_ext=37, diam_int=11, diam_nominal=37, ls_misalign=None, ngrid=1024, npupil=285, file_lyot_stop='', verbose=False, **conf): """ Add a Lyot stop for a focal plane mask """ if mode in ['CVC', 'RAVC', 'CLC']: # load lyot stop from file if provided if os.path.isfile(file_lyot_stop): if verbose is True: print(" apply lyot stop from '%s'"%os.path.basename(file_lyot_stop)) # get amplitude and phase data ls_mask = fits.getdata(file_lyot_stop) # resize to npupil ls_mask = resize_img(ls_mask, npupil) # pad with zeros and add to wavefront proper.prop_multiply(wf, pad_img(ls_mask, ngrid)) # if no lyot stop, create one else: # scale nominal values to pupil external diameter scaling = diam_nominal/diam_ext # LS parameters r_obstr = ravc_r if mode in ['RAVC'] else diam_int/diam_ext ls_int = r_obstr + ls_dRint*scaling ls_ext = 1 - ls_dRext*scaling ls_spi = spi_width/diam_ext + ls_dRspi*scaling # LS misalignments ls_misalign = [0,0,0,0,0,0] if ls_misalign is None else list(ls_misalign) dx_amp, dy_amp, dz_amp = ls_misalign[0:3] dx_phase, dy_phase, dz_phase = ls_misalign[3:6] # create Lyot stop proper.prop_circular_aperture(wf, ls_ext, dx_amp, dy_amp, NORM=True) if diam_int > 0: proper.prop_circular_obscuration(wf, ls_int, dx_amp, dy_amp, NORM=True) if spi_width > 0: for angle in spi_angles: proper.prop_rectangular_obscuration(wf, 2*ls_spi, 2, \ dx_amp, dy_amp, ROTATION=angle, NORM=True) if verbose is True: print(' apply Lyot stop: ls_int=%s, ls_ext=%s, ls_spi=%s'\ %(round(ls_int, 4), round(ls_ext, 4), round(ls_spi, 4))) return wf
def add_obscurations(wf, M2_frac=0, d_primary=0, d_secondary=0, legs_frac=0.05, plane_name=None): """ adds central obscuration (secondary shadow) and/or spider legs as spatial mask to the wavefront :param wf: 2D proper wavefront :param M2_frac: ratio of tp.diam the M2 occupies :param d_primary: diameter of the primary mirror :param d_secondary: diameter of the secondary mirror :param legs_frac: fractional size of spider legs relative to d_primary :return: acts upon wfo, applies a spatial mask of s=circular secondary obscuration and possibly spider legs """ if tp.obscure is False: pass else: # dprint('Including Obscurations') if M2_frac > 0 and d_primary > 0: proper.prop_circular_obscuration(wf, M2_frac * d_primary) elif d_secondary > 0: proper.prop_circular_obscuration(wf, d_secondary) else: raise ValueError( 'must either specify M2_frac and d_primary or d_secondary') if legs_frac > 0: proper.prop_rectangular_obscuration(wf, legs_frac * d_primary, d_primary * 1.3, ROTATION=20) proper.prop_rectangular_obscuration(wf, d_primary * 1.3, legs_frac * d_primary, ROTATION=20)
def lyotstop(wf, conf, RAVC): input_dir = conf['INPUT_DIR'] diam = conf['DIAM'] npupil = conf['NPUPIL'] spiders_angle = conf['SPIDERS_ANGLE'] r_obstr = conf['R_OBSTR'] Debug = conf['DEBUG'] Debug_print = conf['DEBUG_PRINT'] LS_amplitude_apodizer_file = conf['AMP_APODIZER'] LS_misalignment = np.array(conf['LS_MIS_ALIGN']) if conf['PHASE_APODIZER_FILE'] == 0: LS_phase_apodizer_file = 0 else: LS_phase_apodizer_file = fits.getdata(input_dir + '/' + conf['PHASE_APODIZER_FILE']) LS = conf['LYOT_STOP'] LS_parameters = np.array(conf['LS_PARA']) n = proper.prop_get_gridsize(wf) if (RAVC == True): # define the inner radius of the Lyot Stop t1_opt = 1. - 1. / 4 * ( r_obstr**2 + r_obstr * (math.sqrt(r_obstr**2 + 8.)) ) # define the apodizer transmission [Mawet2013] R1_opt = (r_obstr / math.sqrt(1. - t1_opt) ) # define teh apodizer radius [Mawet2013] r_LS = R1_opt + LS_parameters[ 1] # when a Ring apodizer is present, the inner LS has to have at least the value of the apodizer radius else: r_LS = r_obstr + LS_parameters[ 1] # when no apodizer, the LS has to have at least the radius of the pupil central obstruction if LS == True: # apply the LS if (Debug_print == True): print("LS parameters: ", LS_parameters) proper.prop_circular_aperture(wf, LS_parameters[0], LS_misalignment[0], LS_misalignment[1], NORM=True) proper.prop_circular_obscuration(wf, r_LS, LS_misalignment[0], LS_misalignment[1], NORM=True) if (LS_parameters[2] != 0): for iter in range(0, len(spiders_angle)): if (Debug_print == True): print("LS_misalignment: ", LS_misalignment) proper.prop_rectangular_obscuration( wf, LS_parameters[2], 2 * diam, LS_misalignment[0], LS_misalignment[1], ROTATION=spiders_angle[iter]) # define the spiders if (Debug == True): out_dir = str('./output_files/') fits.writeto( out_dir + '_Lyot_stop.fits', proper.prop_get_amplitude(wf)[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) if (isinstance(LS_phase_apodizer_file, (list, tuple, np.ndarray)) == True): xc_pixels = int(LS_misalignment[3] * npupil) yc_pixels = int(LS_misalignment[4] * npupil) apodizer_pixels = (LS_phase_apodizer_file.shape)[0] ## fits file size scaling_factor = float(npupil) / float( apodizer_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation # scaling_factor = float(npupil)/float(pupil_pixels) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) apodizer_scale = cv2.resize( LS_phase_apodizer_file.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("apodizer_resample", apodizer_scale.shape) apodizer_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("npupil: ", npupil) apodizer_large[ int(n / 2) + 1 - int(npupil / 2) - 1 + xc_pixels:int(n / 2) + 1 + int(npupil / 2) + xc_pixels, int(n / 2) + 1 - int(npupil / 2) - 1 + yc_pixels:int(n / 2) + 1 + int(npupil / 2) + yc_pixels] = apodizer_scale # insert the scaled pupil into the 0s grid phase_multiply = np.array(np.zeros((n, n)), dtype=complex) # create a complex array phase_multiply.imag = apodizer_large # define the imaginary part of the complex array as the atm screen apodizer = np.exp(phase_multiply) proper.prop_multiply(wf, apodizer) if (Debug == True): fits.writeto('LS_apodizer.fits', proper.prop_get_phase(wf), overwrite=True) if (isinstance(LS_amplitude_apodizer_file, (list, tuple, np.ndarray)) == True): print('4th') xc_pixels = int(LS_misalignment[0] * npupil) yc_pixels = int(LS_misalignment[1] * npupil) apodizer_pixels = ( LS_amplitude_apodizer_file.shape)[0] ## fits file size scaling_factor = float(npupil) / float( pupil_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) apodizer_scale = cv2.resize( amplitude_apodizer_file.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("apodizer_resample", apodizer_scale.shape) apodizer_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("grid_size: ", n) print("npupil: ", npupil) apodizer_large[ int(n / 2) + 1 - int(npupil / 2) - 1 + xc_pixels:int(n / 2) + 1 + int(npupil / 2) + xc_pixels, int(n / 2) + 1 - int(npupil / 2) - 1 + yc_pixels:int(n / 2) + 1 + int(npupil / 2) + yc_pixels] = apodizer_scale # insert the scaled pupil into the 0s grid apodizer = apodizer_large proper.prop_multiply(wf, apodizer) if (Debug == True): fits.writeto('LS_apodizer.fits', proper.prop_get_amplitude(wf), overwrite=True) return wf
def lyotstop(self, wf, RAVC=None, APP=None, get_pupil='no', dnpup=50): """Add a Lyot stop, or an APP.""" # load parameters npupil = 1 #conf['NPUPIL'] pad = int((210 - npupil) / 2) # get LS misalignments LS_misalignment = (np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) * npupil).astype(int) dx_amp, dy_amp, dz_amp = LS_misalignment[0:3] dx_phase, dy_phase, dz_phase = LS_misalignment[3:6] # case 1: Lyot stop (no APP) if APP is not True: # Lyot stop parameters: R_out, dR_in, spi_width # outer radius (absolute %), inner radius (relative %), spider width (m) (R_out, dR_in, spi_width) = [0.98, 0.03, 0] # Lyot stop inner radius at least as large as obstruction radius R_in = 0.15 # case of a ring apodizer if RAVC is True: # define the apodizer transmission and apodizer radius [Mawet2013] # apodizer radius at least as large as obstruction radius T_ravc = 1 - (R_in**2 + R_in * np.sqrt(R_in**2 + 8)) / 4 R_in /= np.sqrt(1 - T_ravc) # oversize Lyot stop inner radius R_in += dR_in # create Lyot stop proper.prop_circular_aperture(wf, R_out, dx_amp, dy_amp, NORM=True) if R_in > 0: proper.prop_circular_obscuration(wf, R_in, dx_amp, dy_amp, NORM=True) if spi_width > 0: for angle in [10]: proper.prop_rectangular_obscuration(wf, 0.05 * 8, 8 * 1.3, ROTATION=20) proper.prop_rectangular_obscuration(wf, 8 * 1.3, 0.05 * 8, ROTATION=20) # proper.prop_rectangular_obscuration(wf, spi_width, 2 * 8, \ # dx_amp, dy_amp, ROTATION=angle) # case 2: APP (no Lyot stop) else: # get amplitude and phase files APP_amp_file = os.path.join(conf['INPUT_DIR'], conf['APP_AMP_FILE']) APP_phase_file = os.path.join(conf['INPUT_DIR'], conf['APP_PHASE_FILE']) # get amplitude and phase data APP_amp = getdata(APP_amp_file) if os.path.isfile(APP_amp_file) \ else np.ones((npupil, npupil)) APP_phase = getdata(APP_phase_file) if os.path.isfile(APP_phase_file) \ else np.zeros((npupil, npupil)) # resize to npupil APP_amp = resize(APP_amp, (npupil, npupil), preserve_range=True, mode='reflect') APP_phase = resize(APP_phase, (npupil, npupil), preserve_range=True, mode='reflect') # pad with zeros to match PROPER gridsize APP_amp = np.pad(APP_amp, [(pad + 1 + dx_amp, pad - dx_amp), \ (pad + 1 + dy_amp, pad - dy_amp)], mode='constant') APP_phase = np.pad(APP_phase, [(pad + 1 + dx_phase, pad - dx_phase), \ (pad + 1 + dy_phase, pad - dy_phase)], mode='constant') # multiply the loaded APP proper.prop_multiply(wf, APP_amp * np.exp(1j * APP_phase)) # get the pupil amplitude or phase for output if get_pupil.lower() in 'amplitude': return wf, proper.prop_get_amplitude(wf)[pad + 1 - dnpup:-pad + dnpup, pad + 1 - dnpup:-pad + dnpup] elif get_pupil.lower() in 'phase': return wf, proper.prop_get_phase(wf)[pad + 1 - dnpup:-pad + dnpup, pad + 1 - dnpup:-pad + dnpup] else: return wf
def pupil(diam, gridsize, spiders_width, spiders_angle, pixelsize, r_obstr, wavelength, pupil_file, missing_segments_number=0, Debug='False', Debug_print='False', prefix='test'): beam_ratio = pixelsize * 4.85e-9 / (wavelength / diam) wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) n = int(gridsize) npupil = np.ceil( gridsize * beam_ratio ) # compute the pupil size --> has to be ODD (proper puts the center in the up right pixel next to the grid center) if npupil % 2 == 0: npupil = npupil + 1 if (Debug_print == True): print("npupil: ", npupil) print("lambda: ", wavelength) if (missing_segments_number == 0): if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True): pupil = pupil_file pupil_pixels = (pupil.shape)[0] ## fits file size scaling_factor = float(npupil) / float( pupil_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) pupil_scale = cv2.resize( pupil.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("pupil_resample", pupil_scale.shape) pupil_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("n: ", n) print("npupil: ", npupil) pupil_large[ int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2), int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2 )] = pupil_scale # insert the scaled pupil into the 0s grid proper.prop_circular_aperture( wfo, diam / 2) # create a wavefront with a circular pupil if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True): proper.prop_multiply(wfo, pupil_large) # multiply the saved pupil else: proper.prop_circular_obscuration( wfo, r_obstr, NORM=True ) # create a wavefront with a circular central obscuration if (spiders_width != 0): for iter in range(0, len(spiders_angle)): proper.prop_rectangular_obscuration( wfo, spiders_width, 2 * diam, ROTATION=spiders_angle[iter]) # define the spiders else: if (missing_segments_number == 1): pupil = fits.getdata( input_dir + '/ELT_2048_37m_11m_5mas_nospiders_1missing_cut.fits') if (missing_segments_number == 2): pupil = fits.getdata( input_dir + '/ELT_2048_37m_11m_5mas_nospiders_2missing_cut.fits') if (missing_segments_number == 4): pupil = fits.getdata( input_dir + '/ELT_2048_37m_11m_5mas_nospiders_4missing_cut.fits') if (missing_segments_number == 7): pupil = fits.getdata( input_dir + '/ELT_2048_37m_11m_5mas_nospiders_7missing_1_cut.fits') pupil_pixels = (pupil.shape)[0] ## fits file size scaling_factor = float(npupil) / float( pupil_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) pupil_scale = cv2.resize( pupil.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("pupil_resample", pupil_scale.shape) pupil_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("n: ", n) print("npupil: ", npupil) pupil_large[ int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2), int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2)] = pupil_scale # insert the scaled pupil into the 0s grid proper.prop_multiply(wfo, pupil_large) # multiply the saved pupil if (spiders_width != 0): for iter in range(0, len(spiders_angle)): proper.prop_rectangular_obscuration( wfo, spiders_width, 2 * diam, ROTATION=spiders_angle[iter]) # define the spiders if (Debug == True): fits.writeto( out_dir + prefix + '_intial_pupil.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 return (npupil, wfo)
def create_pupil(nhr=2**10, npupil=285, pupil_img_size=40, diam_ext=37, diam_int=11, spi_width=0.5, spi_angles=[0, 60, 120], seg_width=0, seg_gap=0, seg_rms=0, seg_ny=[ 10, 13, 16, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 19, 16, 13, 10 ], seg_missing=[], seed=123456, **conf): ''' Create a pupil. Args: nhr: int high resolution grid npupil: int number of pixels of the pupil pupil_img_size: float pupil image (for PROPER) in m diam_ext: float outer circular aperture in m diam_int: float central obscuration in m spi_width: float spider width in m spi_angles: list of float spider angles in deg seg_width: float segment width in m seg_gap: float gap between segments in m seg_rms: float rms of the reflectivity of all segments seg_ny: list of int number of hexagonal segments per column (from left to right) seg_missing: list of tupples coordinates of missing segments ''' # create a high res pupil with PROPER of even size (nhr) nhr_size = pupil_img_size * nhr / (nhr - 1) wf_tmp = proper.prop_begin(nhr_size, 1, nhr, diam_ext / nhr_size) if diam_ext > 0: proper.prop_circular_aperture(wf_tmp, 1, NORM=True) if diam_int > 0: proper.prop_circular_obscuration(wf_tmp, diam_int / diam_ext, NORM=True) if spi_width > 0: for angle in spi_angles: proper.prop_rectangular_obscuration(wf_tmp, spi_width/nhr_size, 2, \ ROTATION=angle, NORM=True) pup = proper.prop_get_amplitude(wf_tmp) # crop the pupil to odd size (nhr-1), and resize to npupil pup = pup[1:, 1:] pup = resize_img(pup, npupil) # add segments if seg_width > 0: segments = np.zeros((nhr, nhr)) # sampling in meters/pixel sampling = pupil_img_size / nhr # dist between center of two segments, side by side seg_d = seg_width * np.cos(np.pi / 6) + seg_gap # segment radius seg_r = seg_width / 2 # segment radial distance wrt x and y axis seg_ny = np.array(seg_ny) seg_nx = len(seg_ny) seg_rx = np.arange(seg_nx) - (seg_nx - 1) / 2 seg_ry = (seg_ny - 1) / 2 # loop through segments np.random.seed(seed) for i in range(seg_nx): seg_x = seg_rx[i] * seg_d * np.cos(np.pi / 6) seg_y = -seg_ry[i] * seg_d for j in range(1, seg_ny[i] + 1): # removes secondary and if any missing segment is present if (np.sqrt(seg_x**2 + seg_y**2) <= 4.01*seg_d) \ or ((seg_rx[i], j) in seg_missing): seg_y += seg_d else: # creates one hexagonal segment at x, y position in meters segment = create_hexagon(nhr, seg_r, seg_y, seg_x, sampling) # multiply by segment reflectivity and add to segments seg_refl = np.random.normal(1, seg_rms) segments += segment * seg_refl seg_y += seg_d # need to transpose, due to the orientation of hexagons in create_hexagon segments = segments.T # resize to npupil, and add to pupil segments = resize_img(segments, npupil) pup *= segments return pup
def falco_gen_pupil_WFIRSTcycle6_LS(Nbeam, Dbeam, ID, OD, strut_width, centering, rot180deg=False): strut_width = strut_width * Dbeam # now in meters dx = Dbeam / Nbeam clock_deg = 0 magfacD = 1 xshift = 0 yshift = 0 pad_strut = 0 Dmask = Dbeam # % width of the beam (so can have zero padding if LS is undersized) (meters) diam = Dmask # width of the mask (meters) # minimum even number of points across to fully contain the actual aperture (if interpixel centered) NapAcross = Dmask / dx wf = _init_proper(Dmask, dx, centering) # 0 shift for pixel-centered pupil, or -dx shift for inter-pixel centering if centering == "interpixel": cshift = -dx / 2 elif rot180deg: cshift = -dx else: cshift = 0 # DATA FROM THE VISIO FILE D0 = 8 # inches, pupil diameter in Visio file x0 = -26 # inches, pupil center in x in Visio file y0 = 20.25 # inches, pupil center in y in Visio file Dconv = diam / D0 # conversion factor from inches and Visio units to meters # PRIMARY MIRROR (OUTER DIAMETER) ra_OD = (Dbeam * OD / 2) * magfacD cx_OD = cshift + xshift cy_OD = cshift + yshift proper.prop_circular_aperture(wf, ra_OD, cx_OD, cy_OD) # SECONDARY MIRROR (INNER DIAMETER) ra_ID = (Dbeam * ID / 2) * magfacD cx_ID = cshift + xshift cy_ID = cshift + yshift proper.prop_circular_obscuration(wf, ra_ID, cx_ID, cy_ID) sx_s = magfacD * (3.6 * (diam / D0) + pad_strut) sy_s = magfacD * (strut_width + pad_strut) clock_rot = np.array( [[np.cos(np.radians(clock_deg)), -np.sin(np.radians(clock_deg))], [np.sin(np.radians(clock_deg)), np.cos(np.radians(clock_deg))]]) def _get_strut_cxy(x, y): cx_s = (x - x0) * Dconv cy_s = (y - y0) * Dconv cxy = magfacD * clock_rot.dot([cx_s, cy_s]) + cshift return cxy + [xshift, yshift] # STRUT 1 rot_s1 = 77.56 + clock_deg # degrees cx_s1, cy_s1 = _get_strut_cxy(-24.8566, 22.2242) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s1, cy_s1, ROTATION=rot_s1) # STRUT 2 rot_s2 = -17.56 + clock_deg # degrees cx_s2, cy_s2 = _get_strut_cxy(-23.7187, 20.2742) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s2, cy_s2, ROTATION=rot_s2) # STRUT 3 rot_s3 = -42.44 + clock_deg # degrees cx_s3, cy_s3 = _get_strut_cxy(-24.8566, 18.2758) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s3, cy_s3, ROTATION=rot_s3) # STRUT 4 rot_s4 = 42.44 + clock_deg # degrees cx_s4, cy_s4 = _get_strut_cxy(-27.1434, 18.2758) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s4, cy_s4, ROTATION=rot_s4) # STRUT 5 rot_s5 = 17.56 + clock_deg # degrees cx_s5, cy_s5 = _get_strut_cxy(-28.2813, 20.2742) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s5, cy_s5, ROTATION=rot_s5) # STRUT 6 rot_s6 = 102.44 + clock_deg # degrees cx_s6, cy_s6 = _get_strut_cxy(-27.1434, 22.2242) proper.prop_rectangular_obscuration(wf, sx_s, sy_s, cx_s6, cy_s6, ROTATION=rot_s6) mask = np.fft.ifftshift(np.abs(wf.wfarr)) if rot180deg: mask = np.rot90(mask, 2) return mask
def pupil(wfo, CAL, npupil, diam, r_obstr, spiders_width, spiders_angle, pupil_file, missing_segments_number, Debug, Debug_print): n = int(proper.prop_get_gridsize(wfo)) if (missing_segments_number == 0): if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True): pupil = pupil_file pupil_pixels = (pupil.shape)[0] ## fits file size scaling_factor = float(npupil) / float( pupil_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) pupil_scale = cv2.resize( pupil.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("pupil_resample", pupil_scale.shape) pupil_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("n: ", n) print("npupil: ", npupil) pupil_large[ int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2), int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2 )] = pupil_scale # insert the scaled pupil into the 0s grid proper.prop_circular_aperture( wfo, diam / 2) # create a wavefront with a circular pupil if CAL == 0: # CAL=1 is for the back-propagation if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True): proper.prop_multiply(wfo, pupil_large) # multiply the saved pupil else: proper.prop_circular_obscuration( wfo, r_obstr, NORM=True ) # create a wavefront with a circular central obscuration if (spiders_width != 0): for iter in range(0, len(spiders_angle)): proper.prop_rectangular_obscuration( wfo, spiders_width, 2 * diam, ROTATION=spiders_angle[iter]) # define the spiders else: PACKAGE_PATH = os.path.abspath(os.path.join(__file__, os.pardir)) if (missing_segments_number == 1): pupil = fits.getdata( PACKAGE_PATH + '/ELT_2048_37m_11m_5mas_nospiders_1missing_cut.fits') if (missing_segments_number == 2): pupil = fits.getdata( PACKAGE_PATH + '/ELT_2048_37m_11m_5mas_nospiders_2missing_cut.fits') if (missing_segments_number == 4): pupil = fits.getdata( PACKAGE_PATH + '/ELT_2048_37m_11m_5mas_nospiders_4missing_cut.fits') if (missing_segments_number == 7): pupil = fits.getdata( PACKAGE_PATH + '/ELT_2048_37m_11m_5mas_nospiders_7missing_1_cut.fits') pupil_pixels = (pupil.shape)[0] ## fits file size scaling_factor = float(npupil) / float( pupil_pixels ) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print == True): print("scaling_factor: ", scaling_factor) pupil_scale = cv2.resize( pupil.astype(np.float32), (0, 0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR ) # scale the pupil to the pupil size of the simualtions if (Debug_print == True): print("pupil_resample", pupil_scale.shape) pupil_large = np.zeros( (n, n)) # define an array of n-0s, where to insert the pupuil if (Debug_print == True): print("n: ", n) print("npupil: ", npupil) pupil_large[ int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2), int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 + int(npupil / 2)] = pupil_scale # insert the scaled pupil into the 0s grid if CAL == 0: # CAL=1 is for the back-propagation proper.prop_multiply(wfo, pupil_large) # multiply the saved pupil if (spiders_width != 0): for iter in range(0, len(spiders_angle)): proper.prop_rectangular_obscuration( wfo, spiders_width, 2 * diam, ROTATION=spiders_angle[iter]) # define the spiders return
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 lyotstop(wf, 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 (RAVC==True): # define the inner radius of the Lyot Stop t1_opt = 1. - 1./4*(r_obstr**2 + r_obstr*(math.sqrt(r_obstr**2 + 8.))) # define the apodizer transmission [Mawet2013] R1_opt = (r_obstr/math.sqrt(1. - t1_opt)) # define teh apodizer radius [Mawet2013] r_LS = R1_opt + LS_parameters[1] # when a Ring apodizer is present, the inner LS has to have at least the value of the apodizer radius else: r_LS = r_obstr + LS_parameters[1] # when no apodizer, the LS has to have at least the radius of the pupil central obstruction if LS==True: # apply the LS if (Debug_print==True): print("LS parameters: ", LS_parameters) proper.prop_circular_aperture(wf, LS_parameters[0], LS_misalignment[0], LS_misalignment[1], NORM=True) proper.prop_circular_obscuration(wf, r_LS, LS_misalignment[0], LS_misalignment[1], NORM=True) if (LS_parameters[2]!=0): for iter in range(0,len(spiders_angle)): if (Debug_print==True): print("LS_misalignment: ", LS_misalignment) proper.prop_rectangular_obscuration(wf, LS_parameters[2], 2*diam,LS_misalignment[0], LS_misalignment[1], ROTATION=spiders_angle[iter]) # define the spiders if (isinstance(LS_phase_apodizer_file, (list, tuple, np.ndarray)) == True): xc_pixels = int(LS_misalignment[3]*npupil) yc_pixels = int(LS_misalignment[4]*npupil) apodizer_pixels = (LS_phase_apodizer_file.shape)[0]## fits file size scaling_factor = float(npupil)/float(pupil_pixels) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print==True): print ("scaling_factor: ", scaling_factor) apodizer_scale = cv2.resize(phase_apodizer_file.astype(np.float32), (0,0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR) # scale the pupil to the pupil size of the simualtions if (Debug_print==True): print ("apodizer_resample", apodizer_scale.shape) apodizer_large = np.zeros((n,n)) # define an array of n-0s, where to insert the pupuil if (Debug_print==True): print("n: ", n) print("npupil: ", npupil) apodizer_large[int(n/2)+1-int(npupil/2)-1 + xc_pixels:int(n/2)+1+int(npupil/2)+ xc_pixels,int(n/2)+1-int(npupil/2)-1+ yc_pixels:int(n/2)+1+int(npupil/2)+ yc_pixels] =apodizer_scale # insert the scaled pupil into the 0s grid phase_multiply = np.array(np.zeros((n,n)), dtype=complex) # create a complex array phase_multiply.imag = apodizer_large # define the imaginary part of the complex array as the atm screen apodizer = np.exp(phase_multiply) proper.prop_multiply(wf, apodizer) if (Debug == True): fits.writeto(path + 'LS_apodizer.fits', proper.prop_get_phase(wf), overwrite=True) if (isinstance(LS_amplitude_apodizer_file, (list, tuple, np.ndarray)) == True): xc_pixels = int(LS_misalignment[0]*npupil) yc_pixels = int(LS_misalignment[1]*npupil) apodizer_pixels = (LS_amplitude_apodizer_file.shape)[0]## fits file size scaling_factor = float(npupil)/float(pupil_pixels) ## scaling factor between the fits file size and the pupil size of the simulation if (Debug_print==True): print ("scaling_factor: ", scaling_factor) apodizer_scale = cv2.resize(amplitude_apodizer_file.astype(np.float32), (0,0), fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_LINEAR) # scale the pupil to the pupil size of the simualtions if (Debug_print==True): print ("apodizer_resample", apodizer_scale.shape) apodizer_large = np.zeros((n,n)) # define an array of n-0s, where to insert the pupuil if (Debug_print==True): print("n: ", n) print("npupil: ", npupil) apodizer_large[int(n/2)+1-int(npupil/2)-1 + xc_pixels:int(n/2)+1+int(npupil/2)+ xc_pixels,int(n/2)+1-int(npupil/2)-1+ yc_pixels:int(n/2)+1+int(npupil/2)+ yc_pixels] =apodizer_scale # insert the scaled pupil into the 0s grid apodizer = apodizer_large proper.prop_multiply(wf, apodizer) if (Debug == True): fits.writeto(path + 'LS_apodizer.fits', proper.prop_get_amplitude(wf), overwrite=True) return