def weight_visibility(vis: Visibility, im: Image, **kwargs) -> Visibility: """ Reweight the visibility data using a selected algorithm Imaging uses the column "imaging_weight" when imaging. This function sets that column using a variety of algorithms Options are: - Natural: by visibility weight (optimum for noise in final image) - Uniform: weight of sample divided by sum of weights in cell (optimum for sidelobes) - Super-uniform: As uniform, by sum of weights is over extended box region - Briggs: Compromise between natural and uniform - Super-briggs: As Briggs, by sum of weights is over extended box region :param vis: :param im: :return: visibility with imaging_weights column added and filled """ assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis assert get_parameter(kwargs, "padding", False) is False spectral_mode, vfrequencymap = get_frequency_map(vis, im) polarisation_mode, vpolarisationmap = get_polarisation_map(vis, im) uvw_mode, shape, padding, vuvwmap = get_uvw_map(vis, im) density = None densitygrid = None weighting = get_parameter(kwargs, "weighting", "uniform") vis.data['imaging_weight'], density, densitygrid = weight_gridding( im.data.shape, vis.data['weight'], vuvwmap, vfrequencymap, vpolarisationmap, weighting) return vis, density, densitygrid
def predict_skycomponent_visibility( vis: Union[Visibility, BlockVisibility], sc: Union[Skycomponent, List[Skycomponent]] ) -> Union[Visibility, BlockVisibility]: """Predict the visibility from a Skycomponent, add to existing visibility, for Visibility or BlockVisibility :param vis: Visibility or BlockVisibility :param sc: Skycomponent or list of SkyComponents :return: Visibility or BlockVisibility """ if sc is None: return vis if not isinstance(sc, collections.Iterable): sc = [sc] if isinstance(vis, Visibility): _, im_nchan = list(get_frequency_map(vis, None)) for comp in sc: assert isinstance(comp, Skycomponent), comp assert_same_chan_pol(vis, comp) l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) phasor = simulate_point(vis.uvw, l, m) comp = comp.flux[im_nchan, :] vis.data['vis'][...] += comp[:, :] * phasor[:, numpy.newaxis] elif isinstance(vis, BlockVisibility): ntimes, nant, _, nchan, npol = vis.vis.shape k = numpy.array(vis.frequency) / constants.c.to('m s^-1').value for comp in sc: # assert isinstance(comp, Skycomponent), comp assert_same_chan_pol(vis, comp) flux = comp.flux if comp.polarisation_frame != vis.polarisation_frame: flux = convert_pol_frame(flux, comp.polarisation_frame, vis.polarisation_frame) l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) uvw = vis.uvw[..., numpy.newaxis] * k phasor = numpy.ones([ntimes, nant, nant, nchan, npol], dtype='complex') for chan in range(nchan): phasor[:, :, :, chan, :] = simulate_point(uvw[..., chan], l, m)[..., numpy.newaxis] vis.data['vis'][..., :, :] += flux[:, :] * phasor[..., :] return vis
def test_get_frequency_map_gleam(self): self.model = create_low_test_image_from_gleam( npixel=128, cellsize=0.001, frequency=self.frequency, channel_bandwidth=self.channel_bandwidth, flux_limit=10.0) spectral_mode, vfrequency_map = get_frequency_map(self.vis, self.model) assert numpy.max(vfrequency_map) == self.model.nchan - 1 assert spectral_mode == 'channel'
def test_get_frequency_map_mfs(self): self.model = create_image_from_visibility( self.vis, npixel=128, cellsize=0.001, nchan=1, frequency=self.startfrequency) spectral_mode, vfrequency_map = get_frequency_map(self.vis, self.model) assert numpy.max(vfrequency_map) == 0 assert spectral_mode == 'mfs'
def test_get_frequency_map_different_channel(self): self.model = create_image_from_visibility( self.vis, npixel=128, cellsize=0.001, frequency=self.startfrequency, nchan=3, channel_bandwidth=2e7) spectral_mode, vfrequency_map = get_frequency_map(self.vis, self.model) assert numpy.max(vfrequency_map) == self.model.nchan - 1 assert spectral_mode == 'channel'
def predict_2d(vis: Union[BlockVisibility, Visibility], model: Image, **kwargs) -> Union[BlockVisibility, Visibility]: """ Predict using convolutional degridding. This is at the bottom of the layering i.e. all transforms are eventually expressed in terms of this function. Any shifting needed is performed here. :param vis: Visibility to be predicted :param model: model image :return: resulting visibility (in place works) """ if isinstance(vis, BlockVisibility): log.debug("imaging.predict: coalescing prior to prediction") avis = coalesce_visibility(vis, **kwargs) else: avis = vis assert isinstance(avis, Visibility), avis _, _, ny, nx = model.data.shape padding = {} if get_parameter(kwargs, "padding", False): padding = {'padding': get_parameter(kwargs, "padding", False)} spectral_mode, vfrequencymap = get_frequency_map(avis, model) polarisation_mode, vpolarisationmap = get_polarisation_map(avis, model) uvw_mode, shape, padding, vuvwmap = get_uvw_map(avis, model, **padding) kernel_name, gcf, vkernellist = get_kernel_list(avis, model, **kwargs) uvgrid = fft((pad_mid(model.data, int(round(padding * nx))) * gcf).astype(dtype=complex)) avis.data['vis'] = convolutional_degrid(vkernellist, avis.data['vis'].shape, uvgrid, vuvwmap, vfrequencymap) # Now we can shift the visibility from the image frame to the original visibility frame svis = shift_vis_to_image(avis, model, tangent=True, inverse=True) if isinstance(vis, BlockVisibility) and isinstance(svis, Visibility): log.debug("imaging.predict decoalescing post prediction") return decoalesce_visibility(svis) else: return svis
def sum_visibility(vis: Visibility, direction: SkyCoord) -> numpy.array: """ Direct Fourier summation in a given direction :param vis: Visibility to be summed :param direction: Direction of summation :return: flux[nch,npol], weight[nch,pol] """ # TODO: Convert to Visibility or remove? assert isinstance(vis, Visibility) or isinstance(vis, BlockVisibility), vis svis = copy_visibility(vis) l, m, n = skycoord_to_lmn(direction, svis.phasecentre) phasor = numpy.conjugate(simulate_point(svis.uvw, l, m)) # Need to put correct mapping here _, frequency = get_frequency_map(svis, None) frequency = list(frequency) nchan = max(frequency) + 1 npol = svis.polarisation_frame.npol flux = numpy.zeros([nchan, npol]) weight = numpy.zeros([nchan, npol]) coords = svis.vis, svis.weight, phasor, list(frequency) for v, wt, p, ic in zip(*coords): for pol in range(npol): flux[ic, pol] += numpy.real(wt[pol] * v[pol] * p) weight[ic, pol] += wt[pol] flux[weight > 0.0] = flux[weight > 0.0] / weight[weight > 0.0] flux[weight <= 0.0] = 0.0 return flux, weight
def invert_2d(vis: Visibility, im: Image, dopsf: bool = False, normalize: bool = True, **kwargs) \ -> (Image, numpy.ndarray): """ Invert using 2D convolution function, including w projection optionally Use the image im as a template. Do PSF in a separate call. This is at the bottom of the layering i.e. all transforms are eventually expressed in terms of this function. . Any shifting needed is performed here. :param vis: Visibility to be inverted :param im: image template (not changed) :param dopsf: Make the psf instead of the dirty image :param normalize: Normalize by the sum of weights (True) :return: resulting image """ if not isinstance(vis, Visibility): svis = coalesce_visibility(vis, **kwargs) else: svis = copy_visibility(vis) if dopsf: svis.data['vis'] = numpy.ones_like(svis.data['vis']) svis = shift_vis_to_image(svis, im, tangent=True, inverse=False) nchan, npol, ny, nx = im.data.shape padding = {} if get_parameter(kwargs, "padding", False): padding = {'padding': get_parameter(kwargs, "padding", False)} spectral_mode, vfrequencymap = get_frequency_map(svis, im) polarisation_mode, vpolarisationmap = get_polarisation_map(svis, im) uvw_mode, shape, padding, vuvwmap = get_uvw_map(svis, im, **padding) kernel_name, gcf, vkernellist = get_kernel_list(svis, im, **kwargs) # Optionally pad to control aliasing imgridpad = numpy.zeros( [nchan, npol, int(round(padding * ny)), int(round(padding * nx))], dtype='complex') imgridpad, sumwt = convolutional_grid(vkernellist, imgridpad, svis.data['vis'], svis.data['imaging_weight'], vuvwmap, vfrequencymap) # Fourier transform the padded grid to image, multiply by the gridding correction # function, and extract the unpadded inner part. # Normalise weights for consistency with transform sumwt /= float(padding * int(round(padding * nx)) * ny) imaginary = get_parameter(kwargs, "imaginary", False) if imaginary: log.debug("invert_2d: retaining imaginary part of dirty image") result = extract_mid(ifft(imgridpad) * gcf, npixel=nx) resultreal = create_image_from_array(result.real, im.wcs, im.polarisation_frame) resultimag = create_image_from_array(result.imag, im.wcs, im.polarisation_frame) if normalize: resultreal = normalize_sumwt(resultreal, sumwt) resultimag = normalize_sumwt(resultimag, sumwt) return resultreal, sumwt, resultimag else: result = extract_mid(numpy.real(ifft(imgridpad)) * gcf, npixel=nx) resultimage = create_image_from_array(result, im.wcs, im.polarisation_frame) if normalize: resultimage = normalize_sumwt(resultimage, sumwt) return resultimage, sumwt