Exemple #1
0
def visibility_scatter(vis: Visibility,
                       vis_iter,
                       vis_slices=1) -> List[Visibility]:
    """Scatter a visibility into a list of subvisibilities
    
    If vis_iter is over time then the type of the outvisibilities will be the same as inout
    If vis_iter is over w then the type of the output visibilities will always be Visibility

    :param vis: Visibility
    :param vis_iter: visibility iterator
    :param vis_slices: Number of slices to be made
    :return: list of subvisibilitys
    """

    assert vis is not None

    if vis_slices == 1:
        return [vis]

    visibility_list = list()
    for i, rows in enumerate(vis_iter(vis, vis_slices=vis_slices)):
        subvis = create_visibility_from_rows(vis, rows)
        visibility_list.append(subvis)

    return visibility_list
 def test_create_visibility_from_rows_makecopy(self):
     self.vis = create_visibility(self.lowcore, self.times, self.frequency, phasecentre=self.phasecentre,
                                  weight=1.0, channel_bandwidth=self.channel_bandwidth)
     rows = self.vis.time > 150.0
     for makecopy in [True, False]:
         selected_vis = create_visibility_from_rows(self.vis, rows, makecopy=makecopy)
         assert selected_vis.nvis == numpy.sum(numpy.array(rows))
 def test_coalesce_decoalesce_with_iter(self):
     for rows in vis_timeslice_iter(self.blockvis):
         visslice = create_visibility_from_rows(self.blockvis, rows)
         cvisslice = convert_blockvisibility_to_visibility(visslice)
         assert numpy.min(cvisslice.frequency) == numpy.min(self.frequency)
         assert numpy.min(cvisslice.frequency) > 0.0
         dvisslice = decoalesce_visibility(cvisslice)
         assert dvisslice.nvis == visslice.nvis
Exemple #4
0
 def test_vis_wslice_iterator(self):
     self.actualSetUp()
     nchunks = vis_wslices(self.vis, wslice=10.0)
     log.debug('Found %d chunks' % (nchunks))
     assert nchunks > 1
     total_rows = 0
     for chunk, rows in enumerate(vis_wslice_iter(self.vis, nchunks)):
         assert len(rows)
         visslice = create_visibility_from_rows(self.vis, rows)
         total_rows += visslice.nvis
         assert numpy.sum(visslice.nvis) < self.vis.nvis
     assert total_rows == self.vis.nvis, "Total rows iterated %d, Original rows %d" % (total_rows, self.vis.nvis)
Exemple #5
0
def create_gaintable_from_screen(vis,
                                 sc,
                                 screen,
                                 height=3e5,
                                 vis_slices=None,
                                 scale=1.0,
                                 **kwargs):
    """ Create gaintables from a screen calculated using ARatmospy

    Screen axes are ['XX', 'YY', 'TIME', 'FREQ']

    :param vis:
    :param sc: Sky components for which pierce points are needed
    :param screen:
    :param height: Height (in m) of screen above telescope e.g. 3e5
    :param scale: Multiply the screen by this factor
    :return:
    """
    assert isinstance(vis, BlockVisibility)

    station_locations = vis.configuration.xyz

    # Convert to TEC
    # phase = image[pixel] * -8.44797245e9 / frequency
    nant = station_locations.shape[0]
    t2r = numpy.pi / 43200.0
    gaintables = [
        create_gaintable_from_blockvisibility(vis, **kwargs) for i in sc
    ]

    # The time in the Visibility is hour angle in seconds!
    for iha, rows in enumerate(vis_timeslice_iter(vis, vis_slices=vis_slices)):
        v = create_visibility_from_rows(vis, rows)
        ha = numpy.average(v.time)
        tec2phase = -8.44797245e9 / numpy.array(vis.frequency)

        number_bad = 0
        number_good = 0

        for icomp, comp in enumerate(sc):
            pp = find_pierce_points(station_locations,
                                    (comp.direction.ra.rad + t2r * ha) * u.rad,
                                    comp.direction.dec,
                                    height=height,
                                    phasecentre=vis.phasecentre)
            scr = numpy.zeros([nant])
            for ant in range(nant):
                pp0 = pp[ant][0:2]
                worldloc = [pp0[0], pp0[1], ha, 1e8]
                try:
                    pixloc = screen.wcs.wcs_world2pix([worldloc],
                                                      0)[0].astype('int')
                    scr[ant] = scale * screen.data[pixloc[3], pixloc[2],
                                                   pixloc[1], pixloc[0]]
                    number_good += 1
                except:
                    number_bad += 1
                    scr[ant] = 0.0

            scr = scr[:, numpy.newaxis] * tec2phase[numpy.newaxis, :]
            # axes of gaintable.gain are time, ant, nchan, nrec
            gaintables[icomp].gain[iha, :, :, :] = numpy.exp(
                1j * scr[..., numpy.newaxis, numpy.newaxis])
            gaintables[icomp].phasecentre = comp.direction

        if number_bad > 0:
            log.warning(
                "create_gaintable_from_screen: %d pierce points are inside the screen image"
                % (number_good))
            log.warning(
                "create_gaintable_from_screen: %d pierce points are outside the screen image"
                % (number_bad))

    return gaintables
Exemple #6
0
def solve_gaintable(vis: BlockVisibility,
                    modelvis: BlockVisibility = None,
                    gt=None,
                    phase_only=True,
                    niter=30,
                    tol=1e-8,
                    crosspol=False,
                    normalise_gains=True,
                    **kwargs) -> GainTable:
    """Solve a gain table by fitting an observed visibility to a model visibility

    If modelvis is None, a point source model is assumed.

    :param vis: BlockVisibility containing the observed data_models
    :param modelvis: BlockVisibility containing the visibility predicted by a model
    :param gt: Existing gaintable
    :param phase_only: Solve only for the phases (default=True)
    :param niter: Number of iterations (default 30)
    :param tol: Iteration stops when the fractional change in the gain solution is below this tolerance
    :param crosspol: Do solutions including cross polarisations i.e. XY, YX or RL, LR
    :return: GainTable containing solution

    """
    assert isinstance(vis, BlockVisibility), vis
    if modelvis is not None:
        assert isinstance(modelvis, BlockVisibility), modelvis
        assert numpy.max(numpy.abs(
            modelvis.vis)) > 0.0, "Model visibility is zero"

    if phase_only:
        log.debug('solve_gaintable: Solving for phase only')
    else:
        log.debug('solve_gaintable: Solving for complex gain')

    if gt is None:
        log.debug("solve_gaintable: creating new gaintable")
        gt = create_gaintable_from_blockvisibility(vis, **kwargs)
    else:
        log.debug("solve_gaintable: starting from existing gaintable")

    for row in range(gt.ntimes):
        vis_rows = numpy.abs(vis.time - gt.time[row]) < gt.interval[row] / 2.0
        if numpy.sum(vis_rows) > 0:
            subvis = create_visibility_from_rows(vis, vis_rows)
            if modelvis is not None:
                model_subvis = create_visibility_from_rows(modelvis, vis_rows)
                pointvis = divide_visibility(subvis, model_subvis)
                x = numpy.sum(pointvis.vis * pointvis.weight, axis=0)
                xwt = numpy.sum(pointvis.weight, axis=0)
            else:
                x = numpy.sum(subvis.vis * subvis.weight, axis=0)
                xwt = numpy.sum(subvis.weight, axis=0)

            mask = numpy.abs(xwt) > 0.0
            x_shape = x.shape
            x[mask] = x[mask] / xwt[mask]
            x[~mask] = 0.0
            x = x.reshape(x_shape)

            gt = solve_from_X(gt,
                              x,
                              xwt,
                              row,
                              crosspol,
                              niter,
                              phase_only,
                              tol,
                              npol=vis.polarisation_frame.npol)
            if normalise_gains and not phase_only:
                gabs = numpy.average(numpy.abs(gt.data['gain'][row]))
                gt.data['gain'][row] /= gabs

    assert isinstance(gt, GainTable), "gt is not a GainTable: %r" % gt

    assert_vis_gt_compatible(vis, gt)

    return gt
Exemple #7
0
def simulate_gaintable_from_voltage_patterns(vis, sc, vp_list, vp_coeffs, vis_slices=None, order=3, use_radec=False,
                                             **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(v.time)
                har = s2r * ha
                
                # Calculate the az el for this hourangle and the phasecentre declination
                azimuth_centre, elevation_centre = hadec_to_azel(har, vis.phasecentre.dec.rad, latitude)
        
                for icomp, comp in enumerate(sc):
                    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 + har
                    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()
            
                            az_comp = azimuth_centre * r2d
                            el_comp = elevation_centre * r2d
                        
                            # We use WCS sensible coordinate handling by labelling the axes misleadingly
                            wcs_azel.wcs.crval[0] = az_comp
                            wcs_azel.wcs.crval[1] = el_comp
                            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:
                                number_bad += 1
                                antgain[ant] = 0.0
                                
                        antgain[ant] = 1.0/antgain[ant]
                    
                    gaintables[icomp].gain[iha, :, :, :] = antgain[:, numpy.newaxis, numpy.newaxis, numpy.newaxis]
                    gaintables[icomp].phasecentre = comp.direction
    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(v.time)
        
            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:
                            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_voltage_patterns: %d points are inside the voltage pattern image" % (number_good))
        log.warning(
            "simulate_gaintable_from_voltage_patterns: %d points are outside the voltage pattern image" % (number_bad))

    return gaintables