Example #1
0
def plot_azel(bvis_list, plot_file='azel.png', **kwargs):
    """ Standard plot of az el coverage
    
    :param bvis_list:
    :param plot_file:
    :param kwargs:
    :return:
    """
    plt.clf()
    r2d = 180.0 / numpy.pi
    for ibvis, bvis in enumerate(bvis_list):
        ha = numpy.pi * bvis.time / 43200.0
        dec = bvis.phasecentre.dec.rad
        latitude = bvis.configuration.location.lat.rad
        az, el = hadec_to_azel(ha, dec, latitude)
        if ibvis == 0:
            plt.plot(bvis.time,
                     r2d * az,
                     '.',
                     color='r',
                     label='Azimuth (deg)')
            plt.plot(bvis.time,
                     r2d * el,
                     '.',
                     color='b',
                     label='Elevation (deg)')
        else:
            plt.plot(bvis.time, r2d * az, '.', color='r')
            plt.plot(bvis.time, r2d * el, '.', color='b')
    plt.xlabel('HA (s)')
    plt.ylabel('Angle')
    plt.legend()
    plt.title('Azimuth and elevation vs hour angle')
    plt.savefig(plot_file)
    plt.show(block=False)
    def find_vp(band, vis):
        ha = calculate_blockvisibility_hourangles(vis).to('rad').value
        dec = vis.phasecentre.dec.rad
        latitude = vis.configuration.location.lat.rad
        az, el = hadec_to_azel(ha, dec, latitude)

        el_deg = el * 180.0 / numpy.pi
        el_table = max(
            0.0,
            min(
                90.1,
                elevation_sampling *
                ((el_deg + elevation_sampling / 2.0) // elevation_sampling)))
        return get_band_vp(band, el_table)
Example #3
0
    def find_vp(band, vis):
        ha = numpy.pi * numpy.average(vis.time) / 43200.0
        dec = vis.phasecentre.dec.rad
        latitude = vis.configuration.location.lat.rad
        az, el = hadec_to_azel(ha, dec, latitude)

        el_deg = el * 180.0 / numpy.pi
        el_table = max(
            0.0,
            min(
                90.1,
                elevation_sampling *
                ((el_deg + elevation_sampling / 2.0) // elevation_sampling)))
        return get_band_vp(band, el_table)
Example #4
0
 def valid_elevation(time, location, phasecentre):
     ha = numpy.pi * time / 43200.0
     dec = phasecentre.dec.rad
     az, el = hadec_to_azel(ha, dec, location.lat.rad)
     return el > elevation_limit * numpy.pi / 180.0
Example #5
0
def simulate_gaintable_from_zernikes(vis,
                                     sc,
                                     vp_list,
                                     vp_coeffs,
                                     vis_slices=None,
                                     order=3,
                                     use_radec=False,
                                     elevation_limit=15.0 * numpy.pi / 180.0,
                                     **kwargs):
    """ Create gaintables for a set of zernikes

    :param vis:
    :param sc: Sky components for which pierce points are needed
    :param vp: List of Voltage patterns in AZELGEO frame
    :param vp_coeffs: Fractional contribution [nants, nvp]
    :param order: order of spline (default is 3)
    :return:
    """

    ntimes, nant = vis.vis.shape[0:2]
    vp_coeffs = numpy.array(vp_coeffs)
    gaintables = [
        create_gaintable_from_blockvisibility(vis, **kwargs) for i in sc
    ]

    if not use_radec:
        assert isinstance(vis, BlockVisibility)
        assert vis.configuration.mount[
            0] == 'azel', "Mount %s not supported yet" % vis.configuration.mount[
                0]

        # The time in the Visibility is hour angle in seconds!
        number_bad = 0
        number_good = 0

        # Cache the splines, one per voltage pattern
        real_splines = list()
        imag_splines = list()
        for ivp, vp in enumerate(vp_list):
            assert vp.wcs.wcs.ctype[0] == 'AZELGEO long', vp.wcs.wcs.ctype[0]
            assert vp.wcs.wcs.ctype[1] == 'AZELGEO lati', vp.wcs.wcs.ctype[1]

            nchan, npol, ny, nx = vp.data.shape
            real_splines.append(
                RectBivariateSpline(range(ny),
                                    range(nx),
                                    vp.data[0, 0, ...].real,
                                    kx=order,
                                    ky=order))
            imag_splines.append(
                RectBivariateSpline(range(ny),
                                    range(nx),
                                    vp.data[0, 0, ...].imag,
                                    kx=order,
                                    ky=order))

        latitude = vis.configuration.location.lat.rad

        r2d = 180.0 / numpy.pi
        s2r = numpy.pi / 43200.0
        # For each hourangle, we need to calculate the location of a component
        # in AZELGEO. With that we can then look up the relevant gain from the
        # voltage pattern
        for iha, rows in enumerate(
                vis_timeslice_iter(vis, vis_slices=vis_slices)):
            v = create_visibility_from_rows(vis, rows)
            ha = numpy.average(
                calculate_blockvisibility_hourangles(v).to('rad').value)

            # Calculate the az el for this hourangle and the phasecentre declination
            utc_time = Time([numpy.average(v.time) / 86400.0],
                            format='mjd',
                            scale='utc')
            azimuth_centre, elevation_centre = calculate_azel(
                v.configuration.location, utc_time, vis.phasecentre)
            azimuth_centre = azimuth_centre[0].to('deg').value
            elevation_centre = elevation_centre[0].to('deg').value

            for icomp, comp in enumerate(sc):

                if elevation_centre >= elevation_limit:

                    antgain = numpy.zeros([nant], dtype='complex')
                    # Calculate the location of the component in AZELGEO, then add the pointing offset
                    # for each antenna
                    hacomp = comp.direction.ra.rad - vis.phasecentre.ra.rad + ha
                    deccomp = comp.direction.dec.rad
                    azimuth_comp, elevation_comp = hadec_to_azel(
                        hacomp, deccomp, latitude)

                    for ant in range(nant):
                        for ivp, vp in enumerate(vp_list):
                            nchan, npol, ny, nx = vp.data.shape
                            wcs_azel = vp.wcs.deepcopy()

                            # We use WCS sensible coordinate handling by labelling the axes misleadingly
                            wcs_azel.wcs.crval[0] = azimuth_centre
                            wcs_azel.wcs.crval[1] = elevation_centre
                            wcs_azel.wcs.ctype[0] = 'RA---SIN'
                            wcs_azel.wcs.ctype[1] = 'DEC--SIN'

                            worldloc = [
                                azimuth_comp * r2d, elevation_comp * r2d,
                                vp.wcs.wcs.crval[2], vp.wcs.wcs.crval[3]
                            ]
                            try:
                                pixloc = wcs_azel.sub(2).wcs_world2pix(
                                    [worldloc[:2]], 1)[0]
                                assert pixloc[0] > 2
                                assert pixloc[0] < nx - 3
                                assert pixloc[1] > 2
                                assert pixloc[1] < ny - 3
                                gain = real_splines[ivp].ev(pixloc[1], pixloc[0]) \
                                       + 1j * imag_splines[ivp](pixloc[1], pixloc[0])
                                antgain[ant] += vp_coeffs[ant, ivp] * gain
                                number_good += 1
                            except (ValueError, AssertionError):
                                number_bad += 1
                                antgain[ant] = 1.0

                        antgain[ant] = 1.0 / antgain[ant]

                    gaintables[icomp].gain[
                        iha, :, :, :] = antgain[:, numpy.newaxis,
                                                numpy.newaxis, numpy.newaxis]
                    gaintables[icomp].phasecentre = comp.direction
            else:
                gaintables[icomp].gain[...] = 1.0 + 0.0j
                gaintables[icomp].phasecentre = comp.direction
                number_bad += nant

    else:
        assert isinstance(vis, BlockVisibility)
        number_bad = 0
        number_good = 0

        # Cache the splines, one per voltage pattern
        real_splines = list()
        imag_splines = list()
        for ivp, vp in enumerate(vp_list):
            nchan, npol, ny, nx = vp.data.shape
            real_splines.append(
                RectBivariateSpline(range(ny),
                                    range(nx),
                                    vp.data[0, 0, ...].real,
                                    kx=order,
                                    ky=order))
            imag_splines.append(
                RectBivariateSpline(range(ny),
                                    range(nx),
                                    vp.data[0, 0, ...].imag,
                                    kx=order,
                                    ky=order))

        for iha, rows in enumerate(
                vis_timeslice_iter(vis, vis_slices=vis_slices)):

            # The time in the Visibility is hour angle in seconds!
            r2d = 180.0 / numpy.pi
            # For each hourangle, we need to calculate the location of a component
            # in AZELGEO. With that we can then look up the relevant gain from the
            # voltage pattern
            v = create_visibility_from_rows(vis, rows)
            ha = numpy.average(calculate_blockvisibility_hourangles(v))

            for icomp, comp in enumerate(sc):
                antgain = numpy.zeros([nant], dtype='complex')
                antwt = numpy.zeros([nant])
                ra_comp = comp.direction.ra.rad
                dec_comp = comp.direction.dec.rad
                for ant in range(nant):
                    for ivp, vp in enumerate(vp_list):

                        assert vp.wcs.wcs.ctype[
                            0] == 'RA---SIN', vp.wcs.wcs.ctype[0]
                        assert vp.wcs.wcs.ctype[
                            1] == 'DEC--SIN', vp.wcs.wcs.ctype[1]

                        worldloc = [
                            ra_comp * r2d, dec_comp * r2d, vp.wcs.wcs.crval[2],
                            vp.wcs.wcs.crval[3]
                        ]
                        nchan, npol, ny, nx = vp.data.shape

                        try:
                            pixloc = vp.wcs.sub(2).wcs_world2pix(
                                [worldloc[:2]], 1)[0]
                            assert pixloc[0] > 2
                            assert pixloc[0] < nx - 3
                            assert pixloc[1] > 2
                            assert pixloc[1] < ny - 3
                            gain = real_splines[ivp].ev(pixloc[1], pixloc[0]) \
                                   + 1j * imag_splines[ivp](pixloc[1], pixloc[0])
                            antgain[ant] += vp_coeffs[ant, ivp] * gain
                            antwt[ant] = 1.0
                            number_good += 1
                        except (ValueError, AssertionError):
                            number_bad += 1
                            antgain[ant] = 1e15
                            antwt[ant] = 0.0

                        antgain[ant] = 1.0 / antgain[ant]

                    gaintables[icomp].gain[
                        iha, :, :, :] = antgain[:, numpy.newaxis,
                                                numpy.newaxis, numpy.newaxis]
                    gaintables[icomp].weight[
                        iha, :, :, :] = antwt[:, numpy.newaxis, numpy.newaxis,
                                              numpy.newaxis]
                    gaintables[icomp].phasecentre = comp.direction

    if number_bad > 0:
        log.warning(
            "simulate_gaintable_from_zernikes: %d points are inside the voltage pattern image"
            % (number_good))
        log.warning(
            "simulate_gaintable_from_zernikes: %d points are outside the voltage pattern image"
            % (number_bad))

    return gaintables
Example #6
0
def create_visibility(config: Configuration, times: numpy.array, frequency: numpy.array,
                      channel_bandwidth, phasecentre: SkyCoord,
                      weight: float, polarisation_frame=PolarisationFrame('stokesI'),
                      integration_time=1.0,
                      zerow=False, elevation_limit=15.0 * numpy.pi / 180.0, source='unknown', meta=None) -> Visibility:
    """ Create a Visibility from Configuration, hour angles, and direction of source

    Note that we keep track of the integration time for BDA purposes

    :param config: Configuration of antennas
    :param times: hour angles in radians
    :param frequency: frequencies (Hz] [nchan]
    :param weight: weight of a single sample
    :param phasecentre: phasecentre of observation
    :param channel_bandwidth: channel bandwidths: (Hz] [nchan]
    :param integration_time: Integration time ('auto' or value in s)
    :param polarisation_frame: PolarisationFrame('stokesI')
    :return: Visibility
    """
    assert phasecentre is not None, "Must specify phase centre"
    
    if polarisation_frame is None:
        polarisation_frame = correlate_polarisation(config.receptor_frame)
    
    latitude = config.location.geodetic[1].to('rad').value

    nch = len(frequency)
    ants_xyz = config.data['xyz']
    nants = len(config.data['names'])
    nbaselines = int(nants * (nants - 1) / 2)
    ntimes = 0
    for iha, ha in enumerate(times):
    
        # Calculate the positions of the antennas as seen for this hour angle
        # and declination
        _, elevation = hadec_to_azel(ha, phasecentre.dec.rad, latitude)
        if elevation_limit is None or (elevation > elevation_limit):
            ntimes +=1

    npol = polarisation_frame.npol
    nrows = nbaselines * ntimes * nch
    nrowsperintegration = nbaselines * nch
    rvis = numpy.zeros([nrows, npol], dtype='complex')
    rweight = weight * numpy.ones([nrows, npol])
    rtimes = numpy.zeros([nrows])
    rfrequency = numpy.zeros([nrows])
    rchannel_bandwidth = numpy.zeros([nrows])
    rantenna1 = numpy.zeros([nrows], dtype='int')
    rantenna2 = numpy.zeros([nrows], dtype='int')
    ruvw = numpy.zeros([nrows, 3])
    
    n_flagged = 0

    # Do each hour angle in turn
    row = 0
    for iha, ha in enumerate(times):
        
        # Calculate the positions of the antennas as seen for this hour angle
        # and declination
        _, elevation = hadec_to_azel(ha, phasecentre.dec.rad, latitude)
        if elevation_limit is None or (elevation > elevation_limit):
            rtimes[row:row + nrowsperintegration] = ha * 43200.0 / numpy.pi

            # TODO: optimise loop
            # Loop over all pairs of antennas. Note that a2>a1
            ant_pos = xyz_to_uvw(ants_xyz, ha, phasecentre.dec.rad)
            for a1 in range(nants):
                for a2 in range(a1 + 1, nants):
                    rantenna1[row:row + nch] = a1
                    rantenna2[row:row + nch] = a2
                    rweight[row:row+nch,...] = 1.0
                
                    # Loop over all frequencies and polarisations
                    for ch in range(nch):
                        # noinspection PyUnresolvedReferences
                        k = frequency[ch] / constants.c.value
                        ruvw[row, :] = (ant_pos[a2, :] - ant_pos[a1, :]) * k
                        rfrequency[row] = frequency[ch]
                        rchannel_bandwidth[row] = channel_bandwidth[ch]
                        row += 1
    
    if zerow:
        ruvw[..., 2] = 0.0
    assert row == nrows
    rintegration_time = numpy.full_like(rtimes, integration_time)
    vis = Visibility(uvw=ruvw, time=rtimes, antenna1=rantenna1, antenna2=rantenna2,
                     frequency=rfrequency, vis=rvis,
                     weight=rweight, imaging_weight=rweight,
                     integration_time=rintegration_time, channel_bandwidth=rchannel_bandwidth,
                     polarisation_frame=polarisation_frame, source=source, meta=meta)
    vis.phasecentre = phasecentre
    vis.configuration = config
    log.info("create_visibility: %s" % (vis_summary(vis)))
    assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis
    if elevation_limit is not None:
        log.info('create_visibility: flagged %d/%d visibilities below elevation limit %f (rad)' %
                (n_flagged, vis.nvis, elevation_limit))
    else:
        log.info('create_visibility: created %d visibilities' % (vis.nvis))

    return vis
Example #7
0
def create_blockvisibility(config: Configuration,
                           times: numpy.array,
                           frequency: numpy.array,
                           phasecentre: SkyCoord,
                           weight: float = 1.0,
                           polarisation_frame: PolarisationFrame = None,
                           integration_time=1.0,
                           channel_bandwidth=1e6,
                           zerow=False,
                           elevation_limit=None,
                           source='unknown',
                           meta=None,
                           **kwargs) -> BlockVisibility:
    """ Create a BlockVisibility from Configuration, hour angles, and direction of source

    Note that we keep track of the integration time for BDA purposes

    :param config: Configuration of antennas
    :param times: hour angles in radians
    :param frequency: frequencies (Hz] [nchan]
    :param weight: weight of a single sample
    :param phasecentre: phasecentre of observation
    :param channel_bandwidth: channel bandwidths: (Hz] [nchan]
    :param integration_time: Integration time ('auto' or value in s)
    :param polarisation_frame:
    :return: BlockVisibility
    """
    assert phasecentre is not None, "Must specify phase centre"
    
    if polarisation_frame is None:
        polarisation_frame = correlate_polarisation(config.receptor_frame)
    
    latitude = config.location.geodetic[1].to('rad').value
    nch = len(frequency)
    ants_xyz = config.data['xyz']
    nants = len(config.data['names'])

    ntimes = 0
    n_flagged = 0
    for iha, ha in enumerate(times):
    
        # Calculate the positions of the antennas as seen for this hour angle
        # and declination
        _, elevation = hadec_to_azel(ha, phasecentre.dec.rad, latitude)
        if elevation_limit is None or (elevation > elevation_limit):
            ntimes +=1
        else:
            n_flagged += 1

    assert ntimes > 0, "No unflagged points"
    if elevation_limit is not None:
        log.info('create_visibility: flagged %d/%d times below elevation limit %f (rad)' %
                (n_flagged, ntimes, elevation_limit))
    else:
        log.info('create_visibility: created %d times' % (ntimes))
    
    npol = polarisation_frame.npol
    visshape = [ntimes, nants, nants, nch, npol]
    rvis = numpy.zeros(visshape, dtype='complex')
    rweight = weight * numpy.ones(visshape)
    rimaging_weight = numpy.ones(visshape)
    rtimes = numpy.zeros([ntimes])
    ruvw = numpy.zeros([ntimes, nants, nants, 3])
    
    # Do each hour angle in turn
    itime = 0
    for iha, ha in enumerate(times):
        
        # Calculate the positions of the antennas as seen for this hour angle
        # and declination
        ant_pos = xyz_to_uvw(ants_xyz, ha, phasecentre.dec.rad)
        _, elevation = hadec_to_azel(ha, phasecentre.dec.rad, latitude)
        if elevation_limit is None or (elevation > elevation_limit):
            rtimes[itime] = ha * 43200.0 / numpy.pi
            rweight[itime, ...] = 1.0

            # Loop over all pairs of antennas. Note that a2>a1
            for a1 in range(nants):
                for a2 in range(a1 + 1, nants):
                    ruvw[itime, a2, a1, :] = (ant_pos[a2, :] - ant_pos[a1, :])
                    ruvw[itime, a1, a2, :] = (ant_pos[a1, :] - ant_pos[a2, :])
            itime += 1
    
    rintegration_time = numpy.full_like(rtimes, integration_time)
    rchannel_bandwidth = channel_bandwidth
    if zerow:
        ruvw[..., 2] = 0.0
    vis = BlockVisibility(uvw=ruvw, time=rtimes, frequency=frequency, vis=rvis, weight=rweight,
                          imaging_weight=rimaging_weight,
                          integration_time=rintegration_time, channel_bandwidth=rchannel_bandwidth,
                          polarisation_frame=polarisation_frame, source=source, meta=meta)
    vis.phasecentre = phasecentre
    vis.configuration = config
    log.info("create_blockvisibility: %s" % (vis_summary(vis)))
    assert isinstance(vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis

    return vis
Example #8
0
def create_pointingtable_from_blockvisibility(vis: BlockVisibility,
                                              pointing_frame='azel',
                                              timeslice=None,
                                              frequencyslice: float = None,
                                              **kwargs) -> PointingTable:
    """ Create pointing table from visibility.
    
    This makes an empty pointing table consistent with the BlockVisibility.
    
    :param vis: BlockVisibilty
    :param timeslice: Time interval between solutions (s)
    :param frequency_width: Frequency solution width (Hz)
    :return: PointingTable
    
    """
    assert isinstance(
        vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis

    nants = vis.nants

    if timeslice is None or timeslice == 'auto':
        utimes = numpy.unique(vis.time)
        ntimes = len(utimes)
        pointing_interval = numpy.zeros([ntimes])
        if ntimes > 1:
            pointing_interval[:-1] = utimes[1:] - utimes[0:-1]
            pointing_interval[-1] = utimes[-1] - utimes[-2]
        else:
            pointing_interval[...] = 1.0

    else:
        ntimes = numpy.ceil((numpy.max(vis.time) - numpy.min(vis.time)) /
                            timeslice).astype('int')
        utimes = numpy.linspace(numpy.min(vis.time), numpy.max(vis.time),
                                ntimes)
        pointing_interval = timeslice * numpy.ones([ntimes])

    #    log.debug('create_pointingtable_from_blockvisibility: times are %s' % str(utimes))
    #    log.debug('create_pointingtable_from_blockvisibility: intervals are %s' % str(pointing_interval))

    ntimes = len(utimes)
    ufrequency = numpy.unique(vis.frequency)
    nfrequency = len(ufrequency)

    receptor_frame = ReceptorFrame(vis.polarisation_frame.type)
    nrec = receptor_frame.nrec

    pointingshape = [ntimes, nants, nfrequency, nrec, 2]
    pointing = numpy.zeros(pointingshape)
    if nrec > 1:
        pointing[..., 0, 0] = 0.0
        pointing[..., 1, 0] = 0.0
        pointing[..., 0, 1] = 0.0
        pointing[..., 1, 1] = 0.0

    ha = numpy.pi * vis.time / 43200.0
    dec = vis.phasecentre.dec.rad
    latitude = vis.configuration.location.lat.rad
    az, el = hadec_to_azel(ha, dec, latitude)

    pointing_nominal = numpy.zeros([ntimes, nants, nfrequency, nrec, 2])
    pointing_nominal[..., 0] = az[:, numpy.newaxis, numpy.newaxis,
                                  numpy.newaxis]
    pointing_nominal[..., 1] = el[:, numpy.newaxis, numpy.newaxis,
                                  numpy.newaxis]
    pointing_weight = numpy.ones(pointingshape)
    pointing_time = utimes
    pointing_frequency = ufrequency
    pointing_residual = numpy.zeros([ntimes, nfrequency, nrec, 2])
    pointing_frame = pointing_frame

    pt = PointingTable(pointing=pointing,
                       nominal=pointing_nominal,
                       time=pointing_time,
                       interval=pointing_interval,
                       weight=pointing_weight,
                       residual=pointing_residual,
                       frequency=pointing_frequency,
                       receptor_frame=receptor_frame,
                       pointing_frame=pointing_frame,
                       pointingcentre=vis.phasecentre,
                       configuration=vis.configuration)

    assert isinstance(pt, PointingTable), "pt is not a PointingTable: %r" % pt

    return pt