def solve_gaintable(vis: BlockVisibility, modelvis: BlockVisibility = None, gt=None, phase_only=True, niter=30, tol=1e-8, crosspol=False, **kwargs) -> GainTable: """Solve a gain table by fitting an observed visibility to a model visibility If modelvis is None, a point source model is assumed. :param vis: BlockVisibility containing the observed data :param modelvis: BlockVisibility containing the visibility predicted by a model :param gt: Existing gaintable :param phase_only: Solve only for the phases (default=True) :param niter: Number of iterations (default 30) :param tol: Iteration stops when the fractional change in the gain solution is below this tolerance :param crosspol: Do solutions including cross polarisations i.e. XY, YX or RL, LR :return: GainTable containing solution """ assert isinstance(vis, BlockVisibility), vis if modelvis is not None: assert isinstance(modelvis, BlockVisibility), modelvis if phase_only: log.debug('solve_gaintable: Solving for phase only') else: log.debug('solve_gaintable: Solving for complex gain') if gt is None: log.debug("solve_gaintable: creating new gaintable") gt = create_gaintable_from_blockvisibility(vis, **kwargs) else: log.debug("solve_gaintable: starting from existing gaintable") for row in range(gt.ntimes): vis_rows = numpy.abs(vis.time - gt.time[row]) < gt.interval[row] / 2.0 if numpy.sum(vis_rows) > 0: subvis = create_visibility_from_rows(vis, vis_rows) if modelvis is not None: model_subvis = create_visibility_from_rows(modelvis, vis_rows) pointvis = divide_visibility(subvis, model_subvis) x = numpy.sum(pointvis.vis * pointvis.weight, axis=0) xwt = numpy.sum(pointvis.weight, axis=0) else: x = numpy.sum(subvis.vis * subvis.weight, axis=0) xwt = numpy.sum(subvis.weight, axis=0) mask = numpy.abs(xwt) > 0.0 x_shape = x.shape x[mask] = x[mask] / xwt[mask] x[~mask] = 0.0 x = x.reshape(x_shape) gt = solve_from_X(gt, x, xwt, row, crosspol, niter, phase_only, tol, npol=vis.polarisation_frame.npol) assert isinstance(gt, GainTable), "gt is not a GainTable: %r" % gt assert_vis_gt_compatible(vis, gt) return gt
def solve_gaintable(vis: BlockVisibility, modelvis: BlockVisibility=None, phase_only=True, niter=30, tol=1e-8, crosspol=False, **kwargs) -> GainTable: """Solve a gain table by fitting an observed visibility to a model visibility If modelvis is None, a point source model is assumed. :param vis: BlockVisibility containing the observed data :param modelvis: BlockVisibility containing the visibility predicted by a model :param phase_only: Solve only for the phases (default=True) :param niter: Number of iterations (default 30) :param tol: Iteration stops when the fractional change in the gain solution is below this tolerance :param crosspol: Do solutions including cross polarisations i.e. XY, YX or RL, LR :return: GainTable containing solution """ assert type(vis) is BlockVisibility, "vis is not a BlockVisibility: %r" % vis assert type(modelvis) is BlockVisibility or type(modelvis) is None, "modelvis is not None or a " \ "BlockVisibility: %r" % vis if phase_only: log.info('solve_gaintable: Solving for phase only') else: log.info('solve_gaintable: Solving for complex gain') # 根据blockvisibility的元数据初始化一个gaintable gt = create_gaintable_from_blockvisibility(vis) for chunk, rows in enumerate(vis_timeslice_iter(vis, **kwargs)): # 对visibility按照time切片 # 切片好的visibility shape: [1,nant,nant,nchan,npol] subvis = create_visibility_from_rows(vis, rows) #若存在model if modelvis is not None: # model_visibility也要以相同的方式按time切片 model_subvis = create_visibility_from_rows(modelvis, rows) # 两个vis相除计算得到新的block_vis,其中的元数据未改变,只有vis和weight发生了改变 pointvis = divide_visibility(subvis, model_subvis) # 此处因为第0个axis是time轴,并且vis已经按照time分片,所以按照第0axis做了average以后值不发生变化 x = numpy.average(pointvis.vis, axis=0) xwt = numpy.average(pointvis.weight, axis=0) else: x = numpy.average(subvis.vis, axis=0) xwt = numpy.average(subvis.weight, axis=0) # 将数据填入gaintable中 # solve 和 timeslot的分界线 gt = solve_from_X(gt, x, xwt, chunk, crosspol, niter, phase_only, tol, npol=vis.polarisation_frame.npol) assert type(gt) is GainTable, "gt is not a GainTable: %r" % gt assert_vis_gt_compatible(vis, gt) return gt
def test_create_visibility_from_rows_makecopy(self): self.vis = create_visibility(self.lowcore, self.times, self.frequency, phasecentre=self.phasecentre, weight=1.0, channel_bandwidth=self.channel_bandwidth) rows = self.vis.time > 150.0 for makecopy in [True, False]: selected_vis = create_visibility_from_rows(self.vis, rows, makecopy=makecopy) assert selected_vis.nvis == numpy.sum(numpy.array(rows))
def test_vis_timeslice_iterator_timeslice(self): self.actualSetUp() for chunk, rows in enumerate( vis_timeslice_iter(self.vis, timeslice=65.0)): visslice = create_visibility_from_rows(self.vis, rows) assert visslice.vis[0].real == visslice.time[0] assert len(rows) assert numpy.sum(rows) < self.vis.nvis
def test_coalesce_decoalesce_with_iter(self): for rows in vis_timeslice_iter(self.blockvis): visslice = create_visibility_from_rows(self.blockvis, rows) cvisslice = convert_blockvisibility_to_visibility(visslice) assert numpy.min(cvisslice.frequency) == numpy.min(self.frequency) assert numpy.min(cvisslice.frequency) > 0.0 dvisslice = decoalesce_visibility(cvisslice) assert dvisslice.nvis == visslice.nvis
def test_vis_wstack_iterator(self): self.actualSetUp() nchunks = len(list(vis_wstack_iter(self.vis, wstack=10.0))) log.debug('Found %d chunks' % (nchunks)) assert nchunks > 1 for chunk, rows in enumerate(vis_wstack_iter(self.vis, wstack=10.0)): assert len(rows) visslice = create_visibility_from_rows(self.vis, rows) assert numpy.sum(visslice.nvis) < self.vis.nvis
def test_vis_timeslice_iterator(self): self.actualSetUp() nchunks = len(list(vis_timeslice_iter(self.vis))) log.debug('Found %d chunks' % (nchunks)) assert nchunks > 1 for chunk, rows in enumerate(vis_timeslice_iter(self.vis)): visslice = create_visibility_from_rows(self.vis, rows) assert visslice.vis[0].real == visslice.time[0] assert len(rows) assert numpy.sum(rows) < self.vis.nvis
def test_vis_slice_iterator_vis_slices(self): self.actualSetUp() total_rows = 0 for chunk, rows in enumerate(vis_slice_iter(self.vis, vis_slices=11)): visslice = create_visibility_from_rows(self.vis, rows) total_rows += visslice.nvis assert len(rows) assert visslice.vis[0].real == visslice.time[0] assert total_rows == self.vis.nvis, "Total rows iterated %d, Original rows %d" % ( total_rows, self.vis.nvis)
def scatter_vis(vis): # Scatter along the visibility iteration axis if isinstance(vis, BlockVisibility): avis = coalesce_visibility(vis, **kwargs) else: avis = vis result = [ create_visibility_from_rows(avis, rows) for rows in vis_iter(avis, vis_slices=vis_slices, **kwargs) ] return result
def scatter_vis(vis): if isinstance(vis, BlockVisibility): avis = coalesce_visibility(vis, **kwargs) else: avis = vis result = [ create_visibility_from_rows(avis, rows) for rows in vis_iter(avis, vis_slices=vis_slices, **kwargs) ] assert len(result) == vis_slices, "result %s, vis_slices %d" % ( str(result), vis_slices) return result
def test_vis_timeslice_iterator_timeslice(self): self.actualSetUp() total_rows = 0 for chunk, rows in enumerate( vis_timeslice_iter(self.vis, timeslice=65.0)): visslice = create_visibility_from_rows(self.vis, rows) if visslice is not None: total_rows += visslice.nvis assert visslice.vis[0].real == visslice.time[0] assert len(rows) assert numpy.sum(rows) < self.vis.nvis assert total_rows == self.vis.nvis, "Total rows iterated %d, Original rows %d" % ( total_rows, self.vis.nvis)
def test_vis_wstack_iterator(self): self.actualSetUp() nchunks = len(list(vis_wstack_iter(self.vis, wstack=10.0))) log.debug('Found %d chunks' % (nchunks)) assert nchunks > 1 total_rows = 0 for chunk, rows in enumerate(vis_wstack_iter(self.vis, wstack=10.0)): assert len(rows) visslice = create_visibility_from_rows(self.vis, rows) total_rows += visslice.nvis assert numpy.sum(visslice.nvis) < self.vis.nvis assert total_rows == self.vis.nvis, "Total rows iterated %d, Original rows %d" % ( total_rows, self.vis.nvis)
def uv_cut(vis, uv_max): """Cut the visibility data at uv-distances beyond uvmax. Args: vis (obj): ARL visibility data. uv_max (float): maximum uv-coordinate. Returns: vis: New visibility data. """ # Cut off data beyond the maximum uv-distance: uv_dist = np.sqrt(vis.data['uvw'][:, 0]**2 + vis.data['uvw'][:, 1]**2) vis = create_visibility_from_rows(vis, uv_dist < uv_max) return vis
def visibility_scatter(vis: Visibility, vis_iter, vis_slices=1, **kwargs) -> List[Visibility]: """Scatter a visibility into a list of subvisibilities :param vis: Visibility :param vis_iter: visibility iterator :return: list of subvisibilitys """ visibility_list = list() for i, rows in enumerate(vis_iter(vis, vis_slices=vis_slices, **kwargs)): subvis = create_visibility_from_rows(vis, rows) visibility_list.append(subvis) return visibility_list
def test_vis_timeslice_iterator(self): self.actualSetUp() nchunks = len(list(vis_timeslice_iter(self.vis, timeslice='auto'))) log.debug('Found %d chunks' % (nchunks)) assert nchunks > 1 total_rows = 0 for chunk, rows in enumerate( vis_timeslice_iter(self.vis, timeslice='auto')): visslice = create_visibility_from_rows(self.vis, rows) total_rows += visslice.nvis assert visslice.vis[0].real == visslice.time[0] assert len(rows) assert numpy.sum(rows) < self.vis.nvis assert total_rows == self.vis.nvis, "Total rows iterated %d, Original rows %d" % ( total_rows, self.vis.nvis)
def predict_with_vis_iterator(vis: Visibility, model: Image, vis_iter=vis_slice_iter, predict=predict_2d, **kwargs) -> Visibility: """Iterate through prediction in chunks This knows about the structure of predict in different execution frameworks but not anything about the actual processing. """ log.debug("predict_with_vis_iterator: Processing chunks") if not isinstance(vis, Visibility): svis = coalesce_visibility(vis, **kwargs) else: svis = vis # Do each chunk in turn for rows in vis_iter(svis, **kwargs): if numpy.sum(rows) and svis is not None: visslice = create_visibility_from_rows(svis, rows) visslice.data['vis'][...] = 0.0 visslice = predict(visslice, model, **kwargs) svis.data['vis'][rows] += visslice.data['vis'] return svis
def invert_with_vis_iterator(vis: Visibility, im: Image, dopsf=False, normalize=True, vis_iter=vis_slice_iter, invert=invert_2d, **kwargs): """ Invert using a specified iterator and invert This knows about the structure of invert in different execution frameworks but not anything about the actual processing. :param vis: :param im: :param dopsf: Make the psf instead of the dirty image :param normalize: Normalize by the sum of weights (True) :param kwargs: :return: """ resultimage = create_empty_image_like(im) if type(vis) is not Visibility: svis = coalesce_visibility(vis, **kwargs) else: svis = vis i = 0 for rows in vis_iter(svis, **kwargs): if numpy.sum(rows) and svis is not None: visslice = create_visibility_from_rows(svis, rows) workimage, sumwt = invert(visslice, im, dopsf, normalize=False, **kwargs) resultimage.data += workimage.data if i == 0: totalwt = sumwt else: totalwt += sumwt i += 1 if normalize: resultimage = normalize_sumwt(resultimage, totalwt) return resultimage, totalwt
def scatter_vis(vis): if isinstance(vis, BlockVisibility): avis = coalesce_visibility(vis, **kwargs) else: avis = vis return [create_visibility_from_rows(vis, rows) for rows in vis_iter(avis, vis_slices=vis_slices, **kwargs)]
def invert_function(vis, im: Image, dopsf=False, normalize=True, context='2d', inner=None, **kwargs): """ Invert using algorithm specified by context: * 2d: Two-dimensional transform * wstack: wstacking with either vis_slices or wstack (spacing between w planes) set * wprojection: w projection with wstep (spacing between w places) set, also kernel='wprojection' * timeslice: snapshot imaging with either vis_slices or timeslice set. timeslice='auto' does every time * facets: Faceted imaging with facets facets on each axis * facets_wprojection: facets AND wprojection * facets_wstack: facets AND wstacking * wprojection_wstack: wprojection and wstacking :param vis: :param im: :param dopsf: Make the psf instead of the dirty image (False) :param normalize: Normalize by the sum of weights (True) :param context: Imaging context e.g. '2d', 'timeslice', etc. :param inner: Inner loop 'vis'|'image' :param kwargs: :return: Image, sum of weights """ c = imaging_context(context) vis_iter = c['vis_iterator'] image_iter = c['image_iterator'] invert = c['invert'] if inner is None: inner = c['inner'] if not isinstance(vis, Visibility): svis = coalesce_visibility(vis, **kwargs) else: svis = vis resultimage = create_empty_image_like(im) if inner == 'image': totalwt = None for rows in vis_iter(svis, **kwargs): if numpy.sum(rows): visslice = create_visibility_from_rows(svis, rows) sumwt = 0.0 workimage = create_empty_image_like(im) for dpatch in image_iter(workimage, **kwargs): result, sumwt = invert(visslice, dpatch, dopsf, normalize=False, **kwargs) # Ensure that we fill in the elements of dpatch instead of creating a new numpy arrray dpatch.data[...] = result.data[...] # Assume that sumwt is the same for all patches if totalwt is None: totalwt = sumwt else: totalwt += sumwt resultimage.data += workimage.data else: # We assume that the weight is the same for all image iterations totalwt = None workimage = create_empty_image_like(im) for dpatch in image_iter(workimage, **kwargs): totalwt = None for rows in vis_iter(svis, **kwargs): if numpy.sum(rows): visslice = create_visibility_from_rows(svis, rows) result, sumwt = invert(visslice, dpatch, dopsf, normalize=False, **kwargs) # Ensure that we fill in the elements of dpatch instead of creating a new numpy arrray dpatch.data[...] += result.data[...] if totalwt is None: totalwt = sumwt else: totalwt += sumwt resultimage.data += workimage.data workimage.data[...] = 0.0 assert totalwt is not None, "No valid data found for imaging" if normalize: resultimage = normalize_sumwt(resultimage, totalwt) return resultimage, totalwt
def predict_function(vis, model: Image, context='2d', inner=None, **kwargs) -> Visibility: """Predict visibilities using algorithm specified by context * 2d: Two-dimensional transform * wstack: wstacking with either vis_slices or wstack (spacing between w planes) set * wprojection: w projection with wstep (spacing between w places) set, also kernel='wprojection' * timeslice: snapshot imaging with either vis_slices or timeslice set. timeslice='auto' does every time * facets: Faceted imaging with facets facets on each axis * facets_wprojection: facets AND wprojection * facets_wstack: facets AND wstacking * wprojection_wstack: wprojection and wstacking :param vis: :param model: Model image, used to determine image characteristics :param context: Imaing context e.g. '2d', 'timeslice', etc. :param inner: Inner loop 'vis'|'image' :param kwargs: :return: """ c = imaging_context(context) vis_iter = c['vis_iterator'] image_iter = c['image_iterator'] predict = c['predict'] if inner is None: inner = c['inner'] if not isinstance(vis, Visibility): svis = coalesce_visibility(vis, **kwargs) else: svis = vis result = copy_visibility(vis, zero=True) if inner == 'image': for rows in vis_iter(svis, **kwargs): if numpy.sum(rows): visslice = create_visibility_from_rows(svis, rows) visslice.data['vis'][...] = 0.0 # Iterate over images for dpatch in image_iter(model, **kwargs): result.data['vis'][...] = 0.0 result = predict(visslice, dpatch, **kwargs) svis.data['vis'][rows] += result.data['vis'] else: # Iterate over images for dpatch in image_iter(model, **kwargs): for rows in vis_iter(svis, **kwargs): if numpy.sum(rows): visslice = create_visibility_from_rows(svis, rows) result.data['vis'][...] = 0.0 result = predict(visslice, dpatch, **kwargs) svis.data['vis'][rows] += result.data['vis'] return svis
def test_vis_slice_iterator_vis_slices(self): self.actualSetUp() for chunk, rows in enumerate(vis_slice_iter(self.vis, vis_slices=11)): visslice = create_visibility_from_rows(self.vis, rows) assert len(rows) assert visslice.vis[0].real == visslice.time[0]