def setUp(self): from rascil.data_models.parameters import rascil_path self.dir = rascil_path('test_results') self.lowcore = create_named_configuration('LOWBD2-CORE') self.times = (numpy.pi / (12.0)) * numpy.linspace(-3.0, 3.0, 7) self.frequency = numpy.array([1e8]) self.channel_bandwidth = numpy.array([1e6]) self.phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') self.vis = create_visibility( self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('stokesI'), zerow=True) self.vis.data['vis'] *= 0.0 # Create model self.test_model = create_test_image(cellsize=0.001, phasecentre=self.vis.phasecentre, frequency=self.frequency) self.vis = predict_2d(self.vis, self.test_model) assert numpy.max(numpy.abs(self.vis.vis)) > 0.0 self.model = create_image_from_visibility( self.vis, npixel=512, cellsize=0.001, polarisation_frame=PolarisationFrame('stokesI')) self.dirty, sumwt = invert_2d(self.vis, self.model) self.psf, sumwt = invert_2d(self.vis, self.model, dopsf=True)
def test_tapering_Gaussian(self): self.actualSetUp() size_required = 0.010 self.componentvis = weight_visibility(self.componentvis, self.model, algoritm='uniform') self.componentvis = taper_visibility_gaussian(self.componentvis, beam=size_required) psf, sumwt = invert_2d(self.componentvis, self.model, dopsf=True) export_image_to_fits( psf, '%s/test_weighting_gaussian_taper_psf.fits' % self.dir) xfr = fft_image(psf) xfr.data = xfr.data.real.astype('float') export_image_to_fits( xfr, '%s/test_weighting_gaussian_taper_xfr.fits' % self.dir) npixel = psf.data.shape[3] sl = slice(npixel // 2 - 7, npixel // 2 + 8) fit = fit_2dgaussian(psf.data[0, 0, sl, sl]) # if fit.x_stddev <= 0.0 or fit.y_stddev <= 0.0: # raise ValueError('Error in fitting to psf') # fit_2dgaussian returns sqrt of variance. We need to convert that to FWHM. # https://en.wikipedia.org/wiki/Full_width_at_half_maximum scale_factor = numpy.sqrt(8 * numpy.log(2.0)) size = numpy.sqrt(fit.x_stddev * fit.y_stddev) * scale_factor # Now we need to convert to radians size *= numpy.pi * self.model.wcs.wcs.cdelt[1] / 180.0 # Very impressive! Desired 0.01 Acheived 0.0100006250829 assert numpy.abs(size - size_required) < 0.01 * size_required, \ "Fit should be %f, actually is %f" % (size_required, size)
def test_invert(self): uvfitsfile = rascil_path("data/vis/ASKAP_example.fits") nchan_ave = 32 nchan = 192 for schan in range(0, nchan, nchan_ave): max_chan = min(nchan, schan + nchan_ave) bv = create_blockvisibility_from_uvfits(uvfitsfile, range(schan, max_chan))[0] vis = convert_blockvisibility_to_visibility(bv) from rascil.processing_components.visibility.operations import convert_visibility_to_stokesI vis = convert_visibility_to_stokesI(vis) model = create_image_from_visibility( vis, npixel=256, polarisation_frame=PolarisationFrame('stokesI')) dirty, sumwt = invert_2d(vis, model, context='2d') assert (numpy.max(numpy.abs(dirty.data))) > 0.0 assert dirty.shape == (nchan_ave, 1, 256, 256) if self.doplot: import matplotlib.pyplot as plt from rascil.processing_components.image.operations import show_image show_image(dirty) plt.show(block=False) if self.persist: export_image_to_fits( dirty, '%s/test_visibility_uvfits_dirty.fits' % self.dir)
def _predict_base(self, fluxthreshold=1.0, gcf=None, cf=None, name='predict_2d', gcfcf=None, **kwargs): vis = predict_2d(self.vis, self.model, gcfcf=gcfcf, **kwargs) vis.data['vis'] = self.vis.data['vis'] - vis.data['vis'] dirty = invert_2d(vis, self.model, dopsf=False, normalize=True, gcfcf=gcfcf) if self.persist: export_image_to_fits( dirty[0], '%s/test_imaging_%s_residual.fits' % (self.dir, name)) assert numpy.max(numpy.abs(dirty[0].data)), "Residual image is empty" maxabs = numpy.max(numpy.abs(dirty[0].data)) assert maxabs < fluxthreshold, "Error %.3f greater than fluxthreshold %.3f " % ( maxabs, fluxthreshold)
def test_invert_psf_block(self): self.actualSetUp(zerow=False, block=True) psf = invert_2d(self.vis, self.model, dopsf=True) error = numpy.max(psf[0].data) - 1.0 assert abs(error) < 1.0e-12, error if self.persist: export_image_to_fits(psf[0], '%s/test_imaging_2d_psf_block.fits' % (self.dir)) assert numpy.max(numpy.abs(psf[0].data)), "Image is empty"
def test_insert_skycomponent_dft(self): self.sc = create_skycomponent(direction=self.phasecentre, flux=self.sc.flux, frequency=self.component_frequency, polarisation_frame=PolarisationFrame('stokesI')) self.vis.data['vis'][...] = 0.0 self.vis = predict_skycomponent_visibility(self.vis, self.sc) im, sumwt = invert_2d(self.vis, self.model) export_image_to_fits(im, '%s/test_skycomponent_dft.fits' % self.dir) assert numpy.max(numpy.abs(self.vis.vis.imag)) < 1e-3
def test_invert_psf_weighting_block_IQUV(self): self.actualSetUp(zerow=False, block=True, image_pol = PolarisationFrame('stokesIQUV')) for weighting in ["natural", "uniform", "robust"]: self.vis = weight_blockvisibility(self.vis, self.model, weighting=weighting, robustness=-1.0) psf = invert_2d(self.vis, self.model, dopsf=True) error = numpy.max(psf[0].data) - 1.0 assert abs(error) < 1.0e-12, error rms = numpy.std(psf[0].data) print(weighting, rms, psf[1]) if self.persist: export_image_to_fits(psf[0], '%s/test_imaging_2d_psf_block_%s_IQUV.fits' % (self.dir, weighting)) assert numpy.max(numpy.abs(psf[0].data)), "Image is empty"
def test_invert_psf_weighting(self): self.actualSetUp(zerow=False) for weighting in ["natural", "uniform", "robust"]: self.vis = weight_visibility(self.vis, self.model, weighting=weighting) psf = invert_2d(self.vis, self.model, dopsf=True) error = numpy.max(psf[0].data) - 1.0 assert abs(error) < 1.0e-12, error rms = numpy.std(psf[0].data) print(weighting, rms, psf[1]) if self.persist: export_image_to_fits(psf[0], '%s/test_imaging_2d_psf_%s.fits' % (self.dir, weighting)) assert numpy.max(numpy.abs(psf[0].data)), "Image is empty"
def invert_wstack_single(vis: Visibility, im: Image, dopsf, normalize=True, remove=True, gcfcf=None, **kwargs) -> (Image, numpy.ndarray): """Process single w slice The w-stacking or w-slicing approach is to partition the visibility data by slices in w. The measurement equation is approximated as: .. math:: V(u,v,w) =\\sum_i \\int \\frac{ I(l,m) e^{-2 \\pi j (w_i(\\sqrt{1-l^2-m^2}-1))})}{\\sqrt{1-l^2-m^2}} e^{-2 \\pi j (ul+vm)} dl dm If images constructed from slices in w are added after applying a w-dependent image plane correction, the w term will be corrected. :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) :returns: image, sum of weights """ assert image_is_canonical(im) log.debug("invert_wstack_single: predicting using single w slice") kwargs['imaginary'] = True assert isinstance(vis, Visibility), vis # We might want to do wprojection so we remove the average w w_average = numpy.average(vis.w) if remove: vis.data['uvw'][..., 2] -= w_average reWorkimage, sumwt, imWorkimage = invert_2d(vis, im, dopsf, normalize=normalize, gcfcf=gcfcf, **kwargs) if remove: 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_tapering_Tukey(self): self.actualSetUp() self.componentvis = weight_visibility(self.componentvis, self.model, algoritm='uniform') self.componentvis = taper_visibility_tukey(self.componentvis, tukey=1.0) psf, sumwt = invert_2d(self.componentvis, self.model, dopsf=True) export_image_to_fits( psf, '%s/test_weighting_tukey_taper_psf.fits' % self.dir) xfr = fft_image(psf) xfr.data = xfr.data.real.astype('float') export_image_to_fits( xfr, '%s/test_weighting_tukey_taper_xfr.fits' % self.dir)
def setUp(self): from rascil.data_models.parameters import rascil_path self.dir = rascil_path('test_results') self.persist = os.getenv("RASCIL_PERSIST", False) self.niter = 1000 self.lowcore = create_named_configuration('LOWBD2-CORE') self.nchan = 5 self.times = (numpy.pi / 12.0) * numpy.linspace(-3.0, 3.0, 7) self.frequency = numpy.linspace(0.9e8, 1.1e8, self.nchan) self.channel_bandwidth = numpy.array(self.nchan * [self.frequency[1] - self.frequency[0]]) self.phasecentre = SkyCoord(ra=+0.0 * u.deg, dec=-45.0 * u.deg, frame='icrs', equinox='J2000') self.vis = create_visibility(self.lowcore, self.times, self.frequency, self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('stokesI'), zerow=True) self.vis.data['vis'] *= 0.0 # Create model self.test_model = create_low_test_image_from_gleam(npixel=512, cellsize=0.001, phasecentre=self.vis.phasecentre, frequency=self.frequency, channel_bandwidth=self.channel_bandwidth, flux_limit=1.0) beam = create_low_test_beam(self.test_model) if self.persist: export_image_to_fits(beam, "%s/test_deconvolve_mmclean_beam.fits" % self.dir) self.test_model.data *= beam.data if self.persist: export_image_to_fits(self.test_model, "%s/test_deconvolve_mmclean_model.fits" % self.dir) self.vis = predict_2d(self.vis, self.test_model) assert numpy.max(numpy.abs(self.vis.vis)) > 0.0 self.model = create_image_from_visibility(self.vis, npixel=512, cellsize=0.001, polarisation_frame=PolarisationFrame('stokesI')) self.dirty, sumwt = invert_2d(self.vis, self.model) self.psf, sumwt = invert_2d(self.vis, self.model, dopsf=True) if self.persist: export_image_to_fits(self.dirty, "%s/test_deconvolve_mmclean-dirty.fits" % self.dir) if self.persist: export_image_to_fits(self.psf, "%s/test_deconvolve_mmclean-psf.fits" % self.dir) window = numpy.ones(shape=self.model.shape, dtype=numpy.bool) window[..., 129:384, 129:384] = True self.innerquarter = create_image_from_array(window, self.model.wcs, polarisation_frame=PolarisationFrame('stokesI'))
def _invert_base(self, fluxthreshold=1.0, positionthreshold=1.0, check_components=True, name='invert_2d', gcfcf=None, **kwargs): dirty = invert_2d(self.vis, self.model, dopsf=False, normalize=True, gcfcf=gcfcf, **kwargs) if self.persist: export_image_to_fits(dirty[0], '%s/test_imaging_%s_dirty.fits' % (self.dir, name)) for pol in range(dirty[0].npol): assert numpy.max(numpy.abs(dirty[0].data[:, pol])), "Dirty image pol {} is empty".format(pol) for chan in range(dirty[0].nchan): assert numpy.max(numpy.abs(dirty[0].data[chan])), "Dirty image channel {} is empty".format(chan) if check_components: self._checkcomponents(dirty[0], fluxthreshold, positionthreshold)
def _invert_base(self, fluxthreshold=1.0, positionthreshold=1.0, check_components=True, name='predict_2d', gcfcf=None, **kwargs): dirty = invert_2d(self.vis, self.model, dopsf=False, normalize=True, gcfcf=gcfcf, **kwargs) if self.persist: export_image_to_fits( dirty[0], '%s/test_imaging_%s_dirty.fits' % (self.dir, name)) assert numpy.max(numpy.abs(dirty[0].data)), "Image is empty" if check_components: self._checkcomponents(dirty[0], fluxthreshold, positionthreshold)
elapsed = time.time() - start print("Elapsed time = ", elapsed, "sec") #start = time.time() #gcfcf_wt = create_awterm_convolutionfunction(model, make_pb=None, nw=nw, wstep=wstep, oversampling=8, # support=32, use_aaf=False, maxsupport=512, wtowers=True) #wtkern_invert = gcf2wkern2(gcfcf_wt) #elapsed = time.time() - start #print("Elapsed time = ", elapsed, "sec") #wtkern_predict = gcf2wkern2(gcfcf, conjugate=True) # In[9]: # W-proj invert_wt results # In[10]: # In[17]: # W-proj invert_2d results start = time.time() #dirty_wt,_ = invert_wt(blockvis, model, normalize=True, wtkern=wtkern_invert) dirty_2d, _ = invert_2d(blockvis, model, dopsf=False, normalize=True) elapsed = time.time() - start print("Elapsed time = ", elapsed, "sec") plt.rcParams['figure.figsize'] = 10, 10 show_image(dirty_2d, chan=1) plt.savefig("dirty_invert_2d.png")
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