def degrid_visibility_from_griddata(vis, griddata, cf, **kwargs): """Degrid Visibility from a GridData :param vis: Visibility to be degridded :param griddata: GridData containing image :param cf: Convolution function (as GridData) :param kwargs: :return: Visibility """ nchan, npol, nz, oversampling, _, support, _ = cf.shape pu_grid, pu_offset, pv_grid, pv_offset, pwg_grid, pwg_fraction, pwc_grid, pwc_fraction, pfreq_grid = \ convolution_mapping(vis, griddata, cf) _, _, _, _, _, gv, gu = cf.shape newvis = copy_visibility(vis, zero=True) # coords = zip(pfreq_grid, pu_grid, pu_offset, pv_grid, pv_offset, pw_grid) du = gu // 2 dv = gv // 2 nvis = vis.vis.shape[0] for ivis in range(nvis): chan, uu, uuf, vv, vvf, zzg, zzc = pfreq_grid[ivis], pu_grid[ivis], pu_offset[ivis], pv_grid[ivis], \ pv_offset[ivis], pwg_grid[ivis], pwc_grid[ivis] # Use einsum to replace the following: # newvis.vis[i,:] = numpy.sum(griddata.data[chan, :, zzg, (vv - dv):(vv + dv), (uu - du):(uu + du)] * # cf.data[chan, :, zzc, vvf, uuf, :, :], axis=(1, 2)) newvis.vis[ivis, :] += numpy.einsum('ijk,ijk->i', griddata.data[chan, :, zzg, (vv - dv):(vv + dv), (uu - du):(uu + du)], cf.data[chan, :, zzc, vvf, uuf, :, :]) return newvis
def _predict_base(self, fluxthreshold=1.0, name='predict_ng', **kwargs): from rascil.processing_components.imaging.ng import predict_ng, invert_ng original_vis = copy_visibility(self.blockvis) vis = predict_ng(self.blockvis, self.model, verbosity=self.verbosity, **kwargs) vis.data['vis'] = vis.data['vis'] - original_vis.data['vis'] dirty = invert_ng(vis, self.model, dopsf=False, normalize=True, verbosity=self.verbosity, **kwargs) # import matplotlib.pyplot as plt # from rascil.processing_components.image.operations import show_image # npol = dirty[0].shape[1] # for pol in range(npol): # plt.clf() # show_image(dirty[0], pol=pol) # plt.show(block=False) if self.persist: export_image_to_fits( dirty[0], '%s/test_imaging_ng_%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 actualSetUp(self, nfreqwin=3, dospectral=True, dopol=False, amp_errors=None, phase_errors=None, zerow=True): if amp_errors is None: amp_errors = {'T': 0.0, 'G': 0.1} if phase_errors is None: phase_errors = {'T': 1.0, 'G': 0.0} self.npixel = 512 self.low = create_named_configuration('LOWBD2', rmax=750.0) self.freqwin = nfreqwin self.vis_list = list() self.ntimes = 1 self.times = numpy.linspace(-3.0, +3.0, self.ntimes) * numpy.pi / 12.0 self.frequency = numpy.linspace(0.8e8, 1.2e8, self.freqwin) if self.freqwin > 1: self.channelwidth = numpy.array(self.freqwin * [self.frequency[1] - self.frequency[0]]) else: self.channelwidth = numpy.array([1e6]) if dopol: self.vis_pol = PolarisationFrame('linear') self.image_pol = PolarisationFrame('stokesIQUV') f = numpy.array([100.0, 20.0, -10.0, 1.0]) else: self.vis_pol = PolarisationFrame('stokesI') self.image_pol = PolarisationFrame('stokesI') f = numpy.array([100.0]) if dospectral: flux = numpy.array([f * numpy.power(freq / 1e8, -0.7) for freq in self.frequency]) else: flux = numpy.array([f]) self.phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') self.blockvis_list = \ [rsexecute.execute(ingest_unittest_visibility, nout=1)(self.low, [self.frequency[i]], [self.channelwidth[i]], self.times, self.vis_pol, self.phasecentre, block=True, zerow=zerow) for i in range(nfreqwin)] self.blockvis_list = rsexecute.compute(self.blockvis_list, sync=True) for v in self.blockvis_list: v.data['vis'][...] = 1.0 + 0.0j self.error_blockvis_list = [rsexecute.execute(copy_visibility(v)) for v in self.blockvis_list] gt = rsexecute.execute(create_gaintable_from_blockvisibility)(self.blockvis_list[0]) gt = rsexecute.execute(simulate_gaintable)\ (gt, phase_error=0.1, amplitude_error=0.0, smooth_channels=1, leakage=0.0, seed=180555) self.error_blockvis_list = [rsexecute.execute(apply_gaintable)(self.error_blockvis_list[i], gt) for i in range(self.freqwin)] self.error_blockvis_list = rsexecute.compute(self.error_blockvis_list, sync=True) assert numpy.max(numpy.abs(self.error_blockvis_list[0].vis - self.blockvis_list[0].vis)) > 0.0
def actualSetUp(self, freqwin=1, block=True, dopol=False, zerow=False): self.npixel = 1024 self.low = create_named_configuration('LOWBD2', rmax=550.0) self.freqwin = freqwin self.blockvis_list = list() self.ntimes = 5 self.cellsize = 0.0005 # Choose the interval so that the maximum change in w is smallish integration_time = numpy.pi * (24 / (12 * 60)) self.times = numpy.linspace(-integration_time * (self.ntimes // 2), integration_time * (self.ntimes // 2), self.ntimes) if freqwin > 1: self.frequency = numpy.linspace(0.8e8, 1.2e8, self.freqwin) self.channelwidth = numpy.array(freqwin * [self.frequency[1] - self.frequency[0]]) else: self.frequency = numpy.array([1.0e8]) self.channelwidth = numpy.array([4e7]) if dopol: self.vis_pol = PolarisationFrame('linear') self.image_pol = PolarisationFrame('stokesIQUV') f = numpy.array([100.0, 20.0, -10.0, 1.0]) else: self.vis_pol = PolarisationFrame('stokesI') self.image_pol = PolarisationFrame('stokesI') f = numpy.array([100.0]) self.phasecentre = SkyCoord(ra=+0.0 * u.deg, dec=-40.0 * u.deg, frame='icrs', equinox='J2000') self.blockvis_list = [rsexecute.execute(ingest_unittest_visibility)(self.low, [self.frequency[freqwin]], [self.channelwidth[freqwin]], self.times, self.vis_pol, self.phasecentre, block=block, zerow=zerow) for freqwin, _ in enumerate(self.frequency)] self.blockvis_list = rsexecute.compute(self.blockvis_list, sync=True) self.vis_list = [rsexecute.execute(convert_blockvisibility_to_visibility)(bv) for bv in self.blockvis_list] self.vis_list = rsexecute.compute(self.vis_list, sync=True) self.skymodel_list = [rsexecute.execute(create_low_test_skymodel_from_gleam) (npixel=self.npixel, cellsize=self.cellsize, frequency=[self.frequency[f]], phasecentre=self.phasecentre, polarisation_frame=PolarisationFrame("stokesI"), flux_limit=0.6, flux_threshold=1.0, flux_max=5.0) for f, freq in enumerate(self.frequency)] self.skymodel_list = rsexecute.compute(self.skymodel_list, sync=True) assert isinstance(self.skymodel_list[0].image, Image), self.skymodel_list[0].image assert isinstance(self.skymodel_list[0].components[0], Skycomponent), self.skymodel_list[0].components[0] assert len(self.skymodel_list[0].components) == 35, len(self.skymodel_list[0].components) self.skymodel_list = expand_skymodel_by_skycomponents(self.skymodel_list[0]) assert len(self.skymodel_list) == 36, len(self.skymodel_list) assert numpy.max(numpy.abs(self.skymodel_list[-1].image.data)) > 0.0, "Image is empty" self.vis_list = [copy_visibility(self.vis_list[0], zero=True) for i, _ in enumerate(self.skymodel_list)]
def invert_2d(vis: Visibility, im: Image, dopsf: bool = False, normalize: bool = True, gcfcf=None, **kwargs) -> (Image, numpy.ndarray): """ Invert using 2D convolution function, using the specified convolution function 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) :param gcfcf: (Grid correction function i.e. in image space, Convolution function i.e. in uv space) :return: resulting image """ assert isinstance(vis, Visibility), vis svis = copy_visibility(vis) if dopsf: svis.data['vis'][...] = 1.0 + 0.0j svis = shift_vis_to_image(svis, im, tangent=True, inverse=False) if gcfcf is None: gcf, cf = create_pswf_convolutionfunction( im, support=get_parameter(kwargs, "support", 6), oversampling=get_parameter(kwargs, "oversampling", 128)) else: gcf, cf = gcfcf griddata = create_griddata_from_image(im) griddata, sumwt = grid_visibility_to_griddata(svis, griddata=griddata, cf=cf) imaginary = get_parameter(kwargs, "imaginary", False) if imaginary: result0, result1 = fft_griddata_to_image(griddata, gcf, imaginary=imaginary) log.debug("invert_2d: retaining imaginary part of dirty image") if normalize: result0 = normalize_sumwt(result0, sumwt) result1 = normalize_sumwt(result1, sumwt) return result0, sumwt, result1 else: result = fft_griddata_to_image(griddata, gcf) if normalize: result = normalize_sumwt(result, sumwt) return result, sumwt
def test_copy_visibility(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame("stokesIQUV")) vis = copy_visibility(self.vis) self.vis.data['vis'] = 0.0 vis.data['vis'] = 1.0 assert (vis.data['vis'][0, 0].real == 1.0) assert (self.vis.data['vis'][0, 0].real == 0.0)
def test_apply_gaintable_null(self): for spf, dpf in[('stokesI', 'stokesI'), ('stokesIQUV', 'linear'), ('stokesIQUV', 'circular')]: self.actualSetup(spf, dpf) gt = create_gaintable_from_blockvisibility(self.vis, timeslice='auto') gt.data['gain']*=0.0 original = copy_visibility(self.vis) vis = apply_gaintable(self.vis, gt, inverse=True) error = numpy.max(numpy.abs(vis.vis[:,0,1,...] - original.vis[:,0,1,...])) assert error < 1e-12, "Error = %s" % (error)
def test_apply_gaintable_only(self): for spf, dpf in[('stokesI', 'stokesI'), ('stokesIQUV', 'linear'), ('stokesIQUV', 'circular')]: self.actualSetup(spf, dpf) gt = create_gaintable_from_blockvisibility(self.vis, timeslice='auto') log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=0.1, amplitude_error=0.01) original = copy_visibility(self.vis) vis = apply_gaintable(self.vis, gt) error = numpy.max(numpy.abs(vis.vis - original.vis)) assert error > 10.0, "Error = %f" % (error)
def test_solve_gaintable_scalar_timeslice(self): self.actualSetup('stokesI', 'stokesI', f=[100.0], ntimes=10) gt = create_gaintable_from_blockvisibility(self.vis, timeslice=120.0) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=10.0, amplitude_error=0.0) original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=True, niter=200) residual = numpy.max(gtsol.residual) assert residual < 3e-8, "Max residual = %s" % (residual) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def test_solve_gaintable_stokesI_pointsource(self): self.actualSetup('stokesI', 'stokesI', f=[100.0]) gt = create_gaintable_from_blockvisibility(self.vis) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=10.0, amplitude_error=0.0) original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) point_vis = divide_visibility(self.vis, original) gtsol = solve_gaintable(point_vis, phase_only=False, niter=200) residual = numpy.max(gtsol.residual) assert residual < 3e-8, "Max residual = %s" % (residual) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def predict_wstack_single(vis, model, remove=True, gcfcf=None, **kwargs) -> Visibility: """ Predict using a single w slices. This processes a single w plane, rotating out the w beam for the average w 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 predicted :param model: model image :return: resulting visibility (in place works) """ assert isinstance( vis, Visibility), "wstack requires Visibility format not BlockVisibility" assert image_is_canonical(model) vis.data['vis'][...] = 0.0 log.debug("predict_wstack_single: predicting using single w slice") # 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 tempvis = copy_visibility(vis) # Calculate w beam and apply to the model. The imaginary part is not needed workimage = convert_stokes_to_polimage(model, vis.polarisation_frame) w_beam = create_w_term_like(model, w_average, vis.phasecentre) workimage.data = numpy.conjugate(w_beam.data) * workimage.data gcf, cf = gcfcf griddata = create_griddata_from_image(model, vis) griddata = fft_image_to_griddata(workimage, griddata, gcf) vis = degrid_visibility_from_griddata(vis, griddata=griddata, cf=cf) if remove: vis.data['uvw'][..., 2] += w_average return vis
def test_create_gaintable_from_visibility_interval(self): for timeslice in [10.0, 'auto', 1e5]: for spf, dpf in[('stokesIQUV', 'linear')]: self.actualSetup(spf, dpf) gt = create_gaintable_from_blockvisibility(self.vis, timeslice=timeslice) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=1.0) original = copy_visibility(self.vis) vis = apply_gaintable(self.vis, gt) assert numpy.max(numpy.abs(original.vis)) > 0.0 assert numpy.max(numpy.abs(vis.vis)) > 0.0 assert numpy.max(numpy.abs(vis.vis - original.vis)) > 0.0
def test_addnoise_blockvisibility(self): self.vis = create_blockvisibility( self.config, self.times, self.frequency, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('stokesIQUV'), channel_bandwidth=self.channel_bandwidth) original = copy_visibility(self.vis) self.vis = addnoise_visibility(self.vis) actual = numpy.std(numpy.abs(self.vis.vis - original.vis)) assert abs(actual - 0.01077958403015586) < 1e-4, actual
def test_solve_gaintable_stokesI_small_n_large_t(self): # Select only 6 stations self.actualSetup('stokesI', 'stokesI', f=[100.0], ntimes=4000, rmax=83) gt = create_gaintable_from_blockvisibility(self.vis) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=10.0, amplitude_error=0.0) gt.data['gain'] = gt.gain[1, ...] original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=True, niter=200) self.vis = apply_gaintable(self.vis, gtsol) residual = numpy.max(gtsol.residual) assert residual < 3e-8, "Max residual = %s" % (residual) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def test_solve_gaintable_scalar_normalise(self): self.actualSetup('stokesI', 'stokesI', f=[100.0]) gt = create_gaintable_from_blockvisibility(self.vis) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=0.0, amplitude_error=0.1) gt.data['gain'] *= 2.0 original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=False, niter=200, normalise_gains=True) residual = numpy.max(gtsol.residual) assert residual < 3e-8, "Max residual = %s" % (residual) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def test_calibrate_G_function(self): self.actualSetup('stokesIQUV', 'linear', f=[100.0, 0.0, 0.0, 50.0]) # Prepare the corrupted visibility data_models gt = create_gaintable_from_blockvisibility(self.vis) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=0.0, amplitude_error=0.1) original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) # Now get the control dictionary and calibrate controls = create_calibration_controls() controls['G']['first_selfcal'] = 0 calibrated_vis, gaintables = calibrate_chain(self.vis, original, calibration_context='G', controls=controls) residual = numpy.max(gaintables['G'].residual) assert residual < 1e-8, "Max T residual = %s" % residual
def test_solve_gaintable_stokesI_bandpass(self): self.actualSetup('stokesI', 'stokesI', f=[100.0], vnchan=128) gt = create_gaintable_from_blockvisibility(self.vis) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=10.0, amplitude_error=0.01, smooth_channels=8) original = copy_visibility(self.vis) self.vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=False, niter=200, damping=0.5) residual = numpy.max(gtsol.residual) assert residual < 3e-8, "Max residual = %s" % (residual) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def decoalesce_visibility(vis: Visibility, **kwargs) -> BlockVisibility: """ Decoalesce the visibilities to the original values (opposite of coalesce_visibility) This relies upon the block vis and the index being part of the vis. Needs the index generated by coalesce_visibility :param vis: (Coalesced visibility) :return: BlockVisibility with vis and weight columns overwritten """ assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis assert isinstance(vis.blockvis, BlockVisibility), "No blockvisibility in vis %r" % vis assert vis.cindex is not None, "No reverse index in Visibility %r" % vis log.debug( 'decoalesce_visibility: Created new Visibility for decoalesced data_models' ) decomp_vis = copy_visibility(vis.blockvis) vshape = decomp_vis.data['vis'].shape npol = vshape[-1] dvis = numpy.zeros(vshape, dtype='complex') assert numpy.max(vis.cindex) < dvis.size assert numpy.max( vis.cindex ) < vis.vis.shape[0], "Incorrect template used in decoalescing" for i in range(dvis.size // npol): decomp_vis.data['vis'].flat[i:i + npol] = vis.data['vis'][vis.cindex[i]] decomp_vis.data['flags'].flat[i:i + npol] = vis.data['flags'][vis.cindex[i]] decomp_vis.data['weight'].flat[i:i + npol] = vis.data['weight'][ vis.cindex[i]] decomp_vis.data['imaging_weight'].flat[i:i + npol] = vis.data[ 'imaging_weight'][vis.cindex[i]] log.debug('decoalesce_visibility: Coalesced %s, decoalesced %s' % (vis_summary(vis), vis_summary(decomp_vis))) return decomp_vis
def rcal(vis: BlockVisibility, components, **kwargs) -> GainTable: """ Real-time calibration pipeline. Reads visibilities through a BlockVisibility iterator, calculates model visibilities according to a component-based sky model, and performs calibration solution, writing a gaintable for each chunk of visibilities. :param vis: Visibility or Union(Visibility, Iterable) :param components: Component-based sky model :param kwargs: Parameters :return: gaintable """ if not isinstance(vis, collections.abc.Iterable): vis = [vis] for ichunk, vischunk in enumerate(vis): vispred = copy_visibility(vischunk, zero=True) vispred = dft_skycomponent_visibility(vispred, components) gt = solve_gaintable(vischunk, vispred, **kwargs) yield gt
def core_solve(self, spf, dpf, phase_error=0.1, amplitude_error=0.0, leakage=0.0, phase_only=True, niter=200, crosspol=False, residual_tol=1e-6, f=None, vnchan=3, timeslice='auto'): if f is None: f = [100.0, 50.0, -10.0, 40.0] self.actualSetup(spf, dpf, f=f, vnchan=vnchan) gt = create_gaintable_from_blockvisibility(self.vis, timeslice=timeslice) log.info("Created gain table: %s" % (gaintable_summary(gt))) gt = simulate_gaintable(gt, phase_error=phase_error, amplitude_error=amplitude_error, leakage=leakage) original = copy_visibility(self.vis) vis = apply_gaintable(self.vis, gt) gtsol = solve_gaintable(self.vis, original, phase_only=phase_only, niter=niter, crosspol=crosspol, tol=1e-6) vis = apply_gaintable(vis, gtsol, inverse=True) residual = numpy.max(gtsol.residual) assert residual < residual_tol, "%s %s Max residual = %s" % (spf, dpf, residual) log.debug(qa_gaintable(gt)) assert numpy.max(numpy.abs(gtsol.gain - 1.0)) > 0.1
def test_create_vis_iter(self): vis_iter = create_blockvisibility_iterator( self.config, self.times, self.frequency, channel_bandwidth=self.channel_bandwidth, phasecentre=self.phasecentre, weight=1.0, polarisation_frame=PolarisationFrame('stokesI'), integration_time=30.0, number_integrations=3) fullvis = None totalnvis = 0 for i, vis in enumerate(vis_iter): assert vis.nvis if i == 0: fullvis = copy_visibility(vis) totalnvis = vis.nvis else: fullvis = append_visibility(fullvis, vis) totalnvis += vis.nvis assert fullvis.nvis == totalnvis
blockvis_pol, phasecentre, block=block, zerow=zerow) vis = convert_blockvisibility_to_visibility(blockvis) model = create_unittest_model(vis, image_pol, npixel=npixel, nchan=freqwin) components = create_unittest_components(model, flux) model = insert_skycomponent(model, components) blockvis = predict_skycomponent_visibility(blockvis, components) #blockvis = dft_skycomponent_visibility(blockvis, components) blockvis1 = copy_visibility(blockvis) vis1 = convert_blockvisibility_to_visibility(blockvis1) # Calculate the model convolved with a Gaussian. cmodel = smooth_image(model) if persist: export_image_to_fits(model, '%s/test_imaging_2d_model.fits' % rdir) if persist: export_image_to_fits(cmodel, '%s/test_imaging_2d_cmodel.fits' % rdir) # In[4]: print(qa_image(model)) # In[5]:
def invert_ng(bvis: BlockVisibility, model: Image, dopsf: bool = False, normalize: bool = True, **kwargs) -> (Image, numpy.ndarray): """ Invert using nifty-gridder module https://gitlab.mpcdf.mpg.de/ift/nifty_gridder 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 bvis: BlockVisibility to be inverted :param im: image template (not changed) :param normalize: Normalize by the sum of weights (True) :return: (resulting image, sum of the weights for each frequency and polarization) """ assert image_is_canonical(model) assert isinstance(bvis, BlockVisibility), bvis im = copy_image(model) nthreads = get_parameter(kwargs, "threads", 4) epsilon = get_parameter(kwargs, "epsilon", 1e-12) do_wstacking = get_parameter(kwargs, "do_wstacking", True) verbosity = get_parameter(kwargs, "verbosity", 0) sbvis = copy_visibility(bvis) sbvis = shift_vis_to_image(sbvis, im, tangent=True, inverse=False) vis = bvis.vis freq = sbvis.frequency # frequency, Hz nrows, nants, _, vnchan, vnpol = vis.shape uvw = sbvis.uvw.reshape([nrows * nants * nants, 3]) ms = vis.reshape([nrows * nants * nants, vnchan, vnpol]) wgt = sbvis.imaging_weight.reshape( [nrows * nants * nants, vnchan, vnpol]) if dopsf: ms[...] = 1.0 + 0.0j if epsilon > 5.0e-6: ms = ms.astype("c8") wgt = wgt.astype("f4") # Find out the image size/resolution npixdirty = im.nwidth pixsize = numpy.abs(numpy.radians(im.wcs.wcs.cdelt[0])) fuvw = uvw.copy() # We need to flip the u and w axes. fuvw[:, 0] *= -1.0 fuvw[:, 2] *= -1.0 nchan, npol, ny, nx = im.shape im.data[...] = 0.0 sumwt = numpy.zeros([nchan, npol]) ms = convert_pol_frame(ms, bvis.polarisation_frame, im.polarisation_frame, polaxis=2) # There's a latent problem here with the weights. # wgt = numpy.real(convert_pol_frame(wgt, bvis.polarisation_frame, im.polarisation_frame, polaxis=2)) # Set up the conversion from visibility channels to image channels vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix( freq, 0)[0]).astype('int') for vchan in range(vnchan): ichan = vis_to_im[vchan] for pol in range(npol): # Nifty gridder likes to receive contiguous arrays ms_1d = numpy.array([ ms[row, vchan:vchan + 1, pol] for row in range(nrows * nants * nants) ], dtype='complex') ms_1d.reshape([ms_1d.shape[0], 1]) wgt_1d = numpy.array([ wgt[row, vchan:vchan + 1, pol] for row in range(nrows * nants * nants) ]) wgt_1d.reshape([wgt_1d.shape[0], 1]) dirty = ng.ms2dirty(fuvw, freq[vchan:vchan + 1], ms_1d, wgt_1d, npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, pol] += numpy.sum(wgt[:, vchan, pol]) im.data[ichan, pol] += dirty.T if normalize: im = normalize_sumwt(im, sumwt) return im, sumwt
def predict_ng(bvis: BlockVisibility, model: Image, **kwargs) -> BlockVisibility: """ Predict using convolutional degridding. Nifty-gridder version. https://gitlab.mpcdf.mpg.de/ift/nifty_gridder In the imaging and pipeline workflows, this may be invoked using context='ng'. :param bvis: BlockVisibility to be predicted :param model: model image :return: resulting BlockVisibility (in place works) """ assert isinstance(bvis, BlockVisibility), bvis assert image_is_canonical(model) if model is None: return bvis nthreads = get_parameter(kwargs, "threads", 4) epsilon = get_parameter(kwargs, "epsilon", 1e-12) do_wstacking = get_parameter(kwargs, "do_wstacking", True) verbosity = get_parameter(kwargs, "verbosity", 0) newbvis = copy_visibility(bvis, zero=True) # Extracting data from BlockVisibility freq = bvis.frequency # frequency, Hz nrows, nants, _, vnchan, vnpol = bvis.vis.shape uvw = newbvis.data['uvw'].reshape([nrows * nants * nants, 3]) vist = numpy.zeros([vnpol, vnchan, nants * nants * nrows], dtype='complex') # Get the image properties m_nchan, m_npol, ny, nx = model.data.shape # Check if the number of frequency channels matches in bvis and a model # assert (m_nchan == v_nchan) assert (m_npol == vnpol) fuvw = uvw.copy() # We need to flip the u and w axes. The flip in w is equivalent to the conjugation of the # convolution function grid_visibility to griddata fuvw[:, 0] *= -1.0 fuvw[:, 2] *= -1.0 # Find out the image size/resolution pixsize = numpy.abs(numpy.radians(model.wcs.wcs.cdelt[0])) # Make de-gridding over a frequency range and pol fields vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix( freq, 0)[0]).astype('int') mfs = m_nchan == 1 if mfs: for vpol in range(vnpol): vist[vpol, :, :] = ng.dirty2ms( fuvw.astype(numpy.float64), bvis.frequency.astype(numpy.float64), model.data[0, vpol, :, :].T.astype(numpy.float64), pixsize_x=pixsize, pixsize_y=pixsize, epsilon=epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity).T else: for vpol in range(vnpol): for vchan in range(vnchan): imchan = vis_to_im[vchan] vist[vpol, vchan, :] = ng.dirty2ms( fuvw.astype(numpy.float64), numpy.array(freq[vchan:vchan + 1]).astype( numpy.float64), model.data[imchan, vpol, :, :].T.astype(numpy.float64), pixsize_x=pixsize, pixsize_y=pixsize, epsilon=epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity)[:, 0] vis = convert_pol_frame(vist.T, model.polarisation_frame, bvis.polarisation_frame, polaxis=2) newbvis.data['vis'] = vis.reshape([nrows, nants, nants, vnchan, vnpol]) # Now we can shift the visibility from the image frame to the original visibility frame return shift_vis_to_image(newbvis, model, tangent=True, inverse=True)
def invert_ng(bvis: BlockVisibility, model: Image, dopsf: bool = False, normalize: bool = True, **kwargs) -> (Image, numpy.ndarray): """ Invert using nifty-gridder module https://gitlab.mpcdf.mpg.de/ift/nifty_gridder Use the image im as a template. Do PSF in a separate call. In the imaging and pipeline workflows, this may be invoked using context='ng'. :param dopsf: Make the PSF instead of the dirty image :param bvis: BlockVisibility to be inverted :param im: image template (not changed) :param normalize: Normalize by the sum of weights (True) :return: (resulting image, sum of the weights for each frequency and polarization) """ assert image_is_canonical(model) assert isinstance(bvis, BlockVisibility), bvis im = copy_image(model) nthreads = get_parameter(kwargs, "threads", 4) epsilon = get_parameter(kwargs, "epsilon", 1e-12) do_wstacking = get_parameter(kwargs, "do_wstacking", True) verbosity = get_parameter(kwargs, "verbosity", 0) sbvis = copy_visibility(bvis) sbvis = shift_vis_to_image(sbvis, im, tangent=True, inverse=False) freq = sbvis.frequency # frequency, Hz nrows, nants, _, vnchan, vnpol = sbvis.vis.shape # if dopsf: # sbvis = fill_vis_for_psf(sbvis) ms = sbvis.vis.reshape([nrows * nants * nants, vnchan, vnpol]) ms = convert_pol_frame(ms, bvis.polarisation_frame, im.polarisation_frame, polaxis=2) uvw = sbvis.uvw.reshape([nrows * nants * nants, 3]) wgt = sbvis.flagged_imaging_weight.reshape( [nrows * nants * nants, vnchan, vnpol]) if epsilon > 5.0e-6: ms = ms.astype("c8") wgt = wgt.astype("f4") # Find out the image size/resolution npixdirty = im.nwidth pixsize = numpy.abs(numpy.radians(im.wcs.wcs.cdelt[0])) fuvw = uvw.copy() # We need to flip the u and w axes. fuvw[:, 0] *= -1.0 fuvw[:, 2] *= -1.0 nchan, npol, ny, nx = im.shape im.data[...] = 0.0 sumwt = numpy.zeros([nchan, npol]) # There's a latent problem here with the weights. # wgt = numpy.real(convert_pol_frame(wgt, bvis.polarisation_frame, im.polarisation_frame, polaxis=2)) # Set up the conversion from visibility channels to image channels vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix( freq, 0)[0]).astype('int') # Nifty gridder likes to receive contiguous arrays so we transpose # at the beginning mfs = nchan == 1 if dopsf: mst = ms.T mst[...] = 0.0 mst[0, ...] = 1.0 wgtt = wgt.T if mfs: dirty = ng.ms2dirty(fuvw.astype(numpy.float64), bvis.frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[0, :, :].T), numpy.ascontiguousarray(wgtt[0, :, :].T), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[0, :] += numpy.sum(wgtt[0, 0, :].T, axis=0) im.data[0, :] += dirty.T else: for vchan in range(vnchan): ichan = vis_to_im[vchan] frequency = numpy.array(freq[vchan:vchan + 1]).astype( numpy.float64) dirty = ng.ms2dirty( fuvw.astype(numpy.float64), frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[0, vchan, :][..., numpy.newaxis]), numpy.ascontiguousarray(wgtt[0, vchan, :][..., numpy.newaxis]), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, :] += numpy.sum(wgtt[0, ichan, :].T, axis=0) im.data[ichan, :] += dirty.T else: mst = ms.T wgtt = wgt.T for pol in range(npol): if mfs: dirty = ng.ms2dirty( fuvw.astype(numpy.float64), bvis.frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[pol, :, :].T), numpy.ascontiguousarray(wgtt[pol, :, :].T), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[0, pol] += numpy.sum(wgtt[pol, 0, :].T, axis=0) im.data[0, pol] += dirty.T else: for vchan in range(vnchan): ichan = vis_to_im[vchan] frequency = numpy.array(freq[vchan:vchan + 1]).astype( numpy.float64) dirty = ng.ms2dirty(fuvw.astype(numpy.float64), frequency.astype(numpy.float64), numpy.ascontiguousarray( mst[pol, vchan, :][..., numpy.newaxis]), numpy.ascontiguousarray( wgtt[pol, vchan, :][..., numpy.newaxis]), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, pol] += numpy.sum(wgtt[pol, ichan, :].T, axis=0) im.data[ichan, pol] += dirty.T if normalize: im = normalize_sumwt(im, sumwt) return im, sumwt
def degrid_blockvisibility_from_griddata(vis, griddata, cf, **kwargs): """Degrid blockVisibility from a GridData :param vis: Visibility to be degridded :param griddata: GridData containing image :param cf: Convolution function (as GridData) :param kwargs: :return: Visibility """ assert vis.polarisation_frame == griddata.polarisation_frame newvis = copy_visibility(vis, zero=True) nchan, npol, nz, oversampling, _, support, _ = cf.shape vis_to_im = numpy.round( griddata.grid_wcs.sub([5]).wcs_world2pix(vis.frequency, 0)[0]).astype('int') nrows, nants, _, nvchan, nvpol = vis.vis.shape fvist = numpy.zeros([nvpol, nvchan, nrows * nants * nants], dtype='complex') _, _, _, _, _, gv, gu = cf.shape du = gu // 2 dv = gv // 2 for vchan in range(nvchan): imchan = vis_to_im[vchan] frequency = vis.frequency[vchan] pu_grid, pu_offset, pv_grid, pv_offset, pwg_grid, pwg_fraction, pwc_grid, pwc_fraction = \ convolution_mapping_blockvisibility(vis, griddata, frequency, cf) for pol in range(nvpol): for row in range(nrows * nants * nants): subgrid = griddata.data[imchan, \ pol, \ pwg_grid[row], \ (pv_grid[row] - dv):(pv_grid[row] + dv), \ (pu_grid[row] - du):(pu_grid[row] + du)] subcf = cf.data[imchan, pol, pwc_grid[row], pv_offset[row], pu_offset[row], :, :] fvist[pol, vchan, row] = numpy.einsum('ij,ij', subgrid, subcf)# / numpy.sum(subcf.real) # import matplotlib.pyplot as plt # plt.clf() # plt.plot(pu_offset[::10], numpy.abs(fvist[0, 0, ::10]), '.') # plt.title("U offset") # plt.show(block=False) # plt.clf() # plt.plot(pv_offset[::10], numpy.abs(fvist[0, 0, ::10]), '.') # plt.title("V offset") # plt.show(block=False) # plt.clf() # plt.plot(pu_offset[::10], pv_offset[::10], '.') # plt.title("U vs V offset") # plt.show(block=False) newvis.data['vis'][...] = fvist.T.reshape([nrows, nants, nants, nvchan, nvpol]) return newvis