def invert_wstack_single(vis: Visibility, im: Image, dopsf, normalize=True, invert_inner=invert_2d_base, **kwargs) -> (Image, numpy.ndarray): """Process single w slice :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) """ log.debug("invert_wstack_single: predicting using single w slice") kwargs['imaginary'] = True assert type(vis) == Visibility # We might want to do wprojection so we remove the average w w_average = numpy.average(vis.w) vis.data['uvw'][...,2] -= w_average reWorkimage, sumwt, imWorkimage = invert_inner(vis, im, dopsf, normalize=normalize, **kwargs) vis.data['uvw'][...,2] += w_average # Calculate w beam and apply to the model. The imaginary part is not needed w_beam = create_w_term_like(im, w_average, vis.phasecentre) reWorkimage.data = w_beam.data.real * reWorkimage.data - w_beam.data.imag * imWorkimage.data return reWorkimage, sumwt
def test_convert_image_to_kernel(self): m31image = create_test_image(cellsize=0.001, frequency=[1e8], canonical=True) screen = create_w_term_like(m31image, w=20000.0, remove_shift=True) screen_fft = fft_image(screen) converted = convert_image_to_kernel(screen_fft, 8, 8) assert converted.shape == (1, 1, 8, 8, 8, 8) with self.assertRaises(AssertionError): converted = convert_image_to_kernel(m31image, 15, 1) with self.assertRaises(AssertionError): converted = convert_image_to_kernel(m31image, 15, 1000)
def test_create_w_term_image(self): m31image = create_test_image(cellsize=0.001) im = create_w_term_like(m31image, w=20000.0, remove_shift=True) im.data = im.data.real for x in [64, 64 + 128]: for y in [64, 64 + 128]: self.assertAlmostEqual(im.data[0, 0, y, x], 0.84946344276442431, 7) export_image_to_fits(im, '%s/test_wterm.fits' % self.dir) assert im.data.shape == (1, 1, 256, 256) self.assertAlmostEqual(numpy.max(im.data.real), 1.0, 7)
def predict_wstack_single(vis, model, remove=True, **kwargs) -> Visibility: """ Predict using a single w slices. This processes a single w plane, rotating out the w beam for the average w :param vis: Visibility to be predicted :param model: model image :return: resulting visibility (in place works) """ if not isinstance(vis, Visibility): log.debug("predict_wstack_single: Coalescing") avis = coalesce_visibility(vis, **kwargs) else: avis = vis log.debug("predict_wstack_single: predicting using single w slice") avis.data['vis'] *= 0.0 # We might want to do wprojection so we remove the average w w_average = numpy.average(avis.w) avis.data['uvw'][..., 2] -= w_average tempvis = copy_visibility(avis) # Calculate w beam and apply to the model. The imaginary part is not needed workimage = copy_image(model) w_beam = create_w_term_like(model, w_average, vis.phasecentre) # Do the real part workimage.data = w_beam.data.real * model.data avis = predict_2d_base(avis, workimage, **kwargs) # and now the imaginary part workimage.data = w_beam.data.imag * model.data tempvis = predict_2d_base(tempvis, workimage, **kwargs) avis.data['vis'] -= 1j * tempvis.data['vis'] if not remove: avis.data['uvw'][..., 2] += w_average if isinstance(vis, BlockVisibility) and isinstance(avis, Visibility): log.debug("imaging.predict decoalescing post prediction") return decoalesce_visibility(avis) else: return avis
def w_kernel_list(vis: Visibility, im: Image, oversampling=1, wstep=50.0, kernelwidth=16, **kwargs): """ Calculate w convolution kernels Uses create_w_term_like to calculate the w screen. This is exactly as wstacking does. Returns (indices to the w kernel for each row, kernels) Each kernel has axes [centre_v, centre_u, offset_v, offset_u]. We currently use the same convolution function for all channels and polarisations. Changing that behaviour would require modest changes here and to the gridding/degridding routines. :param vis: visibility :param image: Template image (padding, if any, occurs before this) :param oversampling: Oversampling factor :param wstep: Step in w between cached functions :return: (indices to the w kernel for each row, kernels) """ nchan, npol, ny, nx = im.shape gcf, _ = anti_aliasing_calculate((ny, nx)) assert oversampling % 2 == 0 or oversampling == 1, "oversampling must be unity or even" assert kernelwidth % 2 == 0, "kernelwidth must be even" wmaxabs = numpy.max(numpy.abs(vis.w)) log.debug( "w_kernel_list: Maximum absolute w = %.1f, step is %.1f wavelengths" % (wmaxabs, wstep)) def digitise(w, wstep): return numpy.ceil((w + wmaxabs) / wstep).astype('int') # Find all the unique indices for which we need a kernel nwsteps = digitise(wmaxabs, wstep) + 1 w_list = numpy.linspace(-wmaxabs, +wmaxabs, nwsteps) print('====', nwsteps, wstep, len(w_list)) wtemplate = copy_image(im) wtemplate.data = numpy.zeros(wtemplate.shape, dtype=im.data.dtype) padded_shape = list(wtemplate.shape) padded_shape[3] *= oversampling padded_shape[2] *= oversampling # For all the unique indices, calculate the corresponding w kernel kernels = list() for w in w_list: # Make a w screen wscreen = create_w_term_like(wtemplate, w, vis.phasecentre, **kwargs) wscreen.data /= gcf assert numpy.max(numpy.abs(wscreen.data)) > 0.0, 'w screen is empty' wscreen_padded = pad_image(wscreen, padded_shape) wconv = fft_image(wscreen_padded) wconv.data *= float(oversampling)**2 # For the moment, ignore the polarisation and channel axes kernels.append( convert_image_to_kernel(wconv, oversampling, kernelwidth).data[0, 0, ...]) # Now make a lookup table from row number of vis to the kernel kernel_indices = digitise(vis.w, wstep) assert numpy.max(kernel_indices) < len(kernels), "wabsmax %f wstep %f" % ( wmaxabs, wstep) assert numpy.min(kernel_indices) >= 0, "wabsmax %f wstep %f" % (wmaxabs, wstep) return kernel_indices, kernels