def copy_skymodel(sm): """ Copy a sky model :param sm: SkyModel to be copied :return: SkyModel """ if sm.components is not None: newcomps = [copy_skycomponent(comp) for comp in sm.components] else: newcomps = None if sm.image is not None: newimage = copy_image(sm.image) else: newimage = None if sm.mask is not None: newmask = copy_image(sm.mask) else: newmask = None if sm.gaintable is not None: newgt = copy_gaintable(sm.gaintable) else: newgt = None return SkyModel(components=newcomps, image=newimage, gaintable=newgt, mask=newmask, fixed=sm.fixed)
def partition_skymodel_by_flux(sc, model, flux_threshold=-numpy.inf): """Partition skymodel according to flux Bright skycomponents are put into a SkyModel as a list, and weak skycomponents are inserted into SkyModel as an image. :param sc: List of skycomponents :param model: Model image :param flux_threshold: :return: SkyModel For example:: fluxes = numpy.linspace(0, 1.0, 11) sc = [create_skycomponent(direction=phasecentre, flux=numpy.array([[f]]), frequency=frequency, polarisation_frame=PolarisationFrame('stokesI')) for f in fluxes] sm = partition_skymodel_by_flux(sc, model, flux_threshold=0.31) assert len(sm.components) == 7, len(sm.components) """ brightsc = filter_skycomponents_by_flux(sc, flux_min=flux_threshold) weaksc = filter_skycomponents_by_flux(sc, flux_max=flux_threshold) log.info( 'Converted %d components into %d bright components and one image containing %d components' % (len(sc), len(brightsc), len(weaksc))) im = copy_image(model) im = insert_skycomponent(im, weaksc) return SkyModel(components=[copy_skycomponent(comp) for comp in brightsc], image=copy_image(im), mask=None, fixed=False)
def initialize_skymodel_voronoi(model, comps, gt=None): """Create a skymodel by Voronoi partitioning of the components, fill with components :param model: Model image :param comps: Skycomponents :param gt: Gaintable :return: For example:: gaintable = create_gaintable_from_blockvisibility(block_vis) mpccal_skymodel = initialize_skymodel_voronoi(model, ical_components, gaintable) """ skymodel_images = list() for i, mask in enumerate(image_voronoi_iter(model, comps)): im = copy_image(model) im.data *= mask.data if gt is not None: newgt = copy_gaintable(gt) newgt.phasecentre = comps[i].direction else: newgt = None skymodel_images.append( SkyModel(image=im, components=None, gaintable=newgt, mask=mask)) return skymodel_images
def show_skymodel(sms, psf_width=1.75, cm='Greys', vmax=None, vmin=None): """ Show a list of SkyModels :param sms: List of SkyModels :param psf_width: Width of PSF in pixels :param cm: matplotlib colormap :param vmax: Maximum in image display :param vmin: Minimum in image display :return: """ sp = 1 for ism, sm in enumerate(sms): plt.clf() plt.subplot(121, projection=sms[ism].image.wcs.sub([1, 2])) sp += 1 smodel = copy_image(sms[ism].image) smodel = insert_skycomponent(smodel, sms[ism].components) smodel = smooth_image(smodel, psf_width) if vmax is None: vmax = numpy.max(smodel.data[0, 0, ...]) if vmin is None: vmin = numpy.min(smodel.data[0, 0, ...]) plt.imshow(smodel.data[0, 0, ...], origin='lower', cmap=cm, vmax=vmax, vmin=vmin) plt.xlabel(sms[ism].image.wcs.wcs.ctype[0]) plt.ylabel(sms[ism].image.wcs.wcs.ctype[1]) plt.title('SkyModel%d' % ism) components = sms[ism].components if components is not None: for sc in components: x, y = skycoord_to_pixel(sc.direction, sms[ism].image.wcs, 0, 'wcs') plt.plot(x, y, marker='+', color='red') gaintable = sms[ism].gaintable if gaintable is not None: plt.subplot(122) sp += 1 phase = numpy.angle(sm.gaintable.gain[:, :, 0, 0, 0]) phase -= phase[:, 0][:, numpy.newaxis] plt.imshow(phase, origin='lower') plt.xlabel('Dish/Station') plt.ylabel('Integration') plt.show()
def expand_skymodel_by_skycomponents(sm, **kwargs): """ Expand a sky model so that all components and the image are in separate skymodels The mask and gaintable are taken to apply for all new skymodels. :param sm: SkyModel :return: List of SkyModels """ result = [ SkyModel(components=[comp], image=None, gaintable=copy_gaintable(sm.gaintable), mask=copy_image(sm.mask), fixed=sm.fixed) for comp in sm.components ] if sm.image is not None: result.append( SkyModel(components=None, image=copy_image(sm.image), gaintable=copy_gaintable(sm.gaintable), mask=copy_image(sm.mask), fixed=sm.fixed)) return result
def update_skymodel_from_image(sm, im, damping=0.5): """Update a skymodel for an image, applying damping factor :param sm: List of skymodels :param im: Image :return: List of SkyModels """ for i, th in enumerate(sm): newim = copy_image(im) if th.mask is not None: newim.data *= th.mask.data th.image.data += damping * newim.data return sm
def ft_ift_sm(ov, sm, g): assert isinstance(ov, Visibility) or isinstance(ov, BlockVisibility), ov assert isinstance(sm, SkyModel), sm if g is not None: assert len(g) == 2, g assert isinstance(g[0], Image), g[0] assert isinstance(g[1], ConvolutionFunction), g[1] v = copy_visibility(ov) v.data['vis'][...] = 0.0 + 0.0j if len(sm.components) > 0: if isinstance(sm.mask, Image): comps = copy_skycomponent(sm.components) comps = apply_beam_to_skycomponent(comps, sm.mask) v = dft_skycomponent_visibility(v, comps) else: v = dft_skycomponent_visibility(v, sm.components) if isinstance(sm.image, Image): if numpy.max(numpy.abs(sm.image.data)) > 0.0: if isinstance(sm.mask, Image): model = copy_image(sm.image) model.data *= sm.mask.data else: model = sm.image v = predict_list_serial_workflow([v], [model], context=context, vis_slices=vis_slices, facets=facets, gcfcf=[g], **kwargs)[0] assert isinstance(sm.image, Image), sm.image result = invert_list_serial_workflow([v], [sm.image], context=context, vis_slices=vis_slices, facets=facets, gcfcf=[g], **kwargs)[0] if isinstance(sm.mask, Image): result[0].data *= sm.mask.data return result
def calculate_skymodel_equivalent_image(sm): """Calculate an equivalent image for a skymodel Uses the image from the first skymodel as the template for the image :param sm: List of skymodels :return: Image """ combined_model = copy_image(sm[0].image) combined_model.data[...] = 0.0 for th in sm: if th.image is not None: if th.mask is not None: combined_model.data += th.mask.data * th.image.data else: combined_model.data += th.image.data return combined_model
def ft_cal_sm(ov, sm, g): assert isinstance(ov, Visibility), ov assert isinstance(sm, SkyModel), sm if g is not None: assert len(g) == 2, g assert isinstance(g[0], Image), g[0] assert isinstance(g[1], ConvolutionFunction), g[1] v = copy_visibility(ov) v.data['vis'][...] = 0.0 + 0.0j if len(sm.components) > 0: if isinstance(sm.mask, Image): comps = copy_skycomponent(sm.components) comps = apply_beam_to_skycomponent(comps, sm.mask) v = dft_skycomponent_visibility(v, comps) else: v = dft_skycomponent_visibility(v, sm.components) if isinstance(sm.image, Image): if numpy.max(numpy.abs(sm.image.data)) > 0.0: if isinstance(sm.mask, Image): model = copy_image(sm.image) model.data *= sm.mask.data else: model = sm.image v = predict_list_serial_workflow([v], [model], context=context, vis_slices=vis_slices, facets=facets, gcfcf=[g], **kwargs)[0] if docal and isinstance(sm.gaintable, GainTable): bv = convert_visibility_to_blockvisibility(v) bv = apply_gaintable(bv, sm.gaintable, inverse=True) v = convert_blockvisibility_to_visibility(bv) return v
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), "wstack requires Visibility format not BlockVisibility" if dopsf: vis = fill_vis_for_psf(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 gcf, cf = gcfcf griddata = create_griddata_from_image(im, vis) griddata, sumwt = grid_visibility_to_griddata(vis, griddata=griddata, cf=cf) cim = fft_griddata_to_image(griddata, gcf) cim = normalize_sumwt(cim, sumwt) 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) cworkimage = copy_image(cim) # cworkimage.data = numpy.conjugate(w_beam.data) * cim.data cworkimage.data = w_beam.data * cim.data workimage = convert_polimage_to_stokes(cworkimage) return workimage, sumwt
for noll in key_nolls: zernike = {'coeff': 1.0, 'noll': noll} zernike['vp'] = create_vp_generic_numeric(model, pointingcentre=None, diameter=15.0, blockage=0.0, taper='gaussian', edge=0.03162278, zernikes=[zernike], padding=2, use_local=True) zernikes.append(zernike) for trial in range(ntrials): coeffs = numpy.random.normal(0.0, 0.03, len(key_nolls)) vp = copy_image(default_vp) for i in range(len(key_nolls)): vp.data += coeffs[i] * zernikes[i]['vp'].data vp.data = vp.data / numpy.max(numpy.abs(vp.data)) vp_data = vp.data / numpy.max(numpy.abs(vp.data)) vp.data = numpy.real(vp_data) print(trial, qa_image(vp)) export = False if export: export_image_to_fits( vp, "%s/test_voltage_pattern_real_%s_trial%d.fits" % (dir, 'MID_RANDOM_ZERNIKES', trial)) row = (trial - 1) // 4
def sum_images(imagelist): out = copy_image(imagelist[0]) out.data += imagelist[1].data return out
def _test(self, time_range=None, flux=None, test_vp=False, name=""): # Set up details of simulated observation npixel = 1024 band = 'B2' frequency = [1.36e9] rmax = 1e3 self.createVis(rmax=rmax) if time_range is None: time_range = [-0.01, 0.01] time_chunk = 1800.0 integration_time = 1800.0 imaging_context = "2d" cellsize = 1e-05 vis_slices = 1 telescope = "MID_FEKO_B2" result = dict() if flux is None: flux = [[1.0, 0.0, 0.0, 0.0]] else: flux = [flux] cellsize_deg = 180.0 * cellsize / numpy.pi offset = [0.0, 0.25 - 0.3309316221544 * cellsize_deg] ra = self.phasecentre.ra.deg dec = self.phasecentre.dec.deg print(ra, dec) odirection = SkyCoord( ra=(ra + offset[0] / numpy.cos(numpy.pi * dec / 180.0)) * u.deg, dec=(dec + offset[1]) * u.deg, frame='icrs', equinox='J2000') print(self.phasecentre) print(odirection) original_components = [ Skycomponent(direction=odirection, frequency=frequency, flux=flux, polarisation_frame=PolarisationFrame('stokesIQUV')) ] for method in ["fft", "dft"]: bvis_graph = create_standard_mid_simulation_rsexecute_workflow( band, rmax, self.phasecentre, time_range, time_chunk, integration_time, polarisation_frame=PolarisationFrame("linear"), zerow=True) #imaging_context == "2d") bvis_graph = rsexecute.persist(bvis_graph) def find_vp_actual(telescope, normalise=True): vp = create_vp(telescope=telescope) if test_vp: vp.data[:, 0, ...] = 1.0 vp.data[:, 1, ...] = 0.0 vp.data[:, 2, ...] = 0.0 vp.data[:, 3, ...] = 1.0 if normalise: g = numpy.zeros([4]) g[0] = numpy.max(numpy.abs(vp.data[:, 0, ...])) g[3] = numpy.max(numpy.abs(vp.data[:, 3, ...])) g[1] = g[2] = numpy.sqrt(g[0] * g[3]) for chan in range(4): vp.data[:, chan, ...] /= g[chan] return vp future_model_list = [ rsexecute.execute(create_image_from_visibility)( bvis, npixel=npixel, frequency=frequency, nchan=1, cellsize=cellsize, phasecentre=self.phasecentre, polarisation_frame=PolarisationFrame("stokesIQUV")) for bvis in bvis_graph ] centre_model = \ [rsexecute.execute(create_image_from_visibility)(v, npixel=npixel, nchan=1, cellsize=cellsize, phasecentre=self.phasecentre, polarisation_frame=PolarisationFrame("stokesIQUV")) for v in bvis_graph] centre_model = rsexecute.persist(centre_model) # Now make all the residual images: if method == "dft": # The parallactic angle rotation is done when the voltage pattern is # converted to a gaintable def make_ejterm(model): vp = find_vp_actual(telescope=telescope) return vp vp_list = [ rsexecute.execute(make_ejterm)(centre_model[ibvis]) for ibvis, bvis in enumerate(bvis_graph) ] vp_list = rsexecute.persist(vp_list) gt_list = [ rsexecute.execute(simulate_gaintable_from_voltage_pattern)( bvis, original_components, vp_list[ibv], use_radec=False) for ibv, bvis in enumerate(bvis_graph) ] gt_list = rsexecute.persist(gt_list) dirty_list = \ calculate_residual_dft_rsexecute_workflow(bvis_graph, original_components, future_model_list, gt_list=gt_list, context=imaging_context, vis_slices=vis_slices, do_wstacking=False) dirty_list = rsexecute.persist(dirty_list) else: def make_ejterm_rotated(model, bvis): vp = find_vp_actual(telescope=telescope) pa = numpy.average( calculate_blockvisibility_parallactic_angles(bvis)) vp_rotated = convert_azelvp_to_radec(vp, model, -pa) return vp_rotated vp_list = [ rsexecute.execute(make_ejterm_rotated)(centre_model[ibvis], bvis) for ibvis, bvis in enumerate(bvis_graph) ] vp_list = rsexecute.persist(vp_list) dirty_list = \ calculate_residual_fft_rsexecute_workflow(bvis_graph, original_components, future_model_list, vp_list=vp_list, context=imaging_context, vis_slices=vis_slices, do_wstacking=False) dirty_list = rsexecute.persist(dirty_list) dirty_list = rsexecute.compute(dirty_list, sync=True) for ipol, pol in enumerate(["I", "Q", "U", "V"]): result["model_{}".format(pol)] = flux[0][ipol] polimage = copy_image(dirty_list[0]) polimage.data = polimage.data[:, ipol, ...][:, numpy.newaxis, ...] qa = qa_image(polimage, context="Stokes " + pol) result["peak_{}_{}".format(method, pol)] = max(qa.data['min'], qa.data['max'], key=abs) export_image_to_fits( dirty_list[0], "{}/test_voltage_pattern_pol_rsexecute_{}_{}.fits".format( self.dir, name, method)) if self.verbose: print(name) for ipol, pol in enumerate(["I", "Q", "U", "V"]): result["peak_diff_{}".format(pol)] = result["peak_fft_{}".format( pol)] - result["peak_dft_{}".format(pol)] result["peak_modeldiff_{}".format(pol)] = result[ "peak_dft_{}".format(pol)] - result["model_{}".format(pol)] if self.verbose: print( "{} model: {:.2f} fft: {:.6f} dft: {:.6f} fft - dft: {:.6f} dft - model: {:.6f}" .format(pol, result["model_{}".format(pol)], result["peak_fft_{}".format(pol)], result["peak_dft_{}".format(pol)], result["peak_diff_{}".format(pol)], result["peak_modeldiff_{}".format(pol)])) return result