Example #1
0
def integrate_visibility_by_channel(vis: BlockVisibility) -> BlockVisibility:
    """ Integrate visibility across channels, returning new visibility
    
    :param vis:
    :return: BlockVisibility
    """

    assert isinstance(vis, Visibility) or isinstance(vis, BlockVisibility), vis

    vis_shape = list(vis.vis.shape)
    ntimes, nants, _, nchan, npol = vis_shape
    vis_shape[-2] = 1
    newvis = BlockVisibility(
        data=None,
        frequency=numpy.ones([1]) * numpy.average(vis.frequency),
        channel_bandwidth=numpy.ones([1]) * numpy.sum(vis.channel_bandwidth),
        phasecentre=vis.phasecentre,
        configuration=vis.configuration,
        uvw=vis.uvw,
        time=vis.time,
        vis=numpy.zeros(vis_shape, dtype='complex'),
        weight=numpy.ones(vis_shape, dtype='float'),
        integration_time=vis.integration_time,
        polarisation_frame=vis.polarisation_frame)

    newvis.data['vis'][...,
                       0, :] = numpy.sum(vis.data['vis'] * vis.data['weight'],
                                         axis=-2)
    newvis.data['weight'][..., 0, :] = numpy.sum(vis.data['weight'], axis=-2)
    mask = newvis.data['weight'] > 0.0
    newvis.data['vis'][
        mask] = newvis.data['vis'][mask] / newvis.data['weight'][mask]

    return newvis
Example #2
0
def divide_visibility(vis: BlockVisibility, modelvis: BlockVisibility):
    """ Divide visibility by model forming visibility for equivalent point source

    This is a useful intermediate product for calibration. Variation of the visibility in time and
    frequency due to the model structure is removed and the data can be averaged to a limit determined
    by the instrumental stability. The weight is adjusted to compensate for the division.
    
    Zero divisions are avoided and the corresponding weight set to zero.

    :param vis:
    :param modelvis:
    :return:
    """
    assert isinstance(vis, Visibility) or isinstance(vis, BlockVisibility), vis

    # Different for scalar and vector/matrix cases
    isscalar = vis.polarisation_frame.npol == 1

    if isscalar:
        # Scalar case is straightforward
        x = numpy.zeros_like(vis.vis)
        xwt = numpy.abs(modelvis.vis)**2 * vis.weight
        mask = xwt > 0.0
        x[mask] = vis.vis[mask] / modelvis.vis[mask]
    else:
        nrows, nants, _, nchan, npol = vis.vis.shape
        nrec = 2
        assert nrec * nrec == npol
        xshape = (nrows, nants, nants, nchan, nrec, nrec)
        x = numpy.zeros(xshape, dtype='complex')
        xwt = numpy.zeros(xshape)
        for row in range(nrows):
            for ant1 in range(nants):
                for ant2 in range(ant1 + 1, nants):
                    for chan in range(nchan):
                        ovis = numpy.matrix(vis.vis[row, ant2, ant1,
                                                    chan].reshape([2, 2]))
                        mvis = numpy.matrix(modelvis.vis[row, ant2, ant1,
                                                         chan].reshape([2, 2]))
                        wt = numpy.matrix(vis.weight[row, ant2, ant1,
                                                     chan].reshape([2, 2]))
                        x[row, ant2, ant1,
                          chan] = numpy.matmul(numpy.linalg.inv(mvis), ovis)
                        xwt[row, ant2, ant1,
                            chan] = numpy.dot(mvis,
                                              numpy.multiply(wt, mvis.H)).real
        x = x.reshape((nrows, nants, nants, nchan, nrec * nrec))
        xwt = xwt.reshape((nrows, nants, nants, nchan, nrec * nrec))

    pointsource_vis = BlockVisibility(data=None,
                                      frequency=vis.frequency,
                                      channel_bandwidth=vis.channel_bandwidth,
                                      phasecentre=vis.phasecentre,
                                      configuration=vis.configuration,
                                      uvw=vis.uvw,
                                      time=vis.time,
                                      integration_time=vis.integration_time,
                                      vis=x,
                                      weight=xwt)
    return pointsource_vis
Example #3
0
def apply_gaintable(vis: BlockVisibility,
                    gt: GainTable,
                    inverse=False,
                    **kwargs) -> BlockVisibility:
    """Apply a gain table to a block visibility
    
    The corrected visibility is::
    
        V_corrected = {g_i * g_j^*}^-1 V_obs
        
    If the visibility data are polarised e.g. polarisation_frame("linear") then the inverse operator
    represents an actual inverse of the gains.
    
    :param vis: Visibility to have gains applied
    :param gt: Gaintable to be applied
    :param inverse: Apply the inverse (default=False)
    :return: input vis with gains applied
    
    """
    assert type(
        vis) is BlockVisibility, "vis is not a BlockVisibility: %r" % vis
    assert type(gt) is GainTable, "gt is not a GainTable: %r" % gt

    assert_vis_gt_compatible(vis, gt)

    if inverse:
        log.debug('apply_gaintable: Apply inverse gaintable')
    else:
        log.debug('apply_gaintable: Apply gaintable')
    # 按照time对vis进行切片
    for chunk, rows in enumerate(vis_timeslice_iter(vis)):
        vistime = numpy.average(vis.time[rows])
        integration_time = numpy.average(vis.integration_time[rows])
        gaintable_rows = abs(gt.time - vistime) < integration_time / 2.0

        # Lookup the gain for this set of visibilities
        gain = gt.data['gain'][gaintable_rows]

        # The shape of the mueller matrix is
        ntimes, nant, nchan, nrec, _ = gain.shape

        original = vis.vis[rows]
        applied = copy.deepcopy(original)
        for time in range(ntimes):
            for a1 in range(vis.nants - 1):
                for a2 in range(a1 + 1, vis.nants):
                    for chan in range(nchan):
                        mueller = numpy.kron(
                            gain[time, a1, chan, :, :],
                            numpy.conjugate(gain[time, a2, chan, :, :]))
                        if inverse:
                            mueller = numpy.linalg.inv(mueller)

                        applied[time, a2, a1, chan, :] = numpy.matmul(
                            mueller, original[time, a2, a1, chan, :])

        vis.data['vis'][rows] = applied
    return vis
Example #4
0
    def extract_channel(v, chan):
        vis_shape = numpy.array(v.data['vis'].shape)
        vis_shape[3] = 1

        vis = BlockVisibility(data=None,
                              frequency=numpy.array([v.frequency[chan]]),
                              channel_bandwidth=numpy.array([v.channel_bandwidth[chan]]),
                              phasecentre=v.phasecentre,
                              configuration=v.configuration,
                              uvw=v.uvw,
                              time=v.time,
                              vis=v.vis[..., chan, :][..., numpy.newaxis, :],
                              weight=v.weight[..., chan, :][..., numpy.newaxis, :],
                              integration_time=v.integration_time,
                              polarisation_frame=v.polarisation_frame)
        return vis
Example #5
0
def visibility_gather_channel(vis_list: List[Visibility], vis: Visibility = None, **kwargs):
    """ Gather a visibility by channel
    
    :param vis_list:
    :param vis:
    :param kwargs:
    :return:
    """
    
    cols = ['vis', 'weight']
    
    if vis is None:

        vis_shape = numpy.array(vis_list[0].vis.shape)
        vis_shape[-2] = len(vis_list)
        for v in vis_list:
            assert len(v.frequency) == 1
            assert len(v.channel_bandwidth) == 1
        vis = BlockVisibility(data=None,
                              frequency=numpy.array([v.frequency[0] for v in vis_list]),
                              channel_bandwidth=numpy.array([v.channel_bandwidth[0] for v in vis_list]),
                              phasecentre=vis_list[0].phasecentre,
                              configuration=vis_list[0].configuration,
                              uvw=vis_list[0].uvw,
                              time=vis_list[0].time,
                              vis=numpy.zeros(vis_shape, dtype=vis_list[0].vis.dtype),
                              weight=numpy.ones(vis_shape, dtype=vis_list[0].weight.dtype),
                              integration_time=vis_list[0].integration_time,
                              polarisation_frame=vis_list[0].polarisation_frame)
    
    assert len(vis.frequency) == len(vis_list)
    
    for chan, _ in enumerate(vis_list):
        subvis = vis_list[chan]
        assert abs(subvis.frequency[0] - vis.frequency[chan]) < 1e-15
        for col in cols:
            vis.data[col][..., chan, :] = subvis.data[col][..., 0, :]
        vis.frequency[chan] = subvis.frequency[0]
        
    nchan = vis.vis.shape[-2]
    assert nchan == len(vis.frequency)
    
    return vis
Example #6
0
def apply_gaintable(vis: BlockVisibility,
                    gt: GainTable,
                    inverse=False,
                    **kwargs) -> BlockVisibility:
    """Apply a gain table to a block visibility
    
    The corrected visibility is::
    
        V_corrected = {g_i * g_j^*}^-1 V_obs
        
    If the visibility data are polarised e.g. polarisation_frame("linear") then the inverse operator
    represents an actual inverse of the gains.
    
    :param vis: Visibility to have gains applied
    :param gt: Gaintable to be applied
    :param inverse: Apply the inverse (default=False)
    :return: input vis with gains applied
    
    """
    assert isinstance(
        vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis
    assert isinstance(gt, GainTable), "gt is not a GainTable: %r" % gt

    assert_vis_gt_compatible(vis, gt)

    if inverse:
        log.debug('apply_gaintable: Apply inverse gaintable')
    else:
        log.debug('apply_gaintable: Apply gaintable')

    is_scalar = gt.gain.shape[-2:] == (1, 1)
    if is_scalar:
        log.debug('apply_gaintable: scalar gains')

    for chunk, rows in enumerate(vis_timeslice_iter(vis, **kwargs)):
        if numpy.sum(rows) > 0:
            vistime = numpy.average(vis.time[rows])
            gaintable_rows = abs(gt.time - vistime) < gt.interval / 2.0

            # Lookup the gain for this set of visibilities
            gain = gt.data['gain'][gaintable_rows]

            # The shape of the mueller matrix is
            ntimes, nant, nchan, nrec, _ = gain.shape

            original = vis.vis[rows]
            applied = copy.deepcopy(original)
            for time in range(ntimes):
                for a1 in range(vis.nants - 1):
                    for a2 in range(a1 + 1, vis.nants):
                        if is_scalar:
                            smueller = gain[time, a1, :, 0] * numpy.conjugate(
                                gain[time, a2, :, 0])
                            if inverse:
                                if numpy.abs(smueller).all() > 0.0:
                                    applied[time, a2, a1, :,
                                            0][..., numpy.newaxis] = original[
                                                time, a2, a1, :,
                                                0][...,
                                                   numpy.newaxis] / smueller
                            else:
                                applied[time, a2, a1, :,
                                        0][..., numpy.newaxis] = original[
                                            time, a2, a1, :,
                                            0][..., numpy.newaxis] * smueller
                        else:
                            for chan in range(nchan):
                                mueller = numpy.kron(
                                    gain[time, a1, chan, :, :],
                                    numpy.conjugate(gain[time, a2,
                                                         chan, :, :]))
                                if inverse:
                                    # If the Mueller is singular, ignore it
                                    try:
                                        mueller = numpy.linalg.inv(mueller)
                                        applied[time, a2, a1,
                                                chan, :] = numpy.matmul(
                                                    mueller,
                                                    original[time, a2, a1,
                                                             chan, :])
                                    except numpy.linalg.linalg.LinAlgError:
                                        applied[time, a2, a1,
                                                chan, :] = original[time, a2,
                                                                    a1,
                                                                    chan, :]
                                else:
                                    applied[time, a2, a1,
                                            chan, :] = numpy.matmul(
                                                mueller, original[time, a2, a1,
                                                                  chan, :])

            vis.data['vis'][rows] = applied
    return vis
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,
                           **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)

    nch = len(frequency)
    ants_xyz = config.data['xyz']
    nants = len(config.data['names'])
    ntimes = len(times)
    npol = polarisation_frame.npol
    visshape = [ntimes, nants, nants, nch, npol]
    rvis = numpy.zeros(visshape, dtype='complex')
    rweight = weight * numpy.ones(visshape)
    rtimes = numpy.zeros([ntimes])
    ruvw = numpy.zeros([ntimes, nants, nants, 3])

    # Do each hour angle in turn
    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)
        rtimes[iha] = ha * 43200.0 / numpy.pi

        # Loop over all pairs of antennas. Note that a2>a1
        for a1 in range(nants):
            for a2 in range(a1 + 1, nants):
                ruvw[iha, a2, a1, :] = (ant_pos[a2, :] - ant_pos[a1, :])
                ruvw[iha, a1, a2, :] = (ant_pos[a1, :] - ant_pos[a2, :])

    rintegration_time = numpy.full_like(rtimes, integration_time)
    rchannel_bandwidth = numpy.full_like(frequency, channel_bandwidth)
    if zerow:
        ruvw[..., 2] = 0.0
    vis = BlockVisibility(uvw=ruvw,
                          time=rtimes,
                          frequency=frequency,
                          vis=rvis,
                          weight=rweight,
                          integration_time=rintegration_time,
                          channel_bandwidth=rchannel_bandwidth,
                          polarisation_frame=polarisation_frame)
    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 divide_visibility(vis: BlockVisibility, modelvis: BlockVisibility):
    """ Divide visibility by model forming visibility for equivalent point source

    This is a useful intermediate product for calibration. Variation of the visibility in time and
    frequency due to the model structure is removed and the data can be averaged to a limit determined
    by the instrumental stability. The weight is adjusted to compensate for the division.
    
    Zero divisions are avoided and the corresponding weight set to zero.

    :param vis:
    :param modelvis:
    :return:
    """
    # Different for scalar and vector/matrix cases
    # 使用modelvis去除以vis
    isscalar = vis.polarisation_frame.npol == 1
    # 若npol=1
    if isscalar:
        # Scalar case is straightforward
        x = numpy.zeros_like(vis.vis)
        xwt = numpy.abs(modelvis.vis)**2 * vis.weight
        mask = xwt > 0.0
        x[mask] = vis.vis[mask] / modelvis.vis[mask]
    # 否则
    else:
        nrows, nants, _, nchan, npol = vis.vis.shape
        nrec = 2
        assert nrec * nrec == npol
        xshape = (nrows, nants, nants, nchan, nrec, nrec)
        x = numpy.zeros(xshape, dtype='complex')
        xwt = numpy.zeros(xshape)
        # 该处因为ant2永远大于ant1,所以实际上blockvisibility中vis的所有第1维id小于等于第2维id的值都未被修改
        for row in range(nrows):
            for ant1 in range(nants):
                for ant2 in range(ant1 + 1, nants):
                    for chan in range(nchan):
                        # print(vis.vis[row, ant2, ant1, chan])
                        # print(row, ant2, ant1, chan)
                        ovis = numpy.matrix(vis.vis[row, ant2, ant1,
                                                    chan].reshape([2, 2]))
                        mvis = numpy.matrix(modelvis.vis[row, ant2, ant1,
                                                         chan].reshape([2, 2]))
                        wt = numpy.matrix(vis.weight[row, ant2, ant1,
                                                     chan].reshape([2, 2]))
                        x[row, ant2, ant1,
                          chan] = numpy.matmul(numpy.linalg.inv(mvis), ovis)
                        xwt[row, ant2, ant1,
                            chan] = numpy.dot(mvis,
                                              numpy.multiply(wt, mvis.H)).real
        x[abs(x) < 1e-10] = 0.0
        # 计算得到新的vis和新的权重, 并且矩阵大部分值为0,因为只计算了ant2 > ant1的部分, 个人认为可以直接使用visibility计算
        x = x.reshape((nrows, nants, nants, nchan, nrec * nrec))
        xwt = xwt.reshape((nrows, nants, nants, nchan, nrec * nrec))

    # 只有vis和weight得到了新的值,其他数据均不变
    pointsource_vis = BlockVisibility(data=None,
                                      frequency=vis.frequency,
                                      channel_bandwidth=vis.channel_bandwidth,
                                      phasecentre=vis.phasecentre,
                                      configuration=vis.configuration,
                                      uvw=vis.uvw,
                                      time=vis.time,
                                      integration_time=vis.integration_time,
                                      vis=x,
                                      weight=xwt)
    return pointsource_vis