コード例 #1
0
def invert_serial(vis, im: Image, dopsf=False, normalize=True, context='2d', vis_slices=1,
                  facets=1, overlap=0, taper=None, **kwargs):
    """ Invert using algorithm specified by context:

     * 2d: Two-dimensional transform
     * wstack: wstacking with either vis_slices or wstack (spacing between w planes) set
     * wprojection: w projection with wstep (spacing between w places) set, also kernel='wprojection'
     * timeslice: snapshot imaging with either vis_slices or timeslice set. timeslice='auto' does every time
     * facets: Faceted imaging with facets facets on each axis
     * facets_wprojection: facets AND wprojection
     * facets_wstack: facets AND wstacking
     * wprojection_wstack: wprojection and wstacking


    :param vis:
    :param im:
    :param dopsf: Make the psf instead of the dirty image (False)
    :param normalize: Normalize by the sum of weights (True)
    :param context: Imaging context e.g. '2d', 'timeslice', etc.
    :param kwargs:
    :return: Image, sum of weights
    """
    c = imaging_context(context)
    vis_iter = c['vis_iterator']
    invert = c['invert']

    if not isinstance(vis, Visibility):
        svis = convert_blockvisibility_to_visibility(vis)
    else:
        svis = vis
    
    resultimage = create_empty_image_like(im)
    
    totalwt = None
    for rows in vis_iter(svis, vis_slices=vis_slices):
        if numpy.sum(rows):
            visslice = create_visibility_from_rows(svis, rows)
            sumwt = 0.0
            workimage = create_empty_image_like(im)
            for dpatch in image_scatter_facets(workimage, facets=facets, overlap=overlap, taper=taper):
                result, sumwt = invert(visslice, dpatch, dopsf, normalize=False, facets=facets,
                                       vis_slices=vis_slices, **kwargs)
                # Ensure that we fill in the elements of dpatch instead of creating a new numpy arrray
                dpatch.data[...] = result.data[...]
            # Assume that sumwt is the same for all patches
            if totalwt is None:
                totalwt = sumwt
            else:
                totalwt += sumwt
            resultimage.data += workimage.data
    
    assert totalwt is not None, "No valid data found for imaging"
    if normalize:
        resultimage = normalize_sumwt(resultimage, totalwt)
    
    return resultimage, totalwt
    def test_scatter_gather_facet(self):

        m31original = create_test_image(
            polarisation_frame=PolarisationFrame('stokesI'))
        assert numpy.max(numpy.abs(m31original.data)), "Original is empty"

        for nraster in [1, 4, 8]:
            m31model = create_test_image(
                polarisation_frame=PolarisationFrame('stokesI'))
            image_list = image_scatter_facets(m31model, facets=nraster)
            for patch in image_list:
                assert patch.data.shape[3] == (m31model.data.shape[3] // nraster), \
                    "Number of pixels in each patch: %d not as expected: %d" % (patch.data.shape[3],
                                                                                (m31model.data.shape[3] // nraster))
                assert patch.data.shape[2] == (m31model.data.shape[2] // nraster), \
                    "Number of pixels in each patch: %d not as expected: %d" % (patch.data.shape[2],
                                                                                (m31model.data.shape[2] // nraster))
                patch.data[...] = 1.0
            m31reconstructed = create_empty_image_like(m31model)
            m31reconstructed = image_gather_facets(image_list,
                                                   m31reconstructed,
                                                   facets=nraster)
            flat = image_gather_facets(image_list,
                                       m31reconstructed,
                                       facets=nraster,
                                       return_flat=True)

            assert numpy.max(numpy.abs(
                flat.data)), "Flat is empty for %d" % nraster
            assert numpy.max(numpy.abs(
                m31reconstructed.data)), "Raster is empty for %d" % nraster
 def test_scatter_gather_facet_overlap_taper(self):
 
     m31original = create_test_image(polarisation_frame=PolarisationFrame('stokesI'))
     assert numpy.max(numpy.abs(m31original.data)), "Original is empty"
 
     for taper in ['linear', None]:
         for nraster, overlap in [(1, 0), (4, 8), (8, 8), (8, 16)]:
             m31model = create_test_image(polarisation_frame=PolarisationFrame('stokesI'))
             image_list = image_scatter_facets(m31model, facets=nraster, overlap=overlap, taper=taper)
             for patch in image_list:
                 assert patch.data.shape[3] == (2 * overlap + m31model.data.shape[3] // nraster), \
                     "Number of pixels in each patch: %d not as expected: %d" % (patch.data.shape[3],
                                                                                 (2 * overlap + m31model.data.shape[3] //
                                                                                  nraster))
                 assert patch.data.shape[2] == (2 * overlap + m31model.data.shape[2] // nraster), \
                     "Number of pixels in each patch: %d not as expected: %d" % (patch.data.shape[2],
                                                                                 (2 * overlap + m31model.data.shape[2] //
                                                                                  nraster))
             m31reconstructed = create_empty_image_like(m31model)
             m31reconstructed = image_gather_facets(image_list, m31reconstructed, facets=nraster, overlap=overlap,
                                                    taper=taper)
             flat = image_gather_facets(image_list, m31reconstructed, facets=nraster, overlap=overlap,
                                        taper=taper, return_flat=True)
             export_image_to_fits(m31reconstructed,
                                  "%s/test_image_gather_scatter_%dnraster_%doverlap_%s_reconstructed.fits" %
                                  (self.dir, nraster, overlap, taper))
             export_image_to_fits(flat,
                                  "%s/test_image_gather_scatter_%dnraster_%doverlap_%s_flat.fits" %
                                  (self.dir, nraster, overlap, taper))
 
             assert numpy.max(numpy.abs(flat.data)), "Flat is empty for %d" % nraster
             assert numpy.max(numpy.abs(m31reconstructed.data)), "Raster is empty for %d" % nraster
コード例 #4
0
def create_low_test_beam(model: Image) -> Image:
    """Create a test power beam for LOW using an image from OSKAR

    :param model: Template image
    :return: Image
    """

    beam = import_image_from_fits(arl_path('data/models/SKA1_LOW_beam.fits'))

    # Scale the image cellsize to account for the different in frequencies. Eventually we will want to
    # use a frequency cube
    log.info("create_low_test_beam: primary beam is defined at %.3f MHz" %
             (beam.wcs.wcs.crval[2] * 1e-6))

    nchan, npol, ny, nx = model.shape

    # We need to interpolate each frequency channel separately. The beam is assumed to just scale with
    # frequency.

    reprojected_beam = create_empty_image_like(model)

    for chan in range(nchan):

        model2dwcs = model.wcs.sub(2).deepcopy()
        model2dshape = [model.shape[2], model.shape[3]]
        beam2dwcs = beam.wcs.sub(2).deepcopy()

        # The frequency axis is the second to last in the beam
        frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        fscale = beam.wcs.wcs.crval[2] / frequency

        beam2dwcs.wcs.cdelt = fscale * beam.wcs.sub(2).wcs.cdelt
        beam2dwcs.wcs.crpix = beam.wcs.sub(2).wcs.crpix
        beam2dwcs.wcs.crval = model.wcs.sub(2).wcs.crval
        beam2dwcs.wcs.ctype = model.wcs.sub(2).wcs.ctype
        model2dwcs.wcs.crpix = [
            model.shape[2] // 2 + 1, model.shape[3] // 2 + 1
        ]

        beam2d = create_image_from_array(beam.data[0, 0, :, :], beam2dwcs,
                                         model.polarisation_frame)
        reprojected_beam2d, footprint = reproject_image(beam2d,
                                                        model2dwcs,
                                                        shape=model2dshape)
        assert numpy.max(
            footprint.data) > 0.0, "No overlap between beam and model"

        reprojected_beam2d.data *= reprojected_beam2d.data
        reprojected_beam2d.data[footprint.data <= 0.0] = 0.0
        for pol in range(npol):
            reprojected_beam.data[chan,
                                  pol, :, :] = reprojected_beam2d.data[:, :]

    return reprojected_beam
コード例 #5
0
def create_low_test_vp(model: Image, use_local=True) -> Image:
    """Create a test power beam for LOW using an image from OSKAR

    :param model: Template image
    :return: Image
    """
    
    # TODO: Get true voltage beam from OSKAR
    beam = import_image_from_fits(arl_path('data/models/SKA1_LOW_beam.fits'))
    beam.data = numpy.sqrt(beam.data).astype('complex')
    
    # Scale the image cellsize to account for the different in frequencies. Eventually we will want to
    # use a frequency cube
    log.debug("create_low_test_beam: LOW voltage pattern is defined at %.3f MHz" % (beam.wcs.wcs.crval[2] * 1e-6))
    
    nchan, npol, ny, nx = model.shape
    
    # We need to interpolate each frequency channel separately. The beam is assumed to just scale with
    # frequency.
    
    reprojected_beam = create_empty_image_like(model)
    reprojected_beam.data = reprojected_beam.data.astype('complex')
    
    for chan in range(nchan):
        
        model2dwcs = model.wcs.sub(2).deepcopy()
        model2dshape = [model.shape[2], model.shape[3]]
        beam2dwcs = beam.wcs.sub(2).deepcopy()
        
        # The frequency axis is the second to last in the beam
        frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        fscale = beam.wcs.wcs.crval[2] / frequency
        
        beam2dwcs.wcs.cdelt = fscale * beam.wcs.sub(2).wcs.cdelt
        beam2dwcs.wcs.crpix = beam.wcs.sub(2).wcs.crpix
        beam2dwcs.wcs.crval = model.wcs.sub(2).wcs.crval
        beam2dwcs.wcs.ctype = model.wcs.sub(2).wcs.ctype
        model2dwcs.wcs.crpix = [model.shape[2] // 2 + 1, model.shape[3] // 2 + 1]
        
        beam2d_real = create_image_from_array(numpy.real(beam.data[0, 0, :, :]), beam2dwcs, model.polarisation_frame)
        beam2d_imag = create_image_from_array(numpy.imag(beam.data[0, 0, :, :]), beam2dwcs, model.polarisation_frame)
        reprojected_beam2d_real, footprint = reproject_image(beam2d_real, model2dwcs, shape=model2dshape)
        reprojected_beam2d_imag, footprint = reproject_image(beam2d_imag, model2dwcs, shape=model2dshape)
        assert numpy.max(footprint.data) > 0.0, "No overlap between beam and model"
        
        reprojected_beam2d_real.data[footprint.data <= 0.0] = 0.0
        reprojected_beam2d_imag.data[footprint.data <= 0.0] = 0.0
        for pol in range(npol):
            reprojected_beam.data[chan, pol, :, :] = reprojected_beam2d_real.data[:, :] \
                                                     + 1j * reprojected_beam2d_imag.data[:, :]
    
    set_pb_header(reprojected_beam, use_local=use_local)
    return reprojected_beam
コード例 #6
0
 def test_raster_overlap(self):
 
     m31original = create_test_image(polarisation_frame=PolarisationFrame('stokesI'))
     assert numpy.max(numpy.abs(m31original.data)), "Original is empty"
     flat = create_empty_image_like(m31original)
 
     for nraster, overlap in [(1, 0),  (1, 16), (4, 8), (4, 16), (8, 8), (16, 4), (9, 5)]:
         m31model = create_test_image(polarisation_frame=PolarisationFrame('stokesI'))
         for patch, flat_patch in zip(image_raster_iter(m31model, facets=nraster, overlap=overlap),
                                      image_raster_iter(flat, facets=nraster, overlap=overlap)):
             patch.data *= 2.0
             flat_patch.data[...] += 1.0
     
         assert numpy.max(numpy.abs(m31model.data)), "Raster is empty for %d" % nraster
コード例 #7
0
def mosaic_pb(model, telescope, pointingcentres, use_local=True):
    """ Create a mosaic primary beam by adding primary beams for a set of pointing centres
    
    Note that the addition is root sum of squares
    
    :param model:  Template image
    :param telescope:
    :param pointingcentres:  list of pointing centres
    :return:
    """
    assert isinstance(pointingcentres, collections.Iterable), "Need a list of pointing centres"
    sumpb = create_empty_image_like(model)
    for pc in pointingcentres:
        pb = create_pb(model, telescope, pointingcentre=pc, use_local=use_local)
        sumpb.data += pb.data ** 2
    sumpb.data = numpy.sqrt(sumpb.data)
    return sumpb
コード例 #8
0
def create_vp_generic(model,
                      pointingcentre=None,
                      diameter=25.0,
                      blockage=1.8,
                      use_local=True):
    """
    Make an image like model and fill it with an analytical model of the primary beam
    :param model:
    :return:
    """
    beam = create_empty_image_like(model)
    beam.data = numpy.zeros(beam.data.shape, dtype='complex')

    nchan, npol, ny, nx = model.shape

    if pointingcentre is not None:
        cx, cy = pointingcentre.to_pixel(model.wcs, origin=0)
    else:
        cx, cy = beam.wcs.sub(2).wcs.crpix[0] - 1, beam.wcs.sub(
            2).wcs.crpix[1] - 1

    for chan in range(nchan):

        # The frequency axis is the second to last in the beam
        frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        wavelength = const.c.to('m s^-1').value / frequency

        d2r = numpy.pi / 180.0
        scale = d2r * numpy.abs(beam.wcs.sub(2).wcs.cdelt[0])
        xx, yy = numpy.meshgrid(scale * (range(nx) - cx),
                                scale * (range(ny) - cy))
        # Radius of each cell in radians
        rr = numpy.sqrt(xx**2 + yy**2)

        blockage_factor = (blockage / diameter)**2

        for pol in range(npol):
            reflector = ft_disk(rr * numpy.pi * diameter / wavelength)
            blockage = ft_disk(rr * numpy.pi * blockage / wavelength)
            beam.data[chan, pol, ...] = reflector - blockage_factor * blockage

    set_pb_header(beam, use_local=use_local)
    return beam
コード例 #9
0
def create_pb_generic(model, pointingcentre=None, diameter=25.0, blockage=1.8):
    """
    Make an image like model and fill it with an analytical model of the primary beam
    :param model:
    :return:
    """
    beam = create_empty_image_like(model)

    nchan, npol, ny, nx = model.shape

    if pointingcentre is not None:
        cx, cy = skycoord_to_pixel(pointingcentre, model.wcs, 0, 'wcs')
    else:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', FITSFixedWarning)
            cx, cy = beam.wcs.sub(2).wcs.crpix[0] - 1, beam.wcs.sub(
                2).wcs.crpix[1] - 1

    for chan in range(nchan):

        # The frequency axis is the second to last in the beam
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', FITSFixedWarning)
            frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        wavelength = const.c.to('m s^-1').value / frequency

        d2r = numpy.pi / 180.0
        scale = d2r * numpy.abs(beam.wcs.sub(2).wcs.cdelt[0])
        xx, yy = numpy.meshgrid(scale * (range(nx) - cx),
                                scale * (range(ny) - cy))
        # Radius of each cell in radians
        rr = numpy.sqrt(xx**2 + yy**2)

        blockage_factor = (blockage / diameter)**2

        for pol in range(npol):
            reflector = ft_disk(rr * numpy.pi * diameter / wavelength)
            blockage = ft_disk(rr * numpy.pi * blockage / wavelength)
            beam.data[chan, pol, ...] = reflector - blockage_factor * blockage

    beam.data *= beam.data
    return beam
コード例 #10
0
    def test_grid_gaintable_to_screen(self):
        screen = import_image_from_fits(
            arl_path('data/models/test_mpc_screen.fits'))
        beam = create_test_image(cellsize=0.0015,
                                 phasecentre=self.vis.phasecentre,
                                 frequency=self.frequency)

        beam = create_low_test_beam(beam, use_local=False)

        gleam_components = create_low_test_skycomponents_from_gleam(
            flux_limit=1.0,
            phasecentre=self.phasecentre,
            frequency=self.frequency,
            polarisation_frame=PolarisationFrame('stokesI'),
            radius=0.2)

        pb_gleam_components = apply_beam_to_skycomponent(
            gleam_components, beam)

        actual_components = filter_skycomponents_by_flux(pb_gleam_components,
                                                         flux_min=1.0)

        gaintables = create_gaintable_from_screen(self.vis, actual_components,
                                                  screen)
        assert len(gaintables) == len(actual_components), len(gaintables)
        assert gaintables[0].gain.shape == (3, 94, 3, 1,
                                            1), gaintables[0].gain.shape

        newscreen = create_empty_image_like(screen)

        newscreen, weights = grid_gaintable_to_screen(self.vis, gaintables,
                                                      newscreen)
        assert numpy.max(numpy.abs(screen.data)) > 0.0
        if self.persist:
            export_image_to_fits(
                newscreen,
                arl_path('test_results/test_mpc_screen_gridded.fits'))
        if self.persist:
            export_image_to_fits(
                weights,
                arl_path('test_results/test_mpc_screen_gridded_weights.fits'))
コード例 #11
0
def sum_invert_results(image_list, normalize=True):
    """ Sum a set of invert results with appropriate weighting

    :param image_list: List of [image, sum weights] pairs
    :return: image, sum of weights
    """
    if len(image_list) == 1:
        return image_list[0]

    im = create_empty_image_like(image_list[0][0])
    sumwt = image_list[0][1].copy()
    sumwt *= 0.0

    for i, arg in enumerate(image_list):
        if arg is not None:
            im.data += arg[1][..., numpy.newaxis, numpy.newaxis] * arg[0].data
            sumwt += arg[1]

    if normalize:
        im = normalize_sumwt(im, sumwt)
    return im, sumwt
コード例 #12
0
def grid_gaintable_to_screen(vis,
                             gaintables,
                             screen,
                             height=3e5,
                             gaintable_slices=None,
                             scale=1.0,
                             **kwargs):
    """ Grid a gaintable to a screen image
    
    The phases are just average per grid cell, no phase unwrapping is performed.

    :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: gridded screen image, weights image
    """
    assert isinstance(vis, BlockVisibility)

    station_locations = vis.configuration.xyz

    nant = station_locations.shape[0]
    t2r = numpy.pi / 43200.0

    newscreen = create_empty_image_like(screen)
    weights = create_empty_image_like(screen)
    nchan, ntimes, ny, nx = screen.shape

    # The time in the Visibility is hour angle in seconds!
    number_no_weight = 0
    for gaintable in gaintables:
        for iha, rows in enumerate(
                gaintable_timeslice_iter(gaintable,
                                         gaintable_slices=gaintable_slices)):
            gt = create_gaintable_from_rows(gaintable, rows)
            ha = numpy.average(gt.time)

            pp = find_pierce_points(station_locations,
                                    (gt.phasecentre.ra.rad + t2r * ha) * u.rad,
                                    gt.phasecentre.dec,
                                    height=height,
                                    phasecentre=vis.phasecentre)
            scr = numpy.angle(gt.gain[0, :, 0, 0, 0])
            wt = gt.weight[0, :, 0, 0, 0]
            for ant in range(nant):
                pp0 = pp[ant][0:2]
                worldloc = [pp0[0], pp0[1], ha, 1e8]
                pixloc = newscreen.wcs.wcs_world2pix([worldloc],
                                                     0)[0].astype('int')
                assert pixloc[0] >= 0
                assert pixloc[0] < nx
                assert pixloc[1] >= 0
                assert pixloc[1] < ny
                newscreen.data[pixloc[3], pixloc[2], pixloc[1],
                               pixloc[0]] += wt[ant] * scr[ant]
                weights.data[pixloc[3], pixloc[2], pixloc[1],
                             pixloc[0]] += wt[ant]
                if wt[ant] == 0.0:
                    number_no_weight += 1
    if number_no_weight > 0:
        print("grid_gaintable_to_screen: %d pierce points are have no weight" %
              (number_no_weight))
        log.warning(
            "grid_gaintable_to_screen: %d pierce points are have no weight" %
            (number_no_weight))

    newscreen.data[weights.data > 0.0] = newscreen.data[
        weights.data > 0.0] / weights.data[weights.data > 0.0]

    return newscreen, weights
    def test_mpccal_MPCCAL_manysources_subimages(self):

        self.actualSetup()

        model = create_empty_image_like(self.theta_list[0].image)

        if arlexecute.using_dask:
            progress = None
        else:
            progress = self.progress

        future_vis = arlexecute.scatter(self.all_skymodel_noniso_vis)
        future_model = arlexecute.scatter(model)
        future_theta_list = arlexecute.scatter(self.theta_list)
        result = mpccal_skymodel_list_arlexecute_workflow(
            future_vis,
            future_model,
            future_theta_list,
            mpccal_progress=progress,
            nmajor=5,
            context='2d',
            algorithm='hogbom',
            scales=[0, 3, 10],
            fractional_threshold=0.3,
            threshold=0.2,
            gain=0.1,
            niter=1000,
            psf_support=256,
            deconvolve_facets=8,
            deconvolve_overlap=8,
            deconvolve_taper='tukey')

        (self.theta_list, residual) = arlexecute.compute(result, sync=True)

        combined_model = calculate_skymodel_equivalent_image(self.theta_list)

        psf_obs = invert_list_arlexecute_workflow(
            [self.all_skymodel_noniso_vis], [model], context='2d', dopsf=True)
        result = restore_list_arlexecute_workflow([combined_model], psf_obs,
                                                  [(residual, 0.0)])
        result = arlexecute.compute(result, sync=True)

        if self.persist:
            export_image_to_fits(
                residual,
                arl_path('test_results/test_mpccal_no_edge_residual.fits'))
        if self.persist:
            export_image_to_fits(
                result[0],
                arl_path('test_results/test_mpccal_no_edge_restored.fits'))
        if self.persist:
            export_image_to_fits(
                combined_model,
                arl_path('test_results/test_mpccal_no_edge_deconvolved.fits'))

        recovered_mpccal_components = find_skycomponents(result[0],
                                                         fwhm=2,
                                                         threshold=0.32,
                                                         npixels=12)

        def max_flux(elem):
            return numpy.max(elem.flux)

        recovered_mpccal_components = sorted(recovered_mpccal_components,
                                             key=max_flux,
                                             reverse=True)

        assert recovered_mpccal_components[
            0].name == 'Segment 8', recovered_mpccal_components[0].name
        assert numpy.abs(recovered_mpccal_components[0].flux[0, 0] - 7.773751416364857) < 1e-7, \
            recovered_mpccal_components[0].flux[0, 0]

        newscreen = create_empty_image_like(self.screen)
        gaintables = [th.gaintable for th in self.theta_list]
        newscreen, weights = grid_gaintable_to_screen(
            self.all_skymodel_noniso_blockvis, gaintables, newscreen)
        if self.persist:
            export_image_to_fits(
                newscreen,
                arl_path('test_results/test_mpccal_no_edge_screen.fits'))
        if self.persist:
            export_image_to_fits(
                weights,
                arl_path(
                    'test_results/test_mpccal_no_edge_screenweights.fits'))

        arlexecute.close()
コード例 #14
0
def create_awterm_convolutionfunction(im,
                                      make_pb=None,
                                      nw=1,
                                      wstep=1e15,
                                      oversampling=8,
                                      support=6,
                                      use_aaf=True,
                                      maxsupport=512):
    """ Fill AW projection kernel into a GridData.

    :param im: Image template
    :param make_pb: Function to make the primary beam model image
    :param nw: Number of w planes
    :param wstep: Step in w (wavelengths)
    :param oversampling: Oversampling of the convolution function in uv space
    :return: griddata correction Image, griddata kernel as GridData
    """
    d2r = numpy.pi / 180.0

    # We only need the griddata correction function for the PSWF so we make
    # it for the shape of the image
    nchan, npol, ony, onx = im.data.shape

    assert isinstance(im, Image)
    # Calculate the template convolution kernel.
    cf = create_convolutionfunction_from_image(im,
                                               oversampling=oversampling,
                                               support=support)

    cf_shape = list(cf.data.shape)
    cf_shape[2] = nw
    cf.data = numpy.zeros(cf_shape).astype('complex')

    cf.grid_wcs.wcs.crpix[4] = nw // 2 + 1.0
    cf.grid_wcs.wcs.cdelt[4] = wstep
    cf.grid_wcs.wcs.ctype[4] = 'WW'
    if numpy.abs(wstep) > 0.0:
        w_list = cf.grid_wcs.sub([5]).wcs_pix2world(range(nw), 0)[0]
    else:
        w_list = [0.0]

    assert isinstance(oversampling, int)
    assert oversampling > 0

    nx = max(maxsupport, 2 * oversampling * support)
    ny = max(maxsupport, 2 * oversampling * support)

    qnx = nx // oversampling
    qny = ny // oversampling

    cf.data[...] = 0.0

    subim = copy_image(im)
    ccell = onx * numpy.abs(d2r * subim.wcs.wcs.cdelt[0]) / qnx

    subim.data = numpy.zeros([nchan, npol, qny, qnx])
    subim.wcs.wcs.cdelt[0] = -ccell / d2r
    subim.wcs.wcs.cdelt[1] = +ccell / d2r
    subim.wcs.wcs.crpix[0] = qnx // 2 + 1.0
    subim.wcs.wcs.crpix[1] = qny // 2 + 1.0

    if use_aaf:
        this_pswf_gcf, _ = create_pswf_convolutionfunction(subim,
                                                           oversampling=1,
                                                           support=6)
        norm = 1.0 / this_pswf_gcf.data
    else:
        norm = 1.0

    if make_pb is not None:
        pb = make_pb(subim)
        rpb, footprint = reproject_image(pb, subim.wcs, shape=subim.shape)
        rpb.data[footprint.data < 1e-6] = 0.0
        norm *= rpb.data

    # We might need to work with a larger image
    padded_shape = [nchan, npol, ny, nx]
    thisplane = copy_image(subim)
    thisplane.data = numpy.zeros(thisplane.shape, dtype='complex')
    for z, w in enumerate(w_list):
        thisplane.data[...] = 0.0 + 0.0j
        thisplane = create_w_term_like(thisplane, w, dopol=True)
        thisplane.data *= norm
        paddedplane = pad_image(thisplane, padded_shape)
        paddedplane = fft_image(paddedplane)

        ycen, xcen = ny // 2, nx // 2
        for y in range(oversampling):
            ybeg = y + ycen + (support * oversampling) // 2 - oversampling // 2
            yend = y + ycen - (support * oversampling) // 2 - oversampling // 2
            vv = range(ybeg, yend, -oversampling)
            for x in range(oversampling):
                xbeg = x + xcen + (support *
                                   oversampling) // 2 - oversampling // 2
                xend = x + xcen - (support *
                                   oversampling) // 2 - oversampling // 2

                uu = range(xbeg, xend, -oversampling)
                for chan in range(nchan):
                    for pol in range(npol):
                        cf.data[chan, pol, z, y, x, :, :] = paddedplane.data[
                            chan, pol, :, :][vv, :][:, uu]

    cf.data /= numpy.sum(
        numpy.real(cf.data[0, 0, nw // 2, oversampling // 2,
                           oversampling // 2, :, :]))
    cf.data = numpy.conjugate(cf.data)

    if use_aaf:
        pswf_gcf, _ = create_pswf_convolutionfunction(im,
                                                      oversampling=1,
                                                      support=6)
    else:
        pswf_gcf = create_empty_image_like(im)
        pswf_gcf.data[...] = 1.0

    return pswf_gcf, cf
コード例 #15
0
def create_awterm_convolutionfunction(im,
                                      make_pb=None,
                                      nw=1,
                                      wstep=1e15,
                                      oversampling=8,
                                      support=6,
                                      use_aaf=True,
                                      maxsupport=512,
                                      **kwargs):
    """ Fill AW projection kernel into a GridData.

    :param im: Image template
    :param make_pb: Function to make the primary beam model image (hint: use a partial)
    :param nw: Number of w planes
    :param wstep: Step in w (wavelengths)
    :param oversampling: Oversampling of the convolution function in uv space
    :return: griddata correction Image, griddata kernel as GridData
    """
    d2r = numpy.pi / 180.0

    # We only need the griddata correction function for the PSWF so we make
    # it for the shape of the image
    nchan, npol, ony, onx = im.data.shape

    assert isinstance(im, Image)
    # Calculate the template convolution kernel.
    cf = create_convolutionfunction_from_image(im,
                                               oversampling=oversampling,
                                               support=support)

    cf_shape = list(cf.data.shape)
    cf_shape[2] = nw
    cf.data = numpy.zeros(cf_shape).astype('complex')

    cf.grid_wcs.wcs.crpix[4] = nw // 2 + 1.0
    cf.grid_wcs.wcs.cdelt[4] = wstep
    cf.grid_wcs.wcs.ctype[4] = 'WW'
    if numpy.abs(wstep) > 0.0:
        w_list = cf.grid_wcs.sub([5]).wcs_pix2world(range(nw), 0)[0]
    else:
        w_list = [0.0]

    assert isinstance(oversampling, int)
    assert oversampling > 0

    nx = max(maxsupport, 2 * oversampling * support)
    ny = max(maxsupport, 2 * oversampling * support)

    qnx = nx // oversampling
    qny = ny // oversampling

    cf.data[...] = 0.0

    subim = copy_image(im)
    ccell = onx * numpy.abs(d2r * subim.wcs.wcs.cdelt[0]) / qnx

    subim.data = numpy.zeros([nchan, npol, qny, qnx])
    subim.wcs.wcs.cdelt[0] = -ccell / d2r
    subim.wcs.wcs.cdelt[1] = +ccell / d2r
    subim.wcs.wcs.crpix[0] = qnx // 2 + 1.0
    subim.wcs.wcs.crpix[1] = qny // 2 + 1.0

    if use_aaf:
        this_pswf_gcf, _ = create_pswf_convolutionfunction(subim,
                                                           oversampling=1,
                                                           support=6)
        norm = 1.0 / this_pswf_gcf.data
    else:
        norm = 1.0

    if make_pb is not None:
        pb = make_pb(subim)
        rpb, footprint = reproject_image(pb, subim.wcs, shape=subim.shape)
        rpb.data[footprint.data < 1e-6] = 0.0
        norm *= rpb.data

    # We might need to work with a larger image
    padded_shape = [nchan, npol, ny, nx]
    thisplane = copy_image(subim)
    thisplane.data = numpy.zeros(thisplane.shape, dtype='complex')
    for z, w in enumerate(w_list):
        thisplane.data[...] = 0.0 + 0.0j
        thisplane = create_w_term_like(thisplane, w, dopol=True)
        thisplane.data *= norm
        paddedplane = pad_image(thisplane, padded_shape)
        paddedplane = fft_image(paddedplane)

        ycen, xcen = ny // 2, nx // 2
        for y in range(oversampling):
            ybeg = y + ycen + (support * oversampling) // 2 - oversampling // 2
            yend = y + ycen - (support * oversampling) // 2 - oversampling // 2
            # vv = range(ybeg, yend, -oversampling)
            for x in range(oversampling):
                xbeg = x + xcen + (support *
                                   oversampling) // 2 - oversampling // 2
                xend = x + xcen - (support *
                                   oversampling) // 2 - oversampling // 2

                # uu = range(xbeg, xend, -oversampling)
                cf.data[..., z, y,
                        x, :, :] = paddedplane.data[...,
                                                    ybeg:yend:-oversampling,
                                                    xbeg:xend:-oversampling]
                # for chan in range(nchan):
                #     for pol in range(npol):
                #         cf.data[chan, pol, z, y, x, :, :] = paddedplane.data[chan, pol, :, :][vv, :][:, uu]

    cf.data /= numpy.sum(
        numpy.real(cf.data[0, 0, nw // 2, oversampling // 2,
                           oversampling // 2, :, :]))
    cf.data = numpy.conjugate(cf.data)

    #====================================
    #Use ASKAPSoft routine to crop the support size
    crop_ASKAPSOft_like = True
    if crop_ASKAPSOft_like:
        #Hardcode the cellsize: 1 / FOV
        #uv_cellsize = 57.3;#N=1200 pixel and pixelsize is 3 arcseconds
        #uv_cellsize = 43.97;#N=1600 pixel and pixelsize is 3 arcseconds
        #uv_cellsize = 114.6;#N=1800 pixel with 1 arcsecond pixelsize
        #uv_cellsize = 57.3;#N=1800 pixel with 2 arcsecond pixelsize
        #uv_cellsize = 1145.91509915;#N=1800 pixxel with 0.1 arcsecond pixelsize

        #Get from **kwargs
        if kwargs is None:
            #Safe solution works for baselines up to > 100km and result in small kernels
            uv_cellsize = 1145.91509915
            #N=1800 pixxel with 0.1 arcsecond pixelsize

        if 'UVcellsize' in kwargs.keys():
            uv_cellsize = kwargs['UVcellsize']

        #print(uv_cellsize);

        #Cutoff param in ASKAPSoft hardcoded as well
        ASKAPSoft_cutof = 0.1

        wTheta_list = numpy.zeros(len(w_list))
        for i in range(0, len(w_list)):
            if w_list[i] == 0:
                wTheta_list[i] = 0.9
                #This is due to the future if statements cause if it is small, the kernel will be 3 which is a clear cutoff
            else:
                wTheta_list[i] = numpy.fabs(
                    w_list[i]) / (uv_cellsize * uv_cellsize)

        kernel_size_list = []

        #We rounded the kernels according to conventional rounding rules
        for i in range(0, len(wTheta_list)):
            #if wTheta_list[i] < 1:
            if wTheta_list[i] < 1:  #Change to ASKAPSoft
                kernel_size_list.append(int(3.))
            elif ASKAPSoft_cutof < 0.01:
                kernel_size_list.append(int(6 + 1.14 * wTheta_list[i]))
            else:
                kernel_size_list.append(
                    int(numpy.sqrt(49 + wTheta_list[i] * wTheta_list[i])))

        log.info('W-kernel w-terms:')
        log.info(w_list)
        log.info('Corresponding w-kernel sizes:')
        log.info(kernel_size_list)

        print(numpy.unique(kernel_size_list))
        #print(kernel_size_list);

        crop_list = []
        #another rounding according to conventional rounding rules
        for i in range(0, len(kernel_size_list)):
            if support - kernel_size_list[i] <= 0:
                crop_list.append(int(0))
            else:
                crop_list.append(int((support - kernel_size_list[i]) / 2))

        #Crop original suppor
        for i in range(0, nw):
            if crop_list[i] != 0:
                cf.data[0, 0, i, :, :, 0:crop_list[i], :] = 0
                cf.data[0, 0, i, :, :, -crop_list[i]:, :] = 0
                cf.data[0, 0, i, :, :, :, 0:crop_list[i]] = 0
                cf.data[0, 0, i, :, :, :, -crop_list[i]:] = 0
            else:
                pass

            #Plot
            #import matplotlib.pyplot as plt
            #cf.data[0,0,i,0,0,...][cf.data[0,0,i,0,0,...] != 0.] = 1+0.j;
            #plt.imshow(numpy.real(cf.data[0,0,i,0,0,...]))

            #plt.show(block=True)
            #plt.close();

    #====================================

    if use_aaf:
        pswf_gcf, _ = create_pswf_convolutionfunction(im,
                                                      oversampling=1,
                                                      support=6)
    else:
        pswf_gcf = create_empty_image_like(im)
        pswf_gcf.data[...] = 1.0

    return pswf_gcf, cf
コード例 #16
0
def create_vp_generic_numeric(model,
                              pointingcentre=None,
                              diameter=15.0,
                              blockage=0.0,
                              taper='gaussian',
                              edge=0.03162278,
                              zernikes=None,
                              padding=4,
                              use_local=True,
                              rho=0.0,
                              diff=0.0):
    """
    Make an image like model and fill it with an analytical model of the primary beam
    
    The elements of the analytical model are:
    - dish, optionally blocked
    - Gaussian taper, default is -12dB at the edge
    - Offset to pointing centre (optional)
    - zernikes in a list of dictionaries. Each list element is of the form {"coeff":0.1, "noll":5}. See aotools for
    more details
    - Output image can be in RA, DEC coordinates or AZELGEO coordinates (the default). use_local=True means to use
    AZELGEO coordinates centered on 0deg 0deg.
    
    The dish is zero padded according to padding and FFT'ed to get the voltage pattern.
    
    :param model:
    :param pointingcentre: SkyCoord of desired pointing centre
    :param diameter: Diameter of dish in metres
    :param blockage: Blockage of dish in metres
    :param taper: "Gaussian" or None
    :param edge: Value of taper at the end of the dish (default corresponds to -12dB)
    :param zernikes: Zernikes to be applied as phase across the dish (see above)
    :param padding: Pad the image by this amount
    :param use_local: Use local frame (AZELGEO)?
    :return:
    """
    beam = create_empty_image_like(model)
    nchan, npol, ny, nx = beam.shape
    padded_shape = [nchan, npol, padding * ny, padding * nx]
    padded_beam = pad_image(beam, padded_shape)
    padded_beam.data = numpy.zeros(padded_beam.data.shape, dtype='complex')
    _, _, pny, pnx = padded_beam.shape

    xfr = fft_image(padded_beam)
    cx, cy = xfr.wcs.sub(2).wcs.crpix[0] - 1, xfr.wcs.sub(2).wcs.crpix[1] - 1

    for chan in range(nchan):

        # The frequency axis is the second to last in the beam
        frequency = xfr.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        wavelength = const.c.to('m s^-1').value / frequency

        scalex = xfr.wcs.sub(2).wcs.cdelt[0] * wavelength
        scaley = xfr.wcs.sub(2).wcs.cdelt[1] * wavelength
        # xx, yy in metres
        xx, yy = numpy.meshgrid(scalex * (range(pnx) - cx),
                                scaley * (range(pny) - cy))

        # rr in metres
        rr = numpy.sqrt(xx**2 + yy**2)
        for pol in range(npol):
            xfr.data[chan, pol, ...] = tapered_disk(rr,
                                                    diameter / 2.0,
                                                    blockage=blockage / 2.0,
                                                    edge=edge,
                                                    taper=taper)

        if pointingcentre is not None:
            # Correct for pointing centre
            pcx, pcy = pointingcentre.to_pixel(padded_beam.wcs, origin=0)
            pxx, pyy = numpy.meshgrid((range(pnx) - cx), (range(pny) - cy))
            phase = 2 * numpy.pi * ((pcx - cx) * pxx / float(pnx) +
                                    (pcy - cy) * pyy / float(pny))
            for pol in range(npol):
                xfr.data[chan, pol, ...] *= numpy.exp(1j * phase)

        if isinstance(zernikes, collections.Iterable):
            try:
                import aotools
            except ModuleNotFoundError:
                raise ModuleNotFoundError("aotools is not installed")

            ndisk = numpy.ceil(numpy.abs(diameter / scalex)).astype('int')[0]
            ndisk = 2 * ((ndisk + 1) // 2)
            phase = numpy.zeros([ndisk, ndisk])
            for zernike in zernikes:
                phase = zernike['coeff'] * aotools.functions.zernike(
                    zernike['noll'], ndisk)

            # import matplotlib.pyplot as plt
            # plt.clf()
            # plt.imshow(phase)
            # plt.colorbar()
            # plt.show()
            #
            blc = pnx // 2 - ndisk // 2
            trc = pnx // 2 + ndisk // 2
            for pol in range(npol):
                xfr.data[chan, pol, blc:trc,
                         blc:trc] = xfr.data[chan, pol, blc:trc,
                                             blc:trc] * numpy.exp(1j * phase)

    padded_beam = fft_image(xfr, padded_beam)

    # Undo padding
    beam = create_empty_image_like(model)
    beam.data = padded_beam.data[...,
                                 (pny // 2 - ny // 2):(pny // 2 + ny // 2),
                                 (pnx // 2 - nx // 2):(pnx // 2 + nx // 2)]
    for chan in range(nchan):
        beam.data[chan, ...] /= numpy.max(numpy.abs(beam.data[chan, ...]))

    set_pb_header(beam, use_local=use_local)
    return beam
    def ingest_visibility(self,
                          freq=None,
                          chan_width=None,
                          times=None,
                          add_errors=False,
                          block=True,
                          bandpass=False):
        if freq is None:
            freq = [1e8]
        if chan_width is None:
            chan_width = [1e6]
        if times is None:
            times = (numpy.pi / 12.0) * numpy.linspace(-3.0, 3.0, 5)

        lowcore = create_named_configuration('LOWBD2', rmax=750.0)
        frequency = numpy.array(freq)
        channel_bandwidth = numpy.array(chan_width)

        phasecentre = SkyCoord(ra=+180.0 * u.deg,
                               dec=-60.0 * u.deg,
                               frame='icrs',
                               equinox='J2000')
        if block:
            vt = create_blockvisibility(
                lowcore,
                times,
                frequency,
                channel_bandwidth=channel_bandwidth,
                weight=1.0,
                phasecentre=phasecentre,
                polarisation_frame=PolarisationFrame("stokesI"))
        else:
            vt = create_visibility(
                lowcore,
                times,
                frequency,
                channel_bandwidth=channel_bandwidth,
                weight=1.0,
                phasecentre=phasecentre,
                polarisation_frame=PolarisationFrame("stokesI"))
        cellsize = 0.001
        model = create_image_from_visibility(
            vt,
            npixel=self.npixel,
            cellsize=cellsize,
            npol=1,
            frequency=frequency,
            phasecentre=phasecentre,
            polarisation_frame=PolarisationFrame("stokesI"))
        nchan = len(self.frequency)
        flux = numpy.array(nchan * [[100.0]])
        facets = 4

        rpix = model.wcs.wcs.crpix - 1.0
        spacing_pixels = self.npixel // facets
        centers = [-1.5, -0.5, 0.5, 1.5]
        comps = list()
        for iy in centers:
            for ix in centers:
                p = int(round(rpix[0] + ix * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[0]))), \
                    int(round(rpix[1] + iy * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[1])))
                sc = pixel_to_skycoord(p[0], p[1], model.wcs, origin=1)
                comp = create_skycomponent(
                    direction=sc,
                    flux=flux,
                    frequency=frequency,
                    polarisation_frame=PolarisationFrame("stokesI"))
                comps.append(comp)
        if block:
            predict_skycomponent_visibility(vt, comps)
        else:
            predict_skycomponent_visibility(vt, comps)
        insert_skycomponent(model, comps)
        self.comps = comps
        self.model = copy_image(model)
        self.empty_model = create_empty_image_like(model)
        export_image_to_fits(
            model, '%s/test_pipeline_functions_model.fits' % (self.dir))

        if add_errors:
            # These will be the same for all calls
            numpy.random.seed(180555)
            gt = create_gaintable_from_blockvisibility(vt)
            gt = simulate_gaintable(gt, phase_error=1.0, amplitude_error=0.0)
            vt = apply_gaintable(vt, gt)

            if bandpass:
                bgt = create_gaintable_from_blockvisibility(vt, timeslice=1e5)
                bgt = simulate_gaintable(bgt,
                                         phase_error=0.01,
                                         amplitude_error=0.01,
                                         smooth_channels=4)
                vt = apply_gaintable(vt, bgt)

        return vt
コード例 #18
0
 def test_create_empty_image_like(self):
     emptyimage = create_empty_image_like(self.m31image)
     assert emptyimage.shape == self.m31image.shape
     assert numpy.max(numpy.abs(emptyimage.data)) == 0.0