def __init__(self, electric_field, wavelength=1, input_stokes_vector=None, pad_factor=1): shape = electric_field.shaped.shape assert shape[0] == shape[1], "simulation region must be square!" assert shape[ 0] % 2 == 0, "simulation region must be an even number of pixels across!" res = shape[0] new_field = np.pad(electric_field.shaped, int(res * (pad_factor - 1) / 2)).flatten() self.radius = electric_field.grid[-1, 0] self.total_radius = self.radius * pad_factor self.pad_factor = pad_factor self.beam_res = res self.res = pad_factor * res padded_electric_field = hc.Field( new_field, hc.make_pupil_grid(pad_factor * res, 2 * pad_factor * self.radius)) super().__init__(padded_electric_field, wavelength, input_stokes_vector)
def remove_pad(wf, pad): res = wf.electric_field.shaped.shape[0] radius = wf.electric_field.grid[-1, 0] beamres = int(res / pad) padpix = int((pad - 1) * beamres / 2) field = wf.electric_field.shaped[padpix:-padpix, padpix:-padpix] grid = hc.make_pupil_grid(beamres, 2 * radius) return hc.Wavefront(hc.Field(field.flatten(), grid), wavelength=wf.wavelength)
def full_modes_from_file(datadir): """ Read all modes into an array of hcipy.Fields and an array of 2D arrays. :param datadir: string, path to overall data directory containing matrix and results folder :return: all_modes as array of Fields, mode_cube as array of 2D arrays (hcipy vs matplotlib) """ mode_cube = hc.read_fits( os.path.join(datadir, 'results', 'modes', 'fits', 'cube_modes.fits')) all_modes = hc.Field(mode_cube.ravel()) return all_modes, mode_cube
def apply_coef(self): """ Apply the DM shape from its own segment coefficients to make segmented mirror surface. """ self._setup_grids() keep_surf = np.zeros_like(self._seg_x) for i in self.segmentlist: wseg = self._seg_indices[i] keep_surf[wseg] = (self._coef[i - 1, 0] + self._coef[i - 1, 1] * self._seg_x[wseg] + self._coef[i - 1, 2] * self._seg_y[wseg]) return hcipy.Field(keep_surf, self.input_grid)
def make_FPM(focal_grid, N=focal_number): 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)
def read_atm(fname, grid, aper, Hz=Hz): atm_frames = np.load(fname) #The resultant numpy array is 2D where axis=0 is the time step and axis=1 is the # spatial info of the phase that got flattened by HCIPy. If you want to avoid using # the hci.Field and pupil stuff, you get the correct shaping by calling # np.reshape(atm_frames[tstep], (100,100)) #(num_pupil_pixels,num_pup_pix) phase_frames = [] #wf_frames = [] times = np.arange(1, atm_frames.shape[0] + 1) / Hz for ind in range(atm_frames.shape[0]): phase = hci.Field(atm_frames[ind], grid) phase_frames.append(phase) #wf_frames.append(make_wf(phase, aper)) return times, phase_frames #,wf_frames
def coupling_vs_r_pupilplane_single(tele: AOtele.AOtele, pupilfields, rcore, ncore, nclad, wl0): k0 = 2 * np.pi / wl0 fieldshape = pupilfields[0].shape #need to generate the available modes V = LPmodes.get_V(k0, rcore, ncore, nclad) modes = LPmodes.get_modes(V) lpfields = [] for mode in modes: if mode[0] == 0: lpfields.append( normalize( LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0, ncore, nclad))) else: lpfields.append( normalize( LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0, ncore, nclad, "cos"))) lpfields.append( normalize( LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0, ncore, nclad, "sin"))) lppupilfields = [] #then backpropagate for field in lpfields: wf = hc.Wavefront(hc.Field(field.flatten(), tele.focalgrid), wavelength=wl0 * 1.e-6) pupil_wf = tele.back_propagate(wf, True) lppupilfields.append(pupil_wf.electric_field.reshape(fieldshape)) lppupilfields = np.array(lppupilfields) pupilfields = np.array(pupilfields) #compute total overlap powers = np.sum(pupilfields * lppupilfields, axes=(1, 2)) return np.mean(powers), np.stddev(powers)
def _inner_(wf): _power = wf.total_power reals, imags = wf.real, wf.imag reals = np.reshape(reals, (self.hi_pupil_res, self.hi_pupil_res)) imags = np.reshape(imags, (self.hi_pupil_res, self.hi_pupil_res)) if self.hi_pupil_res != col_res: reals = resize2(reals, (col_res, col_res)).flatten() imags = resize2(imags, (col_res, col_res)).flatten() else: reals = reals.flatten() imags = imags.flatten() new_wf = hc.Wavefront( hc.Field(reals + 1.j * imags, self.collimator_grid), wf.wavelength) # make sure power is conserved new_wf.total_power = _power return new_wf
def field_from_array(arr, *axes): grid = hcipy_grid_from_axes(*axes) return hcipy.Field(arr.ravel(), grid)
def __init__(self, diameter, fnum, wavelength, num_DM_acts=30, wavelength_0=None, obstr_frac=0.242): if wavelength_0 is None: wavelength_0 = wavelength self.reference_wavelength = wavelength_0 self.diameter = diameter self.fnum = fnum self.num_acts = num_DM_acts self.obstr_frac = obstr_frac self.wavelength = wavelength ## setting up low and high res pupil grids. the low res grid is used for to only calibrate/control the DM num_pupil_pixels = self.low_pupil_res pupil_pixel_samps = self.low_pupil_res * 0.95 #the keck pupil fits seems be padded with zeros around border by ~5% self.pupil_plane_res = (num_pupil_pixels, num_pupil_pixels) pupil_grid_diam = diameter * num_pupil_pixels / pupil_pixel_samps self.pupil_grid_diam = pupil_grid_diam self.pupil_sample_rate = pupil_grid_diam / num_pupil_pixels self.pupil_grid = hc.make_pupil_grid(self.low_pupil_res, diameter=pupil_grid_diam) self.pupil_grid_hires = hc.make_pupil_grid(self.hi_pupil_res, diameter=pupil_grid_diam) ## now set up the actual pupil fields keck_pupil_hires = np.array( fits.open("pupil_KECK_high_res.fits")[0].data, dtype=np.float32) ap_arr = resize2(keck_pupil_hires, (self.low_pupil_res, self.low_pupil_res)) ap_arr_hires = resize2(keck_pupil_hires, (self.hi_pupil_res, self.hi_pupil_res)) self.ap = hc.Field(ap_arr.flatten(), self.pupil_grid) self.ap_hires = hc.Field(ap_arr_hires.flatten(), self.pupil_grid_hires) ## we need to make two DMs, one sampled on the low res pupil grid and another on the hi res pupil grid act_spacing = diameter / num_DM_acts influence_funcs = hc.make_gaussian_influence_functions( self.pupil_grid, num_DM_acts, act_spacing) self.DM = hc.DeformableMirror(influence_funcs) influence_funcs_hires = hc.make_gaussian_influence_functions( self.pupil_grid_hires, num_DM_acts, act_spacing) self.DM_hires = hc.DeformableMirror(influence_funcs_hires) ## make the rest of our optics (besides PIAA/collimator) self.pwfs = hc.PyramidWavefrontSensorOptics(self.pupil_grid, wavelength_0=wavelength_0) self.detector = hc.NoiselessDetector() self.dt = 1 #integration time in seconds (?) ## focal grid set up. linear resolution in pixels is 2 * q * num_airy self.focal_grid = hc.make_focal_grid(q=16 * 2, num_airy=16, f_number=fnum, reference_wavelength=wavelength_0) self.ref_image = None self.rmat = None ## pupil -> focal and focal -> pupil propagators self.propagator = hc.FraunhoferPropagator(self.pupil_grid, self.focal_grid, focal_length=diameter * fnum) self.propagator_backward = hc.FraunhoferPropagator( self.focal_grid, self.pupil_grid, focal_length=-diameter * fnum) ## misc other stuff that is useful to cache/save self.t_arr = None self.DMshapes = None self.psgen = None self.apodize = None self.apodize_backwards = None self.collimate = None self.collimator_grid = None self.current_phase_screen = None self.wf_pupil, self.wf_pupil_hires, self.wf_focal = None, None, None self.PIAA_args, self.col_args = None, None
print('Setting up optics...') print('Data folder: {}'.format(workdir)) print('Coronagraph: {}'.format(apodizer_design)) # Create SM # Read pupil and indexed pupil inputdir = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/' aper_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000.fits' aper_ind_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000_indexed.fits' aper_read = hc.read_fits(os.path.join(inputdir, aper_path)) aper_ind_read = hc.read_fits(os.path.join(inputdir, aper_ind_path)) # Sample them on a pupil grid and make them hc.Fields pupil_grid = hc.make_pupil_grid(dims=aper_ind_read.shape[0], diameter=15) aper = hc.Field(aper_read.ravel(), pupil_grid) aper_ind = hc.Field(aper_ind_read.ravel(), pupil_grid) # Create the wavefront on the aperture wf_aper = hc.Wavefront(aper, wvln) # Load segment positions from fits header hdr = fits.getheader(os.path.join(inputdir, aper_ind_path)) poslist = [] for i in range(nseg): segname = 'SEG' + str(i + 1) xin = hdr[segname + '_X'] yin = hdr[segname + '_Y'] poslist.append((xin, yin)) poslist = np.transpose(np.array(poslist)) seg_pos = hc.CartesianGrid(poslist)
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 func(grid): res = segmented_aperture(grid) return hcipy.Field(res, grid)
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)
sep = 0.12 #10 IOR = 1.48 #acrylic at 1 um res = 600 #600 seems to be the critical value pad = 1 pupil_grid = hc.make_pupil_grid(res, 2 * radius) r1, r2 = make_remapping_gauss_annulus(res, 0.23, 0, 3) z1, z2 = make_PIAA_lenses(r1 * radius, r2 * radius, IOR, IOR, sep) ## fix radius dependence here! apodizer = fresnel_apodizer(pupil_grid, sep, pad, r1, r2, z1, z2, IOR, IOR) keck_pupil_hires = np.array(fits.open("pupil_KECK_high_res.fits")[0].data, dtype=np.float32) ap_arr = resize2(keck_pupil_hires, (res, res)).flatten() ap = hc.Field(ap_arr, pupil_grid) plt.imshow(ap.real.reshape((600, 600))) plt.show() wf = PaddedWavefront(ap, wavelength=1.e-6, pad_factor=pad) wf.total_power = 1 * pad * pad wf = apodizer(wf) #hc.imshow_field(wf.electric_field) #plt.show() p = wf.power.reshape(pad * res, pad * res) fig, ax = plt.subplots(figsize=(4, 4)) ax.axis("off") plt.xlim(-radius, radius)
def __init__(self, input_dir, apod_design, samp): self.nseg = 120 self.wvln = 638e-9 # m self.diam = 15. # m self.sampling = samp self.lam_over_d = self.wvln / self.diam self.apod_dict = { 'small': { 'pxsize': 1000, 'fpm_rad': 3.5, 'fpm_px': 150, 'iwa': 3.4, 'owa': 12., 'fname': '0_LUVOIR_N1000_FPM350M0150_IWA0340_OWA01200_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits' }, 'medium': { 'pxsize': 1000, 'fpm_rad': 6.82, 'fpm_px': 250, 'iwa': 6.72, 'owa': 23.72, 'fname': '0_LUVOIR_N1000_FPM682M0250_IWA0672_OWA02372_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits' }, 'large': { 'pxsize': 1000, 'fpm_rad': 13.38, 'fpm_px': 400, 'iwa': 13.28, 'owa': 46.88, 'fname': '0_LUVOIR_N1000_FPM1338M0400_IWA1328_OWA04688_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits' } } self.imlamD = 1.2 * self.apod_dict[apod_design]['owa'] # Pupil plane optics aper_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000.fits' aper_ind_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000_indexed.fits' apod_path = os.path.join(input_dir, 'luvoir_stdt_baseline_bw10', apod_design + '_fpm', 'solutions', self.apod_dict[apod_design]['fname']) ls_fname = 'inputs/LS_LUVOIR_ID0120_OD0982_no_struts_gy_ovsamp4_N1000.fits' pup_read = hc.read_fits(os.path.join(input_dir, aper_path)) aper_ind_read = hc.read_fits(os.path.join(input_dir, aper_ind_path)) apod_read = hc.read_fits(os.path.join(input_dir, apod_path)) ls_read = hc.read_fits(os.path.join(input_dir, ls_fname)) pupil_grid = hc.make_pupil_grid( dims=self.apod_dict[apod_design]['pxsize'], diameter=self.diam) self.aperture = hc.Field(pup_read.ravel(), pupil_grid) self.aper_ind = hc.Field(aper_ind_read.ravel(), pupil_grid) self.apod = hc.Field(apod_read.ravel(), pupil_grid) self.ls = hc.Field(ls_read.ravel(), pupil_grid) # Load segment positions from fits header hdr = fits.getheader(os.path.join(input_dir, aper_ind_path)) poslist = [] for i in range(self.nseg): segname = 'SEG' + str(i + 1) xin = hdr[segname + '_X'] yin = hdr[segname + '_Y'] poslist.append((xin, yin)) poslist = np.transpose(np.array(poslist)) self.seg_pos = hc.CartesianGrid(poslist) # Focal plane mask samp_foc = self.apod_dict[apod_design]['fpm_px'] / ( self.apod_dict[apod_design]['fpm_rad'] * 2) focal_grid_fpm = hc.make_focal_grid( pupil_grid=pupil_grid, q=samp_foc, num_airy=self.apod_dict[apod_design]['fpm_rad'], wavelength=self.wvln) self.fpm = 1 - hc.circular_aperture( 2 * self.apod_dict[apod_design]['fpm_rad'] * self.lam_over_d)(focal_grid_fpm) # Final focal plane grid (detector) self.focal_det = hc.make_focal_grid(pupil_grid=pupil_grid, q=self.sampling, num_airy=self.imlamD, wavelength=self.wvln) luvoir_params = { 'wavelength': self.wvln, 'diameter': self.diam, 'imlamD': self.imlamD, 'fpm_rad': self.apod_dict[apod_design]['fpm_rad'] } # Initialize the general segmented telescope with APLC class, includes the SM super().__init__(aper=self.aperture, indexed_aperture=self.aper_ind, seg_pos=self.seg_pos, apod=self.apod, lyotst=self.ls, fpm=self.fpm, focal_grid=self.focal_det, params=luvoir_params) # Propagators self.coro = hc.LyotCoronagraph(pupil_grid, self.fpm, self.ls) self.prop = hc.FraunhoferPropagator(pupil_grid, self.focal_det) self.coro_no_ls = hc.LyotCoronagraph(pupil_grid, self.fpm)