def convert_blockvisibility_to_visibility(vis: BlockVisibility) -> Visibility: """ Convert the BlockVisibility data with no coalescence :param vis: BlockVisibility to be converted :return: Visibility with cindex and blockvis filled in """ assert isinstance( vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis cvis, cuvw, cwts, ctime, cfrequency, cchannel_bandwidth, ca1, ca2, cintegration_time, cindex \ = convert_blocks(vis.data['vis'], vis.data['uvw'], vis.data['weight'], vis.time, vis.integration_time, vis.frequency, vis.channel_bandwidth) cimwt = numpy.ones(cvis.shape) converted_vis = Visibility(uvw=cuvw, time=ctime, frequency=cfrequency, channel_bandwidth=cchannel_bandwidth, phasecentre=vis.phasecentre, antenna1=ca1, antenna2=ca2, vis=cvis, weight=cwts, imaging_weight=cimwt, configuration=vis.configuration, integration_time=cintegration_time, polarisation_frame=vis.polarisation_frame, cindex=cindex, blockvis=vis) log.debug('convert_visibility: Original %s, converted %s' % (vis_summary(vis), vis_summary(converted_vis))) return converted_vis
def convert_hdf_to_visibility(f): """ Convert HDF root to visibility :param f: :return: """ assert f.attrs['ARL_data_model'] == "Visibility", "Not a Visibility" s = f.attrs['phasecentre_coords'].split() ss = [float(s[0]), float(s[1])] * u.deg phasecentre = SkyCoord(ra=ss[0], dec=ss[1], frame=f.attrs['phasecentre_frame']) polarisation_frame = PolarisationFrame(f.attrs['polarisation_frame']) data = numpy.array(f['data']) vis = Visibility(data=data, polarisation_frame=polarisation_frame, phasecentre=phasecentre) vis.configuration = convert_configuration_from_hdf(f) return vis
def visibility_gather(visibility_list: List[Visibility], vis: Visibility, vis_iter, vis_slices=None) -> Visibility: """Gather a list of subvisibilities back into a visibility The iterator setup must be the same as used in the scatter. :param visibility_list: List of subvisibilities :param vis: Output visibility :param vis_iter: visibility iterator :param vis_slices: Number of slices to be gathered (optional) :return: vis """ if vis_slices == 1: return visibility_list[0] if vis_slices is None: vis_slices = len(visibility_list) rowses = [] for i, rows in enumerate(vis_iter(vis, vis_slices=vis_slices)): rowses.append(rows) for i, rows in enumerate(rowses): assert i < len(visibility_list ), "Gather not consistent with scatter for slice %d" % i if visibility_list[i] is not None and numpy.sum(rows): assert numpy.sum(rows) == visibility_list[i].nvis, \ "Mismatch in number of rows (%d, %d) in gather for slice %d" % \ (numpy.sum(rows), visibility_list[i].nvis, i) vis.data[rows] = visibility_list[i].data[...] return vis
def weight_visibility(vis: Visibility, im: Image, **kwargs) -> Visibility: """ Reweight the visibility data using a selected algorithm Imaging uses the column "imaging_weight" when imaging. This function sets that column using a variety of algorithms Options are: - Natural: by visibility weight (optimum for noise in final image) - Uniform: weight of sample divided by sum of weights in cell (optimum for sidelobes) - Super-uniform: As uniform, by sum of weights is over extended box region - Briggs: Compromise between natural and uniform - Super-briggs: As Briggs, by sum of weights is over extended box region :param vis: :param im: :return: visibility with imaging_weights column added and filled """ assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis assert get_parameter(kwargs, "padding", False) is False spectral_mode, vfrequencymap = get_frequency_map(vis, im) polarisation_mode, vpolarisationmap = get_polarisation_map(vis, im) uvw_mode, shape, padding, vuvwmap = get_uvw_map(vis, im) density = None densitygrid = None weighting = get_parameter(kwargs, "weighting", "uniform") vis.data['imaging_weight'], density, densitygrid = weight_gridding( im.data.shape, vis.data['weight'], vuvwmap, vfrequencymap, vpolarisationmap, weighting) return vis, density, densitygrid
def shift_vis_to_image(vis: Visibility, im: Image, tangent: bool = True, inverse: bool = False) \ -> Visibility: """Shift visibility to the FFT phase centre of the image in place :param vis: Visibility data :param im: Image model used to determine phase centre :param tangent: Is the shift purely on the tangent plane True|False :param inverse: Do the inverse operation True|False :return: visibility with phase shift applied and phasecentre updated """ assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis nchan, npol, ny, nx = im.data.shape # Convert the FFT definition of the phase center to world coordinates (1 relative) # This is the only place in ARL where the relationship between the image and visibility # frames is defined. image_phasecentre = pixel_to_skycoord(nx // 2 + 1, ny // 2 + 1, im.wcs, origin=1) if vis.phasecentre.separation(image_phasecentre).rad > 1e-15: if inverse: log.debug("shift_vis_from_image: shifting phasecentre from image phase centre %s to visibility phasecentre " "%s" % (image_phasecentre, vis.phasecentre)) else: log.debug("shift_vis_from_image: shifting phasecentre from vis phasecentre %s to image phasecentre %s" % (vis.phasecentre, image_phasecentre)) vis = phaserotate_visibility(vis, image_phasecentre, tangent=tangent, inverse=inverse) vis.phasecentre = im.phasecentre assert isinstance(vis, Visibility), "after phase_rotation, vis is not a Visibility" return vis
def taper_visibility_tukey(vis: Visibility, tukey=0.1) -> Visibility: """ Taper the visibility weights This algorithm is present in WSClean. See https://sourceforge.net/p/wsclean/wiki/Tapering tukey, a circular taper that smooths the outer edge set by -maxuv-l inner-tukey, a circular taper that smooths the inner edge set by -minuv-l edge-tukey, a square-shaped taper that smooths the edge set by the uv grid and -taper-edge. These are cumulative. If You can reset the imaging_weights using :py:mod:`processing_library.imaging.weighting.weight_visibility` :param vis: Visibility with imaging_weight's to be tapered :return: visibility with imaging_weight column modified """ assert isinstance(vis, Visibility), vis uvdist = numpy.sqrt(vis.u**2 + vis.v**2) uvdistmax = numpy.max(uvdist) uvdist /= uvdistmax wt = numpy.array([tukey_filter(uv, tukey) for uv in uvdist]) vis.data['imaging_weight'][:, :] = vis.imaging_weight[:, :] * wt[:, numpy. newaxis] return vis
def coalesce_visibility(vis: BlockVisibility, **kwargs) -> Visibility: """ Coalesce the BlockVisibility data_models. The output format is a Visibility, as needed for imaging Coalesce by baseline-dependent averaging (optional). The number of integrations averaged goes as the ratio of the maximum possible baseline length to that for this baseline. This number can be scaled by coalescence_factor and limited by max_coalescence. When faceting, the coalescence factors should be roughly the same as the number of facets on one axis. If coalescence_factor=0.0 then just a format conversion is done :param vis: BlockVisibility to be coalesced :return: Coalesced visibility with cindex and blockvis filled in """ assert isinstance( vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis time_coal = get_parameter(kwargs, 'time_coal', 0.0) max_time_coal = get_parameter(kwargs, 'max_time_coal', 100) frequency_coal = get_parameter(kwargs, 'frequency_coal', 0.0) max_frequency_coal = get_parameter(kwargs, 'max_frequency_coal', 100) if time_coal == 0.0 and frequency_coal == 0.0: return convert_blockvisibility_to_visibility((vis)) cvis, cuvw, cwts, cimwt, ctime, cfrequency, cchannel_bandwidth, ca1, ca2, cintegration_time, cindex \ = average_in_blocks(vis.data['vis'], vis.data['uvw'], vis.data['weight'], vis.data['imaging_weight'], vis.time, vis.integration_time, vis.frequency, vis.channel_bandwidth, time_coal, max_time_coal, frequency_coal, max_frequency_coal) coalesced_vis = Visibility(uvw=cuvw, time=ctime, frequency=cfrequency, channel_bandwidth=cchannel_bandwidth, phasecentre=vis.phasecentre, antenna1=ca1, antenna2=ca2, vis=cvis, weight=cwts, imaging_weight=cimwt, configuration=vis.configuration, integration_time=cintegration_time, polarisation_frame=vis.polarisation_frame, cindex=cindex, blockvis=vis, meta=vis.meta) log.debug( 'coalesce_visibility: Created new Visibility for coalesced data_models, coalescence factors (t,f) = (%.3f,%.3f)' % (time_coal, frequency_coal)) log.debug('coalesce_visibility: Maximum coalescence (t,f) = (%d, %d)' % (max_time_coal, max_frequency_coal)) log.debug('coalesce_visibility: Original %s, coalesced %s' % (vis_summary(vis), vis_summary(coalesced_vis))) return coalesced_vis
def helper_create_visibility_object(c_vis): # This may be incorrect # especially the data field... tvis = Visibility(data=c_vis, frequency=c_vis['frequency'], channel_bandwidth=c_vis['channel_bandwidth'], integration_time=c_vis['integration_time'], antenna1=c_vis['antenna1'], antenna2=c_vis['antenna2'], weight=c_vis['weight'], imaging_weight=c_vis['imaging_weight'], uvw=c_vis['uvw'], time=c_vis['time']) return tvis
def convert_visibility_to_stokesI(vis): """Convert the polarisation frame data into Stokes I dropping other polarisations, return new Visibility Args: vis (obj): ARL visibility data. Returns: vis: New, converted visibility data. """ polarisation_frame = PolarisationFrame('stokesI') poldef = vis.polarisation_frame if poldef == PolarisationFrame('linear'): vis_data = convert_linear_to_stokesI(vis.data['vis']) vis_weight = (vis.weight[..., 0] + vis.weight[..., 3])[..., numpy.newaxis] vis_imaging_weight = (vis.imaging_weight[..., 0] + vis.imaging_weight[..., 3])[..., numpy.newaxis] elif poldef == PolarisationFrame('circular'): vis_data = convert_circular_to_stokesI(vis.data['vis']) vis_weight = (vis.weight[..., 0] + vis.weight[..., 3])[..., numpy.newaxis] vis_imaging_weight = (vis.imaging_weight[..., 0] + vis.imaging_weight[..., 3])[..., numpy.newaxis] else: raise NameError("Polarisation frame %s unknown" % poldef) return Visibility(frequency=vis.frequency, channel_bandwidth=vis.channel_bandwidth, phasecentre=vis.phasecentre, configuration=vis.configuration, uvw=vis.uvw, time=vis.time, antenna1=vis.antenna1, antenna2=vis.antenna2, vis=vis_data, weight=vis_weight, imaging_weight=vis_imaging_weight, integration_time=vis.integration_time, polarisation_frame=polarisation_frame, cindex=vis.cindex, blockvis=vis.blockvis, source=vis.source, meta=vis.meta)
def visibility_gather_channel(vis_list: List[Visibility], vis: Visibility = None): """ Gather a visibility by channel :param vis_list: :param vis: :return: """ cols = ['vis', 'weight'] if vis is None: vis_shape = numpy.array(vis_list[0].vis.shape) vis_shape[-2] = len(vis_list) for v in vis_list: assert len(v.frequency) == 1 assert len(v.channel_bandwidth) == 1 vis = BlockVisibility(data=None, frequency=numpy.array([v.frequency[0] for v in vis_list]), channel_bandwidth=numpy.array([v.channel_bandwidth[0] for v in vis_list]), phasecentre=vis_list[0].phasecentre, configuration=vis_list[0].configuration, uvw=vis_list[0].uvw, time=vis_list[0].time, vis=numpy.zeros(vis_shape, dtype=vis_list[0].vis.dtype), weight=numpy.ones(vis_shape, dtype=vis_list[0].weight.dtype), integration_time=vis_list[0].integration_time, polarisation_frame=vis_list[0].polarisation_frame) assert len(vis.frequency) == len(vis_list) for chan, _ in enumerate(vis_list): subvis = vis_list[chan] assert abs(subvis.frequency[0] - vis.frequency[chan]) < 1e-15 for col in cols: vis.data[col][..., chan, :] = subvis.data[col][..., 0, :] vis.frequency[chan] = subvis.frequency[0] nchan = vis.vis.shape[-2] assert nchan == len(vis.frequency) return vis
def taper_visibility_gaussian(vis: Visibility, beam=None) -> Visibility: """ Taper the visibility weights These are cumulative. If You can reset the imaging_weights using :py:mod:`processing_library.imaging.weighting.weight_visibility` :param vis: Visibility with imaging_weight's to be tapered :param beam: desired resolution (Full width half maximum, radians) :return: visibility with imaging_weight column modified """ assert isinstance(vis, Visibility), vis if beam is None: raise ValueError("Beam size not specified for Gaussian taper") uvdistsq = vis.u**2 + vis.v**2 # See http://mathworld.wolfram.com/FourierTransformGaussian.html scale_factor = numpy.pi**2 * beam**2 / (4.0 * numpy.log(2.0)) prior = vis.imaging_weight[:, :] wt = numpy.exp(-scale_factor * uvdistsq) vis.data['imaging_weight'][:, :] = vis.imaging_weight[:, :] * wt[:, numpy. newaxis] return vis
def import_visibility_from_oskar(oskar_file: str) -> Visibility: """ Import a visibility set from an OSKAR visibility file :param oskar_file: Name of OSKAR visibility file :returns: Visibility """ # Extract data from Oskar file oskar_vis = OskarVis(oskar_file) ra, dec = oskar_vis.phase_centre() a1, a2 = oskar_vis.stations(flatten=True) # Make configuration location = EarthLocation(lon=oskar_vis.telescope_lon, lat=oskar_vis.telescope_lat, height=oskar_vis.telescope_alt) antxyz = numpy.transpose([oskar_vis.station_x, oskar_vis.station_y, oskar_vis.station_z]) config = Configuration( name=oskar_vis.telescope_path, location=location, xyz=antxyz ) # Construct visibilities return Visibility( frequency=[oskar_vis.frequency(i) for i in range(oskar_vis.num_channels)], phasecentre=SkyCoord(frame=ICRS, ra=ra, dec=dec, unit=u.deg), configuration=config, uvw=numpy.transpose(oskar_vis.uvw(flatten=True)), time=oskar_vis.times(flatten=True), antenna1=a1, antenna2=a2, vis=oskar_vis.amplitudes(flatten=True), weight=numpy.ones(a1.shape))
def create_visibility(config: Configuration, times: numpy.array, frequency: numpy.array, channel_bandwidth, phasecentre: SkyCoord, weight: float, polarisation_frame=PolarisationFrame('stokesI'), integration_time=1.0, zerow=False) -> Visibility: """ Create a Visibility from Configuration, hour angles, and direction of source Note that we keep track of the integration time for BDA purposes :param config: Configuration of antennas :param times: hour angles in radians :param frequency: frequencies (Hz] [nchan] :param weight: weight of a single sample :param phasecentre: phasecentre of observation :param channel_bandwidth: channel bandwidths: (Hz] [nchan] :param integration_time: Integration time ('auto' or value in s) :param polarisation_frame: PolarisationFrame('stokesI') :return: Visibility """ assert phasecentre is not None, "Must specify phase centre" if polarisation_frame is None: polarisation_frame = correlate_polarisation(config.receptor_frame) nch = len(frequency) ants_xyz = config.data['xyz'] nants = len(config.data['names']) nbaselines = int(nants * (nants - 1) / 2) ntimes = len(times) npol = polarisation_frame.npol nrows = nbaselines * ntimes * nch nrowsperintegration = nbaselines * nch row = 0 rvis = numpy.zeros([nrows, npol], dtype='complex') rweight = weight * numpy.ones([nrows, npol]) rtimes = numpy.zeros([nrows]) rfrequency = numpy.zeros([nrows]) rchannel_bandwidth = numpy.zeros([nrows]) rantenna1 = numpy.zeros([nrows], dtype='int') rantenna2 = numpy.zeros([nrows], dtype='int') ruvw = numpy.zeros([nrows, 3]) # Do each hour angle in turn for iha, ha in enumerate(times): # Calculate the positions of the antennas as seen for this hour angle # and declination ant_pos = xyz_to_uvw(ants_xyz, ha, phasecentre.dec.rad) rtimes[row:row + nrowsperintegration] = ha * 43200.0 / numpy.pi # Loop over all pairs of antennas. Note that a2>a1 for a1 in range(nants): for a2 in range(a1 + 1, nants): rantenna1[row:row + nch] = a1 rantenna2[row:row + nch] = a2 # Loop over all frequencies and polarisations for ch in range(nch): # noinspection PyUnresolvedReferences k = frequency[ch] / constants.c.value ruvw[row, :] = (ant_pos[a2, :] - ant_pos[a1, :]) * k rfrequency[row] = frequency[ch] rchannel_bandwidth[row] = channel_bandwidth[ch] row += 1 if zerow: ruvw[..., 2] = 0.0 assert row == nrows rintegration_time = numpy.full_like(rtimes, integration_time) vis = Visibility(uvw=ruvw, time=rtimes, antenna1=rantenna1, antenna2=rantenna2, frequency=rfrequency, vis=rvis, weight=rweight, imaging_weight=rweight, integration_time=rintegration_time, channel_bandwidth=rchannel_bandwidth, polarisation_frame=polarisation_frame) vis.phasecentre = phasecentre vis.configuration = config log.info("create_visibility: %s" % (vis_summary(vis))) assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis return vis
def create_visibility_from_ms(msname, channum=0, ack=False): """ Minimal MS to Visibility converter The MS format is much more general than the ARL Visibility so we cut many corners. This requires casacore to be installed. If not an exception ModuleNotFoundError is raised. Creates a list of Visibilities, one per phasecentre """ try: from casacore.tables import table # pylint: disable=import-error except ModuleNotFoundError: raise ModuleNotFoundError("casacore is not installed") tab = table(msname, ack=ack) log.debug("create_visibility_from_ms: %s" % str(tab.info())) fields = numpy.unique(tab.getcol('FIELD_ID')) log.debug("create_visibility_from_ms: Found unique field ids %s" % str(fields)) vis_list = list() for field in fields: # First get the main table information ms = tab.query("FIELD_ID==%d" % field) log.debug("create_visibility_from_ms: Found %d rows for field %d" % (ms.nrows(), field)) time = ms.getcol('TIME') channels = len(numpy.transpose(ms.getcol('DATA'))[0]) log.debug("create_visibility_from_ms: Found %d channels" % (channels)) try: vis = ms.getcol('DATA')[:, channum, :] except IndexError: raise IndexError("channel number exceeds max. within ms") weight = ms.getcol('WEIGHT') uvw = -1 * ms.getcol('UVW') antenna1 = ms.getcol('ANTENNA1') antenna2 = ms.getcol('ANTENNA2') integration_time = ms.getcol('INTERVAL') ddid = ms.getcol('DATA_DESC_ID') # Now get info from the subtables spwtab = table('%s/SPECTRAL_WINDOW' % msname, ack=False) cfrequency = spwtab.getcol('CHAN_FREQ') frequency = numpy.array([cfrequency[dd] for dd in ddid])[:, channum] cchannel_bandwidth = spwtab.getcol('CHAN_WIDTH') channel_bandwidth = numpy.array( [cchannel_bandwidth[dd] for dd in ddid])[:, 0] uvw *= frequency[:, numpy.newaxis] / constants.c.to('m s^-1').value # Get polarisation info poltab = table('%s/POLARIZATION' % msname, ack=False) corr_type = poltab.getcol('CORR_TYPE') # These correspond to the CASA Stokes enumerations if numpy.array_equal(corr_type[0], [1, 2, 3, 4]): polarisation_frame = PolarisationFrame('stokesIQUV') elif numpy.array_equal(corr_type[0], [5, 6, 7, 8]): polarisation_frame = PolarisationFrame('circular') elif numpy.array_equal(corr_type[0], [9, 10, 11, 12]): polarisation_frame = PolarisationFrame('linear') else: raise KeyError("Polarisation not understood: %s" % str(corr_type)) print("create_visibility_from_ms: polarisation %s" % polarisation_frame.type) # Get configuration anttab = table('%s/ANTENNA' % msname, ack=False) mount = anttab.getcol('MOUNT') names = anttab.getcol('NAME') diameter = anttab.getcol('DISH_DIAMETER') xyz = anttab.getcol('POSITION') configuration = Configuration(name='', data=None, location=None, names=names, xyz=xyz, mount=mount, frame=None, receptor_frame=ReceptorFrame("linear"), diameter=diameter) # Get phasecentres fieldtab = table('%s/FIELD' % msname, ack=False) pc = fieldtab.getcol('PHASE_DIR')[field, 0, :] phasecentre = SkyCoord(ra=[pc[0]] * u.rad, dec=pc[1] * u.rad, frame='icrs', equinox='J2000') vis_list.append( Visibility(uvw=uvw, time=time, antenna1=antenna1, antenna2=antenna2, frequency=frequency, vis=vis, weight=weight, imaging_weight=weight, integration_time=integration_time, channel_bandwidth=channel_bandwidth, configuration=configuration, phasecentre=phasecentre, polarisation_frame=polarisation_frame)) return vis_list
def create_visibility_from_ms_maps(msname, poldef): """ Minimal MS to Visibility converter The MS format is much more general than the ARL Visibility so we cut many corners. This requires casacore to be installed. If not an exception ModuleNotFoundError is raised. Creates a list of Visibilities, one per phasecentre """ try: from casacore.tables import table # pylint: disable=import-error except ModuleNotFoundError: raise ModuleNotFoundError("casacore is not installed") tab = table(msname) print(tab.info()) fields = numpy.unique(tab.getcol('FIELD_ID')) print("Found unique field ids %s" % fields) # for field in fields: # First get the main table information ms = tab.query("FIELD_ID==%d" % fields[0]) print("Found %d rows for field %d" % (ms.nrows(), fields[0])) time = ms.getcol('TIME') weight = ms.getcol('WEIGHT') uvw = -1 * ms.getcol('UVW') antenna1 = ms.getcol('ANTENNA1') antenna2 = ms.getcol('ANTENNA2') integration_time = ms.getcol('INTERVAL') ddid = ms.getcol('DATA_DESC_ID') # Get polarisation info # poltab = table('%s/POLARIZATION' % msname, ack=False) # corr_type = poltab.getcol('CORR_TYPE') # TODO: Do interpretation correctly # polarisation_frame = PolarisationFrame('stokesIQUV') # Set the polarisation frame: if poldef == 'lin': polarisation_frame = PolarisationFrame('linear') if poldef == 'circ': polarisation_frame = PolarisationFrame('circular') # Get configuration anttab = table('%s/ANTENNA' % msname, ack=False) mount = anttab.getcol('MOUNT') names = anttab.getcol('NAME') diameter = anttab.getcol('DISH_DIAMETER') xyz = anttab.getcol('POSITION') configuration = Configuration(name='', data=None, location=None, names=names, xyz=xyz, mount=mount, frame=None, receptor_frame=ReceptorFrame("linear"), diameter=diameter) # Get phasecentres fieldtab = table('%s/FIELD' % msname, ack=False) pc = fieldtab.getcol('PHASE_DIR')[fields[0], 0, :] print(pc[0], pc[1]) phasecentre = SkyCoord(ra=[pc[0]] * u.rad, dec=pc[1] * u.rad, frame='icrs', equinox='J2000') channels = len(numpy.transpose(ms.getcol('DATA'))[0]) print("Found %d channels" % (channels)) spwtab = table('%s/SPECTRAL_WINDOW' % msname, ack=False) cfrequency = spwtab.getcol('CHAN_FREQ') cchannel_bandwidth = spwtab.getcol('CHAN_WIDTH') channel_bandwidth = numpy.array([cchannel_bandwidth[dd] for dd in ddid])[:, 0] # Now get info from the subtables maps_data = list() for channum in range(channels): try: vis = ms.getcol('DATA')[:, channum, :] except IndexError: raise IndexError("channel number exceeds max. within ms") frequency = numpy.array([cfrequency[dd] for dd in ddid])[:, channum] uvw *= frequency[:, numpy.newaxis] / constants.c.to('m/s').value vis_list = Visibility(uvw=uvw, time=time, antenna1=antenna1, antenna2=antenna2, frequency=frequency, vis=vis, weight=weight, imaging_weight=weight, integration_time=integration_time, channel_bandwidth=channel_bandwidth, configuration=configuration, phasecentre=phasecentre, polarisation_frame=polarisation_frame) maps_data.append(vis_list) return maps_data