def _luvoir_matrix_one_pair(design, norm, wfe_aber, zern_mode, resDir, savepsfs, saveopds, segment_pair): """ Function to calculate LVUOIR-A mean contrast of one aberrated segment pair; for num_matrix_luvoir_multiprocess(). :param design: str, what coronagraph design to use - 'small', 'medium' or 'large' :param norm: float, direct PSF normalization factor (peak pixel of direct PSF) :param wfe_aber: float, calibration aberration per segment in m :param zern_mode: Zernike mode object, local Zernike aberration :param resDir: str, directory for matrix calculations :param savepsfs: bool, if True, all PSFs will be saved to disk individually, as fits files :param saveopds: bool, if True, all pupil surface maps of aberrated segment pairs will be saved to disk as PDF :param segment_pair: tuple, pair of segments to aberrate, 0-indexed. If same segment gets passed in both tuple entries, the segment will be aberrated only once. Note how LUVOIR segments start numbering at 1, with 0 being the center segment that doesn't exist. :return: contrast as float, and segment pair as tuple """ # Instantiate LUVOIR object sampling = CONFIG_PASTIS.getfloat('LUVOIR', 'sampling') optics_input = CONFIG_PASTIS.get('LUVOIR', 'optics_path') luv = LuvoirAPLC(optics_input, design, sampling) log.info(f'PAIR: {segment_pair[0]+1}-{segment_pair[1]+1}') # Put aberration on correct segments. If i=j, apply only once! luv.flatten() luv.set_segment(segment_pair[0]+1, wfe_aber / 2, 0, 0) if segment_pair[0] != segment_pair[1]: luv.set_segment(segment_pair[1]+1, wfe_aber / 2, 0, 0) log.info('Calculating coro image...') image, inter = luv.calc_psf(ref=False, display_intermediate=False, return_intermediate='intensity') # Normalize PSF by reference image psf = image / norm # Save PSF image to disk if savepsfs: filename_psf = f'psf_{zern_mode.name}_{zern_mode.convention + str(zern_mode.index)}_segs_{segment_pair[0]+1}-{segment_pair[1]+1}' hcipy.write_fits(psf, os.path.join(resDir, 'psfs', filename_psf + '.fits')) # Plot segmented mirror WFE and save to disk if saveopds: opd_name = f'opd_{zern_mode.name}_{zern_mode.convention + str(zern_mode.index)}_segs_{segment_pair[0]+1}-{segment_pair[1]+1}' plt.clf() hcipy.imshow_field(inter['seg_mirror'], grid=luv.aperture.grid, mask=luv.aperture, cmap='RdBu') plt.savefig(os.path.join(resDir, 'OTE_images', opd_name + '.pdf')) log.info('Calculating mean contrast in dark hole') dh_intensity = psf * luv.dh_mask contrast = np.mean(dh_intensity[np.where(luv.dh_mask != 0)]) log.info(f'contrast: {float(contrast)}') # contrast is a Field, here casting to normal float return float(contrast), segment_pair
def plot_single_mode(mode_nr, pastis_modes, out_dir, design, figsize=(8.5, 8.5), vmin=None, vmax=None, fname_suffix='', save=False): """ Plot a single PASTIS mode. :param mode_nr: int, mode index :param pastis_modes: array, PASTIS modes [seg, mode] in nm :param out_dir: str, output path to save the figure to if save=True :param design: str, "small", "medium", or "large" LUVOIR-A APLC design :param figsize: tuple, size of figure, default=(8.5,8.5) :param vmin: matplotlib min extent of image, default is None :param vmax: matplotlib max extent of image, default is None :param fname_suffix: str, optional, suffix to add to the saved file name :param save: bool, whether to save to disk or not, default is False :return: """ fname = f'mode_{mode_nr}' if fname_suffix != '': fname += f'_{fname_suffix}' # Create luvoir instance sampling = CONFIG_PASTIS.getfloat('LUVOIR', 'sampling') optics_input = CONFIG_PASTIS.get('LUVOIR', 'optics_path') luvoir = LuvoirAPLC(optics_input, design, sampling) plt.figure(figsize=figsize, constrained_layout=False) one_mode = apply_mode_to_luvoir(pastis_modes[:, mode_nr - 1], luvoir)[0] hcipy.imshow_field(one_mode.phase, cmap='RdBu', vmin=vmin, vmax=vmax) plt.axis('off') plt.annotate(f'{mode_nr}', xy=(-7.1, -6.9), fontweight='roman', fontsize=43) cbar = plt.colorbar( fraction=0.046, pad=0.04 ) # no clue what these numbers mean but it did the job of adjusting the colorbar size to the actual plot size cbar.ax.tick_params( labelsize=40) # this changes the numbers on the colorbar plt.tight_layout() if save: plt.savefig(os.path.join(out_dir, '.'.join([fname, 'pdf'])))
def plot_all_modes(pastis_modes, out_dir, design, fname_suffix='', save=False): """ Plot all PATIS modes onto a grid. :param pastis_modes: array, PASTIS modes [seg, mode] in nm :param out_dir: str, output path to save the figure to if save=True :param design: str, "small", "medium", or "large" LUVOIR-A APLC design :param fname_suffix: str, optional, suffix to add to the saved file name :param save: bool, whether to save to disk or not, default is False :return: """ fname = f'all_modes' if fname_suffix != '': fname += f'_{fname_suffix}' # Calculate phases of all modes all_modes = calculate_mode_phases(pastis_modes, design) # Plot them fig, axs = plt.subplots(12, 10, figsize=(20, 24)) for i, ax in enumerate(axs.flat): im = hcipy.imshow_field(all_modes[i], cmap='RdBu', ax=ax, vmin=-0.0045, vmax=0.0045) ax.axis('off') ax.annotate(f'{i + 1}', xy=(-6.8, -6.8), fontweight='roman', fontsize=13) fig.tight_layout() if save: plt.savefig(os.path.join(out_dir, '.'.join([fname, 'pdf'])))
def run_loyt(): from hcipy import make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront import numpy as np import matplotlib.pyplot as plt pupil_grid = make_pupil_grid(256) focal_grid = make_focal_grid(pupil_grid, 8, 32) prop = FraunhoferPropagator(pupil_grid, focal_grid) aperture = circular_aperture(1) aperture = evaluate_supersampled(aperture, pupil_grid, 8) mask = 1 - circular_aperture(3)(focal_grid) stop = circular_aperture(0.7)(pupil_grid) coro = LyotCoronagraph(pupil_grid, mask, stop) wf = Wavefront(aperture) lyot = coro(wf) img = prop(lyot) img_ref = prop(wf) output_path = get_output_path("miscellaneous") fig = plt.figure() imshow_field(np.log10(img.power / img_ref.power.max()), vmin=-6, vmax=0) plt.xlim(-25, 25) plt.ylim(-25, 25) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") fig.savefig(output_path + "lyot_psf") fig = plt.figure() imshow_field(np.log10(img_ref.power / img_ref.power.max()), vmin=-6, vmax=0) plt.xlim(-25, 25) plt.ylim(-25, 25) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") fig.savefig(output_path + "normal_psf")
def run_loyt(): from hcipy import make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront import numpy as np import matplotlib.pyplot as plt pupil_grid = make_pupil_grid(256) focal_grid = make_focal_grid(pupil_grid, 8, 32) prop = FraunhoferPropagator(pupil_grid, focal_grid) aperture = circular_aperture(1) aperture = evaluate_supersampled(aperture, pupil_grid, 8) mask = 1 - circular_aperture(3)(focal_grid) stop = circular_aperture(0.7)(pupil_grid) coro = LyotCoronagraph(pupil_grid, mask, stop) wf = Wavefront(aperture) lyot = coro(wf) img = prop(lyot) img_ref = prop(wf) output_path = get_output_path("miscellaneous") fig = plt.figure() imshow_field(np.log10(img.power / img_ref.power.max()), vmin=-6, vmax=0) plt.xlim(-25,25) plt.ylim(-25,25) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") fig.savefig(output_path+"lyot_psf") fig = plt.figure() imshow_field(np.log10(img_ref.power / img_ref.power.max()), vmin=-6, vmax=0) plt.xlim(-25,25) plt.ylim(-25,25) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") fig.savefig(output_path+"normal_psf")
def score_matrix3(aberrations, show=False): # Make segmented mirror aper, segments = hcipy.make_hexagonal_segmented_aperture(num_rings, segment_flat_to_flat, gap_size, starting_ring=1, return_segments=True) aper = hcipy.evaluate_supersampled(aper, pupil_grid, 1) segments = hcipy.evaluate_supersampled(segments, pupil_grid, 1) # Instantiate the segmented mirror hsm = hcipy.SegmentedDeformableMirror(segments) # Make a pupil plane wavefront from aperture wf = hcipy.Wavefront(aper, wavelength) hsm.flatten() # Get poke segments for i in range(0,len(aberrations)): if float(aberrations[i]) != 0: hsm.set_segment_actuators(i, aber_to_opd(aber_rad, wavelength) / (1/float(aberrations[i])), 0, 0) if show: plt.figure(figsize=(8,8)) plt.title('OPD for HCIPy SM') hcipy.imshow_field(hsm.surface * 2, mask=aper, cmap='RdBu_r', vmin=-5e-7, vmax=5e-7) plt.colorbar() plt.show() ### PROPAGATE AND SCORE ### wf_fp_pistoned = hsm(wf) # Propagate from SM to image plane im_pistoned_hc = prop(wf_fp_pistoned) norm_hc = np.max(im_pistoned_hc.intensity) if show: # Display intensity in image plane hcipy.imshow_field(np.log10(im_pistoned_hc.intensity / norm_hc), cmap='inferno', vmin=-9) plt.title('Image plane after SM') plt.colorbar() plt.show() hcipy.imshow_field(np.log10((im_pistoned_hc.intensity / norm_hc)*(annulus)), cmap='inferno', vmin=-9) plt.title('Annular image plane region') plt.colorbar() plt.show() interested_field = (im_pistoned_hc.intensity / norm_hc)*(1-annulus) score = float(hcipy.Field.sum(interested_field)/hcipy.Field.sum(im_pistoned_hc.intensity / norm_hc))*100 return score
def full_modes_from_themselves(pmodes, datadir, sm, wf_aper, saving=False): """ Put all modes onto the pupuil SM and get full 2D modes. Take the pmodes array of all modes (shape [segnum, modenum] = [nseg, nseg]) and apply them onto a segmenter mirror in the pupil. This phase gets returned both as an array of hcipy.Fields, as well as a standard array of 2D arrays. Optionally, save a PDF displaying all modes, a fits cube and individual PDF images. :param pmodes: array of PASTIS modes [segnum, modenum] :param datadir: string, path to overall data directory containing matrix and results folder :param saving: bool, whether to save figure to disk or not :return: all_modes as array of Fields, mode_cube as array of 2D arrays (hcipy vs matplotlib) """ nseg = 120 ### Put all modes on the SM and get their phase all_modes = [] for thismode in range(nseg): print('Working on mode {}/{}.'.format(thismode + 1, nseg)) wf_sm = apply_mode_to_sm(pmodes[:, thismode], sm, wf_aper) all_modes.append(wf_sm.phase / wf_sm.wavenumber ) # wf.phase is in rad, so this converts it to meters ### Check for results directory structure and create if it doesn't exist if saving: subdirs = [ os.path.join(datadir, 'results'), os.path.join(datadir, 'results', 'modes'), os.path.join(datadir, 'results', 'modes', 'fits'), os.path.join(datadir, 'results', 'modes', 'pdf') ] for place in subdirs: if not os.path.isdir(place): os.mkdir(place) ### Plot all modes together and save if saving: print('Saving all PASTIS modes...') plt.figure(figsize=(36, 30)) for thismode in range(nseg): plt.subplot(12, 10, thismode + 1) hc.imshow_field(all_modes[thismode], cmap='RdBu') plt.axis('off') plt.title('Mode ' + str(thismode + 1)) plt.savefig( os.path.join(datadir, 'results', 'modes', 'modes_piston.pdf')) ### Plot them individually and save as fits and pdf mode_cube = [] # to save as a fits cube for thismode in range(nseg): # pdf plt.clf() hc.imshow_field(all_modes[thismode], cmap='RdBu') plt.axis('off') plt.title('Mode ' + str(thismode + 1), size=30) if saving: plt.savefig( os.path.join(datadir, 'results', 'modes', 'pdf', 'mode' + str(thismode + 1) + '.pdf')) # for the fits cube mode_cube.append(all_modes[thismode].shaped) # fits cube mode_cube = np.array(mode_cube) if saving: hc.write_fits( mode_cube, os.path.join(datadir, 'results', 'modes', 'fits', 'cube_modes.fits')) return all_modes, mode_cube
### Calculate segment-based static constraints if calculate_mus: print('Calculating static segment-based constraints') mus = np.zeros_like(sigmas) for segnum in range(nseg): mus[segnum] = calculate_segment_constraints(pmodes, sigmas, segnum) np.savetxt( os.path.join(workdir, 'results', 'mus_' + str(c_stat) + '_test.txt'), mus) # Put mus on SM and plot wf_constraints = apply_mode_to_sm(mus, sm, wf_aper) plt.figure() hc.imshow_field(wf_constraints.phase / wf_constraints.wavenumber, cmap='Blues') # in meters plt.title('Static segment constraints $\mu_p$ for C = ' + str(c_stat), size=20) plt.colorbar() plt.savefig( os.path.join(workdir, 'results', 'static_constraints_' + str(c_stat) + '_test.pdf')) else: print('Reading mus from {}'.format(workdir)) mus = np.loadtxt( os.path.join(workdir, 'results', 'mus_' + str(c_stat) + '_test.txt')) ### Calculate Monte Carlo confirmation with E2E if run_monte_carlo:
def clean_vapp(): import numpy as np import matplotlib.pyplot as plt from hcipy import read_fits, make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront script_path = os.path.realpath(__file__).split("vApp_reduction",1)[0] full_path = script_path+"vApp_reduction/data/" amplitude_file = full_path+'SCExAO_vAPP_amplitude_resampled.fits' phase_file = full_path+'SCExAO_vAPP_phase_resampled.fits' # loading the files required for generating the vAPP. amplitude_temp = read_fits(amplitude_file) phase_temp = read_fits(phase_file) # number of pixels along one axis in the pupil Npix = amplitude_temp.shape[0] # generating the grids pupil_grid = make_pupil_grid(Npix) focal_grid = make_focal_grid(pupil_grid, 4, 25) # Mapping from pupil plane to focal plane propagator = FraunhoferPropagator(pupil_grid, focal_grid) # converting the amplitude and phase to fields amplitude = Field(amplitude_temp.ravel(), pupil_grid) phase = Field(phase_temp.ravel(), pupil_grid) # the wavefront for the three PSFs pupil_wf_PSF_1 = Wavefront(amplitude * np.exp(1j * phase)) # coronagraphic PSF 1 pupil_wf_PSF_2 = Wavefront(amplitude * np.exp(-1j * phase)) # coronagraphic PSF 2 pupil_wf_PSF_3 = Wavefront(amplitude) # leakage # Propagating them to the focal plane focal_wf_PSF_1 = propagator(pupil_wf_PSF_1) focal_wf_PSF_2 = propagator(pupil_wf_PSF_2) focal_wf_PSF_3 = propagator(pupil_wf_PSF_3) # setting the total power in the images focal_wf_PSF_1.total_power = 1 focal_wf_PSF_2.total_power = 1 focal_wf_PSF_3.total_power = 1 # the strenght of the leakage term leakage = 0.02 # getting the power and scaling with leakage PSF_1_pwr = focal_wf_PSF_1.power * (1 - leakage / 2) PSF_2_pwr = focal_wf_PSF_2.power * (1 - leakage / 2) PSF_3_pwr = focal_wf_PSF_3.power * leakage # generating the total PSF of the vAPP total_PSF = PSF_1_pwr + PSF_2_pwr + PSF_3_pwr # normalizing to sum = 1 total_PSF /= np.sum(total_PSF) fig = plt.figure() imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") plt.show() output_path = get_output_path("miscellaneous") fig.savefig(output_path+"clean_vapp")
def gen_atmos(plot=False): """ generates atmospheric phase distortions using hcipy (updated from original using CAOS) read more on HCIpy here: https://hcipy.readthedocs.io/en/latest/index.html In hcipy, the atmosphere evolves as a function of time, specified by the user. User can thus specify the timescale of evolution through both velocity of layer and time per step in the obs_sequence, in loop for medis_main.gen_timeseries(). :param plot: turn plotting on or off :return: """ dprint("Making New Atmosphere Model") # Saving Parameters # np.savetxt(iop.atmosconfig, ['Grid Size', 'Wvl Range', 'Number of Frames', 'Layer Strength', 'Outer Scale', 'Velocity', 'Scale Height', cp.model]) # np.savetxt(iop.atmosconfig, ['ap.grid_size', 'ap.wvl_range', 'ap.numframes', 'atmp.cn_sq', 'atmp.L0', 'atmp.vel', 'atmp.h', 'cp.model']) # np.savetxt(iop.atmosconfig, [ap.grid_size, ap.wvl_range, ap.numframes, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, cp.model], fmt='%s') wsamples = np.linspace(ap.wvl_range[0], ap.wvl_range[1], ap.n_wvl_init) wavefronts = [] ################################## # Initiate HCIpy Atmosphere Type ################################## pupil_grid = hcipy.make_pupil_grid(sp.grid_size, tp.entrance_d) if atmp.model == 'single': layers = [ hcipy.InfiniteAtmosphericLayer(pupil_grid, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, 2) ] elif atmp.model == 'hcipy_standard': # Make multi-layer atmosphere layers = hcipy.make_standard_atmospheric_layers( pupil_grid, atmp.outer_scale) elif atmp.model == 'evolving': raise NotImplementedError atmos = hcipy.MultiLayerAtmosphere(layers, scintilation=False) for wavelength in wsamples: wavefronts.append( hcipy.Wavefront(hcipy.Field(np.ones(pupil_grid.size), pupil_grid), wavelength)) ########################################### # Evolving Wavefront using HCIpy tools ########################################### for it, t in enumerate( np.arange(0, sp.numframes * sp.sample_time, sp.sample_time)): atmos.evolve_until(t) for iw, wf in enumerate(wavefronts): wf2 = atmos.forward(wf) filename = get_filename(it, wsamples[iw]) dprint(f"atmos file = {filename}") hdu = fits.ImageHDU(wf2.phase.reshape(sp.grid_size, sp.grid_size)) hdu.header['PIXSIZE'] = tp.entrance_d / sp.grid_size hdu.writeto(filename, overwrite=True) if plot and iw == 0: import matplotlib.pyplot as plt from medis.twilight_colormaps import sunlight plt.figure() plt.title( f"Atmosphere Phase Map t={t} lambda={eformat(wsamples[iw], 3, 2)}" ) hcipy.imshow_field(wf2.phase, cmap=sunlight) plt.colorbar() plt.show(block=True)
def get_atlast_aperture(normalized=False, with_segment_gaps=True, segment_transmissions=1, write_to_disk=False, outDir=None): """Make the ATLAST/HiCAT pupil mask. This function is a copy of make_hicat_aperture(), except that it also returns the segment positions. Parameters ---------- normalized : boolean If this is True, the outer diameter will be scaled to 1. Otherwise, the diameter of the pupil will be 15.0 meters. with_segment_gaps : boolean Include the gaps between individual segments in the aperture. segment_transmissions : scalar or array_like The transmission for each of the segments. If this is a scalar, this transmission will be used for all segments. Returns ------- Field generator The ATLAST aperture. CartesianGrid The segment positions. """ pupil_diameter = PUP_DIAMETER segment_circum_diameter = 2 / np.sqrt(3) * pupil_diameter / 7 num_rings = 3 segment_gap = CONFIG_PASTIS.getfloat(which_tel, 'gaps') if not with_segment_gaps: segment_gap = 0 if normalized: segment_circum_diameter /= pupil_diameter segment_gap /= pupil_diameter pupil_diameter = 1.0 segment_positions = hcipy.make_hexagonal_grid( segment_circum_diameter / 2 * np.sqrt(3), num_rings) segment_positions = segment_positions.subset(lambda grid: ~( hcipy.circular_aperture(segment_circum_diameter)(grid) > 0)) hexagon = hcipy.hexagonal_aperture(segment_circum_diameter - segment_gap) def segment(grid): return hexagon(grid.rotated(np.pi / 2)) segmented_aperture = hcipy.make_segmented_aperture(segment, segment_positions, segment_transmissions) def func(grid): res = segmented_aperture(grid) return hcipy.Field(res, grid) # Save pupil to disk, as pdf and fits if write_to_disk: pupil_grid = hcipy.make_pupil_grid(dims=pupil_size, diameter=pupil_diameter) atlast = hcipy.evaluate_supersampled(func, pupil_grid, 8) hcipy.imshow_field(atlast) for i in range(36): plt.annotate(str(i + 1), size='x-large', xy=(segment_positions.x[i] - pupil_diameter * 0.03, segment_positions.y[i] - pupil_diameter * 0.02)) # -0.03/-0.02 is for shifting the numbers closer to the segment centers. Scaling that by pupil_diameter # keeps them in place. plt.savefig(os.path.join(outDir, 'ATLAST_pupil.pdf')) util.write_fits(atlast.shaped, os.path.join(outDir, 'pupil.fits')) return func, segment_positions
def gen_atmos(plot=False, debug=True): """ generates atmospheric phase distortions using hcipy (updated from original using CAOS) read more on HCIpy here: https://hcipy.readthedocs.io/en/latest/index.html In hcipy, the atmosphere evolves as a function of time, specified by the user. User can thus specify the timescale of evolution through both velocity of layer and time per step in the obs_sequence, in loop for medis_main.gen_timeseries(). :param plot: turn plotting on or off :return: todo add simple mp.Pool.map code to make maps in parrallel """ if tp.use_atmos is False: pass # only make new atmosphere map if using the atmosphere else: if sp.verbose: dprint("Making New Atmosphere Model") # Saving Parameters # np.savetxt(iop.atmosconfig, ['Grid Size', 'Wvl Range', 'Number of Frames', 'Layer Strength', 'Outer Scale', 'Velocity', 'Scale Height', cp.model]) # np.savetxt(iop.atmosconfig, ['ap.grid_size', 'ap.wvl_range', 'ap.numframes', 'atmp.cn_sq', 'atmp.L0', 'atmp.vel', 'atmp.h', 'cp.model']) # np.savetxt(iop.atmosconfig, [ap.grid_size, ap.wvl_range, ap.numframes, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, cp.model], fmt='%s') wsamples = np.linspace(ap.wvl_range[0], ap.wvl_range[1], ap.n_wvl_init) wavefronts = [] ################################## # Initiate HCIpy Atmosphere Type ################################## pupil_grid = hcipy.make_pupil_grid(sp.grid_size, tp.entrance_d) if atmp.model == 'single': layers = [ hcipy.InfiniteAtmosphericLayer(pupil_grid, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, 2) ] elif atmp.model == 'hcipy_standard': # Make multi-layer atmosphere # layers = hcipy.make_standard_atmospheric_layers(pupil_grid, atmp.L0) heights = np.array([500, 1000, 2000, 4000, 8000, 16000]) velocities = np.array([10, 10, 10, 10, 10, 10]) Cn_squared = np.array( [0.2283, 0.0883, 0.0666, 0.1458, 0.3350, 0.1350]) * 3.5e-12 layers = [] for h, v, cn in zip(heights, velocities, Cn_squared): layers.append( hcipy.InfiniteAtmosphericLayer(pupil_grid, cn, atmp.L0, v, h, 2)) elif atmp.model == 'evolving': raise NotImplementedError atmos = hcipy.MultiLayerAtmosphere(layers, scintilation=False) for wavelength in wsamples: wavefronts.append( hcipy.Wavefront( hcipy.Field(np.ones(pupil_grid.size), pupil_grid), wavelength)) if atmp.correlated_sampling: # Damage Detection and Localization from Dense Network of Strain Sensors # fancy sampling goes here normal = corrsequence(sp.numframes, atmp.tau / sp.sample_time)[1] * atmp.std uniform = (special.erf(normal / np.sqrt(2)) + 1) times = np.cumsum(uniform) * sp.sample_time if debug: import matplotlib.pylab as plt plt.plot(normal) plt.figure() plt.plot(uniform) plt.figure() plt.hist(uniform) plt.figure() plt.plot( np.arange(0, sp.numframes * sp.sample_time, sp.sample_time)) plt.plot(times) plt.show() else: times = np.arange(0, sp.numframes * sp.sample_time, sp.sample_time) ########################################### # Evolving Wavefront using HCIpy tools ########################################### for it, t in enumerate(times): atmos.evolve_until(t) for iw, wf in enumerate(wavefronts): wf2 = atmos.forward(wf) filename = get_filename( it, wsamples[iw], (iop.atmosdir, sp.sample_time, atmp.model)) if sp.verbose: dprint(f"atmos file = {filename}") hdu = fits.ImageHDU( wf2.phase.reshape(sp.grid_size, sp.grid_size)) hdu.header['PIXSIZE'] = tp.entrance_d / sp.grid_size hdu.writeto(filename, overwrite=True) if plot and iw == 0: import matplotlib.pyplot as plt from medis.twilight_colormaps import sunlight plt.figure() plt.title( f"Atmosphere Phase Map t={t} lambda={eformat(wsamples[iw], 3, 2)}" ) hcipy.imshow_field(wf2.phase, cmap=sunlight) plt.colorbar() plt.show(block=True)
def calc_psf(self, ref=False, display_intermediate=False, return_intermediate=None): """Calculate the PSF of the segmented telescope, normalized to contrast units. Parameters: ---------- ref : bool Keyword for additionally returning the refrence PSF without the FPM. display_intermediate : bool Keyword for display of all planes. return_intermediate : string Either 'intensity', return the intensity in all planes; except phase on the SM (first plane) or 'efield', return the E-fields in all planes. Default none. Returns: -------- wf_im_coro.intensity : Field Coronagraphic image, normalized to contrast units by max of reference image (even when ref not returned). wf_im_ref.intensity : Field, optional Reference image without FPM. intermediates : dict of Fields, optional Intermediate plane intensity images; except for full wavefront on segmented mirror. wf_im_coro : Wavefront Wavefront in last focal plane. wf_im_ref : Wavefront, optional Wavefront of reference image without FPM. intermediates : dict of Wavefronts, optional Intermediate plane E-fields; except intensity in focal plane after FPM. """ # Create fake FPM for plotting fpm_plot = 1 - hc.circular_aperture(2 * self.fpm_rad * self.lamDrad)( self.focal_det) # Create apodozer as hc.Apodizer() object to be able to propagate through it apod_prop = hc.Apodizer(self.apodizer) # Calculate all wavefronts of the full propagation wf_sm = self.sm(self.wf_aper) wf_apod = apod_prop(wf_sm) wf_lyot = self.coro(wf_apod) wf_im_coro = self.prop(wf_lyot) # Wavefronts in extra planes wf_before_fpm = self.prop(wf_apod) int_after_fpm = np.log10( wf_before_fpm.intensity / wf_before_fpm.intensity.max() ) * fpm_plot # this is the intensity straight wf_before_lyot = self.coro_no_ls(wf_apod) # Wavefronts of the reference propagation wf_ref_pup = hc.Wavefront(self.apodizer * self.lyotstop, wavelength=self.wvln) wf_im_ref = self.prop(wf_ref_pup) # Display intermediate planes if display_intermediate: plt.figure(figsize=(15, 15)) plt.subplot(331) hc.imshow_field(wf_sm.phase, mask=self.aper, cmap='RdBu') plt.title('Seg aperture phase') plt.subplot(332) hc.imshow_field(wf_apod.intensity, cmap='inferno') plt.title('Apodizer') plt.subplot(333) hc.imshow_field(wf_before_fpm.intensity / wf_before_fpm.intensity.max(), norm=LogNorm(), cmap='inferno') plt.title('Before FPM') plt.subplot(334) hc.imshow_field(int_after_fpm / wf_before_fpm.intensity.max(), cmap='inferno') plt.title('After FPM') plt.subplot(335) hc.imshow_field(wf_before_lyot.intensity / wf_before_lyot.intensity.max(), norm=LogNorm(vmin=1e-3, vmax=1), cmap='inferno') plt.title('Before Lyot stop') plt.subplot(336) hc.imshow_field(wf_lyot.intensity / wf_lyot.intensity.max(), norm=LogNorm(vmin=1e-3, vmax=1), cmap='inferno', mask=self.lyotstop) plt.title('After Lyot stop') plt.subplot(337) hc.imshow_field(wf_im_coro.intensity / wf_im_ref.intensity.max(), norm=LogNorm(vmin=1e-10, vmax=1e-3), cmap='inferno') plt.title('Final image') plt.colorbar() if return_intermediate == 'intensity': # Return the intensity in all planes; except phase on the SM (first plane) intermediates = { 'seg_mirror': wf_sm.phase, 'apod': wf_apod.intensity, 'before_fpm': wf_before_fpm.intensity / wf_before_fpm.intensity.max(), 'after_fpm': int_after_fpm / wf_before_fpm.intensity.max(), 'before_lyot': wf_before_lyot.intensity / wf_before_lyot.intensity.max(), 'after_lyot': wf_lyot.intensity / wf_lyot.intensity.max() } if ref: return wf_im_coro.intensity, wf_im_ref.intensity, intermediates else: return wf_im_coro.intensity, intermediates if return_intermediate == 'efield': # Return the E-fields in all planes; except intensity in focal plane after FPM intermediates = { 'seg_mirror': wf_sm, 'apod': wf_apod, 'before_fpm': wf_before_fpm, 'after_fpm': int_after_fpm, 'before_lyot': wf_before_lyot, 'after_lyot': wf_lyot } if ref: return wf_im_coro, wf_im_ref, intermediates else: return wf_im_coro, intermediates if ref: return wf_im_coro.intensity, wf_im_ref.intensity return wf_im_coro.intensity
def num_matrix_luvoir(design, savepsfs=False, saveopds=True): """ Generate a numerical PASTIS matrix for a LUVOIR A coronagraph. -- Depracated function, the LUVOIR PASTIS matrix is better calculated with num_matrix_multiprocess(), which can do this for your choice of one of the implemented instruments (LUVOIR, HiCAT, JWST). -- All inputs are read from the (local) configfile and saved to the specified output directory. The LUVOIR STDT delivery in May 2018 included three different apodizers we can work with, you pick which of the three you want with the 'design' parameter. :param design: string, what coronagraph design to use - 'small', 'medium' or 'large' :param savepsfs: bool, if True, all PSFs will be saved to disk individually, as fits files, additionally to the total PSF cube. If False, the total cube will still get saved at the very end of the script. :param saveopds: bool, if True, all pupil surface maps of aberrated segment pairs will be saved to disk as PDF :return overall_dir: string, experiment directory """ # Keep track of time start_time = time.time() ### Parameters # System parameters overall_dir = util.create_data_path(CONFIG_PASTIS.get('local', 'local_data_path'), telescope='luvoir-'+design) os.makedirs(overall_dir, exist_ok=True) resDir = os.path.join(overall_dir, 'matrix_numerical') # Create necessary directories if they don't exist yet os.makedirs(resDir, exist_ok=True) os.makedirs(os.path.join(resDir, 'OTE_images'), exist_ok=True) os.makedirs(os.path.join(resDir, 'psfs'), exist_ok=True) # Set up logger util.setup_pastis_logging(resDir, f'pastis_matrix_{design}') log.info('Building numerical matrix for LUVOIR\n') # Read calibration aberration zern_number = CONFIG_PASTIS.getint('calibration', 'local_zernike') zern_mode = util.ZernikeMode(zern_number) # Create Zernike mode object for easier handling # General telescope parameters nb_seg = CONFIG_PASTIS.getint('LUVOIR', 'nb_subapertures') wvln = CONFIG_PASTIS.getfloat('LUVOIR', 'lambda') * 1e-9 # m diam = CONFIG_PASTIS.getfloat('LUVOIR', 'diameter') # m wfe_aber = CONFIG_PASTIS.getfloat('LUVOIR', 'calibration_aberration') * 1e-9 # m # Image system parameters sampling = CONFIG_PASTIS.getfloat('LUVOIR', 'sampling') # Record some of the defined parameters log.info(f'LUVOIR apodizer design: {design}') log.info(f'Wavelength: {wvln} m') log.info(f'Telescope diameter: {diam} m') log.info(f'Number of segments: {nb_seg}') log.info(f'Sampling: {sampling} px per lambda/D') log.info(f'wfe_aber: {wfe_aber} m') # Copy configfile to resulting matrix directory util.copy_config(resDir) ### Instantiate Luvoir telescope with chosen apodizer design optics_input = CONFIG_PASTIS.get('LUVOIR', 'optics_path') luvoir = LuvoirAPLC(optics_input, design, sampling) ### Reference images for contrast normalization and coronagraph floor unaberrated_coro_psf, ref = luvoir.calc_psf(ref=True, display_intermediate=False, return_intermediate=False) norm = np.max(ref) dh_intensity = (unaberrated_coro_psf / norm) * luvoir.dh_mask contrast_floor = np.mean(dh_intensity[np.where(luvoir.dh_mask != 0)]) log.info(f'contrast floor: {contrast_floor}') ### Generating the PASTIS matrix and a list for all contrasts contrast_matrix = np.zeros([nb_seg, nb_seg]) # Generate empty matrix all_psfs = [] all_contrasts = [] for i in range(nb_seg): for j in range(nb_seg): log.info(f'\nSTEP: {i+1}-{j+1} / {nb_seg}-{nb_seg}') # Put aberration on correct segments. If i=j, apply only once! luvoir.flatten() luvoir.set_segment(i+1, wfe_aber/2, 0, 0) if i != j: luvoir.set_segment(j+1, wfe_aber/2, 0, 0) log.info('Calculating coro image...') image, inter = luvoir.calc_psf(ref=False, display_intermediate=False, return_intermediate='intensity') # Normalize PSF by reference image psf = image / norm all_psfs.append(psf.shaped) # Save image to disk if savepsfs: # TODO: I might want to change this to matplotlib images since I save the PSF cube anyway. filename_psf = f'psf_{zern_mode.name}_{zern_mode.convention + str(zern_mode.index)}_segs_{i+1}-{j+1}' hcipy.write_fits(psf, os.path.join(resDir, 'psfs', filename_psf + '.fits')) # Save OPD images for testing if saveopds: opd_name = f'opd_{zern_mode.name}_{zern_mode.convention + str(zern_mode.index)}_segs_{i+1}-{j+1}' plt.clf() hcipy.imshow_field(inter['seg_mirror'], mask=luvoir.aperture, cmap='RdBu') plt.savefig(os.path.join(resDir, 'OTE_images', opd_name + '.pdf')) log.info('Calculating mean contrast in dark hole') dh_intensity = psf * luvoir.dh_mask contrast = np.mean(dh_intensity[np.where(luvoir.dh_mask != 0)]) log.info(f'contrast: {float(contrast)}') # contrast is a Field, here casting to normal float all_contrasts.append(contrast) # Fill according entry in the matrix and subtract baseline contrast contrast_matrix[i,j] = contrast - contrast_floor # Transform saved lists to arrays all_psfs = np.array(all_psfs) all_contrasts = np.array(all_contrasts) # Save the PSF image *cube* as well (as opposed to each one individually) hcipy.write_fits(all_psfs, os.path.join(resDir, 'psfs', 'psf_cube.fits'),) np.savetxt(os.path.join(resDir, 'pair-wise_contrasts.txt'), all_contrasts, fmt='%e') # Filling the off-axis elements log.info('\nCalculating off-axis matrix elements...') matrix_two_N = np.copy(contrast_matrix) # This is just an intermediary copy so that I don't mix things up. matrix_pastis = np.copy(contrast_matrix) # This will be the final PASTIS matrix. for i in range(nb_seg): for j in range(nb_seg): if i != j: matrix_off_val = (matrix_two_N[i,j] - matrix_two_N[i,i] - matrix_two_N[j,j]) / 2. matrix_pastis[i,j] = matrix_off_val log.info(f'Off-axis for i{i+1}-j{j+1}: {matrix_off_val}') # Normalize matrix for the input aberration - this defines what units the PASTIS matrix will be in. The PASTIS # matrix propagation function (util.pastis_contrast()) then needs to take in the aberration vector in these same # units. I have chosen to keep this to 1nm, so, we normalize the PASTIS matrix to units of nanometers. matrix_pastis /= np.square(wfe_aber * 1e9) # 1e9 converts the calibration aberration back to nanometers # Save matrix to file filename_matrix = f'PASTISmatrix_num_{zern_mode.name}_{zern_mode.convention + str(zern_mode.index)}' hcipy.write_fits(matrix_pastis, os.path.join(resDir, filename_matrix + '.fits')) log.info(f'Matrix saved to: {os.path.join(resDir, filename_matrix + ".fits")}') # Tell us how long it took to finish. end_time = time.time() log.info(f'Runtime for matrix_building.py: {end_time - start_time}sec = {(end_time - start_time) / 60}min') log.info(f'Data saved to {resDir}') return overall_dir
def num_matrix_luvoir(design): """ Generate a numerical PASTIS matrix for a LUVOIR A coronagraph. All inputs are read from the (local) configfile and saved to the specified output directory. The LUVOIR STDT delivery in May 2018 included three different apodizers we can work with, so I will implement an easy way of making a choice between them. small, medium and large """ # Keep track of time start_time = time.time() # runtime is currently around 150 minutes print('Building numerical matrix for LUVOIR\n') ### Parameters # System parameters resDir = os.path.join(CONFIG_INI.get('local', 'local_data_path'), 'active', 'matrix_numerical') zern_number = CONFIG_INI.getint('calibration', 'zernike') zern_mode = util.ZernikeMode( zern_number) # Create Zernike mode object for easier handling # General telescope parameters nb_seg = CONFIG_INI.getint('LUVOIR', 'nb_subapertures') wvln = CONFIG_INI.getfloat('LUVOIR', 'lambda') * 1e-9 # m diam = CONFIG_INI.getfloat('LUVOIR', 'diameter') # m nm_aber = CONFIG_INI.getfloat('calibration', 'single_aberration') * 1e-9 # m # Image system parameters im_lamD = 30 # image size in lambda/D sampling = 4 # Print some of the defined parameters print('LUVOIR apodizer design: {}'.format(design)) print() print('Wavelength: {} m'.format(wvln)) print('Telescope diameter: {} m'.format(diam)) print('Number of segments: {}'.format(nb_seg)) print() print('Image size: {} lambda/D'.format(im_lamD)) print('Sampling: {} px per lambda/D'.format(sampling)) ### Setting up the paths # If subfolder "matrix_numerical" doesn't exist yet, create it. if not os.path.isdir(resDir): os.mkdir(resDir) # If subfolder "OTE_images" doesn't exist yet, create it. if not os.path.isdir(os.path.join(resDir, 'OTE_images')): os.mkdir(os.path.join(resDir, 'OTE_images')) # If subfolder "psfs" doesn't exist yet, create it. if not os.path.isdir(os.path.join(resDir, 'psfs')): os.mkdir(os.path.join(resDir, 'psfs')) ### Instantiate Luvoir telescope with chosen apodizer design optics_input = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/' luvoir = LuvoirAPLC(optics_input, design, sampling) ### Dark hole mask dh_outer = hc.circular_aperture(2 * luvoir.apod_dict[design]['owa'] * luvoir.lam_over_d)(luvoir.focal_det) dh_inner = hc.circular_aperture(2 * luvoir.apod_dict[design]['iwa'] * luvoir.lam_over_d)(luvoir.focal_det) dh_mask = (dh_outer - dh_inner).astype('bool') ### Reference images for contrast normalization and coronagraph floor unaberrated_coro_psf, ref = luvoir.calc_psf(ref=True, display_intermediate=False, return_intermediate=False) norm = np.max(ref) dh_intensity = unaberrated_coro_psf / norm * dh_mask contrast_floor = np.mean(dh_intensity[np.where(dh_intensity != 0)]) print(contrast_floor) ### Generating the PASTIS matrix and a list for all contrasts matrix_direct = np.zeros([nb_seg, nb_seg]) # Generate empty matrix all_psfs = [] all_contrasts = [] print('nm_aber: {} m'.format(nm_aber)) for i in range(nb_seg): for j in range(nb_seg): print('\nSTEP: {}-{} / {}-{}'.format(i + 1, j + 1, nb_seg, nb_seg)) # Put aberration on correct segments. If i=j, apply only once! luvoir.flatten() luvoir.set_segment(i + 1, nm_aber / 2, 0, 0) if i != j: luvoir.set_segment(j + 1, nm_aber / 2, 0, 0) print('Calculating coro image...') image, inter = luvoir.calc_psf(ref=False, display_intermediate=False, return_intermediate='intensity') # Normalize PSF by reference image psf = image / norm # Save image to disk filename_psf = 'psf_' + zern_mode.name + '_' + zern_mode.convention + str( zern_mode.index) + '_segs_' + str(i + 1) + '-' + str(j + 1) hc.write_fits(psf, os.path.join(resDir, 'psfs', filename_psf + '.fits')) all_psfs.append(psf) # Save OPD images for testing (are these actually surface images, not OPD?) opd_name = 'opd_' + zern_mode.name + '_' + zern_mode.convention + str( zern_mode.index) + '_segs_' + str(i + 1) + '-' + str(j + 1) plt.clf() hc.imshow_field(inter['seg_mirror'], mask=luvoir.aperture, cmap='RdBu') plt.savefig(os.path.join(resDir, 'OTE_images', opd_name + '.pdf')) print('Calculating mean contrast in dark hole') dh_intensity = psf * dh_mask contrast = np.mean(dh_intensity[np.where(dh_intensity != 0)]) print('contrast:', contrast) all_contrasts.append(contrast) # Fill according entry in the matrix and subtract baseline contrast matrix_direct[i, j] = contrast - contrast_floor # Transform saved lists to arrays all_psfs = np.array(all_psfs) all_contrasts = np.array(all_contrasts) # Filling the off-axis elements matrix_two_N = np.copy( matrix_direct ) # This is just an intermediary copy so that I don't mix things up. matrix_pastis = np.copy( matrix_direct) # This will be the final PASTIS matrix. for i in range(nb_seg): for j in range(nb_seg): if i != j: matrix_off_val = (matrix_two_N[i, j] - matrix_two_N[i, i] - matrix_two_N[j, j]) / 2. matrix_pastis[i, j] = matrix_off_val print('Off-axis for i{}-j{}: {}'.format( i + 1, j + 1, matrix_off_val)) # Normalize matrix for the input aberration - the whole code is set up to be normalized to 1 nm, and even if # the units entered are in m for the sake of HCIPy, everything else is assuming the baseline is 1nm, so the # normalization can be taken out if we're working with exactly 1 nm for the aberration, even if entered in meters. #matrix_pastis /= np.square(nm_aber) # Save matrix to file filename_matrix = 'PASTISmatrix_num_' + zern_mode.name + '_' + zern_mode.convention + str( zern_mode.index) hc.write_fits(matrix_pastis, os.path.join(resDir, filename_matrix + '.fits')) print('Matrix saved to:', os.path.join(resDir, filename_matrix + '.fits')) # Save the PSF image *cube* as well (as opposed to each one individually) hc.write_fits( all_psfs, os.path.join(resDir, 'psfs', 'psf_cube' + '.fits'), ) np.savetxt(os.path.join(resDir, 'contrasts.txt'), all_contrasts, fmt='%e') # Tell us how long it took to finish. end_time = time.time() print('Runtime for matrix_building.py:', end_time - start_time, 'sec =', (end_time - start_time) / 60, 'min') print('Data saved to {}'.format(resDir))
def clean_vapp(): import numpy as np import matplotlib.pyplot as plt from hcipy import read_fits, make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront script_path = os.path.realpath(__file__).split("vApp_reduction", 1)[0] full_path = script_path + "vApp_reduction/data/" amplitude_file = full_path + 'SCExAO_vAPP_amplitude_resampled.fits' phase_file = full_path + 'SCExAO_vAPP_phase_resampled.fits' # loading the files required for generating the vAPP. amplitude_temp = read_fits(amplitude_file) phase_temp = read_fits(phase_file) # number of pixels along one axis in the pupil Npix = amplitude_temp.shape[0] # generating the grids pupil_grid = make_pupil_grid(Npix) focal_grid = make_focal_grid(pupil_grid, 4, 25) # Mapping from pupil plane to focal plane propagator = FraunhoferPropagator(pupil_grid, focal_grid) # converting the amplitude and phase to fields amplitude = Field(amplitude_temp.ravel(), pupil_grid) phase = Field(phase_temp.ravel(), pupil_grid) # the wavefront for the three PSFs pupil_wf_PSF_1 = Wavefront(amplitude * np.exp(1j * phase)) # coronagraphic PSF 1 pupil_wf_PSF_2 = Wavefront(amplitude * np.exp(-1j * phase)) # coronagraphic PSF 2 pupil_wf_PSF_3 = Wavefront(amplitude) # leakage # Propagating them to the focal plane focal_wf_PSF_1 = propagator(pupil_wf_PSF_1) focal_wf_PSF_2 = propagator(pupil_wf_PSF_2) focal_wf_PSF_3 = propagator(pupil_wf_PSF_3) # setting the total power in the images focal_wf_PSF_1.total_power = 1 focal_wf_PSF_2.total_power = 1 focal_wf_PSF_3.total_power = 1 # the strenght of the leakage term leakage = 0.02 # getting the power and scaling with leakage PSF_1_pwr = focal_wf_PSF_1.power * (1 - leakage / 2) PSF_2_pwr = focal_wf_PSF_2.power * (1 - leakage / 2) PSF_3_pwr = focal_wf_PSF_3.power * leakage # generating the total PSF of the vAPP total_PSF = PSF_1_pwr + PSF_2_pwr + PSF_3_pwr # normalizing to sum = 1 total_PSF /= np.sum(total_PSF) fig = plt.figure() imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") plt.show() output_path = get_output_path("miscellaneous") fig.savefig(output_path + "clean_vapp") fig = plt.figure() imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0) bbox_props = dict(boxstyle="circle,pad=0.3", fill=False, alpha=1, fc=None, ec="red", lw=5) plt.text(10.3, 10.7, " ", ha="center", va="center", rotation=45, size=110, bbox=bbox_props) plt.text(-10.3, -10.7, " ", ha="center", va="center", rotation=45, size=110, bbox=bbox_props) bbox_props = dict(boxstyle="circle,pad=0.3", fill=False, alpha=1, fc=None, ec="white", lw=5) plt.text(0, 0, " ", ha="center", va="center", rotation=45, size=55, bbox=bbox_props) plt.text(8, -15, " ", ha="center", va="center", rotation=45, size=55, bbox=bbox_props) plt.text(-8, 15, " ", ha="center", va="center", rotation=45, size=55, bbox=bbox_props) cbar = plt.colorbar() cbar.set_label(r"$^{10}\log(contrast)$") plt.ylabel(r"$\lambda/D$") plt.xlabel(r"$\lambda/D$") plt.show() output_path = get_output_path("miscellaneous") fig.savefig(output_path + "clean_vapp_annotated")
u, avg, s = tele.run_closed_loop(leak, gain, fileout, run_for, freq, save_every, wl=wl) print(s) plt.imshow(np.abs(u)) plt.show() #planar wf masked by aperture wf = tele.wf_pupil_hires hc.imshow_field(wf.electric_field) plt.show() #turbulence induced abberation wf = tele.propagate_through_turb(wf) hc.imshow_field(wf.electric_field) plt.show() #partial AO correction wf = tele.DM_hires.forward(wf) hc.imshow_field(wf.electric_field) plt.show() #beam shrinking
array = np.array([[0.0]*N]*N) for i in range(0,N): for j in range (0, N): x = abs(int(N/2) - i) y = abs(int(N/2) - j) r = np.sqrt(x**2 + y**2) if r < 3.5*N/16 and r > 2*N/16: array[i][j] = 1.0 array_flat = array.flatten() return hcipy.Field(array_flat, focal_grid) annulus = make_FPM(focal_grid) hcipy.imshow_field(annulus) plt.show() # In[100]: def score_matrix3(aberrations, show=False): # Make segmented mirror aper, segments = hcipy.make_hexagonal_segmented_aperture(num_rings, segment_flat_to_flat, gap_size, starting_ring=1, return_segments=True)