Exemple #1
0
def create_low_test_beam(model: Image, use_local=True) -> Image:
    """Create a test power beam for LOW using an image from OSKAR

    This is not fit for anything except the most basic testing. It does not include any form of elevation/pa dependence.

    :param model: Template image
    :return: Image
    """
    beam = import_image_from_fits(
        rascil_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.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)

    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[footprint.data <= 0.0] = 0.0
        for pol in range(npol):
            reprojected_beam.data[chan,
                                  pol, :, :] = reprojected_beam2d.data[:, :]

    set_pb_header(reprojected_beam, use_local=use_local)
    return reprojected_beam
    def test_reproject(self):
        # Reproject an image
        cellsize = 1.5 * self.cellsize
        newwcs = self.m31image.wcs.deepcopy()
        newwcs.wcs.cdelt[0] = -cellsize
        newwcs.wcs.cdelt[1] = +cellsize

        newshape = numpy.array(self.m31image.data.shape)
        newshape[2] /= 1.5
        newshape[3] /= 1.5
        newimage, footprint = reproject_image(self.m31image,
                                              newwcs,
                                              shape=newshape)
def convert_azelvp_to_radec(vp, im, pa):
    """ Convert AZELGEO image to image coords at specific parallactic angle
    
    :param pb: Primary beam or voltagee pattern
    :param im: Template image
    :param pa: Parallactic angle (radians)
    :return:
    """
    vp = scale_and_rotate_image(vp, angle=pa)
    vp.wcs.wcs.crval[0] = im.wcs.wcs.crval[0]
    vp.wcs.wcs.crval[1] = im.wcs.wcs.crval[1]
    vp.wcs.wcs.ctype[0] = im.wcs.wcs.ctype[0]
    vp.wcs.wcs.ctype[1] = im.wcs.wcs.ctype[1]

    rvp, footprint = reproject_image(vp, im.wcs, shape=im.shape)
    rvp.data[footprint.data < 1e-6] = 0.0

    return rvp
Exemple #4
0
def invert_timeslice_single(vis: Visibility,
                            im: Image,
                            dopsf,
                            normalize=True,
                            remove=True,
                            gcfcf=None,
                            **kwargs) -> (Image, numpy.ndarray):
    """Process single time slice

    Extracted for re-use in parallel version

    The w-term can be viewed as a time-variable distortion. Approximating the array as instantaneously
    co-planar, we have that w can be expressed in terms of u,v:

    .. math::
        w = a u + b v

    Transforming to a new coordinate system:

    .. math::

        l' = l + a ( \\sqrt{1-l^2-m^2}-1))

    .. math::

        m' = m + b ( \\sqrt{1-l^2-m^2}-1))

    Ignoring changes in the normalisation term, we have:

    .. math::

        V(u,v,w) =\\int \\frac{ I(l',m')} { \\sqrt{1-l'^2-m'^2}} e^{-2 \\pi j (ul'+um')} dl' dm'

    :param vis: Visibility to be inverted
    :param im: image template (not changed)
    :param dopsf: Make the psf instead of the dirty image
    :param gcfcf: (Grid correction function, convolution function)
    :param normalize: Normalize by the sum of weights (True)
    :returns: image, sum of weights
    """
    assert isinstance(vis, Visibility), vis
    assert image_is_canonical(im)

    uvw = vis.uvw
    vis, p, q = fit_uvwplane(vis, remove=remove)

    workimage, sumwt = invert_2d(vis,
                                 im,
                                 dopsf,
                                 normalize=normalize,
                                 gcfcf=gcfcf,
                                 **kwargs)
    # Work image is distorted. We describe the distortion by putting the olbiquity parameters in
    # the wcs. The output image should be described as having zero olbiquity parameters.

    if numpy.abs(p) > 1e-7 or numpy.abs(q) > 1e-7:
        # Note that this has to be zero relative in first element, one relative in second!!!!
        workimage.wcs.wcs.set_pv([(0, 1, -p), (0, 2, -q)])

        finalimage, footprint = reproject_image(workimage, im.wcs, im.shape)
        finalimage.data[footprint.data <= 0.0] = 0.0
        finalimage.wcs.wcs.set_pv([(0, 1, 0.0), (0, 2, 0.0)])

        if remove:
            vis.data['uvw'][...] = uvw

        return finalimage, sumwt
    else:
        if remove:
            vis.data['uvw'][...] = uvw

        return workimage, sumwt
Exemple #5
0
def predict_timeslice_single(vis: Visibility,
                             model: Image,
                             predict=predict_2d,
                             remove=True,
                             gcfcf=None,
                             **kwargs) -> Visibility:
    """ Predict using a single time slices.

    This fits a single plane and corrects the image geometry.

    The w-term can be viewed as a time-variable distortion. Approximating the array as instantaneously
    co-planar, we have that w can be expressed in terms of u,v:

    .. math::
        w = a u + b v

    Transforming to a new coordinate system:

    .. math::

        l' = l + a ( \\sqrt{1-l^2-m^2}-1))

    .. math::

        m' = m + b ( \\sqrt{1-l^2-m^2}-1))

    Ignoring changes in the normalisation term, we have:

    .. math::

        V(u,v,w) =\\int \\frac{ I(l',m')} { \\sqrt{1-l'^2-m'^2}} e^{-2 \\pi j (ul'+um')} dl' dm'

    :param vis: Visibility to be predicted
    :param model: model image
    :param predict:
    :param remove: Remove fitted w (so that wprojection will do the right thing)
    :param gcfcf: (Grid correction function, convolution function)
    :return: resulting visibility (in place works)
    """
    assert image_is_canonical(model)

    assert isinstance(vis, Visibility), vis

    vis.data['vis'][...] = 0.0

    # Fit and remove best fitting plane for this slice
    uvw = vis.uvw
    avis, p, q = fit_uvwplane(vis, remove=remove)

    # We want to describe work image as distorted. We describe the distortion by putting
    # the olbiquity parameters in the wcs. The input model should be described as having
    # zero olbiquity parameters.
    # Note that this has to be zero relative in first element, one relative in second!!!
    if numpy.abs(p) > 1e-7 or numpy.abs(q) > 1e-7:

        newwcs = model.wcs.deepcopy()
        newwcs.wcs.set_pv([(0, 1, -p), (0, 2, -q)])
        workimage, footprintimage = reproject_image(model,
                                                    newwcs,
                                                    shape=model.shape)
        workimage.data[footprintimage.data <= 0.0] = 0.0
        workimage.wcs.wcs.set_pv([(0, 1, -p), (0, 2, -q)])

        # Now we can do the predict
        vis = predict(avis, workimage, gcfcf=gcfcf, **kwargs)
    else:
        vis = predict(avis, model, gcfcf=gcfcf, **kwargs)

    if remove:
        avis.data['uvw'][...] = uvw

    return vis
Exemple #6
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 (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)

    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