Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #8
0
 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))
Exemple #9
0
    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:]
Exemple #10
0
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
Exemple #11
0
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)
Exemple #14
0
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)
Exemple #17
0
    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)