def run_timestep(self, t): self.kwargs['iter'] = t return proper.prop_run(tp.prescription, 1, sp.grid_size, PASSVALUE=self.kwargs, QUIET=True)
def generate_images(zern, opt): pix_size = opt.pixel_size height = opt.sensor_height() beam_ratio = 0.5 npix = int(height / beam_ratio / pix_size) #number of pixels that the grid should span gridsize = 512 setting = { 'ZERN': zern.at_wavelength(opt.wavelength), 'DEFOCUS': opt.defocus, 'diam': opt.aperature, 'focal_length': opt.focal_length, 'beam_ratio': beam_ratio } #add the prescriptions to the path sys.path.append(os.path.dirname(os.path.abspath(__file__))) #run the optical simulation pre_im, sampling = proper.prop_run('prefocal_image', opt.wavelength_as_um(), gridsize, PASSVALUE=setting, QUIET=True) pos_im, sampling = proper.prop_run('postfocal_image', opt.wavelength_as_um(), gridsize, PASSVALUE=setting, QUIET=True) #invert postfocal image pos_im = [[ pos_im[gridsize - y - 1][gridsize - x - 1] for x in range(gridsize) ] for y in range(gridsize)] #Discretize according to the distance of the camera pre_im = cv2.resize(np.array(pre_im), (npix, npix)) pos_im = cv2.resize(np.array(pos_im), (npix, npix)) #Correct weird offset from proper (NOTE: Work in progress, may not be accurate for defocus != 1e-3 M = np.float32([[1, 0, -0.01513], [0, 1, -0.01513]]) pos_im = cv2.warpAffine(pos_im, M, pos_im.shape) return pre_im, pos_im
def gen_timeseries(self): """ Time loop wrapper for prescriptions. :param inqueue: time index for parallelization (used by multiprocess) :param out_queue: series of intensity images (spectral image cube) in the multiprocessing format :return: returns the observation sequence, but through the multiprocessing tools, not through more standard return protocols. :timestep_field is the complex-valued E-field in the planes specified by sp.save_list. has shape [timestep, planes, wavelength, objects, x, y] :sampling is the final sampling per wavelength in the focal plane """ start = time.time() for it, t in enumerate(iter(self.time_idx.get, sentinel)): kwargs = {'iter': t, 'params': [iop, sp, ap, tp, cdip]} timestep_field, sampling = proper.prop_run(tp.prescription, 1, sp.grid_size, PASSVALUE=kwargs, VERBOSE=False, TABLE=False) # 1 is dummy wavelength chunk_ind = it % self.chunk_steps self.fields_chunk[chunk_ind] = timestep_field self.seen_substeps[chunk_ind] = 1 chunk_seen = np.all(self.seen_substeps) final_chunk_seen = it == sp.numframes-1 and np.all(self.seen_substeps[:self.final_chunk_size]) while (chunk_ind == self.chunk_steps-1 and not chunk_seen) or \ (chunk_ind == self.final_chunk_size-1 and not final_chunk_seen): print(f'Waiting for chunk {it//self.chunk_steps} to finish being poplulated before saving') #if sp.verbose time.sleep(1) if chunk_seen or final_chunk_seen: # chunk completed or simulation finished self.out_chunk.put((self.fields_chunk, sampling)) if sp.save_to_disk: self.save(self.fields_chunk, sampling) if sp.debug: view_spectra(np.sum(np.abs(self.fields_chunk) ** 2, axis=(0, 1))[:, 0], title='Chunk Spectral Cube') self.init_fields_chunk() now = time.time() elapsed = float(now - start) each_iter = float(elapsed) / (sp.numframes + 1) print('***********************************') print(f'{elapsed/60.:.2f} minutes elapsed, each time step took {each_iter:.2f} minutes')
def generate(self): self.telescope = auto_load(Telescope) self.cpx_sequence = np.zeros((self.sp.numframes, len(self.sp.save_list), self.ap.n_wvl_init, 1 + len(self.ap.contrast), self.sp.grid_size, self.sp.grid_size), dtype=np.complex) for t in range(self.sp.numframes): kwargs = {'iter': t, 'params': [self.ap, self.tp, self.iop, self.sp], 'theta': self.cdip.theta_series[t]} self.cpx_sequence[t], self.sampling = proper.prop_run(self.tp.prescription, 1, self.sp.grid_size, PASSVALUE=kwargs, VERBOSE=False, TABLE=False) # 1 is dummy wavelength return self.cpx_sequence, self.sampling
def form_multi_psf(prescription, sources, gridsize, common_sampling, npsf, multi=True): source_psfs = [] for source in sources: settings = source['settings'] wavelengths = source['wavelengths'] wl_weights = source['weights'] if multi is True: (wavefronts, samplings) = proper.prop_run_multi(prescription, wavelengths, gridsize=gridsize, QUIET=True, PRINT_INTENSITY=False, PASSVALUE=settings) # prop_run_multi returns complex arrays, even when PSFs are intensity, so make real with abs psfs = normalise_sampling(np.abs(wavefronts), samplings, common_sampling, npsf) else: wavefronts = [] samplings = [] for wl in wavelengths: (wavefront, sampling) = proper.prop_run(prescription, wl, gridsize=gridsize, QUIET=True, PRINT_INTENSITY=False, PASSVALUE=settings) wavefronts.append(wavefront) samplings.append(sampling) psfs = normalise_sampling(wavefronts, samplings, common_sampling, npsf) source_psfs.append(combine_psfs(psfs, wl_weights)) psf_all = combine_psfs(np.stack(source_psfs), [1. for i in range(len(source_psfs))]) return psf_all
def cdi_postprocess(fp_seq, cdi_zip, map_dir=None, plot=False, debug=False): """ this is the function that accepts the timeseries of intensity images from the simulation and returns the processed single image. This function calculates the speckle amplitude phase, and then corrects for it to create the dark hole over the specified region of the image. :param fp_seq: focal plane sequence (temporal cube) [nx, ny, time] :param cdi_zip: cdi_zipdata from .pkl file from DM settings and timestream created at runtime :param map_dir: directory where the DM telemetry data (generated by scexaortc) is stored :param plot: toggle to display plots or not :return: nothing, lots of plots though """ ## print(f'\nStarting CDI post-processing') st = time.time() nx = fp_seq.shape[1] # size of MEC images ny = fp_seq.shape[2] dm_act = cdi_zip.probe.DM_cmd_cycle.shape[-1] # number of DM actuators n_pairs = cdi_zip.ts.n_probes // 2 # number of deltas (probe differentials) n_nulls = int(cdi_zip.ts.null_time / cdi_zip.ts.phase_integration_time) n_cycles = cdi_zip.ts.n_cycles n_probes = cdi_zip.ts.n_probes # MEC Probe Commands (removes flat (null step) commands ) msk = np.tile(np.append(np.repeat(True, n_probes), False), n_cycles) # there is no beginning 'flat' command cmds_probe_only = cdi_zip.ts.cmd_tstamps[msk] cmds_nulls_only = cdi_zip.ts.cmd_tstamps[~msk] # # Sorting fp_seq if 'irreg' in datf: # Each 'null' step is much longer in time than the probe commands; matches the format of the probe timesteps # since the null was sent with a single flat command and lasts the length of a null as determined by mec_cdi.py reg_msk = msk else: # this assumes fp_seq was created with the null steps spaced out over time via photontable.temporal cube # regular bins in read_photons.py. Must reformat mask if there is one large null step, as in irreg_bins reg_msk = np.tile(np.append(np.repeat(True, n_probes), np.repeat(False, n_nulls)), n_cycles) # raise ValueError(f'No longer working for regular binned data, use irreg instead') if len(reg_msk) > fp_seq.shape[0]: # h5 might be cutoff mid-cycle if the dataset was long reg_msk = reg_msk[0:fp_seq.shape[0]] mec_probed = fp_seq[ reg_msk] mec_nulls = fp_seq[~reg_msk] intensity_counter(mec_probed, mec_nulls) # Define arrays for sorting probe vs null steps sim_grid = 256 # phase propagation simulation grid size nxn extracted = [nx,ny] probe_tstamps = np.zeros((len(cmds_probe_only))) probe_maps = np.zeros((len(cmds_probe_only), dm_act, dm_act)) null_tstamps = np.zeros((len(cmds_nulls_only))) null_maps = np.zeros((len(cmds_nulls_only), dm_act, dm_act)) ## Loading or simulating DM voltage maps lst = time.time() # # Complex Map # fp_mask, edges = get_fp_mask(cdi_zip) # cl = LineCollection(edges, colors='r') if map_dir: # Load DM Telemetry Data => dm voltage maps saved by scexaortc (referred to as map) # cpx_dm_sim = np.zeros((len(cmds_probe_only), nx, ny), dtype=complex) # cpx_null_sim = np.zeros((len(cmds_nulls_only), nx, ny), dtype=complex) cpx_dm = np.zeros((len(cmds_probe_only), nx, ny), dtype=complex) cpx_null = np.zeros((len(cmds_nulls_only), nx, ny), dtype=complex) # Converting .txt string to Unix to compare with MEC command timestamp fn = sorted(os.listdir(map_dir)) txts = [x for x in fn if ".fits" not in x] tt = [x.replace('dm00disp_', '') for x in txts] # 'dm00disp03_' tt = [x.replace('.txt', '') for x in tt] ymd = cdi_zip.ts.cmd_tstamps[0].astype('datetime64[D]') ymd = ymd.astype('<U18') tt = [(ymd + 'T' + x) for x in tt] tt = [datetime_to_unix(np.datetime64(x)) for x in tt] # #--------------------- # Saving DM map that matches closest prior probe command flat = get_standard_flat(debug=False) # Probes for ix in range(len(cmds_probe_only)): # len(cmds_probe_only) map_ts, dm_map, ixsync = sync_tstep(ix, cmds_probe_only, txts, tt) probe_tstamps[ix] = map_ts[ixsync] probe_maps[ix] = dm_map[ixsync, :, :] # cpx_dm[ix] = basic_fft(dm_map[ixsync, :, :], nx, ny) cpx_dm[ix], smp = proper.prop_run('scexao_model', .9, sim_grid, # for some reason 0.9 gives 900 nm PASSVALUE={'map':probe_maps[ix]*1e-6, 'psf_size':extracted, 'verbose':debug, 'ix':ix}, QUIET=True) # Nulls for ix in range(len(cmds_nulls_only)): # len(cmds_nulls_only) map_ts, dm_map, ixsync = sync_tstep(ix, cmds_nulls_only, txts, tt) null_tstamps[ix] = map_ts[ixsync] null_maps[ix] = dm_map[ixsync, :, :]-flat # cpx_null[ix] = basic_fft(null_maps[ix], nx, ny) cpx_null[ix], smp = proper.prop_run('scexao_model', .9, sim_grid, # for some reason 0.9 gives 900 nm PASSVALUE={'map': null_maps[ix]*1e-6, 'psf_size':extracted, 'verbose':False, 'ix':ix}, QUIET=True) # # Rescaling to match MEC focal plane dimensions # for ix in range(cpx_dm_sim.shape[0]): # cpx_dm[ix] = resample_cpx(cpx_dm_sim[ix], nx, ny) # for ix in range(cpx_null_sim.shape[0]): # cpx_null[ix] = resample_cpx(cpx_null_sim[ix], nx, ny) elt = time.time() print( f'Phase propagation finished in {elt - lst:.1f} sec == {(elt - lst) / 60:.2f} min') else: # Just use the DM probe pattern as the voltage map cpx_all_sim = np.zeros((len(cdi_zip.probe.DM_cmd_cycle), extracted[0], extracted[1]), dtype=complex) cpx_all_1 = np.zeros((n_pairs*2+n_nulls, nx, ny), dtype=complex) cpx_all = np.zeros((len(reg_msk), nx, ny), dtype=complex) # flat = get_standard_flat(debug=False) # standard flat 900e-9/1e6 * flat = np.zeros((50,50),dtype=float) # empty # cos function # dmx, dmy = np.meshgrid( # np.linspace(-0.5, 0.5, 50), # np.linspace(-0.5, 0.5, 50)) # # xm = dmx * 12 * 2.0 * np.pi # ym = dmy * 2.0 * np.pi # flat = 1e-8*np.sin(xm) # # # Test Probe # x = np.linspace(-1/2 - 5/50, 1/2 - 5/50, 50, dtype=np.float32) # y = np.linspace(-1/2 - 5/50, 1/2 - 5/50, 50, dtype=np.float32) # X,Y = np.meshgrid(x,y) # flat = np.sinc(10 * X) * np.sinc(5 * Y) * np.cos(2 * np.pi * 10 * Y + np.pi/4) # complex of all maps from the probe pattern # last probe in the command cycle is the null for ix in range(len(cdi_zip.probe.DM_cmd_cycle)): map = 1e-6 * (flat + cdi_zip.probe.DM_cmd_cycle[ix]) #TODO replace flat + cmd # cpx_all_sim[ix] = basic_fft(map, 128, 128) cpx_all_sim[ix], smp = proper.prop_run('scexao_model', .9, sim_grid, PASSVALUE={'map': map, 'psf_size':extracted, 'verbose': debug, 'ix':ix}, QUIET=True) # Copying FP Null image for n_nulls steps ix=0 while ix < n_nulls-1: cpx_all_sim = np.concatenate((cpx_all_sim, np.array([cpx_all_sim[-1,:,:]])),axis=0) ix+=1 # repeat cycle of n_probes+n_nulls for n_cycles # for ix in range(len(cpx_all_sim)): # cpx_all_1[ix] = resample_cpx(cpx_all_sim[ix], nx, ny) # cycle through the probe cycle for length of observation cpx_all = np.tile(cpx_all_sim, (cdi_zip.ts.n_cycles, 1, 1)) # Probes cpx_dm = cpx_all[reg_msk] probe_maps = (cdi_zip.probe.DM_cmd_cycle[0:cdi_zip.ts.n_probes] + flat) probe_tstamps = cdi_zip.ts.cmd_tstamps[msk].astype('float')/1e9 # Nulls cpx_null = cpx_all[~reg_msk] null_maps = np.tile(cdi_zip.probe.DM_cmd_cycle[-1] + flat, (cdi_zip.ts.n_cycles, 1, 1)) null_tstamps = cdi_zip.ts.cmd_tstamps[~msk].astype('float')/1e9 elt = time.time() print( f'\nPhase propagation finished in {elt - lst:.1f} sec == {(elt - lst) / 60:.2f} min\n') if debug: # Plot DM Map Probe Sequence fig, subplot = plt.subplots(2, cdi_zip.ts.n_probes//2, figsize=(14, 8)) fig.suptitle(f'DM Telemetry Data, Probe Commands: ' f'target = {target_name}\n' f' N probes={cdi_zip.ts.n_probes}, ' f'N null steps={int(cdi_zip.ts.null_time / cdi_zip.ts.phase_integration_time)}, ' f'integration time={cdi_zip.ts.phase_integration_time} sec', fontweight='bold', fontsize=14) for ax, ix in zip(subplot.flatten(), range(len(cdi_zip.probe.DM_cmd_cycle))): im = ax.imshow(probe_maps[ix], # vmax=np.max(probe_maps[0]), vmin=-np.max(probe_maps[0]) # np.min(probe_maps[0]) ) ax.set_title(f"t={probe_tstamps[ix] - (cdi_zip.ts.cmd_tstamps[0]).astype('float')/1e9:.2f}") cax = fig.add_axes([0.91, 0.2, 0.02, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label('DM voltage (relative scale)') plt.savefig(f'{plt_path}/{target_name}_dmMap_probeseq.png') # Null DM Map fig, subplot = plt.subplots(2, len(cmds_nulls_only) // 2, figsize=(14, 8)) fig.suptitle(f'DM Telemetry Data, Non-probed Timesteps (nulls): ' f'target = {target_name}\n' f' N probes={n_probes}, ' f'N null steps={int(n_nulls)}, ' f'integration time={cdi_zip.ts.phase_integration_time} sec', fontweight='bold', fontsize=14) for ax, ix in zip(subplot.flatten(), range(len(cmds_nulls_only))): im = ax.imshow(null_maps[ix], # vmax=np.max(null_maps[0]), vmin=-np.max(null_maps[0]) # 0 ) ax.set_title(f"t={null_tstamps[ix] - (cdi_zip.ts.cmd_tstamps[0]).astype('float') / 1e9:.2f}") cax = fig.add_axes([0.91, 0.2, 0.02, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label(f'DM actuator height (' + r'$\mu$' + 'm, uncalibrated)') plt.savefig(f'{plt_path}/{target_name}_dmMap_nullseq.png') # Re-center array to match mec images cpx_dm = np.roll(cpx_dm , (-3, 20),(1,2)) cpx_null = np.roll(cpx_null,(-3, 20),(1,2)) if plot: # Complex Map # fp_mask, edges = get_fp_mask(cdi_zip) # cl = LineCollection(edges, colors='r') fig, subplot = plt.subplots(2, n_probes // 2, figsize=(14, 8)) fig.suptitle(f'Propogated Intensity through SCExAO Model (probes): ' f'target = {target_name}\n' f' N probes={cdi_zip.ts.n_probes}, ' f'N null steps={int(cdi_zip.ts.null_time / cdi_zip.ts.phase_integration_time)}, ' f'integration time={cdi_zip.ts.phase_integration_time} sec', fontweight='bold', fontsize=14) for ax, ix in zip(subplot.flatten(), range(n_probes)): im = ax.imshow(np.abs(cpx_dm[ix])**2, interpolation='none', norm=LogNorm(vmin=1e-5,vmax=1e-2) ) # ax.add_collection(cl) ax.set_title(f"t={probe_tstamps[ix] - (cdi_zip.ts.cmd_tstamps[0]).astype('float')/1e9:.2f}") cax = fig.add_axes([0.91, 0.2, 0.02, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label(f'Intensity') plt.savefig(f'{plt_path}/{target_name}_simulated_focalplane.png') # plt.show() ###################### # CDI Algorithm # #################### # Defining Matrices delta = np.zeros((n_pairs, nx, ny), dtype=float) E_pupil = np.zeros((n_nulls*n_cycles, nx, ny), dtype=complex) H = np.zeros((n_pairs, 2), dtype=float) b = np.zeros((n_pairs, 1)) # Masking mask2D, imsk, jmsk, irng, jrng, imx, imn, jmx, jmn = get_fp_mask(cdi_zip, thresh=1e-3, shft=[-3, 20]) # , shft=[25,10] if debug: fig, ax = plt.subplots(1,1) fig.suptitle(f'Masked FP in CDI probe Region', fontweight='bold', fontsize=14) im = ax.imshow((mec_probed[0,:,:]*mask2D).T) cax = fig.add_axes([0.85, 0.2, 0.02, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label(f'Counts') cdit = time.time() for cy in range(1): # range(cdi_zip.ts.n_cycles) cycle = cy*n_nulls for i in range(140): # range(80,85) irng range(140) for j in range(140): # range(80,85) jrng range(140) for xn in range(n_nulls): for ip in range(n_pairs): # print(f'writing to [{cycle + xn}, i={i}, j={j}], cycle={cycle}, cy={cy}, xn={xn}') # Differance Images (delta) # (I_ip+ - I_ip-)/2 delta[ip,:,:] = (mec_probed[cycle+ip, :, :] - mec_probed[cycle + ip + n_pairs, :, :]) / 2 #TODO does this get overwritten each cycle? # Amplitude DeltaP Ip = mec_probed[cycle + ip, i, j] Im = mec_probed[cycle + ip + n_pairs, i, j] Io = mec_nulls[cycle + xn, i, j] #TODO fix this to run over all nulls in series abs = (Ip + Im) / 2 - Io if abs < 0: abs = 0 absDeltaP = np.sqrt(abs) # absDeltaP = np.sqrt(np.abs((Ip + Im) / 2 - Io)) # Phase DeltaP # The phase of the change in the focal plane of the probe applied to the DM # First subtract Eo vector from each probe phase to make new field vectors dEa, dEb, # then take the angle between the two dEp = cpx_dm[cycle + ip, i, j] - cpx_null[cycle + xn, i, j] dEm = cpx_dm[cycle+ip+n_pairs, i, j] - cpx_null[cycle + xn, i, j] # dEp = fp_seq[i, j, ip] - fp_seq[i, j, cdi_zip.ts.n_probes + xn] # dEm = fp_seq[i, j, ip + n_pairs] - fp_seq[i, j, cdi_zip.ts.n_probes + xn] phsDeltaP = np.arctan2(dEp.imag - dEm.imag, dEp.real - dEm.real) # print(f'dEp={dEp}, dEm={dEm}, xn={xn}\n' # f'abs={absDeltaP}, phs={phsDeltaP}') cpxDeltaP = absDeltaP * np.exp(1j * phsDeltaP) H[ip, :] = [-cpxDeltaP.imag, cpxDeltaP.real] # [n_pairs, 2] b[ip] = delta[ip, i, j] # [n_pairs, 1] a = 2 * H Exy = sl.lstsq(a, b)[0] # returns tuple, not array # print(f'writing to [{cycle + xn}, i={i}, j={j}], cycle={cycle}, cy={cy}, xn={xn}') E_pupil[cycle + xn, i, j] = Exy[0] + (1j * Exy[1]) et = time.time() print(f'CDI post-processing for {n_nulls*cdi_zip.ts.n_cycles} null-images' f' finished in {et-cdit:.1f} sec == {(et-cdit)/60:.2f} min\n') # I_processed I_processed = np.zeros((len(E_pupil), nx, ny)) for ix in range(len(E_pupil)): I_processed[ix] = np.floor(np.abs(E_pupil[ix]) ** 2 ) ## if plot: #################### # Difference Images fig, subplot = plt.subplots(1, n_pairs, figsize=(14,5)) fig.subplots_adjust(wspace=0.3, right=0.90, left=0.05) fig.suptitle((r'$I_i^+ - I_i^-$' ' for CDI Probes'), fontweight='bold', fontsize=14) for ax, ix in zip(subplot.flatten(), range(n_pairs)): im = ax.imshow(delta[ix].T, interpolation='none', # norm=SymLogNorm(linthresh=1e-2), vmin=-1, vmax=1) #, norm=SymLogNorm(linthresh=1e-5)) ax.set_title(f"Diff Probe\n" + r'$\theta$' + f'={cdi_zip.ts.phase_cycle[ix]/np.pi:.3f}' + r'$\pi$ -$\theta$' + f'={cdi_zip.ts.phase_cycle[ix+n_pairs]/np.pi:.3f}' + r'$\pi$') # cax = fig.add_axes([0.9, 0.2, 0.03, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] # cb = fig.colorbar(im, orientation='vertical', cax=cax) # # cb.set_label('Intensity') ############################## # Focal Plane E-field Estimate fig, subplt = plt.subplots(2, 4, figsize=(14, 7)) fig.subplots_adjust(wspace=0.3, right=0.85, left=0.05) fig.suptitle('Estimated Focal-Plane E-field', fontweight='bold', fontsize=14) for ax, ix in zip(subplt.flatten(), range(8)): im = ax.imshow(I_processed[ix].T, interpolation='none', # , vmin=-1, vmax=200) # , # norm=LogNorm()) ax.set_title(f'Estimation timestep {ix}') cax = fig.add_axes([0.9, 0.2, 0.03, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label('Intensity') ###################### # Subtracted E-field fig, subplot = plt.subplots(1, 3, figsize=(14, 5)) fig.subplots_adjust(wspace=0.1, right=0.85, left=0.05) fig.suptitle(f' Subtracted E-field', fontweight='bold', fontsize=14) for ax, ix in zip(subplot, range(3)): imsx = ax.imshow(mec_nulls[ix,:,:].T-I_processed[ix].T, interpolation='none', vmin=-1, vmax=2000) # norm=LogNorm()) ax.set_title(f'Estimation timestep {ix}') cax = fig.add_axes([0.9, 0.2, 0.03, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(imsx, orientation='vertical', cax=cax) # # cb.set_label('Intensity') ###################################################### # Subtracted E-field fig, subplot = plt.subplots(2, 3, figsize=(14, 10)) fig.subplots_adjust(wspace=0.1, right=0.85) fig.suptitle(f'{target_name} Subtracted E-field', fontweight='bold', fontsize=14) ax1, ax2, ax3, ax4, ax5, ax6 = subplot.flatten() ax1.imshow(fp_seq[0 + n_nulls].T, interpolation='none', vmin=-1, vmax=2000) ax1.set_title(f'Null Step 1') ax2.imshow(fp_seq[1 + n_nulls].T, interpolation='none', vmin=-1, vmax=2000) ax2.set_title(f'Null Step 2') ax3.imshow(fp_seq[2 + n_nulls].T, interpolation='none', vmin=-1, vmax=2000) ax3.set_title(f'Null Step 3') ax4.imshow(fp_seq[0 + n_nulls].T-I_processed[0].T, interpolation='none', vmin=-1, vmax=2000) ax4.set_title(f'CDI Subtracted Null 1') ax5.imshow(fp_seq[1 + n_nulls].T - I_processed[0].T, interpolation='none', vmin=-1, vmax=2000) ax5.set_title(f'CDI Subtracted Null 2') ax6.imshow(fp_seq[ 2 + n_nulls].T - I_processed[0].T, interpolation='none', vmin=-1, vmax=2000) ax6.set_title(f'CDI Subtracted Null 3') # plt.show() ## # DeltaP fig, subplot = plt.subplots(2, n_pairs, figsize=(12, 8)) fig.subplots_adjust(wspace=0.5, right=0.85) fig.suptitle(r'$\frac{I_i^+ + I_i^-}{2} - I_{null}$ for CDI Probes ' + f'target = {target_name}, \n' f'Probe Amp = {cdi_zip.probe.amp}, N probes={cdi_zip.ts.n_probes}, ' f'N null steps={int(cdi_zip.ts.null_time / cdi_zip.ts.phase_integration_time)}, ' f'integration time={cdi_zip.ts.phase_integration_time} sec\n', fontweight='bold', fontsize=14) cnt = np.tile(range(n_pairs), 2) xn = 1 for ax, ix in zip(subplot.flatten(), range(2 * n_pairs)): Ip = fp_seq[cnt[ix] ] Im = fp_seq[cnt[ix] + n_pairs] Io = fp_seq[cdi_zip.ts.n_probes + (ix // n_pairs + 0)] absDP = (Ip + Im) / 2 - Io # if absDP.any() < 0: # absDP = 0 # absDeltaP = np.sqrt(absDP) im = ax.imshow(absDP.T, interpolation='none', # vmin=-1, vmax=1, cmap='plasma', ) # , norm=SymLogNorm(linthresh=1e-5)) ax.set_title(f"probe phase pair {cnt[ix] + 1},\nnull step {ix // n_pairs + 1 + 0}") # cl = LineCollection(edges, colors='r') # ax.add_collection(cl) if ix + 1 > xn * n_pairs - 1: xn += 1 cax = fig.add_axes([0.9, 0.2, 0.03, 0.6]) # Add axes for colorbar @ position [left,bottom,width,height] cb = fig.colorbar(im, orientation='vertical', cax=cax) # cb.set_label('Intensity')
def coronagraph_demo(): n = 512 # grid size lamda = 0.55 # wavelength (microns) (no_errors, no_errors_sampl) = proper.prop_run("run_coronagraph_dm", lamda, n, PASSVALUE={ 'use_errors': False, 'use_dm': False, 'occulter_type': '8TH_ORDER' }, VERBOSE=False) (with_errors, with_errors_sampl) = proper.prop_run("run_coronagraph_dm", lamda, n, PASSVALUE={ 'use_errors': True, 'use_dm': False, 'occulter_type': '8TH_ORDER' }, VERBOSE=False) (with_dm, with_dm_sampl) = proper.prop_run("run_coronagraph_dm", lamda, n, PASSVALUE={ 'use_errors': True, 'use_dm': True, 'occulter_type': '8TH_ORDER' }, VERBOSE=False) nd = 256 psfs = np.zeros([3, nd, nd], dtype=np.float64) psfs[0, :, :] = no_errors[int(n / 2 - nd / 2):int(n / 2 + nd / 2), int(n / 2 - nd / 2):int(n / 2 + nd / 2)] psfs[1, :, :] = with_errors[int(n / 2 - nd / 2):int(n / 2 + nd / 2), int(n / 2 - nd / 2):int(n / 2 + nd / 2)] psfs[2, :, :] = with_dm[int(n / 2 - nd / 2):int(n / 2 + nd / 2), int(n / 2 - nd / 2):int(n / 2 + nd / 2)] plt.figure(figsize=(14, 7)) plt.suptitle("PSFs", fontsize=18, fontweight='bold') plt.subplot(1, 3, 1) plt.title('No errors') plt.imshow(psfs[0, :, :]**0.25, origin="lower", cmap=plt.cm.gray) plt.subplot(1, 3, 2) plt.title('With errors') plt.imshow(psfs[1, :, :]**0.25, origin="lower", cmap=plt.cm.gray) plt.subplot(1, 3, 3) plt.title('DM corrected') plt.imshow(psfs[2, :, :]**0.25, origin="lower", cmap=plt.cm.gray) plt.show() print("Maximum speckle flux / stellar flux :") print(" No wavefront errors = {0:0.3E}".format(np.max(no_errors), np.min(no_errors))) print(" With wavefront errors = {0:0.3E}".format(np.max(with_errors))) print(" With DM correction = {0:0.3E}".format(np.max(with_dm)))
if (mp.Nsbp == 1): lambdaFacs = np.array([1.]) else: lambdaFacs = np.linspace(1 - mp.fracBW / 2., 1 + mp.fracBW / 2., mp.Nsbp) # Get the Input Pupil's E-field mp.P1.compact.E = np.ones( (mp.P1.compact.Nbeam + 2, mp.P1.compact.Nbeam + 2, mp.Nsbp), dtype=complex) # Initialize for si in range(mp.Nsbp): lambda_um = 1e6 * mp.lambda0 * lambdaFacs[si] fldFull, sampling = proper.prop_run('wfirst_phaseb', lambda_um, nout, QUIET=True, PASSVALUE=optval.__dict__) if (mp.flagPlot): plt.figure(1) plt.imshow(np.angle(fldFull)) plt.colorbar() plt.hsv() plt.pause(1e-2) plt.figure(2) plt.imshow(np.abs(fldFull)) plt.colorbar() plt.magma() plt.pause(0.5) # figure(605); imagesc(angle(fldFull)); axis xy equal tight; colorbar; colormap hsv; drawnow; # figure(606); imagesc(abs(fldFull)); axis xy equal tight; colorbar; colormap parula; drawnow;
def telescope(self): """ main script to organize calls to various aspects of the telescope simulation initialize different sub-processes, such as atmosphere and aberration maps, MKID device parameters sets up the multiprocessing features returns the observation sequence :return: obs_sequence [n_timesteps, n_saved_planes, n_wavelengths, n_stars/planets, grid_size, grid_size] """ print('Beginning Telescope Simulation with MEDIS') print('***************************************') start = time.time() # ======================================================================= # Intialization # ======================================================================= # Check for Existing File #todo update this automatic load if exists functionality # check = mu.check_exists_obs_sequence(plot=False) # if check: # if iop.obs_seq[-3:] == '.h5': # obs_sequence = mu.open_obs_sequence_hdf5(iop.obs_seq) # else: # obs_sequence = mu.open_obs_sequence(iop.obs_seq) # # return obs_sequence if ap.companion is False: ap.contrast = [] # Initialize CDI probes if cdip.use_cdi is True: theta_series = cdi.gen_CDI_phase_stream() else: theta_series = np.zeros(sp.numframes) * np.nan # string of Nans # Initialize Obs Sequence self.cpx_sequence = np.zeros((sp.numframes, len(sp.save_list), ap.n_wvl_init, 1 + len(ap.contrast), sp.grid_size, sp.grid_size), dtype=np.complex) self.sampling = np.zeros((len(sp.save_list), ap.n_wvl_init)) # ======================================================================================================= # Closed-Loop- No Multiprocessing # ======================================================================================================= if sp.closed_loop: ########################## # Generating Timeseries ########################## for t in range(sp.numframes): kwargs = {'iter': t, 'params': [ap, tp, iop, sp], 'WFS_map':self.cpx_sequence[t-sp.ao_delay]} self.cpx_sequence[t], self.sampling = proper.prop_run(tp.prescription, 1, sp.grid_size, PASSVALUE=kwargs, VERBOSE=False, TABLE=False) # 1 is dummy wavelength print('MEDIS Telescope Run Completed') print('**************************************') finish = time.time() print(f'Time elapsed: {(finish - start) / 60:.2f} minutes') # print(f"Number of timesteps = {np.shape(cpx_sequence)[0]}") return self.cpx_sequence, self.sampling # ======================================================================================================= # Open-Loop- Uses Multiprocessing # ======================================================================================================= else: try: multiprocessing.set_start_method('spawn') except RuntimeError: pass # Multiprocessing Settings time_idx = multiprocessing.Queue() # time indicies that begin each timestep calculation out_chunk = multiprocessing.Queue() # tuple of planes and sampling after each chunk is calculated jobs = [] # Everything initialised in Timeseries is available to us in this obj. planes etc need to be accessed using a queue mt = MutliTime(time_idx, out_chunk) # Create the processes for i in range(sp.num_processes): p = multiprocessing.Process(target=mt.gen_timeseries, args=()) jobs.append(p) p.start() # Populate the time indicies and start the simulation for t in range(sp.startframe, sp.startframe + sp.numframes): time_idx.put(t) # Tell the simulation to stop after the final time index is reached for i in range(sp.num_processes): time_idx.put(sentinel) # ======================== # Read Obs Sequence # ======================== # Getting Returned Variables from gen_timeseries for it in range(int(np.ceil(mt.num_chunks))): fields_chunk, sampling = out_chunk.get() self.cpx_sequence[it*mt.chunk_steps - sp.startframe : (it+1)*mt.chunk_steps - sp.startframe, :, :, :, :, :] = fields_chunk self.sampling = sampling # # Ending the gen_timeseries loop via multiprocessing protocol for i, p in enumerate(jobs): p.join() # Wait for all the jobs to finish and consolidate them here print('MEDIS Telescope Run Completed') print('**************************************') finish = time.time() print(f'Time elapsed: {(finish - start) / 60:.2f} minutes') # print(f"Number of timesteps = {np.shape(cpx_sequence)[0]}") mu.display_sequence_shape(self.cpx_sequence) return self.cpx_sequence, self.sampling
lambdaFacs = np.array([1.]) else: lambdaFacs = np.linspace(1 - mp.fracBW / 2, 1 + mp.fracBW / 2, mp.Nsbp) # Get the Input Pupil's E-field nCompact = falco.util.ceil_even(mp.P1.compact.Nbeam + 1) mp.P1.compact.E = np.ones((nCompact, nCompact, mp.Nsbp), dtype=complex) for iSubband in range(mp.Nsbp): lambda_um = 1e6 * mp.lambda0 * lambdaFacs[iSubband] # Get aberrations for the full optical train optval.pinhole_diam_m = 0 # 0 means don't use the pinhole at FPAM fieldFullAll, sampling = proper.prop_run('roman_phasec', lambda_um, nout, QUIET=True, PASSVALUE=optval.__dict__) # Put pinhole at FPM to get back-end optical aberrations optval.pinhole_diam_m = mp.F3.pinhole_diam_m fieldFullBackEnd, sampling = proper.prop_run('roman_phasec', lambda_um, nout, QUIET=True, PASSVALUE=optval.__dict__) optval.pinhole_diam_m = 0 # 0 means don't use the pinhole at FPAM # Subtract off back-end phase aberrations from the phase retrieval estimate phFrontEnd = np.angle(fieldFullAll) - np.angle(fieldFullBackEnd) # swMask = ampthresh(fieldFullAll)
# quicklook_wf(wfo) # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() proper.prop_lens(wfo, fl_eye, "eye") proper.prop_propagate(wfo, fl_eye, "retina") # plt.imshow(proper.prop_get_amplitude(wfo)) # plt.show() quicklook_wf(wfo) phase_map = proper.prop_get_phase(wfo) amp_map = proper.prop_get_amplitude(wfo) # quicklook_im(phase_map) amp_map[80:100, 80:100] = 0 quicklook_im(amp_map, logAmp=True) import numpy as np wfo.wfarr = proper.prop_shift_center(amp_map * np.cos(phase_map) + 1j * amp_map * np.sin(phase_map)) # quicklook_wf(wf_array[iw,0]) proper.prop_propagate(wfo, fl_eye, "retina") proper.prop_lens(wfo, fl_eye, "eye") quicklook_wf(wfo) # End (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling) proper.prop_run('simple_telescope', 1.1, 128, PHASE_OFFSET=1)
#code to run CAOS if tp.use_atmos and glob.glob(cp.atmosdir + '*.fits') == []: import Atmosphere.caos as caos #import here since pidly can stay open sometimes and that's annoying caos.make_idl_params() caos.generate_maps() # hypercube = [] for t in range(1): print 'propagating frame:', t kwargs = { 'iter': t, 'atmos_map': cp.atmosdir + 'telz%f.fits' % (t * mp.frame_time) } no_occult = proper.prop_run("run_system", 1, tp.grid_size, PASSVALUE=kwargs, VERBOSE=False, PHASE_OFFSET=1)[0][0] tp.occult_loc = (4, -6) #opposit sense to normal x y direction tp.occulter_type = 'GAUSSIAN' # None# for t in range(1): print 'propagating frame:', t kwargs = { 'iter': t, 'atmos_map': cp.atmosdir + 'telz%f.fits' % (t * mp.frame_time) } occult = proper.prop_run("run_system", 1, tp.grid_size,
def full(mp, modvar, isNorm=True): """ Truth model used to generate images in simulation. Truth model used to generate images in simulation. Can include aberrations/errors that are unknown to the estimator and controller. This function is the wrapper for full models of any coronagraph type. Parameters ---------- mp : ModelParameters Structure containing optical model parameters modvar : ModelVariables Structure containing temporary optical model variables isNorm : bool If False, return an unnormalized image. If True, return a normalized image with the currently stored norm value. Returns ------- Eout : numpy ndarray 2-D electric field in final focal plane """ if type(mp) is not falco.config.ModelParameters: raise TypeError('Input "mp" must be of type ModelParameters') if hasattr(modvar, 'sbpIndex'): normFac = mp.Fend.full.I00[modvar.sbpIndex, modvar.wpsbpIndex] # Value to normalize the PSF. Set to 0 when finding the norm factor # Optional Keyword arguments if not isNorm: normFac = 0 # Set the wavelength if (hasattr(modvar, 'wvl')): # For FALCO or standalone use of full model wvl = modvar.wvl elif (hasattr(modvar, 'sbpIndex')): # For use in FALCO wvl = mp.full.lambdasMat[modvar.sbpIndex, modvar.wpsbpIndex] else: raise ValueError('Need to specify value or indices for wavelength.') """ Input E-fields """ if modvar.whichSource.lower() == 'offaxis': # Use for thput calculations TTphase = (-1.) * (2 * np.pi * (modvar.x_offset * mp.P2.full.XsDL + modvar.y_offset * mp.P2.full.YsDL)) Ett = np.exp(1j * TTphase * mp.lambda0 / wvl) Ein = Ett * np.squeeze(mp.P1.full.E[:, :, modvar.wpsbpIndex, modvar.sbpIndex]) else: # Default to using the starlight Ein = np.squeeze(mp.P1.full.E[:, :, modvar.wpsbpIndex, modvar.sbpIndex]) # Shift the source off-axis to compute the intensity normalization value. # This replaces the previous way of taking the FPM out in the optical model if normFac == 0: source_x_offset = mp.source_x_offset_norm # source offset in lambda0/D source_y_offset = mp.source_y_offset_norm # source offset in lambda0/D TTphase = (-1) * (2 * np.pi * (source_x_offset * mp.P2.full.XsDL + source_y_offset * mp.P2.full.YsDL)) Ett = np.exp(1j * TTphase * mp.lambda0 / wvl) Ein = Ett * np.squeeze(mp.P1.full.E[:, :, modvar.wpsbpIndex, modvar.sbpIndex]) # Apply a Zernike (in amplitude) at input pupil if specified if not (hasattr(modvar, 'zernIndex')): modvar.zernIndex = 1 if not modvar.zernIndex == 1: indsZnoll = modvar.zernIndex # Just send in 1 Zernike mode zernMat = np.squeeze( falco.zern.gen_norm_zern_maps(mp.P1.full.Nbeam, mp.centering, indsZnoll)) zernMat = pad_crop(zernMat, mp.P1.full.Narr) Ein = Ein * zernMat * ( 2 * np.pi / wvl) * mp.jac.Zcoef[mp.jac.zerns == modvar.zernIndex] # %% Pre-compute the FPM first for HLC if mp.layout.lower() == 'fourier' or mp.layout.lower() == 'proper': # ilam = (modvar.sbpIndex-1)*mp.Nwpsbp + modvar.wpsbpIndex if mp.coro.upper() == 'HLC': mp.F3.full.mask = falco.hlc.gen_fpm_from_LUT( mp, modvar.sbpIndex, modvar.wpsbpIndex, 'full') elif mp.layout.lower() == 'fpm_scale': if mp.coro.upper() == 'HLC': if mp.Nsbp > 1 and mp.Nwpsbp > 1: # Weird indexing is because interior wavelengths at # edges of sub-bands are the same, and the fpmCube # contains only the minimal set of masks. ilam = (modvar.sbpIndex-2)*mp.Nwpsbp + modvar.wpsbpIndex + \ (mp.Nsbp-modvar.sbpIndex+1) elif mp.Nsbp == 1 and mp.Nwpsbp > 1: ilam = modvar.wpsbpIndex elif mp.Nwpsbp == 1: ilam = modvar.sbpIndex mp.F3.full.mask = mp.full.fpmCube[:, :, ilam] # %% Select which optical layout's full model to use. if mp.layout.lower() == 'fourier': Eout = full_Fourier(mp, wvl, Ein, normFac) elif mp.layout.lower() == 'fpm_scale': # FPM scales with wavelength Eout = full_Fourier(mp, wvl, Ein, normFac, flagScaleFPM=True) elif mp.layout.lower() == 'proper': optval = copy.copy(vars(mp.full)) if any(mp.dm_ind == 1): optval['use_dm1'] = True optval['dm1'] = mp.dm1.V * mp.dm1.VtoH + mp.full.dm1FlatMap if any(mp.dm_ind == 2): optval['use_dm2'] = True optval['dm2'] = mp.dm2.V * mp.dm2.VtoH + mp.full.dm2FlatMap if normFac == 0: optval['xoffset'] = -mp.source_x_offset_norm optval['yoffset'] = -mp.source_y_offset_norm if mp.coro.upper() in ('VORTEX', 'VC', 'AVC'): optval['use_fpm'] = False optval['xoffset'] = 0 optval['yoffset'] = 0 pass # wavelength needs to be in microns instead of meters for PROPER [Eout, sampling_m] = proper.prop_run(mp.full.prescription, wvl * 1e6, mp.P1.full.Narr, QUIET=True, PASSVALUE=optval) if not normFac == 0: Eout = Eout / np.sqrt(normFac) del optval elif mp.layout.lower() in ('wfirst_phaseb_proper', 'roman_phasec_proper'): optval = copy.copy(vars(mp.full)) optval['use_dm1'] = True optval['use_dm2'] = True optval['dm1_m'] = mp.dm1.V * mp.dm1.VtoH + mp.full.dm1.flatmap optval['dm2_m'] = mp.dm2.V * mp.dm2.VtoH + mp.full.dm2.flatmap if normFac == 0: optval['source_x_offset'] = -mp.source_x_offset_norm optval['source_y_offset'] = -mp.source_y_offset_norm if mp.layout.lower() == 'wfirst_phaseb_proper': fn_proper = 'wfirst_phaseb' elif mp.layout.lower() == 'roman_phasec_proper': fn_proper = 'roman_phasec' [Eout, sampling] = proper.prop_run(fn_proper, wvl * 1e6, int(2**falco.util.nextpow2(mp.Fend.Nxi)), QUIET=True, PASSVALUE=optval) Eout = pad_crop(Eout, (mp.Fend.Nxi, mp.Fend.Nxi)) if not normFac == 0: Eout = Eout / np.sqrt(normFac) return Eout
def Simulation(inqueue, output, datacubes, xxx_todo_changeme): # def Simulation(inqueue, output, (dp, cp)): (tp, ap, sp, iop, cp, mp) = xxx_todo_changeme # import matplotlib.pylab as plt # plt.plot(list(range(10))) # plt.show() # plt.show(block=True) try: if tp.detector == 'MKIDs': with open(iop.device_params, 'rb') as handle: dp = pickle.load(handle) # with open(iop.NCPA_meas, 'rb') as handle: # tp.Imaps, tp.phase_map = pickle.load(handle) # hypercube = [] start = time.time() for it, t in enumerate(iter(inqueue.get, sentinel)): if cp.vary_r0: # # print cp.r0s, cp.r0s_idx # cp.r0s_idx = caos.random_r0walk(cp.r0s_idx, cp.r0s) # # print cp.r0s_idx # r0 = cp.r0s[cp.r0s_idx] element = int(np.random.random() * len(cp.r0s)) # cp.r0s_idx = element r0 = cp.r0s[element] else: r0 = cp.r0s # this is a scalar in this instance # dprint((t, r0, 'r0', tp.rot_rate)) atmos_map = cp.atmosdir + 'telz%f_%1.3f.fits' % ( t * cp.frame_time, r0) #t * # dprint((atmos_map, cp.atmosdir)) kwargs = { 'iter': t, 'atmos_map': atmos_map, 'params': [ap, tp, iop, sp] } # dprint(tp.occulter_type) datacube, _ = proper.prop_run("run_system", 1, tp.grid_size, PASSVALUE=kwargs, VERBOSE=False, PHASE_OFFSET=1) # view_datacube(datacube, logAmp=True) # print np.sum(datacube,axis=(1,2)) if tp.detector == 'ideal': image = np.sum(datacube, axis=0) vmin = np.min(datacube) * 10 # cube = ideal.assign_calibtime(datacube,PASSVALUE['iter']) # cube = rawImageIO.arange_into_cube(packets, value='phase') # rawImageIO.make_phase_map(cube, plot=True) # return '' elif tp.detector == 'H2RG': image = np.sum(datacube, axis=0) vmin = np.min(datacube) * 10 elif tp.detector == 'MKIDs': # dprint(dp.__dict__) # print np.sum(datacube, axis=(1,2)), 'sum' packets = read.get_packets(datacube, t, dp, mp) # dprint(packets.shape) # plt.hist(packets[:,1] - packets[:,0]) # plt.show() if sp.show_wframe or sp.show_cube or sp.return_cube: cube = pipe.arange_into_cube( packets, (mp.array_size[0], mp.array_size[1])) # # if mp.remove_close: # # timecube = read.remove_close_photons(cube) if sp.show_wframe: image = pipe.make_intensity_map( cube, (mp.array_size[0], mp.array_size[1])) # # # packets = rawImageIO.arange_into_packets(cube) # # # wfo = read.convert_to_wfo(image, wfo) if sp.show_cube or sp.return_cube: datacube = pipe.make_datacube( cube, (mp.array_size[0], mp.array_size[1], tp.w_bins)) # dprint(datacube.shape) # datacube = datacube[:,:mp.array_size[0],:mp.array_size[0]] # dprint(datacube.shape) # print packets.shape if sp.save_obs: command = read.get_obs_command(packets, t) output.put(command) vmin = 0.9 # return command # else: # return '' # hypercube.append(datacube) if sp.show_wframe: quicklook_im(image, logAmp=True, show=sp.show_wframe, vmin=vmin) # dprint(np.sum(image)) if sp.show_cube: # import matplotlib.pyplot as plt # plt.plot(np.sum(datacube,axis=(1,2))) # plt.show() view_datacube(datacube, logAmp=True, vmin=vmin) if sp.return_cube: datacubes.put((t, datacube)) # dprint('lol') # return datacube now = time.time() elapsed = float(now - start) / 60. each_iter = float(elapsed) / (it + 1) # print ap.numframes, each_iter dprint('%i elapsed of %i mins' % (elapsed, each_iter * ap.numframes / sp.num_processes)) except Exception as e: # print ' **** Caught Exception ****' traceback.print_exc() # raise e pass
('normLyotDiam', 0.95), ('vortexCharge', 6), ('xoffset', 0), ('yoffset', 0) ]) # %% No Correction # Phase Retrieval of Pupil optval['use_pr'] = True optval['pr_pupil_diam_pix'] = 248 optval['use_errors'] = 1 # 1 = use optical surface errors, 0 = none optval['use_fpm'] = 0 # use focal plane mask (0 = no FPM) optval['use_lyot_stop'] = 1 # use Lyot stop (0 = no stop) optval['use_field_stop'] = 0 # use field stop (0 = no stop) [Epup, sampling_m] = proper.prop_run(prescription, lambda_um, gridsize, PASSVALUE=optval, QUIET=True) mask = np.zeros(Epup.shape) mask[np.abs(Epup) > 0.1*np.max(np.abs(Epup))] = 1 plt.figure(1); plt.imshow(np.abs(Epup)); plt.colorbar(); plt.title('abs(Epupil)'); plt.pause(1e-2) plt.figure(2); plt.imshow(mask*np.angle(Epup)); plt.colorbar(); plt.clim(-1, 1); plt.title('angle(Epupil)'); plt.pause(1e-2) # PSF for normalization optval['use_pr'] = False optval['use_errors'] = 1; #-- 1 = use optical surface errors, 0 = none optval['use_fpm'] = 0; #-- use focal plane mask (0 = no FPM) optval['use_lyot_stop'] = 1 #-- use Lyot stop (0 = no stop) optval['use_field_stop'] = 0 #-- use field stop (0 = no stop) [EforNorm, sampling_m] = proper.prop_run(prescription, lambda_um, gridsize, PASSVALUE=optval, QUIET=True ) IforNorm = np.abs(EforNorm)**2
lambdaFacs = (1, ) else: lambdaFacs = np.linspace(1 - mp.fracBW / 2, 1 + mp.fracBW / 2, mp.Nsbp) prescription = 'habex' # Get the Input Pupil's E-field Nf = nout #--N full Nc = falco.util.ceil_even((mp.P1.compact.Nbeam / mp.P1.full.Nbeam) * Nf) mp.P1.compact.E = np.ones((Nc, Nc, mp.Nsbp), dtype=complex) # mp.P1.compact.E = ones(mp.P1.compact.Nbeam+2, mp.P1.compact.Nbeam+2, mp.Nsbp); %--Initialize for si in range(mp.Nsbp): lambda_um = 1e6 * mp.lambda0 * lambdaFacs[si] [fldFull, sampling_m] = proper.prop_run(prescription, lambda_um, nout, PASSVALUE=optval, QUIET=True) if (mp.flagPlot): pass plt.figure(605) plt.imshow(np.angle(fldFull)) plt.colorbar plt.hsv() plt.pause(1e-2) plt.figure(606) plt.imshow(np.abs(fldFull)) plt.colorbar plt.magma() plt.pause(1e-2)
import proper import matplotlib.pyplot as plt from matplotlib import cm def simple_telescope(wavelength, gridsize): diam = 1.0 focal_ratio = 15.0 focal_length = diam * focal_ratio beam_ratio = 0.5 wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio) proper.prop_circular_aperture(wfo, diam / 2) proper.prop_zernikes(wfo, [5], [1e-6]) proper.prop_define_entrance(wfo) proper.prop_lens(wfo, focal_length * 0.98) proper.prop_propagate(wfo, focal_length) (wfo, sampling) = proper.prop_end(wfo) return (wfo, sampling) if __name__ == "__main__": psf, sampling = proper.prop_run('simple_telescope', 0.5, 512) plt.imshow(psf, cmap=cm.gray) plt.show()
def metiscoronagraphsimulator( n, lam, pixelsize, prefix, path, diam=37., r_obstr=0.3, f_lens=658.6, pupil_file=0, spiders_width=0.60, spiders_angle=[0., 60., 120.], charge=0, LS_parameters=[0.0, 0.0, 0.0], amplitude_apodizer_file=0, phase_apodizer_file=0, LS_amplitude_apodizer_file=0, LS_phase_apodizer_file=0, TILT=[0.0, 0.0], atm_screen=0., missing_segments_number=0, apodizer_misalignment=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], LS_misalignment=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], Island_Piston=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], NCPA=0., NoCoro_psf=0, Offaxis_psf=0, ELT_circ=True, Vortex=False, Back=False, RAVC=False, LS=False, Debug=True, Debug_print=True, Norm_max=True, Norm_flux1=False): """MCS. Parameters ---------- n : integer Grid size lam : float in microns Wavelength pixelsize : float in mas Pixelsize in the detector plane prefix : string Prefix for the fits file writing path : string path where to save the outputs Returns ------- None PASSVALUE --------- diam: 37. --> float, meters when both ELT_circ and other_pupil are False, the diameter has to be defined here r_obstr: 0.3 -->float, ratio when both ELT_circ and other_pupil are False, the central obstruction has to be defined here f_lens: 658.6 --> float, meters focal distance pupil_file: 0 --> float matrix it contains the pupil in case the 'other_pupil' is called spiders_width: 0.60 --> float, meters the spiders width has to be defined here, when the 'ELT_circ' is called (the fits file has no spiders) and when both ELT_circ and other_pupil are False and spiders are present spiders_angle: [0., 60., 120.] --> float, degrees the spiders rotation angle has to be defined here, when the 'ELT_circ' is called (the fits file has no spiders) and when both ELT_circ and other_pupil are False and spiders are present charge: 0 -->integer it indicates the charge of the vortex coronagraph ('Vortex' has to be called) LS_parameters : [0.0, 0.0, 0.0] --> float [percentage of the outer diamter, percentage of the outer diamter to add to the central obstruction/apodizer diameter, meters for the spiders] it indicates the values of the Lyot Stop ('LS' has to be called) amplitude_apodizer_file:0, float matrix it contains the pupil amplitude apodizer file in case the 'amplitude_apodizer' is called phase_apodizer_file:0, float matrix it contains the pupil phase apodizer file in case the 'phase_apodizer' is called LS_amplitude_apodizer_file:0, float matrix it contains the Lyot Stop amplitude apodizer file in case the 'LS_amplitude_apodizer' is called LS_phase_apodizer_file:0, float matrix it contains the yot Stop phase apodizer file in case the 'LS_phase_apodizer' is called TILT: [0.0, 0.0] --> float, lambda/D Tilt values : [xtilt, ytilt] !!! PROPER CHANGE THE DIRECTION BETWEEN XTILT AND YTILT !!!! atm_screen: 0 --> float matrix, microns it contains the atm phase screen missing_segments_number: 0 --> integer it contains the number of missing segments ('missing_segments' has to be called) apodizer_misalignment: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] --> float, percentage it indicated the pupil apodizer misalignment: the first 3 are for an amplitude apodizer misalignment ('pupil_amplitude_apodizer_misalignment' has to be called) and the last 3 are for a phase apodizer misalignment ('pupil_phase_apodizer_misalignment' has to be called) LS_misalignment: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] --> float, percentage it indicated the LS apodizer misalignment: the first 3 are for an amplitude apodizer misalignment ('LS_amplitude_apodizer_misalignment' has to be called) and the last 3 are for a phase apodizer misalignment ('LS_phase_apodizer_misalignment' has to be called) Island_Piston: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] --> float, microns it indicated the values for the petals differential pistons. Since only 'ELT_circ' is supported for now, it needs 6 values for the 6 petals NCPA: 0 --> float matrix, microns it contains the NCPA matrix in microns NoCoro_psf: 0 --> float matrix, non coronagraphic psf Offaxis_psf: 0 --> float matrix, off-axis psf kwargs ---------------- ELT_circ : bool If the pupil is the circularised ELT pupil in the file "ELT_2048_37m_11m_5mas_nospiders_cut.fits" Vortex : bool If the coronagraph is a vortex coronagraph, it needs the passvalue 'charge', which contains the charge of the vortex Back : bool If the back-propagation for the vortex coronagraph is needed: the back rpopagation depends on the grid and the pupil size (only the external diamater). RAVC: bool If the coronagraph is a RAVC (to work properly, also the vortex parameter has to be True) LS: bool If the Lyot Stop is present, it needs the passvalue 'LS_parameters' to be completed with the proper values Debug: bool it writes all the fits file, with the prefix Debug_print: bool it print several values Norm_max: bool it normalizes the psfs with respect to the max of the non-coronagraphic psf Norm_flux1: bool it normalizes the psfs with respect to the max of the non-coronagraphic psf, where the total flux has been put to 1 """ if (ELT_circ == True): PACKAGE_PATH = os.path.abspath(os.path.join(__file__, os.pardir)) pupil_file = fits.getdata(PACKAGE_PATH + '/ELT_2048_37m_11m_5mas_nospiders_cut.fits') diam = 37. beam_ratio = pixelsize * 4.85e-9 / (lam * 1e-6 / diam) npupil = math.ceil( n * 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" in kwargs and kwargs["Debug_print"]): if (Debug_print == True): print("npupil: ", npupil) TILT = np.array(TILT) apodizer_misalignment = np.array(apodizer_misalignment) LS_misalignment = np.array(LS_misalignment) Island_Piston = np.array(Island_Piston) if (isinstance(NoCoro_psf, (list, tuple, np.ndarray)) != True): ## Non coronagraphic PSF --> simulate a non-coronagraphic psf (wfo_noCoro, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': 0, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': 0, 'amplitude_apodizer_file': 0, 'TILT': [0., 0.], 'LS': False, 'RAVC': False, 'LS_phase_apodizer_file': 0, 'LS_amplitude_apodizer_file': 0, 'LS_parameters': [0., 0., 0.], 'atm_screen': 0, 'missing_segments_number': 0, 'apodizer_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'LS_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'Island_Piston': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'NCPA': 0, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) NoCoro_psf = (abs(wfo_noCoro))**2 fits.writeto( path + prefix + '_psf_noCoro_nonorm.fits', NoCoro_psf[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) #if ("Norm_max" in kwargs and kwargs["Norm_max"]): if (Norm_max == True): psf_noCoro_maxnorm = NoCoro_psf / np.max(NoCoro_psf) fits.writeto( path + prefix + '_psf_noCoro_maxnorm.fits', psf_noCoro_maxnorm[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) #if ("Norm_flux1" in kwargs and kwargs["Norm_flux1"]): if (Norm_flux1 == True): psf_noCoro_flux1norm = NoCoro_psf / sum(sum(NoCoro_psf)) fits.writeto( path + prefix + '_psf_noCoro_flux1norm.fits', psf_noCoro_flux1norm[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) ## Coronagraphic PSF if (Vortex == True): if (Back == True): ## A/R --> simulate a perfect vortex by propagating a perfectly circular pupil through the vortex to the Lyot Stop, null the amplitude inside (as theory requires), then propagating back to the vortex level and save a "modified" vortex, to use in the future simulations (wfo_AR, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': charge, 'CAL': 1, 'diam': diam, 'spiders_width': 0, 'spiders_angle': [0., 0., 0.], 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': 0., 'pupil_file': 0, 'phase_apodizer_file': 0, 'amplitude_apodizer_file': 0, 'TILT': [0., 0.], 'LS': False, 'RAVC': False, 'LS_phase_apodizer_file': 0, 'LS_amplitude_apodizer_file': 0, 'LS_parameters': [0., 0., 0.], 'atm_screen': 0, 'missing_segments_number': 0, 'apodizer_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'LS_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'Island_Piston': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'NCPA': 0, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) if (isinstance(Offaxis_psf, (list, tuple, np.ndarray)) != True): ## No Vortex Si Mask --> simulate a non-coronagraphic-apodized psf: apodizer and Lyot Stop are present, but not the vortex --> as an off-axis psf (wfo_offaxis, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': 0, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': phase_apodizer_file, 'amplitude_apodizer_file': amplitude_apodizer_file, 'TILT': [0., 0.], 'LS': LS, 'RAVC': RAVC, 'LS_phase_apodizer_file': LS_phase_apodizer_file, 'LS_amplitude_apodizer_file': LS_amplitude_apodizer_file, 'LS_parameters': LS_parameters, 'atm_screen': 0, 'missing_segments_number': missing_segments_number, 'apodizer_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'LS_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'Island_Piston': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'NCPA': 0, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) Offaxis_psf = (abs(wfo_offaxis))**2 fits.writeto(path + prefix + '_psf_offaxis_nonorm.fits', Offaxis_psf[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_max == True): #if ("Norm_max" in kwargs and kwargs["Norm_max"]): psf_noVortex_Mask_maxnorm = Offaxis_psf / np.max(NoCoro_psf) fits.writeto( path + prefix + '_psf_offaxis_maxnorm.fits', psf_noVortex_Mask_maxnorm[ int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_flux1 == True): #if ("Norm_flux1" in kwargs and kwargs["Norm_flux1"]): psf_noVortex_Mask_flux1norm = Offaxis_psf / sum( sum(NoCoro_psf)) fits.writeto( path + prefix + '_psf_offaxis_flux1norm.fits', psf_noVortex_Mask_flux1norm[ int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) atm_screen = np.array(atm_screen) NCPA = np.array(NCPA) if (atm_screen.ndim == 3) or (TILT.ndim == 2) or ( LS_misalignment.ndim == 2) or (apodizer_misalignment.ndim == 2) or (Island_Piston.ndim == 2) or (NCPA.ndim == 3): print('Cube') if (atm_screen.ndim == 3): length_cube = atm_screen.shape[0] if (TILT.ndim == 2): length_cube = TILT.shape[0] if (LS_misalignment.ndim == 2): length_cube = LS_misalignment.shape[0] if (apodizer_misalignment.ndim == 2): length_cube = apodizer_misalignment.shape[0] if (Island_Piston.ndim == 2): length_cube = Island_Piston.shape[0] if (NCPA.ndim == 3): length_cube = NCPA.shape[0] psf_Coro = np.zeros((length_cube, n, n)) for iter in range(0, length_cube): print('iter: ', iter) if ((isinstance(atm_screen, (list, tuple, np.ndarray)) == True)): if (atm_screen.ndim == 3): atm_screen_iter = atm_screen[iter, :, :] else: atm_screen_iter = atm_screen if (TILT.ndim == 2): TILT_iter = TILT[iter, :] print('TILT: ', TILT_iter) else: TILT_iter = TILT if (LS_misalignment.ndim == 2): LS_misalignment_iter = LS_misalignment[iter, :] else: LS_misalignment_iter = LS_misalignment if (apodizer_misalignment.ndim == 2): apodizer_misalignment_iter = apodizer_misalignment[iter, :] else: apodizer_misalignment_iter = apodizer_misalignment if (Island_Piston.ndim == 2): Island_Piston_iter = Island_Piston[iter, :] else: Island_Piston_iter = Island_Piston if (isinstance(NCPA, (list, tuple, np.ndarray)) == True): if (NCPA.ndim == 3): NCPA_iter = NCPA[iter, :, :] else: NCPA_iter = NCPA if (Vortex == True): ## Si Vortex Si Mask --> simulate the coronagraphic-apodized psf (wfo_Coro, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': charge, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': phase_apodizer_file, 'amplitude_apodizer_file': amplitude_apodizer_file, 'TILT': TILT_iter, 'LS': LS, 'RAVC': RAVC, 'LS_phase_apodizer_file': LS_phase_apodizer_file, 'LS_amplitude_apodizer_file': LS_amplitude_apodizer_file, 'LS_parameters': LS_parameters, 'atm_screen': atm_screen_iter, 'missing_segments_number': missing_segments_number, 'apodizer_misalignment': apodizer_misalignment_iter, 'LS_misalignment': LS_misalignment_iter, 'Island_Piston': Island_Piston_iter, 'NCPA': NCPA_iter, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) psf_Coro[iter, :, :] = (abs(wfo_Coro))**2 else: ## Apodizer --> simulate a coronagraphic psf with an apodizer (no Vortex) (wfo_apodizer, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': 0, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': phase_apodizer_file, 'amplitude_apodizer_file': amplitude_apodizer_file, 'TILT': TILT_iter, 'LS': LS, 'RAVC': False, 'LS_phase_apodizer_file': LS_phase_apodizer_file, 'LS_amplitude_apodizer_file': LS_amplitude_apodizer_file, 'LS_parameters': LS_parameters, 'atm_screen': atm_screen_iter, 'missing_segments_number': missing_segments_number, 'apodizer_misalignment': apodizer_misalignment_iter, 'LS_misalignment': LS_misalignment_iter, 'Island_Piston': Island_Piston_iter, 'NCPA': NCPA_iter, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) psf_Coro[iter, :, :] = (abs(wfo_apodizer))**2 fits.writeto( path + prefix + '_psf_cube_Coro_nonorm.fits', psf_Coro[:, int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_max == True): if (Vortex == True): psf_Coro_maxnorm = psf_Coro / np.max(Offaxis_psf) else: psf_Coro_maxnorm = psf_Coro / np.max(NoCoro_psf) fits.writeto(path + prefix + '_psf_cube_Coro_maxnorm.fits', psf_Coro_maxnorm[:, int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_flux1 == True): psf_Coro_flux1norm = psf_Coro / sum(sum(NoCoro_psf)) fits.writeto( path + prefix + '_psf_cube_Coro_flux1norm.fits', psf_Coro_flux1norm[:, int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) else: print('No Cube') if (Vortex == True): print('VC') print( 'ATM: ', int(isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) print('atm screen: ', atm_screen.shape) ## Si Vortex Si Mask --> simulate the coronagraphic-apodized psf (wfo_Coro, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': charge, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': phase_apodizer_file, 'amplitude_apodizer_file': amplitude_apodizer_file, 'TILT': TILT, 'LS': LS, 'RAVC': RAVC, 'LS_phase_apodizer_file': LS_phase_apodizer_file, 'LS_amplitude_apodizer_file': LS_amplitude_apodizer_file, 'LS_parameters': LS_parameters, 'atm_screen': atm_screen, 'missing_segments_number': missing_segments_number, 'apodizer_misalignment': apodizer_misalignment, 'LS_misalignment': LS_misalignment, 'Island_Piston': Island_Piston, 'NCPA': NCPA, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) psf_Coro = (abs(wfo_Coro))**2 else: print('Apodizer') print( 'ATM: ', int(isinstance(atm_screen, (list, tuple, np.ndarray)) == True)) print('atm screen: ', atm_screen.shape) ## Apodizer --> simulate a coronagraphic psf with an apodizer (no Vortex) (wfo_apodizer, sampling) = proper.prop_run( 'telescope', lam, n, PASSVALUE={ 'prefix': prefix, 'path': path, 'charge': 0, 'CAL': 0, 'diam': diam, 'spiders_width': spiders_width, 'spiders_angle': spiders_angle, 'beam_ratio': beam_ratio, 'f_lens': f_lens, 'npupil': npupil, 'r_obstr': r_obstr, 'pupil_file': pupil_file, 'phase_apodizer_file': phase_apodizer_file, 'amplitude_apodizer_file': amplitude_apodizer_file, 'TILT': TILT, 'LS': LS, 'RAVC': False, 'LS_phase_apodizer_file': LS_phase_apodizer_file, 'LS_amplitude_apodizer_file': LS_amplitude_apodizer_file, 'LS_parameters': LS_parameters, 'atm_screen': atm_screen, 'missing_segments_number': missing_segments_number, 'apodizer_misalignment': apodizer_misalignment, 'LS_misalignment': LS_misalignment, 'Island_Piston': Island_Piston, 'NCPA': NCPA, 'Debug_print': Debug_print, 'Debug': Debug }, QUIET=True) psf_Coro = (abs(wfo_apodizer))**2 fits.writeto( path + prefix + '_psf_Coro_nonorm.fits', psf_Coro[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_max == True): if (Vortex == True): psf_Coro_maxnorm = psf_Coro / np.max(Offaxis_psf) else: psf_Coro_maxnorm = psf_Coro / np.max(NoCoro_psf) fits.writeto( path + prefix + '_psf_Coro_maxnorm.fits', psf_Coro_maxnorm[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) if (Norm_flux1 == True): psf_Coro_flux1norm = psf_Coro / sum(sum(NoCoro_psf)) fits.writeto( path + prefix + '_psf_Coro_flux1norm.fits', psf_Coro_flux1norm[int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio), int(n / 2) - math.ceil(50. / beam_ratio):int(n / 2) + math.ceil(50. / beam_ratio)], overwrite=True) return