def make_mf( maskname, instrument, filtname, npix, i_wl=None, peakmethod="fft", n_wl=3, theta_detector=0, cutoff=1e-4, hole_diam=0.8, fw_splodge=0.7, scaling=1, diag_plot=False, verbose=False, display=True, save_to=None, filename=None, ): """ Summary: -------- Compute the match filter mf which give the indices of the peak positions (mf.pvct) and the associated gains (mf.gvct) in the image. Contains also the u-v coordinates, wavelengths informations, holes mask positions (mf.xy_coords), centered mf (mf.cpvct, mf.gpvct), etc. Parameters: ----------- `maskname`: str Name of the mask (number of holes),\n `instrument`: str Instrument used (default = jwst),\n `filtname`: str Name of the filter,\n `npix`: int Size of the image,\n `peakmethod` {str}: 3 methods are used to sample the u-v space: 'fft' uses fft between individual holes to compute the expected splodge positions; 'square' compute the splodge in a square using the expected fraction of pixel to determine its weight; 'gauss' considers a gaussian splodge (with a gaussian weight) to get the same splodge side for each n(n-1)/2 baselines,\n `n_wl`: int number of wavelengths to use to simulate bandwidth,\n `theta_detector`: float Angle [deg] to rotate the mask compare to the detector (if the mask is not perfectly aligned with the detector, e.g.: VLT/VISIR) ,\n `cutoff`: float cutoff limit between noise and signal pixels in simulated transforms,\n `hole_diam`: float Diameter of a single aperture (0.8 for JWST),\n `fw_splodge` {float}: Relative size of the splodge used to compute multiple triangle indices and the fwhm of the 'gauss' technique,\n """ from munch import munchify as dict2class # Get detector, filter and mask informations # ------------------------------------------ pixelsize = get_pixel_size(instrument) # Pixel size of the detector [rad] if pixelsize is np.nan: cprint("Error: Pixel size unknown for %s." % instrument, "red") return None # Wavelength of the filter (filt[0]: central, filt[1]: width) filt = get_wavelength(instrument, filtname) if instrument == "SPHERE-IFS": if isinstance(i_wl, (int, np.integer)): filt = [filt[i_wl], 0.001 * filt[i_wl]] else: filt = [np.mean(filt[i_wl[0] : i_wl[1]]), filt[i_wl[1]] - filt[i_wl[0]]] xy_coords = get_mask(instrument, maskname) # mask coordinates x_mask = xy_coords[:, 0] * scaling y_mask = xy_coords[:, 1] * scaling x_mask_rot = x_mask * np.cos(np.deg2rad(theta_detector)) + y_mask * np.sin( np.deg2rad(theta_detector) ) y_mask_rot = -x_mask * np.sin(np.deg2rad(theta_detector)) + y_mask * np.cos( np.deg2rad(theta_detector) ) xy_coords_rot = [] for i in range(len(x_mask)): xy_coords_rot.append([x_mask_rot[i], y_mask_rot[i]]) xy_coords = np.array(xy_coords_rot) if display: import matplotlib.pyplot as plt _plot_mask_coord(xy_coords, maskname, instrument) if save_to is not None: figname = os.path.join(save_to, Path(filename).stem) plt.savefig(f"{figname}_{1}.pdf") n_holes = xy_coords.shape[0] index_mask = compute_index_mask(n_holes) n_baselines = index_mask.n_baselines n_bispect = index_mask.n_bispect ncp_i = int((n_holes - 1) * (n_holes - 2) / 2) if verbose: cprint("---------------------------", "cyan") cprint( "%s (%s): %i holes masks" % (instrument.upper(), filtname, n_holes), "cyan" ) cprint("---------------------------", "cyan") cprint( "nbl = %i, nbs = %i, ncp_i = %i, ncov = %i" % (n_baselines, n_bispect, ncp_i, index_mask.n_cov), "cyan", ) # Consider the filter to be made up of n_wl wavelengths wl = np.arange(n_wl) / n_wl * filt[1] wl = wl - np.mean(wl) + filt[0] Sum, Sum_c = 0, 0 mf_ix = np.zeros([2, n_baselines], dtype=int) # matched filter mf_ix_c = np.zeros([2, n_baselines], dtype=int) # matched filter if verbose: print("\n- Calculating sampling of", n_holes, "holes array...") innerpix, innerpix_center = _compute_center_splodge( npix, pixelsize, filt, hole_diam=hole_diam ) u, v = _compute_uv_coord( xy_coords, index_mask, filt, pixelsize, npix, round_uv_to_pixel=False ) mf_pvct = mf_gvct = mfc_pvct = mfc_gvct = None for i in range(n_baselines): args = { "i": i, "npix": npix, "pixelsize": pixelsize, "innerpix": innerpix, "innerpix_center": innerpix_center, } if peakmethod == "fft": ind_peak = _peak_fft_method( xy_coords=xy_coords, wl=wl, index_mask=index_mask, **args ) elif peakmethod == "square": ind_peak = _peak_square_method(u=u, v=v, **args) elif peakmethod == "unique": ind_peak = _peak_one_method(u=u, v=v, **args) elif peakmethod == "gauss": ind_peak = _peak_gauss_method( u=u, v=v, filt=filt, index_mask=index_mask, fw_splodge=fw_splodge, **args, hole_diam=hole_diam, ) else: cprint( "Error: choose the extraction method 'gauss', 'fft' or 'square'.", "red" ) return None # Compute the cutoff limit before saving the gain map pixelvector = np.where(ind_peak["flat"] >= cutoff)[0] pixelvector_c = np.where(ind_peak["centered"] >= cutoff)[0] # Now normalise the pixel gain, so that using the matched filter # on an ideal splodge is equivalent to just looking at the peak... if peakmethod == "gauss": pixelgain, pixelgain_c = _normalize_gain( ind_peak["gain_f"], ind_peak["gain_c"], pixelvector, pixelvector_c ) else: pixelgain, pixelgain_c = _normalize_gain( ind_peak["flat"], ind_peak["centered"], pixelvector, pixelvector_c ) mf_ix[0, i] = Sum Sum = Sum + len(pixelvector) mf_ix[1, i] = Sum mf_ix_c[0, i] = Sum_c Sum_c = Sum_c + len(pixelvector_c) mf_ix_c[1, i] = Sum_c if i == 0: mf_pvct = list(pixelvector) mf_gvct = list(pixelgain) mfc_pvct = list(pixelvector_c) mfc_gvct = list(pixelgain_c) else: mf_pvct.extend(list(pixelvector)) mf_gvct.extend(list(pixelgain)) mfc_pvct.extend(list(pixelvector_c)) mfc_gvct.extend(list(pixelgain_c)) mf = np.zeros( [npix, npix, n_baselines], dtype=[("norm", float), ("conj", float), ("norm_c", float), ("conj_c", float)], ) for i in range(n_baselines): mf_tmp = np.zeros([npix, npix]) mf_tmp_c = np.zeros([npix, npix]) ind = mf_pvct[mf_ix[0, i] : mf_ix[1, i]] ind_c = mfc_pvct[mf_ix_c[0, i] : mf_ix_c[1, i]] mf_tmp.ravel()[ind] = mf_gvct[mf_ix[0, i] : mf_ix[1, i]] mf_tmp_c.ravel()[ind_c] = mfc_gvct[mf_ix_c[0, i] : mf_ix_c[1, i]] mf_tmp = mf_tmp.reshape([npix, npix]) mf_tmp_c = mf_tmp_c.reshape([npix, npix]) mf["norm"][:, :, i] = np.roll(mf_tmp, 0, axis=1) mf["norm_c"][:, :, i] = np.roll(mf_tmp_c, 0, axis=1) mf_temp_rot = np.roll(np.roll(np.rot90(np.rot90(mf_tmp)), 1, axis=0), 1, axis=1) mf_temp_rot_c = np.roll( np.roll(np.rot90(np.rot90(mf_tmp_c)), 1, axis=0), 1, axis=1 ) mf["conj"][:, :, i] = mf_temp_rot mf["conj_c"][:, :, i] = mf_temp_rot_c norm = np.sqrt(np.sum(mf["norm"][:, :, i] ** 2)) mf["norm"][:, :, i] = mf["norm"][:, :, i] / norm mf["conj"][:, :, i] = mf["conj"][:, :, i] / norm mf["norm_c"][:, :, i] = mf["norm_c"][:, :, i] / norm mf["conj_c"][:, :, i] = mf["conj_c"][:, :, i] / norm rmat, imat = _make_overlap_mat(mf, n_baselines, display=diag_plot) mf_tot = np.sum(mf["norm"], axis=2) + np.sum(mf["conj"], axis=2) mf_tot_m = np.sum(mf["norm"], axis=2) - np.sum(mf["conj"], axis=2) im_uv = np.roll(np.fft.fftshift(mf_tot), 1, axis=1) if display: import matplotlib.pyplot as plt plt.figure(figsize=(9, 7)) plt.title("(u-v) plan - mask %s" % (maskname), fontsize=14) plt.imshow(im_uv, origin="lower") plt.plot(npix // 2 + 1, npix // 2, "r+") plt.ylabel("Y [pix]") # , fontsize=12) plt.xlabel("X [pix]") # , fontsize=12) plt.tight_layout() out = { "cube": mf["norm"], "imat": imat, "rmat": rmat, "uv": im_uv, "tot": mf_tot, "tot_m": mf_tot_m, "pvct": mf_pvct, "gvct": mf_gvct, "cpvct": mfc_pvct, "cgvct": mfc_gvct, "ix": mf_ix, "u": u * filt[0], "v": v * filt[0], "wl": filt[0], "e_wl": filt[1], "pixelSize": pixelsize, "xy_coords": xy_coords, } return dict2class(out)
def extract_bs( cube, filename, maskname, filtname=None, targetname=None, instrum=None, bs_multi_tri=False, peakmethod="gauss", hole_diam=0.8, cutoff=1e-4, fw_splodge=0.7, naive_err=False, n_wl=3, n_blocks=0, theta_detector=0, scaling_uv=1, i_wl=None, unbias_v2=True, compute_cp_cov=True, expert_plot=False, save_to=None, verbose=False, display=True, ): """Compute the bispectrum (bs, v2, cp, etc.) from a data cube. Parameters: ----------- `cube` {array}: Cleaned and checked data cube ready to extract NRM data,\n `filename` {array}: Name of the file containing the datacube (to keep track on it),\n `maskname` {str}: Name of the mask,\n `filtname` {str}: By default, checks the header to extract the filter, if not in header uses filtname instead (e.g.: F430M, F480M),\n `targetname` {str}: By default, checks the header to extract the target, if not in header uses target_name instead,\n `bs_multi_tri` {bool}: Use the multiple triangle technique to compute the bispectrum (default: False),\n `peakmethod` {str}: 3 methods are used to sample to u-v space: 'fft' uses fft between individual holes to compute the expected splodge position; 'square' compute the splodge in a square using the expected fraction of pixel to determine its weight; 'gauss' considers a gaussian splodge (with a gaussian weight) to get the same splodge side for each n(n-1)/2 baselines,\n `fw_splodge` {float}: Relative size of the splodge used to compute multiple triangle indices and the fwhm of the 'gauss' technique,\n `naive_err` {bool}: If True, the uncertainties are computed using the std of the overall cvis or bs array. Otherwise, the uncertainties are computed using covariance matrices,\n `n_wl` {int}: Number of elements to sample the spectral filters (default: 3),\n `n_blocks` {float}: Number of separated blocks use to split the data cube and get more accurate uncertainties (default: 0, n_blocks = n_ps),\n `theta_detector`: {float} Angle [deg] to rotate the mask compare to the detector (if the mask is not perfectly aligned with the detector, e.g.: VLT/VISIR) ,\n `i_wl`: {int} Only used for IFU data (e.g.: IFS/SPHERE), select the desired spectral channel to retrieve the appropriate wavelength and mask positions, \n `unbias_v2`: {bool} If True, the squared visibilities are unbiased using the Fourier base, \n `targetname` {str}: Name of the target to save in oifits file (if not in header of the cube),\n `save_to` {str}: Name of the repository to save the figures,\n `verbose` {bool}: If True, print usefull informations during the process.\n `display` {bool}: If True, display all figures,\n Returns: -------- `obs_result` {class object}: Return all interferometric observables (.vis2, .e_vis2, .cp, .e_cp, etc.), information relative to the used mask (.mask), the computed matrices and statistic (.matrix) and the important information (.infos). The .mask, .infos and .matrix are also class with various quantities (see .mask.__dict__.keys()). """ if verbose: cprint("\n-- Starting extraction of observables --", "cyan") start_time = time.time() if save_to is not None: if not os.path.exists(save_to): os.mkdir(save_to) with fits.open(filename) as hdu: hdr = hdu[0].header infos = _check_input_infos( hdr, targetname=targetname, filtname=filtname, instrum=instrum, verbose=False ) if "INSTRUME" not in hdr.keys(): hdr["INSTRUME"] = infos["instrument"] # 1. Open the data cube and perform a series of roll (both axis) to avoid # grid artefact (negative fft values). # ------------------------------------------------------------------------ ft_arr, n_ps, npix = _construct_ft_arr(cube) # Number of aperture in the mask try: n_holes = len(get_mask(infos.instrument, maskname)) except TypeError: return None # 2. Determine the number of different baselines (bl), bispectrums (bs) or # covariance matrices (cov) and associates each holes as couple for bl or # triplet for bs (or cp) using compute_index_mask function (see ami_function.py). # ------------------------------------------------------------------------ index_mask = compute_index_mask(n_holes) n_baselines = index_mask.n_baselines closing_tri = _format_closing_triangle(index_mask) # 3. Compute the match filter mf # ------------------------------------------------------------------------ mf = make_mf( maskname, infos.instrument, infos.filtname, npix, peakmethod=peakmethod, fw_splodge=fw_splodge, n_wl=n_wl, cutoff=cutoff, hole_diam=hole_diam, scaling=scaling_uv, theta_detector=theta_detector, i_wl=i_wl, display=display, save_to=save_to, filename=filename, ) ifig = 2 if save_to is not None: figname = os.path.join(save_to, Path(filename).stem) plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 if mf is None: return None # We store the principal results in the new dictionnary to be save at the end obs_result = {"u": mf.u, "v": mf.v, "wl": mf.wl, "e_wl": mf.e_wl} # 4. Compute indices for the multiple triangle technique (tri_pix function) # ------------------------------------------------------------------------- l_B = np.sqrt(mf.u ** 2 + mf.v ** 2) # Length of different bl [m] minbl = np.min(l_B) if n_holes >= 15: sampledisk_r = minbl / 2 / mf.wl * mf.pixelSize * npix * 0.9 else: sampledisk_r = minbl / 2 / mf.wl * mf.pixelSize * npix * fw_splodge if bs_multi_tri: closing_tri_pix = tri_pix(npix, sampledisk_r, display=display, verbose=verbose) else: closing_tri_pix = None # 5. Display the power spectrum of the first frame to check the computed # positions of the peaks. # ------------------------------------------------------------------------ if display: _show_complex_ps(ft_arr) if save_to is not None: plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 _show_peak_position(ft_arr, n_baselines, mf, maskname, peakmethod) if save_to is not None: plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 if verbose: print("\nFilename: %s" % filename) print("# of frames = %i" % n_ps) n_blocks = _set_good_nblocks(n_blocks, n_ps) # 6. Extract the complex quantities from the fft_arr (complex vis, bispectrum, # phase, etc.) # ------------------------------------------------------------------------ fringe_peak = give_peak_info2d(mf, n_baselines, npix, npix) if verbose: print("\nCalculating V^2 and BS...") complex_bs = _compute_complex_bs( ft_arr, index_mask, fringe_peak, mf, dark_ps=None, closing_tri_pix=closing_tri_pix, bs_multi_tri=bs_multi_tri, verbose=verbose, ) cvis_arr = complex_bs["vis_arr"]["complex"] v2_arr = complex_bs["vis_arr"]["squared"] bs_arr = complex_bs["bs_arr"] fluxes = complex_bs["fluxes"] # 7. Compute correlated noise and bias at the peak position # --------------------------------------------------------- bias, dark_bias, autocor_noise = _compute_corr_noise( complex_bs, ft_arr, fringe_peak ) v2_arr_unbiased, bias_arr = _unbias_v2_arr( v2_arr, npix, fringe_peak, bias, dark_bias, autocor_noise, unbias=unbias_v2 ) # 8. Turn Arrays into means and covariance matrices # ------------------------------------------------- v2_quantities = _compute_v2_quantities(v2_arr_unbiased, bias_arr, n_blocks) bs_quantities = _compute_bs_quantities( bs_arr, v2_quantities["v2"], fluxes, index_mask, n_blocks ) bs_v2_cov = _compute_bs_v2_cov( bs_arr, v2_arr_unbiased, v2_quantities["v2"], bs_quantities["bs"], index_mask ) if compute_cp_cov: cp_cov = _compute_cp_cov( bs_arr, bs_quantities["bs"], index_mask, disable=np.invert(verbose) ) else: cp_cov = None # 9. Now normalize all extracted observables vis2_norm, obs_norm = _normalize_all_obs( bs_quantities, v2_quantities, cvis_arr, cp_cov, bs_v2_cov, fluxes, index_mask, infos, expert_plot=display, ) if save_to is not None: plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 obs_result["vis2"] = vis2_norm # 10. Now we compute the cp quantities and store them with the other observables obs_result = _compute_cp(obs_result, obs_norm, infos, expert_plot=display) if save_to is not None: plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 if display: _show_norm_matrices(obs_norm, expert_plot=expert_plot) if save_to is not None: plt.savefig(f"{figname}_{ifig}.pdf") ifig += 1 t3_coord, bl_cp = _compute_t3_coord(mf, index_mask) bl_v2 = np.sqrt(mf.u ** 2 + mf.v ** 2) obs_result["bl"] = bl_v2 obs_result["bl_cp"] = bl_cp # 11. Now we compute the uncertainties using the covariance matrix (for v2) # and the variance matrix for the cp. obs_result = _compute_uncertainties(obs_result, obs_norm, naive_err=naive_err) # 12. Compute scaling error due to phase error (piston) between holes. fitmat = _compute_phs_piston(complex_bs, index_mask, display=expert_plot) phs_v2corr = _compute_phs_error(complex_bs, fitmat, index_mask, npix) obs_norm["phs_v2corr"] = phs_v2corr # 13. Compute the absolute oriention (North-up, East-left) # ------------------------------------------------------------------------ pa = compute_pa(hdr, n_ps, display=display, verbose=verbose) # Compile informations in the storage infos class infos = _add_infos_header(infos, hdr, mf, pa, filename, maskname, npix) mask = { "bl2h_ix": index_mask.bl2h_ix, "bs2bl_ix": index_mask.bs2bl_ix, "closing_tri": closing_tri, "xycoord": mf.xy_coords, "n_holes": index_mask.n_holes, "n_baselines": index_mask.n_baselines, "t3_coord": t3_coord, } # Finally we store the computed matrices (cov, var, arr, etc,), the informations # and the mask parameters to the final output. obs_result["mask"] = mask obs_result["infos"] = infos obs_result["matrix"] = obs_norm t = time.time() - start_time m = t // 60 if save_to is not None: produce_result_pdf(save_to, Path(filename).stem) if verbose: cprint("\nDone (exec time: %d min %2.1f s)." % (m, t - m * 60), color="magenta") return dict2class(obs_result)
def make_mf(maskname, instrument, filtname, npix, peakmethod='fft', n_wl=3, theta_detector=0, cutoff=1e-4, hole_diam=0.8, fw_splodge=0.7, verbose=False, diag_plot=False, display=True): """ Summary: -------- Compute the match filter mf which give the indices of the peak positions (mf.pvct) and the associated gains (mf.gvct) in the image. Contains also the u-v coordinates, wavelengths informations, holes mask positions (mf.xy_coords), centered mf (mf.cpvct, mf.gpvct), etc. Parameters: ----------- `maskname`: str Name of the mask (number of holes),\n `instrument`: str Instrument used (default = jwst),\n `filtname`: str Name of the filter,\n `npix`: int Size of the image,\n `peakmethod` {str}: 3 methods are used to sample the u-v space: 'fft' uses fft between individual holes to compute the expected splodge positions; 'square' compute the splodge in a square using the expected fraction of pixel to determine its weight; 'gauss' considers a gaussian splodge (with a gaussian weight) to get the same splodge side for each n(n-1)/2 baselines,\n `n_wl`: int number of wavelengths to use to simulate bandwidth,\n `theta_detector`: float Angle [deg] to rotate the mask compare to the detector (if the mask is not perfectly aligned with the detector, e.g.: VLT/VISIR) ,\n `cutoff`: float cutoff limit between noise and signal pixels in simulated transforms,\n `hole_diam`: float Diameter of a single aperture (0.8 for JWST),\n `fw_splodge` {float}: Relative size of the splodge used to compute multiple triangle indices and the fwhm of the 'gauss' technique,\n """ # Get detector, filter and mask informations # ------------------------------------------ pixelsize = get_pixel_size(instrument) # Pixel size of the detector [rad] # Wavelength of the filter (filt[0]: central, filt[1]: width) filt = get_wavelength(instrument, filtname) xy_coords = get_mask(instrument, maskname) # mask coordinates x_mask = xy_coords[:, 0] y_mask = xy_coords[:, 1] x_mask_rot = x_mask*np.cos(np.deg2rad(theta_detector)) + \ y_mask*np.sin(np.deg2rad(theta_detector)) y_mask_rot = -x_mask*np.sin(np.deg2rad(theta_detector)) + \ y_mask*np.cos(np.deg2rad(theta_detector)) xy_coords_rot = [] for i in range(len(x_mask)): xy_coords_rot.append([x_mask_rot[i], y_mask_rot[i]]) xy_coords = np.array(xy_coords_rot) if display: _plot_mask_coord(xy_coords, maskname, instrument) n_holes = xy_coords.shape[0] index_mask = compute_index_mask(n_holes) n_baselines = index_mask.n_baselines n_bispect = index_mask.n_bispect ncp_i = int((n_holes - 1)*(n_holes - 2)/2) if verbose: cprint('---------------------------', 'cyan') cprint('%s (%s): %i holes masks' % (instrument.upper(), filtname, n_holes), 'cyan') cprint('---------------------------', 'cyan') cprint('nbl = %i, nbs = %i, ncp_i = %i, ncov = %i' % (n_baselines, n_bispect, ncp_i, index_mask.n_cov), 'cyan') # Consider the filter to be made up of n_wl wavelengths wl = np.arange(n_wl)/n_wl*filt[1] wl = wl - np.mean(wl) + filt[0] Sum, Sum_c = 0, 0 mf_ix = np.zeros([2, n_baselines], dtype=int) # matched filter mf_ix_c = np.zeros([2, n_baselines], dtype=int) # matched filter if verbose: print('\n- Calculating sampling of', n_holes, 'holes array...') innerpix, innerpix_center = _compute_center_splodge(npix, pixelsize, filt, hole_diam=hole_diam) u, v = _compute_uv_coord(xy_coords, index_mask, filt, pixelsize, npix, round_uv_to_pixel=False) mf_pvct = mf_gvct = mfc_pvct = mfc_gvct = None for i in range(n_baselines): args = {'i': i, 'npix': npix, 'pixelsize': pixelsize, 'innerpix': innerpix, 'innerpix_center': innerpix_center} if peakmethod == 'fft': ind_peak = _peak_fft_method(xy_coords=xy_coords, wl=wl, index_mask=index_mask, **args) elif peakmethod == 'square': ind_peak = _peak_square_method(u=u, v=v, **args) elif peakmethod == 'one': ind_peak = _peak_one_method(u=u, v=v, **args) elif peakmethod == 'gauss': ind_peak = _peak_gauss_method(u=u, v=v, filt=filt, index_mask=index_mask, fw_splodge=fw_splodge, **args, hole_diam=hole_diam) else: cprint( "Error: choose the extraction method 'gauss', 'fft' or 'square'.", 'red') return None # Compute the cutoff limit before saving the gain map pixelvector = np.where(ind_peak['flat'] >= cutoff)[0] pixelvector_c = np.where(ind_peak['centered'] >= cutoff)[0] # Now normalise the pixel gain, so that using the matched filter # on an ideal splodge is equivalent to just looking at the peak... if peakmethod == 'gauss': pixelgain, pixelgain_c = _normalize_gain(ind_peak['gain_f'], ind_peak['gain_c'], pixelvector, pixelvector_c) else: pixelgain, pixelgain_c = _normalize_gain(ind_peak['flat'], ind_peak['centered'], pixelvector, pixelvector_c) mf_ix[0, i] = Sum Sum = Sum + len(pixelvector) mf_ix[1, i] = Sum mf_ix_c[0, i] = Sum_c Sum_c = Sum_c + len(pixelvector_c) mf_ix_c[1, i] = Sum_c if (i == 0): mf_pvct = list(pixelvector) mf_gvct = list(pixelgain) mfc_pvct = list(pixelvector_c) mfc_gvct = list(pixelgain_c) else: mf_pvct.extend(list(pixelvector)) mf_gvct.extend(list(pixelgain)) mfc_pvct.extend(list(pixelvector_c)) mfc_gvct.extend(list(pixelgain_c)) mf = np.zeros([npix, npix, n_baselines], dtype=[('norm', float), ('conj', float), ('norm_c', float), ('conj_c', float)]) for i in range(n_baselines): mf_tmp = np.zeros([npix, npix]) mf_tmp_c = np.zeros([npix, npix]) ind = mf_pvct[mf_ix[0, i]:mf_ix[1, i]] ind_c = mfc_pvct[mf_ix_c[0, i]:mf_ix_c[1, i]] mf_tmp.ravel()[ind] = mf_gvct[mf_ix[0, i]:mf_ix[1, i]] mf_tmp_c.ravel()[ind_c] = mfc_gvct[mf_ix_c[0, i]:mf_ix_c[1, i]] mf_tmp = mf_tmp.reshape([npix, npix]) mf_tmp_c = mf_tmp_c.reshape([npix, npix]) mf['norm'][:, :, i] = np.roll(mf_tmp, 0, axis=1) mf['norm_c'][:, :, i] = np.roll(mf_tmp_c, 0, axis=1) mf_temp_rot = np.roll( np.roll(np.rot90(np.rot90(mf_tmp)), 1, axis=0), 1, axis=1) mf_temp_rot_c = np.roll( np.roll(np.rot90(np.rot90(mf_tmp_c)), 1, axis=0), 1, axis=1) mf['conj'][:, :, i] = mf_temp_rot mf['conj_c'][:, :, i] = mf_temp_rot_c norm = np.sqrt(np.sum(mf['norm'][:, :, i]**2)) mf['norm'][:, :, i] = mf['norm'][:, :, i]/norm mf['conj'][:, :, i] = mf['conj'][:, :, i]/norm mf['norm_c'][:, :, i] = mf['norm_c'][:, :, i]/norm mf['conj_c'][:, :, i] = mf['conj_c'][:, :, i]/norm rmat, imat = _make_overlap_mat(mf, n_baselines, display=diag_plot) mf_tot = np.sum(mf['norm'], axis=2) + np.sum(mf['conj'], axis=2) mf_tot_m = np.sum(mf['norm'], axis=2) - np.sum(mf['conj'], axis=2) im_uv = np.roll(np.fft.fftshift(mf_tot), 1, axis=1) if display: plt.figure(figsize=(6, 6)) plt.title('(u-v) plan - mask %s' % (maskname), fontsize=14) plt.imshow(im_uv, origin='lower') plt.plot(npix//2+1, npix//2, 'r+') plt.ylabel('Y [pix]') # , fontsize=12) plt.xlabel('X [pix]') # , fontsize=12) plt.tight_layout() out = {'cube': mf['norm'], 'imat': imat, 'rmat': rmat, 'uv': im_uv, 'tot': mf_tot, 'tot_m': mf_tot_m, 'pvct': mf_pvct, 'gvct': mf_gvct, 'cpvct': mfc_pvct, 'cgvct': mfc_gvct, 'ix': mf_ix, 'u': u*filt[0], 'v': v*filt[0], 'wl': filt[0], 'e_wl': filt[1], 'pixelSize': pixelsize, 'xy_coords': xy_coords } return dict2class(out)