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 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)
Example #3
0
    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)
Example #4
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)
Example #5
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()
Example #6
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():
    """
    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)