def plot_grid(self, filename=None, show=False, plot_radii=[], xy_lim=None): if self.uv_grid is None: self.grid_uvw_coords() grid_size = self.uv_grid.shape[0] wavelength = const.c.value / self.freq_hz fov_rad = Imager.uv_cellsize_to_fov(self.grid_cell_size_m / wavelength, grid_size) extent = Imager.grid_extent_wavelengths(degrees(fov_rad), grid_size) extent = np.array(extent) * wavelength fig, ax = plt.subplots(figsize=(8, 8), ncols=1, nrows=1) fig.subplots_adjust(left=0.125, bottom=0.1, right=0.9, top=0.9, wspace=0.2, hspace=0.2) image = self.uv_grid.real options = dict(interpolation='nearest', cmap='gray_r', extent=extent, origin='lower') im = ax.imshow(image, norm=ImageNormalize(stretch=LogStretch()), **options) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="2%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.set_label('baselines per pixel') cbar.ax.tick_params(labelsize='small') ticks = np.arange(5) * round(image.max() / 5) ticks = np.append(ticks, image.max()) cbar.set_ticks(ticks, update_ticks=True) for r in plot_radii: ax.add_artist(plt.Circle((0, 0), r, fill=False, color='r')) ax.set_xlabel('uu (m)') ax.set_ylabel('vv (m)') ax.grid(True) if xy_lim is not None: ax.set_xlim(-xy_lim, xy_lim) ax.set_ylim(-xy_lim, xy_lim) if filename is not None: label = '' if 'ska1_v5' in filename: label = 'SKA1 v5' if 'model' in filename: label = 'Model ' + str( re.search(r'\d+', os.path.basename(filename)).group()) ax.text(0.02, 0.95, label, weight='bold', transform=ax.transAxes) fig.savefig(filename) if show: plt.show() if filename is not None or show: plt.close(fig) else: return fig
def to_imager(self): """Returns a new imager from the current settings. Returns: oskar.Imager: A configured imager. """ imager = Imager() imager.capsule = _apps_lib.settings_to_imager(self._capsule) return imager
def grid_uvw_coords(self): if self.uu_m is None: self.gen_uvw_coords() b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 wavelength = const.c.value / self.freq_hz # delta theta = 1 / (n * delta u) cell_lm = 1.0 / (grid_size * (self.grid_cell_size_m / wavelength)) lm_max = grid_size * sin(cell_lm) / 2 uv_grid_fov_deg = degrees(asin(lm_max)) * 2 imager = Imager('single') imager.set_grid_kernel('pillbox', 1, 1) imager.set_size(grid_size) imager.set_fov(uv_grid_fov_deg) weight_ = np.ones_like(self.uu_m) amps_ = np.ones_like(self.uu_m, dtype='c8') self.uv_grid = np.zeros((grid_size, grid_size), dtype='c8') norm = imager.update_plane(self.uu_m / wavelength, self.vv_m / wavelength, self.ww_m / wavelength, amps_, weight_, self.uv_grid, plane_norm=0.0) norm = imager.update_plane(-self.uu_m / wavelength, -self.vv_m / wavelength, -self.ww_m / wavelength, amps_, weight_, self.uv_grid, plane_norm=norm) if not int(norm) == self.uu_m.shape[0] * 2: raise RuntimeError('Gridding uv coordinates failed, ' 'grid sum = %i != number of points gridded = %i' % (norm, self.uu_m.shape[0] * 2))
def make_psf(uu, vv, ww, freq, fov, im_size): imager = Imager('single') wave_length = 299792458.0 / freq uu_ = uu / wave_length vv_ = vv / wave_length ww_ = ww / wave_length amp = numpy.ones(uu.shape, dtype='c16') weight = numpy.ones(uu.shape, dtype='f8') image = imager.make_image(uu_, vv_, ww_, amp, weight, fov, im_size) cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) lm_max = math.sin(0.5 * math.radians(fov)) lm_inc = (2.0 * lm_max) / im_size return {'image': image, 'fov': fov, 'im_size': im_size, 'cell': cell, 'lm_max': lm_max, 'lm_inc': lm_inc}
def eval_psf_rms_r(self, num_bins=100, b_min=None, b_max=None): """PSFRMS radial profile""" if self.uv_grid is None: self.grid_uvw_coords() grid_size = self.uv_grid.shape[0] gx, gy = Imager.grid_pixels(self.grid_cell_size_m, grid_size) gr = (gx**2 + gy**2)**0.5 b_max = self.r_uv_m.max() if b_max is None else b_max b_min = self.r_uv_m.min() if b_min is None else b_min r_bins = np.logspace(log10(b_min), log10(b_max), num_bins + 1) self.psf_rms_r = np.zeros(num_bins) for i in range(num_bins): pixels = self.uv_grid[np.where(gr <= r_bins[i + 1])] uv_idx = np.where(self.r_uv_m <= r_bins[i + 1])[0] uv_count = uv_idx.shape[0] * 2 self.psf_rms_r[i] = 1.0 if uv_count == 0 else \ np.sqrt(np.sum(pixels.real**2)) / uv_count self.psf_rms_r_x = r_bins[1:] fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(self.psf_rms_r_x, self.psf_rms_r) ax.set_xscale('log') ax.set_yscale('log') ax.set_xlabel('radius (m)') ax.set_ylabel('PSFRMS') ax.set_xlim(10**floor(log10(self.psf_rms_r_x[0])), 10**ceil(log10(self.psf_rms_r_x[-1]))) ax.set_ylim(10**floor(log10(self.psf_rms_r.min())), 1.05) ax.grid(True) plt.show()
def plot_grid(self, filename=None, show=False, plot_radii=[], x_lim=None, y_lim=None): if self.uv_grid is None: self.grid_uvw_coords() grid_size = self.uv_grid.shape[0] wavelength = const.c.value / self.freq_hz fov_rad = Imager.uv_cellsize_to_fov(self.grid_cell_size_m / wavelength, grid_size) extent = Imager.grid_extent_wavelengths(degrees(fov_rad), grid_size) extent = np.array(extent) * wavelength fig, ax = plt.subplots(figsize=(8, 8), ncols=1, nrows=1) fig.subplots_adjust(left=0.125, bottom=0.1, right=0.9, top=0.9, wspace=0.2, hspace=0.2) image = self.uv_grid.real options = dict(interpolation='nearest', cmap='gray_r', extent=extent, origin='lower') im = ax.imshow(image, norm=ImageNormalize(stretch=LogStretch()), **options) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="2%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.set_label('baselines per pixel') cbar.ax.tick_params(labelsize='small') ticks = np.arange(5) * round(image.max() / 5) ticks = np.append(ticks, image.max()) cbar.set_ticks(ticks, update_ticks=True) for r in plot_radii: ax.add_artist(plt.Circle((0, 0), r, fill=False, color='r')) ax.set_xlabel('uu (m)') ax.set_ylabel('vv (m)') if not x_lim is None: ax.set_xlim(x_lim) if not y_lim is None: ax.set_ylim(y_lim) if filename is not None: fig.savefig(filename) if show: plt.show() if filename is not None or show: plt.close(fig) else: return fig
def grid_uvw_coords(self): if self.uu_m is None: self.gen_uvw_coords() b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 wavelength = const.c.value / self.freq_hz # delta theta = 1 / (n * delta u) cell_lm = 1.0 / (grid_size * (self.grid_cell_size_m / wavelength)) lm_max = grid_size * sin(cell_lm) / 2 uv_grid_fov_deg = degrees(asin(lm_max)) * 2 imager = Imager('single') imager.set_grid_kernel('pillbox', 1, 1) imager.set_size(grid_size) imager.set_fov(uv_grid_fov_deg) weight_ = np.ones_like(self.uu_m) amps_ = np.ones_like(self.uu_m, dtype='c8') self.uv_grid = np.zeros((grid_size, grid_size), dtype='c8') norm = imager.update_plane(self.uu_m / wavelength, self.vv_m / wavelength, self.ww_m / wavelength, amps_, weight_, self.uv_grid, plane_norm=0.0) norm = imager.update_plane(-self.uu_m / wavelength, -self.vv_m / wavelength, -self.ww_m / wavelength, amps_, weight_, self.uv_grid, plane_norm=norm) if not int(norm) == self.uu_m.shape[0] * 2: raise RuntimeError( 'Gridding uv coordinates failed, ' 'grid sum = %i != number of points gridded = %i' % (norm, self.uu_m.shape[0] * 2))
def eval_psf_rms_r(self, num_bins=100, b_min=None, b_max=None): """PSFRMS radial profile""" if self.uv_grid is None: self.grid_uvw_coords() grid_size = self.uv_grid.shape[0] gx, gy = Imager.grid_pixels(self.grid_cell_size_m, grid_size) gr = (gx**2 + gy**2)**0.5 b_max = self.r_uv_m.max() if b_max is None else b_max b_min = self.r_uv_m.min() if b_min is None else b_min r_bins = np.logspace(log10(b_min), log10(b_max), num_bins + 1) self.psf_rms_r = np.zeros(num_bins) for i in range(num_bins): pixels = self.uv_grid[np.where(gr <= r_bins[i + 1])] uv_idx = np.where(self.r_uv_m <= r_bins[i + 1])[0] uv_count = uv_idx.shape[0] * 2 self.psf_rms_r[i] = 1.0 if uv_count == 0 else \ np.sqrt(np.sum(pixels.real**2)) / uv_count self.psf_rms_r_x = r_bins[1:]
def run(config, vis, amp_name, image_name=None): images = [] border_trim = 0.4 # Fraction of 1 for image_id in range(len(config['imaging']['images'])): sim_dir = config['path'] image_config = config['imaging']['images'][image_id] obs_config = config['sim']['observation'] mjd_start = obs_config['start_time_mjd'] num_dumps = obs_config['num_times'] dump_time_s = obs_config['dump_time_s'] freq_hz = obs_config['freq_hz'] vis_ra = obs_config['ra_deg'] vis_dec = obs_config['dec_deg'] image_ra = vis_ra image_dec = vis_dec if 'ra_deg' in image_config: image_ra = image_config['ra_deg'] if 'dec_deg' in image_config: image_dec = image_config['dec_deg'] size = image_config['size'] fov = image_config['fov_deg'] num_vis = len(vis[amp_name]) print('- Making image...') print(' - Description :', image_config['description']) print(' - Amplitude array name :', amp_name) print(' - Number of visibilities :', num_vis) print(' - Size :', size) print(' - FoV : %.1f deg' % fov) # Set up the imager. im = numpy.zeros([size, size], dtype='f8') img = Imager("double") img.set_fov(fov) img.set_size(size) if image_name != None: img.set_output_root(join(sim_dir, image_name + '_' + str(image_id))) img.set_vis_frequency(freq_hz, 0.0, 1) img.set_vis_time(mjd_start + 0.5 * (num_dumps * dump_time_s), dump_time_s, 1) img.set_vis_phase_centre(vis_ra, vis_dec) if image_ra != vis_ra or image_dec != vis_dec: img.set_direction(image_ra, image_dec) block_size = num_vis / 100 num_blocks = (num_vis + block_size - 1) / block_size t0 = time.time() for i in range(num_blocks): start = i * block_size end = start + block_size if end > num_vis: end = num_vis img.update(end-start, vis['uu'][start:end], vis['vv'][start:end], vis['ww'][start:end], vis[amp_name][start:end], vis['weight'][start:end]) img.finalise(im) pix_start = border_trim * size pix_end = size - pix_start images.append(im[pix_start:pix_end, pix_start:pix_end]) print(' - Visibilities imaged in %.1f s' % (time.time() - t0)) return images
def main(): # Options # ========================================================================= # Telescope model lon, lat = 116.63128900, -26.69702400 # degrees station_d = 35.0 # m telescope_radius_cut = 1000 # m (Remote stations in the telescope > this) eta = 1.0 # System efficiency # Observation settings az0, el0, date0 = 0.0, 90.0, '2016/7/14 10:30' # Midpoint coordinates #start_freqs = 50e6 + np.array([0, 6, 12, 18]) * 8e6 # start_freqs = [50e6] start_freqs = 50e6 + np.array([6, 12, 18]) * 8e6 num_channels, freq_inc = 80, 100e3 obs_length_h, noise_obs_length_h = 5, 1000 t_acc = 60.0 # Time resolution of visibility coordinates, in seconds. # Image settings im_size = 512 algorithm = 'w-projection' weights = 'uniform' lambda_cut = True w_planes = 64 # Results directory results_dir = 'noise_cubes_%s_%s' % (weights, algorithm.lower()) if algorithm.lower().startswith('w') and w_planes > 0: results_dir += '_%i' % w_planes # ========================================================================= # Calculate observation equatorial coordinates and start MJD of the # specified target field obs = ephem.Observer() obs.lon, obs.lat, obs.elevation = radians(lon), radians(lat), 0.0 obs.date = str(date0) ra, dec = obs.radec_of(radians(az0), radians(el0)) ra, dec = degrees(ra), degrees(dec) mjd_mid = ephem.julian_date(b'2016/02/25 10:30') - 2400000.5 mjd_start = mjd_mid - obs_length_h / (2 * 24.0) # Load telescope model and generate uvw coordinates, in metres coords_file = join(results_dir, 'uvw_m.npz') x, y, z = load_telescope(telescope_radius_cut, station_d, lon, lat, join(results_dir, 'telescope.eps')) num_stations = x.shape[0] uu, vv, ww, num_times = generate_uvw_coords_m(x, y, z, obs_length_h, mjd_mid, t_acc, ra, dec, join(results_dir, 'uvw')) t0 = time.time() np.savez(coords_file, uu=uu, vv=vv, ww=ww, x=x, y=y, z=z, num_times=num_times) print('- No. stations = %i' % num_stations) print('- Saved uvw coordinates in %.2f s' % (time.time() - t0)) # Evaluate radial uv co-ordinate range (needed for lambda cut) r_uvw = (uu**2 + vv**2)**0.5 r_uvw_min = r_uvw.min() r_uvw_max = r_uvw.max() # Allocate image cubes. noise_cube = np.zeros((num_channels, im_size, im_size)) psf_cube = np.zeros((num_channels, im_size, im_size)) # Loop over cube start frequency. for i, start_freq in enumerate(start_freqs): print() print('- Freq = %.1f MHz (+%i x %0.1f kHz)' % (start_freq / 1e6, num_channels, freq_inc / 1e3)) # Array of cube frequency channels freqs = (start_freq + (np.arange(num_channels) * freq_inc + freq_inc / 2)) # Calculate image FoV and lambda cuts fov_deg = 1.5 * degrees((const.c.value / start_freq) / station_d) print('- FoV = %.2f deg.' % fov_deg) # Generate file names of image cube and noise outputs. if lambda_cut: l_cut_inner = ceil(r_uvw_min / (const.c.value / freqs[-1])) l_cut_outer = floor(r_uvw_max / (const.c.value / freqs[0])) print('- lambda cut = %.0f, %.0f' % (l_cut_inner, l_cut_outer)) suffix = ('%05.1fMHz_lcut_%04i_%04i_%s_%s' % (start_freq / 1e6, l_cut_inner, l_cut_outer, weights, algorithm.lower())) else: suffix = ('%05.1fMHz_%s_%s' % (start_freq / 1e6, weights, algorithm.lower())) if algorithm.lower().startswith('w') and w_planes > 0: suffix += '_%i' % w_planes l_cut = [l_cut_inner, l_cut_outer] if lambda_cut else None noise_cube_file = join(results_dir, 'noise_' + suffix + '.fits') noise_cube_file_k = join(results_dir, 'noise_' + suffix + '_K.fits') psf_cube_file = join(results_dir, 'psf_' + suffix + '.fits') noise_sigma_file = join(results_dir, 'noise_sigma_' + suffix + '.npz') t0 = time.time() # Option to load existing image cubes (used to skip directly to fitting # the psf and converting to K) if os.path.exists(noise_cube_file): noise_cube = fits.getdata(noise_cube_file) psf_cube = fits.getdata(psf_cube_file) # Simulate / image the noise cube (in Jy/beam) and PSF cube. else: sigma_pq, sigma_im = np.zeros(num_channels), np.zeros(num_channels) num_coords = np.zeros(num_channels, dtype='i8') progress_bar = ProgressBar(maxval=num_channels, widgets=[ Bar(marker='='), Counter(format='%03i'), '/%03i ' % num_channels, Percentage(), ' ', Timer(), ' ', ETA() ]).start() # Loop over frequencies in the cube for j, freq in enumerate(freqs): # Convert coordinates wavelength and apply lambda cut wavelength = const.c.value / freq uu_l = (uu / wavelength) vv_l = (vv / wavelength) ww_l = (ww / wavelength) if lambda_cut: r_uv = (uu_l**2 + vv_l**2)**0.5 idx = np.where( np.logical_and(r_uv >= l_cut_inner, r_uv <= l_cut_outer)) uu_l, vv_l, ww_l = uu_l[idx], vv_l[idx], ww_l[idx] num_coords[j] = uu_l.shape[0] # Evaluate visibility noise (and predicted image noise) sigma_pq[j] = evaluate_scaled_noise_rms( freq, num_times, freq_inc, eta, noise_obs_length_h) sigma_im[j] = sigma_pq[j] / num_coords[j]**0.5 # Make the noise image amp = (randn(num_coords[j]) + 1j * randn(num_coords[j])) * sigma_pq[j] noise_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) # Make the psf amp = np.ones(uu_l.shape[0], dtype='c16') psf_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) progress_bar.update(j) progress_bar.finish() # Save noise values and cube images in Jy/beam np.savez(noise_sigma_file, freqs=freqs, sigma_pq=sigma_pq, sigma_im=sigma_im, num_coords=num_coords) write_fits_cube(noise_cube, noise_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) write_fits_cube(psf_cube, psf_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) print('- Time taken = %.2f s (image cube)' % (time.time() - t0)) # Fit the PSF with a gaussian to evaluate the beam area (in arcmin^2) t0 = time.time() r_uv_max_l = l_cut_outer if lambda_cut else \ r_uvw_max / (const.c.value / start_freq) area_arcmin2 = eval_beam_area(psf_cube, r_uv_max_l, fov_deg, freqs, start_freq, results_dir, weights, plot=False) print('- Time taken = %.2f s (fit area)' % (time.time() - t0)) # Convert cube from Jy/beam to K t0 = time.time() for j, freq in enumerate(freqs): image = noise_cube[j, :, :] area_sr = (area_arcmin2[j] / 3600.0) * (pi / 180)**2 image /= area_sr image *= (1e-26 * const.c.value**2) / (2 * const.k_B.value * freq**2) write_fits_cube(noise_cube, noise_cube_file_k, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm, bunit='K') print('- Time taken = %.2f s (convert to K)' % (time.time() - t0)) print()
def make_psf(uu, vv, ww, ra, dec, freq, fov, im_size, file_name): imager = Imager("single") wave_length = 299792458.0 / freq uu_ = uu / wave_length vv_ = vv / wave_length ww_ = ww / wave_length amp = numpy.ones(uu.shape, dtype="c16") weight = numpy.ones(uu.shape, dtype="f8") image = imager.make_image(uu_, vv_, ww_, amp, weight, fov, im_size) cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) lm_max = math.sin(0.5 * math.radians(fov)) lm_inc = (2.0 * lm_max) / im_size off = lm_inc / 2.0 extent = [-lm_max - off, lm_max - off, -lm_max + off, lm_max + off] fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect="equal") divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.07) im = ax.imshow(image, interpolation="nearest", extent=extent, cmap="inferno") cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize="small") t = numpy.linspace(image.min(), image.max(), 7) ax.figure.colorbar(im, cax=cax, ticks=t, format="%.2f") ax.set_xlabel("l", fontsize="small") ax.set_ylabel("m", fontsize="small") ax.tick_params(axis="both", which="major", labelsize="small") ax.tick_params(axis="both", which="minor", labelsize="x-small") pyplot.savefig(file_name + "_%05.2f_%04i_image_lin.png" % (fov, im_size)) pyplot.close(fig) fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect="equal") divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.07) # http://matplotlib.org/api/colors_api.html im = ax.imshow( image, interpolation="nearest", extent=extent, cmap="inferno", norm=SymLogNorm(vmin=-0.01, vmax=1.0, linthresh=0.005, linscale=0.75), ) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize="small") ax.figure.colorbar(im, cax=cax) ax.set_xlabel("l", fontsize="small") ax.set_ylabel("m", fontsize="small") ax.tick_params(axis="both", which="major", labelsize="small") ax.tick_params(axis="both", which="minor", labelsize="x-small") pyplot.savefig(file_name + "_%05.2f_%04i_image_log.png" % (fov, im_size)) pyplot.close(fig) # x = numpy.arange(-image.shape[0]/2, image.shape[0]/2) * lm_inc # x, y = numpy.meshgrid(x, x[::-1]) # r = (x**2 + y**2)**0.5 # x_ = r.flatten() # y_ = image.flatten() # sort_idx = numpy.argsort(x_) # x_ = x_[sort_idx] # y_ = y_[sort_idx] # y_ = numpy.abs(y_) # y_max = numpy.nanmax(y_) # norm_y = y_ / y_max # y_db = 10.0 * numpy.log10(norm_y) # num_bins = 200 # y_mean = numpy.zeros(num_bins) # y_std = numpy.zeros(num_bins) # x_bin = numpy.zeros(num_bins) # bin_inc = (image.shape[0]/2.0 * lm_inc) / float(num_bins) # for i in range(num_bins): # r0 = i * bin_inc # r1 = r0 + bin_inc # x_bin[i] = r0 + (r1 - r0) / 2.0 # idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) # y_bin = y_db[idx] # y_mean[i] = y_bin.mean() # y_std[i] = y_bin.std() # fig = pyplot.figure(figsize=(8, 8)) # ax = fig.add_subplot(111) # ax.plot(x_, y_db, 'k.', alpha=0.01, ms=2.0) # ax.plot(x_bin, y_mean, 'r-') # # ax.plot(x_bin, y_mean + y_std, 'b-', lw=1.0, alpha=0.5) # # ax.plot(x_bin, y_mean - y_std, 'b-', lw=1.0, alpha=0.5) # ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, # edgecolor='blue', facecolor='blue', alpha=0.6) # ax.set_ylim(-40, 0) # ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_title(file_name) # ax.set_xlabel('Radius') # ax.set_ylabel('Decibels') # pyplot.savefig(file_name + '_%05.2f_%04i_log_r_ave.png' % (fov, im_size)) # pyplot.close(fig) # ============== x = numpy.arange(-image.shape[0] / 2, image.shape[0] / 2) * lm_inc x, y = numpy.meshgrid(x, x[::-1]) r = (x ** 2 + y ** 2) ** 0.5 x_ = r.flatten() y_ = image.flatten() sort_idx = numpy.argsort(x_) x_ = x_[sort_idx] y_ = y_[sort_idx] # y_ = numpy.abs(y_) num_bins = 200 y_mean = numpy.zeros(num_bins) y_std = numpy.zeros(num_bins) x_bin = numpy.zeros(num_bins) bin_inc = (image.shape[0] / 2.0 * lm_inc) / float(num_bins) for i in range(num_bins): r0 = i * bin_inc r1 = r0 + bin_inc x_bin[i] = r0 + (r1 - r0) / 2.0 idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) y_bin = y_[idx] y_mean[i] = y_bin.mean() y_std[i] = y_bin.std() fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111) # ax.plot(x_, y_, 'k.', alpha=0.01, ms=2.0) ax.plot(x_bin, y_mean, "r-") ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, edgecolor="blue", facecolor="blue", alpha=0.6) ax.set_ylim(-0.005, 0.05) ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_yscale('symlog', linthreshy=0.00005) # ax.set_yscale('symlog') ax.set_title(file_name) ax.set_xlabel("Radius") ax.grid() # ax.set_ylabel('Decibels') pyplot.savefig(file_name + "_%05.2f_%04i_lin_r_ave.png" % (fov, im_size)) pyplot.close(fig) # ================== # ============== x = numpy.arange(-image.shape[0] / 2, image.shape[0] / 2) * lm_inc x, y = numpy.meshgrid(x, x[::-1]) r = (x ** 2 + y ** 2) ** 0.5 x_ = r.flatten() y_ = image.flatten() sort_idx = numpy.argsort(x_) x_ = x_[sort_idx] y_ = y_[sort_idx] # y_ = numpy.abs(y_) num_bins = 200 y_mean = numpy.zeros(num_bins) y_std = numpy.zeros(num_bins) x_bin = numpy.zeros(num_bins) bin_inc = (image.shape[0] / 2.0 * lm_inc) / float(num_bins) for i in range(num_bins): r0 = i * bin_inc r1 = r0 + bin_inc x_bin[i] = r0 + (r1 - r0) / 2.0 idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) y_bin = y_[idx] y_mean[i] = y_bin.mean() y_std[i] = y_bin.std() fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111) # ax.plot(x_, y_, 'k.', alpha=0.01, ms=2.0) ax.plot(x_bin, y_mean, "r-") ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, edgecolor="blue", facecolor="blue", alpha=0.6) # ax.set_ylim(-0.005, 0.05) ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_yscale('symlog', linthreshy=0.1) ax.set_yscale("symlog") # ax.set_yscale('log', noposy='clip') ax.set_title(file_name) ax.set_xlabel("Radius") ax.grid() # ax.set_ylabel('Decibels') pyplot.savefig(file_name + "_%05.2f_%04i_log_r_ave.png" % (fov, im_size)) pyplot.close(fig)
def eval_psf(self, im_size=None, fov_deg=None, plot2d=False, plot1d=True): if self.uu_m is None: self.gen_uvw_coords() # Evaluate grid size and fov if needed. if im_size is None: b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 else: grid_size = im_size wavelength = const.c.value / self.freq_hz if fov_deg is None: cellsize_wavelengths = self.grid_cell_size_m / wavelength fov_rad = Imager.uv_cellsize_to_fov(cellsize_wavelengths, grid_size) fov_deg = degrees(fov_rad) else: fov_deg = fov_deg uu = self.uu_m / wavelength vv = self.vv_m / wavelength ww = self.ww_m / wavelength amp = np.ones_like(uu, dtype='c8') psf = Imager.make_image(uu, vv, ww, np.ones_like(uu, dtype='c8'), fov_deg, grid_size) extent = Imager.image_extent_lm(fov_deg, grid_size) self.psf = psf self.psf_fov_deg = fov_deg # --- Plotting ---- if plot2d: fig, ax = plt.subplots(figsize=(8, 8)) norm = SymLogNorm(linthresh=0.05, linscale=1.0, vmin=-0.05, vmax=0.5, clip=False) opts = dict(interpolation='nearest', origin='lower', cmap='gray_r', extent=extent, norm=norm) im = ax.imshow(psf, **opts) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize='small') ax.set_xlabel('l') ax.set_ylabel('m') plt.savefig('psf.png') plt.show() plt.close(fig) if plot1d: l, m = Imager.image_pixels(self.psf_fov_deg, grid_size) r_lm = (l**2 + m**2)**0.5 r_lm = r_lm.flatten() idx_sorted = np.argsort(r_lm) r_lm = r_lm[idx_sorted] psf_1d = self.psf.flatten()[idx_sorted] psf_hwhm = (wavelength / (r_lm[-1] * 2.0)) / 2 fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(r_lm, psf_1d, 'k.', ms=2, alpha=0.1) ax.set_xscale('log') ax.set_yscale('log') fig.savefig('TEST_psf1d.png') plt.close(fig) num_bins = 100 # FIXME(BM) make this a function arg psf_1d_mean = np.zeros(num_bins) psf_1d_abs_mean = np.zeros(num_bins) psf_1d_abs_max = np.zeros(num_bins) psf_1d_min = np.zeros(num_bins) psf_1d_max = np.zeros(num_bins) psf_1d_std = np.zeros(num_bins) bin_edges = np.linspace(r_lm[0], r_lm[-1], num_bins + 1) # bin_edges = np.logspace(log10(r_lm[1]), log10(r_lm[-1]), # num_bins + 1) psf_1d_bin_r = (bin_edges[1:] + bin_edges[:-1]) / 2 bin_idx = np.digitize(r_lm, bin_edges) for i in range(1, num_bins + 1): values = psf_1d[bin_idx == i] if values.size > 0: psf_1d_mean[i - 1] = np.mean(values) psf_1d_abs_mean[i - 1] = np.mean(np.abs(values)) psf_1d_abs_max[i - 1] = np.max(np.abs(values)) psf_1d_min[i - 1] = np.min(values) psf_1d_max[i - 1] = np.max(values) psf_1d_std[i - 1] = np.std(values) fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(psf_1d_bin_r, psf_1d_abs_mean, '-', c='b', lw=1, label='abs mean') ax.plot(psf_1d_bin_r, psf_1d_abs_max, '-', c='r', lw=1, label='abs max') ax.plot(psf_1d_bin_r, psf_1d_std, '-', c='g', lw=1, label='std') # ax.set_ylim(-0.1, 0.5) # ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) # ax.set_xscale('log') ax.set_yscale('log') ax.set_ylim(1e-4, 1) ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) ax.set_xlabel('PSF radius (direction cosines)') # ax.set_ylabel('PSF amplitude') ax.set_title('Azimuthally averaged PSF (FoV: %.2f)' % fov_deg) ax.legend() plt.show() plt.close(fig)
def main(): # Options # ========================================================================= # Telescope model lon, lat = 116.63128900, -26.69702400 # degrees station_d = 35.0 # m telescope_radius_cut = 1000 # m (Remote stations in the telescope > this) eta = 1.0 # System efficiency # Observation settings az0, el0, date0 = 0.0, 90.0, '2016/7/14 10:30' # Midpoint coordinates #start_freqs = 50e6 + np.array([0, 6, 12, 18]) * 8e6 # start_freqs = [50e6] start_freqs = 50e6 + np.array([6, 12, 18]) * 8e6 num_channels, freq_inc = 80, 100e3 obs_length_h, noise_obs_length_h = 5, 1000 t_acc = 60.0 # Time resolution of visibility coordinates, in seconds. # Image settings im_size = 512 algorithm = 'w-projection' weights = 'uniform' lambda_cut = True w_planes = 64 # Results directory results_dir = 'noise_cubes_%s_%s' % (weights, algorithm.lower()) if algorithm.lower().startswith('w') and w_planes > 0: results_dir += '_%i' % w_planes # ========================================================================= # Calculate observation equatorial coordinates and start MJD of the # specified target field obs = ephem.Observer() obs.lon, obs.lat, obs.elevation = radians(lon), radians(lat), 0.0 obs.date = str(date0) ra, dec = obs.radec_of(radians(az0), radians(el0)) ra, dec = degrees(ra), degrees(dec) mjd_mid = ephem.julian_date(b'2016/02/25 10:30') - 2400000.5 mjd_start = mjd_mid - obs_length_h / (2 * 24.0) # Load telescope model and generate uvw coordinates, in metres coords_file = join(results_dir, 'uvw_m.npz') x, y, z = load_telescope(telescope_radius_cut, station_d, lon, lat, join(results_dir, 'telescope.eps')) num_stations = x.shape[0] uu, vv, ww, num_times = generate_uvw_coords_m(x, y, z, obs_length_h, mjd_mid, t_acc, ra, dec, join(results_dir, 'uvw')) t0 = time.time() np.savez(coords_file, uu=uu, vv=vv, ww=ww, x=x, y=y, z=z, num_times=num_times) print('- No. stations = %i' % num_stations) print('- Saved uvw coordinates in %.2f s' % (time.time() - t0)) # Evaluate radial uv co-ordinate range (needed for lambda cut) r_uvw = (uu**2 + vv**2)**0.5 r_uvw_min = r_uvw.min() r_uvw_max = r_uvw.max() # Allocate image cubes. noise_cube = np.zeros((num_channels, im_size, im_size)) psf_cube = np.zeros((num_channels, im_size, im_size)) # Loop over cube start frequency. for i, start_freq in enumerate(start_freqs): print() print('- Freq = %.1f MHz (+%i x %0.1f kHz)' % (start_freq / 1e6, num_channels, freq_inc/1e3)) # Array of cube frequency channels freqs = (start_freq + (np.arange(num_channels) * freq_inc + freq_inc / 2)) # Calculate image FoV and lambda cuts fov_deg = 1.5 * degrees((const.c.value / start_freq) / station_d) print('- FoV = %.2f deg.' % fov_deg) # Generate file names of image cube and noise outputs. if lambda_cut: l_cut_inner = ceil(r_uvw_min / (const.c.value / freqs[-1])) l_cut_outer = floor(r_uvw_max / (const.c.value / freqs[0])) print('- lambda cut = %.0f, %.0f' % (l_cut_inner, l_cut_outer)) suffix = ('%05.1fMHz_lcut_%04i_%04i_%s_%s' % (start_freq / 1e6, l_cut_inner, l_cut_outer, weights, algorithm.lower())) else: suffix = ('%05.1fMHz_%s_%s' % (start_freq / 1e6, weights, algorithm.lower())) if algorithm.lower().startswith('w') and w_planes > 0: suffix += '_%i' % w_planes l_cut = [l_cut_inner, l_cut_outer] if lambda_cut else None noise_cube_file = join(results_dir, 'noise_' + suffix + '.fits') noise_cube_file_k = join(results_dir, 'noise_' + suffix + '_K.fits') psf_cube_file = join(results_dir, 'psf_' + suffix + '.fits') noise_sigma_file = join(results_dir, 'noise_sigma_' + suffix + '.npz') t0 = time.time() # Option to load existing image cubes (used to skip directly to fitting # the psf and converting to K) if os.path.exists(noise_cube_file): noise_cube = fits.getdata(noise_cube_file) psf_cube = fits.getdata(psf_cube_file) # Simulate / image the noise cube (in Jy/beam) and PSF cube. else: sigma_pq, sigma_im = np.zeros(num_channels), np.zeros(num_channels) num_coords = np.zeros(num_channels, dtype='i8') progress_bar = ProgressBar(maxval=num_channels, widgets=[ Bar(marker='='), Counter(format='%03i'), '/%03i ' % num_channels, Percentage(), ' ', Timer(), ' ', ETA()]).start() # Loop over frequencies in the cube for j, freq in enumerate(freqs): # Convert coordinates wavelength and apply lambda cut wavelength = const.c.value / freq uu_l = (uu / wavelength) vv_l = (vv / wavelength) ww_l = (ww / wavelength) if lambda_cut: r_uv = (uu_l**2 + vv_l**2)**0.5 idx = np.where(np.logical_and(r_uv >= l_cut_inner, r_uv <= l_cut_outer)) uu_l, vv_l, ww_l = uu_l[idx], vv_l[idx], ww_l[idx] num_coords[j] = uu_l.shape[0] # Evaluate visibility noise (and predicted image noise) sigma_pq[j] = evaluate_scaled_noise_rms( freq, num_times, freq_inc, eta, noise_obs_length_h) sigma_im[j] = sigma_pq[j] / num_coords[j]**0.5 # Make the noise image amp = (randn(num_coords[j]) + 1j * randn(num_coords[j])) * sigma_pq[j] noise_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) # Make the psf amp = np.ones(uu_l.shape[0], dtype='c16') psf_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) progress_bar.update(j) progress_bar.finish() # Save noise values and cube images in Jy/beam np.savez(noise_sigma_file, freqs=freqs, sigma_pq=sigma_pq, sigma_im=sigma_im, num_coords=num_coords) write_fits_cube(noise_cube, noise_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) write_fits_cube(psf_cube, psf_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) print('- Time taken = %.2f s (image cube)' % (time.time() - t0)) # Fit the PSF with a gaussian to evaluate the beam area (in arcmin^2) t0 = time.time() r_uv_max_l = l_cut_outer if lambda_cut else \ r_uvw_max / (const.c.value / start_freq) area_arcmin2 = eval_beam_area(psf_cube, r_uv_max_l, fov_deg, freqs, start_freq, results_dir, weights, plot=False) print('- Time taken = %.2f s (fit area)' % (time.time() - t0)) # Convert cube from Jy/beam to K t0 = time.time() for j, freq in enumerate(freqs): image = noise_cube[j, :, :] area_sr = (area_arcmin2[j] / 3600.0) * (pi / 180)**2 image /= area_sr image *= (1e-26 * const.c.value**2) / (2 * const.k_B.value * freq**2) write_fits_cube(noise_cube, noise_cube_file_k, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm, bunit='K') print('- Time taken = %.2f s (convert to K)' % (time.time() - t0)) print()
def main(): # Settings ---------------------------------------------------------------- freq_hz = 120.0e6 wave_length = 299792458.0 / freq_hz lon = radians(116.63128900) lat = radians(-26.69702400) alt = 0.0 ra = radians(68.698903779331502) dec = radians(-26.568851215532160) mjd_mid = 57443.4375000000 snapshot = True if snapshot: mjd_start = mjd_mid obs_length = 0.0 dt_s = 0.0 num_times = 1 else: obs_length = 4.0 * 3600.0 # seconds num_times = int(obs_length / (3 * 60.0)) dt_s = obs_length / float(num_times) mjd_start = mjd_mid - (obs_length / 2.0) / (3600.0 * 24.0) fov = 45.0 # deg im_size = 512 uv_pb_cut_level = 1.0e-5 out_dir = "TEST_%05.1f_%03i_v2" % (fov, im_size) font_size_ = "small" if os.path.exists(out_dir): shutil.rmtree(out_dir) os.makedirs(out_dir) # === Load telescope coordinates. ======================================== v4d_file = join("v4d.tm", "layout_enu_stations.txt") v4d = numpy.loadtxt(v4d_file) v4o1_file = join("v4o1.tm", "layout_enu_stations.txt") v4o1 = numpy.loadtxt(v4o1_file) station_radius_m = 35.0 / 2.0 num_stations = v4d.shape[0] num_baselines = num_stations * (num_stations - 1) / 2 print("- Loaded telescope model.") # === Create imager object and obtain uv cell size. ======================= imager = Imager("Double") imager.set_fov(fov) imager.set_size(im_size) imager.set_grid_kernel("Pillbox", 1, 1) cell_size_uv_wavelengths = imager.fov_to_uv_cellsize(radians(fov), im_size) uv_cut_radius_wavelengths = ((im_size / 2) - 2) * cell_size_uv_wavelengths c = im_size / 2 dx = cell_size_uv_wavelengths extent_wavelengths = [(c + 0.5) * dx, (-c + 0.5) * dx, (-c - 0.5) * dx, (c - 0.5) * dx] extent_m = numpy.array(extent_wavelengths) * wave_length x = numpy.arange(-im_size / 2, im_size / 2) * cell_size_uv_wavelengths xg, yg = numpy.meshgrid(x[::-1], x[::-1]) rg = (xg ** 2 + yg ** 2) ** 0.5 grid_r_wavelengths = rg.flatten() sort_idx = numpy.argsort(grid_r_wavelengths) grid_r_wavelengths = grid_r_wavelengths[sort_idx] lm_max = math.sin(0.5 * radians(fov)) lm_inc = (2.0 * lm_max) / im_size off = lm_inc / 2.0 extent_lm = [-lm_max - off, lm_max - off, -lm_max + off, lm_max + off] uv_dist_max = (im_size / 2) * cell_size_uv_wavelengths * wave_length print("- wavelength [m]:", wave_length) print("- uv_pixel size [m]:", cell_size_uv_wavelengths * wave_length) print("- max uv [m]:", uv_dist_max) # === Generate UV coordinates ============================================= uu_v4d, vv_v4d, ww_v4d = generate_uv_coordinates( v4d[:, 0], v4d[:, 1], v4d[:, 2], lon, lat, alt, ra, dec, num_times, num_baselines, mjd_start, dt_s, freq_hz, uv_cut_radius_wavelengths, ) print("- No. coordinates v4d : %i" % uu_v4d.shape[0]) uu_v4o1, vv_v4o1, ww_v4o1 = generate_uv_coordinates( v4o1[:, 0], v4o1[:, 1], v4o1[:, 2], lon, lat, alt, ra, dec, num_times, num_baselines, mjd_start, dt_s, freq_hz, uv_cut_radius_wavelengths, ) print("- No. coordinates v4o1 : %i" % uu_v4o1.shape[0]) # UV scatter plot plot_uv_scatter(uu_v4d, vv_v4d, uu_v4o1, vv_v4o1, wave_length, extent_m, out_dir) # Create UV grid images grid_v4d, grid_v4o1 = grid_uv_data(uu_v4d, vv_v4d, ww_v4d, uu_v4o1, vv_v4o1, ww_v4o1, im_size, imager) # Load PB and FFT to UV plane t0 = time.time() prefix = "b_TIME_AVG_CHAN_AVG_CROSS_POWER" beam_dir = "beams_%05.1f_%04i_%05.1fMHz" % (fov, im_size, freq_hz / 1.0e6) beam_amp = pyfits.getdata(join(beam_dir, prefix + "_AMP_I_I.fits")) beam_amp = numpy.squeeze(beam_amp) beam_amp[numpy.isnan(beam_amp)] = 0.0 beam = numpy.array(beam_amp, dtype="c16") uv_beam = numpy.fft.fftshift(numpy.fft.ifft2(numpy.fft.fftshift(beam))) uv_beam /= numpy.max(uv_beam) print("- Generated UV beam response in %.2f s" % (time.time() - t0)) t0 = time.time() y_cut = numpy.abs(uv_beam[:, uv_beam.shape[0] / 2]) x_cut = numpy.abs(uv_beam[uv_beam.shape[1] / 2, :]) z_y = numpy.argmax(y_cut > uv_pb_cut_level) z_x = numpy.argmax(x_cut > uv_pb_cut_level) cut_idx = min(z_y, z_x) centre = uv_beam.shape[0] / 2 offset = uv_beam.shape[0] / 2 - cut_idx pb_kernel = numpy.abs(uv_beam[centre - offset : centre + offset, centre - offset : centre + offset]) if pb_kernel.shape[0] % 2 == 0: pb_kernel = pb_kernel[1:, 1:] pb_kernel /= numpy.sum(pb_kernel) pb_kernel = numpy.abs(pb_kernel) print("- Kernel size =", pb_kernel.shape) print("- Kernel sum =", numpy.sum(pb_kernel)) # Plot image beam beam_amp_norm = beam_amp / numpy.nanmax(beam_amp) plot_image_log(beam_amp_norm, extent_lm, join(out_dir, "beam_amp")) plot_image_lin(beam_amp_norm, extent_lm, join(out_dir, "beam_amp")) # Plot uv beam kernel plot_uv_beam_kernel( uv_beam, y_cut, x_cut, pb_kernel, cell_size_uv_wavelengths, wave_length, station_radius_m, uv_dist_max, uv_pb_cut_level, dx, join(out_dir, "uv_beam"), ) # Convolve UV plane PB with UV image t0 = time.time() grid_v4d_pb = scipy.signal.convolve2d(grid_v4d, pb_kernel, mode="same") grid_v4o1_pb = scipy.signal.convolve2d(grid_v4o1, pb_kernel, mode="same") print("- Convolved with FT(PB) in %.2f s" % (time.time() - t0)) plot_uv_grid(grid_v4d, grid_v4o1, extent_m, station_radius_m, join(out_dir, "uv_grid")) plot_convolved_grid(grid_v4d_pb, grid_v4o1_pb, extent_m, station_radius_m, join(out_dir, "uv_grid_convolved")) return # Sum of convolved and unconvolved should be the same ... # Wont be though unless convolve mode == Full due to uv points near the # edge of the grid. print("- sum unconvolved grid v4d:", numpy.sum(grid_v4d)) print("- sum unconvolved grid v4o1:", numpy.sum(grid_v4o1)) print("- sum convolved grid v4d :", numpy.sum(grid_v4d_pb)) print("- sum convolved grid v4o1:", numpy.sum(grid_v4o1_pb)) # Azimuthal average plot of the UV coverage and / or histogram y_v4d = grid_v4d_pb.flatten() y_v4d = y_v4d[sort_idx] y_v4o1 = grid_v4o1_pb.flatten() y_v4o1 = y_v4o1[sort_idx] plot_az_uv_grid_scatter(grid_r_wavelengths, y_v4d, y_v4o1, cell_size_uv_wavelengths, wave_length, im_size, out_dir) # Bin bin_width = wave_length * 1.0 # num_bins = min(100, int(ceil(uv_dist_max / bin_width))) num_bins = int(ceil(uv_dist_max / bin_width)) print("- num bins:", num_bins) print("- bin width:", uv_dist_max / float(num_bins)) plot_az_uv_grid_bin_mean_std( grid_r_wavelengths, y_v4d, y_v4o1, num_bins, wave_length, cell_size_uv_wavelengths, im_size, join(out_dir, "uv_grid_az_bins"), ) # TODO-BM histogram (grid_r x grid_value) bins = numpy.arange(num_bins) * bin_width plot_convolved_hist(y_v4d, y_v4o1, grid_r_wavelengths, wave_length, bins, uv_dist_max, out_dir) plot_unconvolved_hist(uu_v4d, vv_v4d, uu_v4o1, vv_v4o1, wave_length, uv_dist_max, bins, out_dir) fig = pyplot.figure(figsize=(8, 5)) ax = fig.add_subplot(111) x = v4d_bin_edges[:-1] + numpy.diff(v4d_bin_edges) / 2.0 y = v4d_hist y = numpy.array(y, dtype="f8") y /= float(v4d_hist.max()) ax.plot(x, y, "k-", lw=1.5, label="v4d") x = v4o1_bin_edges[:-1] + numpy.diff(v4o1_bin_edges) / 2.0 y = v4o1_hist y = numpy.array(y, dtype="f8") y /= float(v4d_hist.max()) ax.plot(x, y, "r-", lw=1.5, label="v4o1") ax.set_xlim(0, uv_dist_max) ax.set_xlabel("UV distance (metres)") ax.set_ylabel("Number") ax.legend() ax.grid() pyplot.savefig(join(out_dir, "hist_%04.1fm_%06.1fm_v2.png" % (bin_width, uv_dist_max))) pyplot.close(fig)
def main(): """ 1. Generate a large-ish core of stations using random generator. a. overlap some stations in the core to have a very dense station region 2. After core area start using arms but generate some randomness in the arms by placing antennas randomly near the outer stations keeping them along the spiral 3. Remove radius redundancy in the spiral arms """ # ========================================================================= # ====== Core seed = 1 num_tries = 10 num_core_stations = (1 + 5 + 11 + 17) * 6 + (3 * 6) core_radius_m = 480.0 inner_core_radius_m = 280.0 station_radius_m = 35.0 / 2.0 sll = -28 # ====== Core arms num_arms = 3 core_arm_count = 4 stations_per_arm_cluster = 6 arm_cluster_radius = 75.0 # a = 300.0 # b = 0.513 a = 300.0 b = 0.513 delta_theta = math.radians(37.0) arm_offsets = numpy.radians([35.0, 155.0, 270.0]) num_core_arm_stations = num_arms * core_arm_count * stations_per_arm_cluster # ====== Outer arms outer_arm_count = 12 stations_per_outer_cluster = 6 num_clusters_outer = outer_arm_count * num_arms v4a_ss_enu_file = 'v7ska1lowN1v2rev3R.enu.94x4.fixed.txt' outer_arm_cluster_radius = 80.0 # ===== uvw coordinate generation. lon = radians(116.63128900) lat = radians(-26.69702400) alt = 0.0 ra = radians(68.698903779331502) dec = radians(-26.568851215532160) mjd_mid = 57443.4375000000 obs_length = 0.0 mjd_start = mjd_mid dt_s = 0.0 num_times = 1 obs_length = 2.0 * 3600.0 # seconds num_times = int(obs_length / (3.0 * 60.0)) dt_s = obs_length / float(num_times) mjd_start = mjd_mid - ((obs_length / 2.0) / 3600.0 * 24.0) print('num times = %i' % num_times) out_dir = 'v5c-2h' # ========================================================================= if not os.path.isdir(out_dir): os.makedirs(out_dir) # Generate core stations x_core, y_core, weights, r_weights = \ generate_random_core(num_core_stations, core_radius_m, inner_core_radius_m, sll, station_radius_m, num_tries, seed) # Core arms x_arm, y_arm, cx_arm, cy_arm = \ generate_core_arms(num_arms, core_arm_count, stations_per_arm_cluster, arm_cluster_radius, station_radius_m, a, b, delta_theta, arm_offsets, num_tries) # Outer stations. x_arm_outer, y_arm_outer, cx_outer, cy_outer = \ generate_outer_arms(v4a_ss_enu_file, num_clusters_outer, stations_per_outer_cluster, outer_arm_cluster_radius, station_radius_m, num_tries) # Plotting plot_layout(x_core, y_core, x_arm, y_arm, x_arm_outer, y_arm_outer, cx_arm, cy_arm, cx_outer, cy_outer, station_radius_m, inner_core_radius_m, core_radius_m, arm_cluster_radius, outer_arm_cluster_radius, out_dir) plot_core_thinning_profile(r_weights, weights, core_radius_m, inner_core_radius_m, out_dir) if uvwsim_found: x = numpy.hstack((x_core, x_arm, x_arm_outer)) y = numpy.hstack((y_core, y_arm, y_arm_outer)) print('total stations = %i' % x.shape[0]) num_stations = x.shape[0] z = numpy.zeros_like(x) num_baselines = num_stations * (num_stations - 1) / 2 x, y, z = convert_enu_to_ecef(x, y, z, lon, lat, alt) uu, vv, ww = generate_baseline_uvw(x, y, z, ra, dec, num_times, num_baselines, mjd_start, dt_s) plot_hist(uu, vv, join(out_dir, 'uv_hist_%.2fh.png' % (obs_length/3600.0)), 'v5c %.2f h' % (obs_length/3600.0)) plot_uv_dist(uu, vv, station_radius_m, join(out_dir, 'uv_%.2fh' % (obs_length/3600.0))) # TODO-BM see ALMA memo for plots? # TODO-BM Plot of azimuthal variation # TODO-BM movie of uv coverage histogram improvement with time? # TODO-BM convolve uv response with station beam?! print('making image...') imager = Imager('single') fov = 1.0 im_size = 2048 freq = 150.0e6 wavelength = 299792458.0 / freq uu /= wavelength vv /= wavelength ww /= wavelength amp = numpy.ones(uu.shape, dtype='c16') weight = numpy.ones(uu.shape, dtype='f8') image = imager.make_image(uu, vv, ww, amp, weight, fov, im_size) fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect='equal') ax.imshow(image, interpolation='nearest') pyplot.show() cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) save_fits_image_2(join(out_dir, 'psf.fits'), image, cell, math.degrees(ra), math.degrees(dec), freq)
def eval_psf(self, im_size=None, fov_deg=None, plot2d=False, plot1d=True, filename_root=None, num_bins=100): """Evaluate and plot the PSF.""" if self.uu_m is None: self.gen_uvw_coords() # Work out a usable grid size. if im_size is None: b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 else: grid_size = im_size # Work out the FoV wavelength = const.c.value / self.freq_hz if fov_deg is None: cellsize_wavelengths = self.grid_cell_size_m / wavelength fov_rad = Imager.uv_cellsize_to_fov(cellsize_wavelengths, grid_size) fov_deg = degrees(fov_rad) else: fov_deg = fov_deg uu = self.uu_m / wavelength vv = self.vv_m / wavelength ww = self.ww_m / wavelength amp = np.ones_like(uu, dtype='c8') # _r = (uu**2 + vv**2)**0.5 * wavelength # amp[_r <= 1e3] = 0.0 psf = Imager.make_image(uu, vv, ww, amp, fov_deg, grid_size, weighting='Natural') extent = Imager.image_extent_lm(fov_deg, grid_size) self.psf = psf self.psf_fov_deg = fov_deg # --- Plotting ---- if plot2d: fig, ax = plt.subplots(figsize=(8, 8)) norm = SymLogNorm(linthresh=0.005, linscale=1.0, vmin=-0.005, vmax=1.0, clip=False) opts = dict(interpolation='nearest', origin='lower', cmap='inferno', extent=extent, norm=norm) # opts = dict(interpolation='nearest', origin='lower', cmap='gray_r', # extent=extent) im = ax.imshow(psf, **opts) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize='small') ax.set_xlabel('l') ax.set_ylabel('m') if filename_root: label = '' if 'ska1_v5' in filename_root: label = 'SKA1 v5' if 'model' in filename_root: label = 'Model ' + str( re.search(r'\d+', os.path.basename(filename_root)).group()) ax.text(0.02, 0.95, label, color='white', weight='bold', transform=ax.transAxes) plt.savefig('%s_2d_%.1f.png' % (filename_root, fov_deg)) else: plt.show() plt.close(fig) if plot1d: l, m = Imager.image_pixels(self.psf_fov_deg, grid_size) r_lm = (l**2 + m**2)**0.5 r_lm = r_lm.flatten() idx_sorted = np.argsort(r_lm) r_lm = r_lm[idx_sorted] psf_1d = self.psf.flatten()[idx_sorted] psf_hwhm = (wavelength / (r_lm[-1] * 2.0)) / 2 # fig, ax = plt.subplots(figsize=(8, 8)) # ax.plot(r_lm, psf_1d, 'k.', ms=2, alpha=0.1) # ax.set_xscale('log') # ax.set_yscale('log') # fig.savefig('TEST_psf1d.png') # plt.close(fig) psf_1d_mean = np.zeros(num_bins) psf_1d_abs_mean = np.zeros(num_bins) psf_1d_abs_max = np.zeros(num_bins) psf_1d_min = np.zeros(num_bins) psf_1d_max = np.zeros(num_bins) psf_1d_std = np.zeros(num_bins) psf_1d_rms = np.zeros(num_bins) bin_edges = np.linspace(r_lm[0], r_lm[-1] * 2**(-0.5), num_bins + 1) # bin_edges = np.logspace(log10(r_lm[1]), log10(r_lm[-1]), # num_bins + 1) psf_1d_bin_r = (bin_edges[1:] + bin_edges[:-1]) / 2 bin_idx = np.digitize(r_lm, bin_edges) for i in range(1, num_bins + 1): values = psf_1d[bin_idx == i] if values.size > 0: psf_1d_mean[i - 1] = np.mean(values) psf_1d_abs_mean[i - 1] = np.mean(np.abs(values)) psf_1d_abs_max[i - 1] = np.max(np.abs(values)) psf_1d_min[i - 1] = np.min(values) psf_1d_max[i - 1] = np.max(values) psf_1d_std[i - 1] = np.std(values) psf_1d_rms[i - 1] = np.mean(values**2)**0.5 self.psf_1d['r'] = psf_1d_bin_r self.psf_1d['min'] = psf_1d_min self.psf_1d['max'] = psf_1d_max self.psf_1d['mean'] = psf_1d_mean self.psf_1d['std'] = psf_1d_std self.psf_1d['rms'] = psf_1d_rms self.psf_1d['abs_mean'] = psf_1d_abs_mean self.psf_1d['abs_max'] = psf_1d_abs_max fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(psf_1d_bin_r, psf_1d_abs_mean, '-', c='b', lw=1, label='abs mean') ax.plot(psf_1d_bin_r, psf_1d_abs_max, '-', c='r', lw=1, label='abs max') ax.plot(psf_1d_bin_r, psf_1d_std, '-', c='g', lw=1, label='std') # ax.set_ylim(-0.1, 0.5) # ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) # ax.set_xscale('log') ax.set_yscale('log') ax.set_ylim(1e-4, 1) ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) ax.set_xlabel('PSF radius (direction cosines)') # ax.set_ylabel('PSF amplitude') ax.set_title('Azimuthally averaged PSF (FoV: %.2f)' % fov_deg) ax.legend() if filename_root: plt.savefig('%s_1d_%.1f.png' % (filename_root, fov_deg)) else: plt.show() plt.close(fig)