def create_configuration_from_file(antfile: str, location: EarthLocation = None, mount: str = 'altaz', names: str = "%d", frame: str = 'local', diameter=35.0, rmax=None, name='') -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param location: :param mount: mount type: 'altaz', 'xy' :param frame: 'local' | 'global' :param diameter: Effective diameter of station or antenna :return: Configuration """ antxyz = numpy.genfromtxt(antfile, delimiter=",") assert antxyz.shape[1] == 3, ("Antenna array has wrong shape %s" % antxyz.shape) if frame == 'local': latitude = location.geodetic[1].to(u.rad).value antxyz = xyz_at_latitude(antxyz, latitude) if rmax is not None: lantxyz = antxyz - numpy.average(antxyz, axis=0) r = numpy.sqrt(lantxyz[:, 0] ** 2 + lantxyz[:, 1] ** 2 + lantxyz[:, 2] ** 2) antxyz = antxyz[r < rmax] log.debug('create_configuration_from_file: Maximum radius %.1f m includes %d antennas/stations' % (rmax, antxyz.shape[0])) nants = antxyz.shape[0] anames = [names % ant for ant in range(nants)] mounts = numpy.repeat(mount, nants) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, frame=frame, diameter=diameter, name=name) return fc
def create_LOFAR_configuration(antfile: str, location, rmax=1e6) -> Configuration: """ Define from the LOFAR configuration file :param antfile: :return: Configuration """ antxyz = numpy.genfromtxt(antfile, skip_header=2, usecols=[1, 2, 3], delimiter=",") nants = antxyz.shape[0] assert antxyz.shape[ 1] == 3, "Antenna array has wrong shape %s" % antxyz.shape anames = numpy.genfromtxt(antfile, dtype='str', skip_header=2, usecols=[0], delimiter=",") mounts = numpy.repeat('XY', nants) diameters = numpy.repeat(35.0, nants) antxyz, diameters, mounts, anames = limit_rmax(antxyz, diameters, anames, mounts, rmax) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, diameter=diameters, name='LOFAR') return fc
def create_LOFAR_configuration(antfile: str) -> Configuration: """ Define from the LOFAR configuration file :param antfile: :return: Configuration """ antxyz = numpy.genfromtxt(antfile, skip_header=2, usecols=[1, 2, 3], delimiter=",") nants = antxyz.shape[0] assert antxyz.shape[ 1] == 3, "Antenna array has wrong shape %s" % antxyz.shape anames = numpy.genfromtxt(antfile, dtype='str', skip_header=2, usecols=[0], delimiter=",") mounts = numpy.repeat('XY', nants) location = EarthLocation(x=[3826923.9] * u.m, y=[460915.1] * u.m, z=[5064643.2] * u.m) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, frame='global', diameter=35.0, name='LOFAR') return fc
def convert_configuration_from_hdf(f): """ Extyract configuration from HDF :param f: :return: """ cf = f['configuration'] assert cf.attrs[ 'ARL_data_model'] == "Configuration", "%s is a Configuration" % cf.attrs[ 'ARL_data_model'] name = cf.attrs['name'] location = convert_earthlocation_from_string(cf.attrs['location']) frame = cf.attrs['frame'] receptor_frame = cf.attrs['receptor_frame'] xyz = cf['configuration/xyz'] diameter = cf['configuration/diameter'] names = [str(n) for n in cf['configuration/names']] mount = [str(m) for m in cf['configuration/mount']] return Configuration(name=name, location=location, frame=frame, receptor_frame=receptor_frame, xyz=xyz, diameter=diameter, names=names, mount=mount)
def create_configuration_from_MIDfile(antfile: str, location=None, mount: str = 'azel', rmax=None, name='') -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param mount: mount type: 'azel', 'xy' :return: Configuration """ # X Y Z Diam Station # 9.36976 35.48262 1052.99987 13.50 M001 antxyz = numpy.genfromtxt(antfile, skip_header=5, usecols=[0, 1, 2], delimiter=" ") antxyz = xyz_at_latitude(antxyz, location.lat.rad) antxyz += [ location.geocentric[0].to(u.m).value, location.geocentric[1].to(u.m).value, location.geocentric[2].to(u.m).value ] nants = antxyz.shape[0] assert antxyz.shape[ 1] == 3, "Antenna array has wrong shape %s" % antxyz.shape anames = numpy.genfromtxt(antfile, dtype='str', skip_header=5, usecols=[4], delimiter=" ") mounts = numpy.repeat(mount, nants) diameters = numpy.genfromtxt(antfile, dtype='str', skip_header=5, usecols=[3], delimiter=" ") antxyz, diameters, anames, mounts = limit_rmax(antxyz, diameters, anames, mounts, rmax) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, diameter=diameters, name=name) return fc
def create_configuration_from_SKAfile(antfile: str, mount: str = 'azel', names: str = "%d", rmax=None, name='', location=None) -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param location: :param mount: mount type: 'azel', 'xy', 'equatorial' :param diameter: Effective diameter of station or antenna :return: Configuration """ antdiamlonglat = numpy.genfromtxt(antfile, usecols=[0, 1, 2], delimiter="\t") assert antdiamlonglat.shape[1] == 3, ("Antenna array has wrong shape %s" % antdiamlonglat.shape) antxyz = numpy.zeros([antdiamlonglat.shape[0] - 1, 3]) diameters = numpy.zeros([antdiamlonglat.shape[0] - 1]) for ant in range(antdiamlonglat.shape[0] - 1): loc = EarthLocation(lon=antdiamlonglat[ant, 1], lat=antdiamlonglat[ant, 2], height=0.0).geocentric antxyz[ant] = [ loc[0].to(u.m).value, loc[1].to(u.m).value, loc[2].to(u.m).value ] diameters[ant] = antdiamlonglat[ant, 0] nants = antxyz.shape[0] anames = [names % ant for ant in range(nants)] mounts = numpy.repeat(mount, nants) antxyz, diameters, anames, mounts = limit_rmax(antxyz, diameters, anames, mounts, rmax) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, diameter=diameters, name=name) return fc
def create_configuration_from_SKAfile(antfile: str, mount: str = 'altaz', names: str = "%d", rmax=None, name='') -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param mount: mount type: 'altaz', 'xy' :return: Configuration """ # Diameter, longitude, latitude # 15.00 21.44241720 -30.7342510 # 35 116.7644482 -26.82472208 antdiamlonglat = numpy.genfromtxt(antfile, skip_header=0, usecols=[0, 1, 2], delimiter="\t") assert antdiamlonglat.shape[1] == 3, ("Antenna array has wrong shape %s" % antdiamlonglat.shape) antxyz = numpy.zeros([antdiamlonglat.shape[0] - 1, 3]) diameters = numpy.zeros([antdiamlonglat.shape[0] - 1]) location = EarthLocation(lon=antdiamlonglat[-1, 1], lat=antdiamlonglat[-1, 2], height=0.0) for ant in range(antdiamlonglat.shape[0] - 1): loc = EarthLocation(lon=antdiamlonglat[ant, 1], lat=antdiamlonglat[ant, 2], height=0.0).geocentric antxyz[ant] = [loc[0].to(u.m).value, loc[1].to(u.m).value, loc[2].to(u.m).value] diameters[ant] = antdiamlonglat[ant, 0] if rmax is not None: lantxyz = antxyz - numpy.average(antxyz, axis=0) r = numpy.sqrt(lantxyz[:, 0] ** 2 + lantxyz[:, 1] ** 2 + lantxyz[:, 2] ** 2) antxyz = antxyz[r < rmax] log.debug('create_configuration_from_file: Maximum radius %.1f m includes %d antennas/stations' % (rmax, antxyz.shape[0])) diameters = diameters[r < rmax] else: log.debug('create_configuration_from_file: %d antennas/stations' % (antxyz.shape[0])) nants = antxyz.shape[0] anames = [names % ant for ant in range(nants)] mounts = numpy.repeat(mount, nants) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, frame='global', diameter=diameters, name=name) return fc
def create_configuration_from_file(antfile: str, location: EarthLocation = None, mount: str = 'azel', names: str = "%d", diameter=35.0, rmax=None, name='') -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param location: :param mount: mount type: 'azel', 'xy', 'equatorial' :param diameter: Effective diameter of station or antenna :return: Configuration """ antxyz = numpy.genfromtxt(antfile, delimiter=",") assert antxyz.shape[1] == 3, ("Antenna array has wrong shape %s" % antxyz.shape) latitude = location.geodetic[1].to(u.rad).value antxyz = xyz_at_latitude(antxyz, latitude) antxyz += [ location.geocentric[0].to(u.m).value, location.geocentric[1].to(u.m).value, location.geocentric[2].to(u.m).value ] nants = antxyz.shape[0] diameters = diameter * numpy.ones(nants) anames = [names % ant for ant in range(nants)] mounts = numpy.repeat(mount, nants) antxyz, diameters, anames, mounts = limit_rmax(antxyz, diameters, anames, mounts, rmax) fc = Configuration(location=location, names=anames, mount=mounts, xyz=antxyz, diameter=diameters, name=name) return fc
def create_configuration_from_MIDfile(antfile: str, location=None, mount: str = 'altaz', rmax=None, name='') -> Configuration: """ Define from a file :param names: Antenna names :param antfile: Antenna file name :param mount: mount type: 'altaz', 'xy' :return: Configuration """ # X Y Z Diam Station # 5109237.714735 2006795.661955 -3239109.183708 13.5 M000 antdiamlonglat = numpy.genfromtxt(antfile, skip_header=5, usecols=[0, 1, 2, 3, 4], delimiter=" ", dtype="f8, f8, " "f8, f8, S8") antxyz = numpy.zeros([len(antdiamlonglat), 3]) diameters = numpy.zeros([len(antdiamlonglat)]) names = list() for ant, line in enumerate(antdiamlonglat): lline=list(line) antxyz[ant, :] = lline[0:3] diameters[ant] = lline[3] names.append(lline[4]) if rmax is not None: lantxyz = antxyz - numpy.average(antxyz, axis=0) r = numpy.sqrt(lantxyz[:, 0] ** 2 + lantxyz[:, 1] ** 2 + lantxyz[:, 2] ** 2) antxyz = antxyz[r < rmax] log.debug('create_configuration_from_file: Maximum radius %.1f m includes %d antennas/stations' % (rmax, antxyz.shape[0])) diameters = diameters[r < rmax] names = numpy.array(names)[r < rmax] else: log.debug('create_configuration_from_file: %d antennas/stations' % (antxyz.shape[0])) nants = antxyz.shape[0] mounts = numpy.repeat(mount, nants) fc = Configuration(location=location, names=names, mount=mounts, xyz=antxyz, frame='global', diameter=diameters, name=name) return fc
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_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_blockvisibility_from_ms(msname, channum=None, ack=False): """ Minimal MS to BlockVisibility converter The MS format is much more general than the ARL BlockVisibility so we cut many corners. This requires casacore to be installed. If not an exception ModuleNotFoundError is raised. Creates a list of BlockVisibility's, split by field and spectral window :param msname: File name of MS :param channum: range of channels e.g. range(17,32), default is None meaning all :return: """ 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_blockvisibility_from_ms: %s" % str(tab.info())) fields = numpy.unique(tab.getcol('FIELD_ID')) dds = numpy.unique(tab.getcol('DATA_DESC_ID')) log.debug( "create_blockvisibility_from_ms: Found unique fields %s, unique data descriptions %s" % (str(fields), str(dds))) vis_list = list() for dd in dds: dtab = table(msname, ack=ack).query('DATA_DESC_ID==%d' % dd, style='') for field in fields: ms = dtab.query('FIELD_ID==%d' % field, style='') assert ms.nrows( ) > 0, "Empty selection for FIELD_ID=%d and DATA_DESC_ID=%d" % ( field, dd) log.debug("create_blockvisibility_from_ms: Found %d rows" % (ms.nrows())) time = ms.getcol('TIME') channels = ms.getcol('DATA').shape[-2] log.debug("create_visibility_from_ms: Found %d channels" % (channels)) if channum is None: channum = range(channels) try: ms_vis = ms.getcol('DATA')[:, channum, :] ms_weight = ms.getcol('WEIGHT')[:, :] except IndexError: raise IndexError("channel number exceeds max. within ms") uvw = -1 * ms.getcol('UVW') antenna1 = ms.getcol('ANTENNA1') antenna2 = ms.getcol('ANTENNA2') integration_time = ms.getcol('INTERVAL') # Now get info from the subtables spwtab = table('%s/SPECTRAL_WINDOW' % msname, ack=False) cfrequency = spwtab.getcol('CHAN_FREQ')[dd][channum] cchannel_bandwidth = spwtab.getcol('CHAN_WIDTH')[dd][channum] nchan = cfrequency.shape[0] # 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)) npol = 4 # Get configuration anttab = table('%s/ANTENNA' % msname, ack=False) nants = anttab.nrows() 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') bv_times = numpy.unique(time) ntimes = len(bv_times) bv_vis = numpy.zeros([ntimes, nants, nants, nchan, npol]).astype('complex') bv_weight = numpy.zeros([ntimes, nants, nants, nchan, npol]) bv_uvw = numpy.zeros([ntimes, nants, nants, 3]) time_last = time[0] time_index = 0 for row, _ in enumerate(ms_vis): # MS has shape [row, npol, nchan] # BV has shape [ntimes, nants, nants, nchan, npol] if time[row] != time_last: assert time[ row] > time_last, "MS is not time-sorted - cannot convert" time_index += 1 time_last = time[row] bv_vis[time_index, antenna2[row], antenna1[row], ...] = ms_vis[row, ...] bv_weight[time_index, antenna2[row], antenna1[row], :, ...] = ms_weight[row, numpy.newaxis, ...] bv_uvw[time_index, antenna2[row], antenna1[row], :] = uvw[row, :] vis_list.append( BlockVisibility(uvw=bv_uvw, time=bv_times, frequency=cfrequency, channel_bandwidth=cchannel_bandwidth, vis=bv_vis, weight=bv_weight, configuration=configuration, phasecentre=phasecentre, polarisation_frame=polarisation_frame)) tab.close() return vis_list
def __initData_WGS84(self): """Private function to generate a random set of data for writing a Measurements file. The data is returned as a dictionary with keys: * freq - frequency array in Hz * site - observatory object * stands - array of stand numbers * bl - list of baseline pairs in real stand numbers * vis - array of visibility data in baseline x freq format """ if run_ms_tests == False: return # Frequency range freq = numpy.arange(0, 512) * 20e6 / 512 + 40e6 channel_width = numpy.full_like(freq, 20e6 / 512.) # Site and stands obs = EarthLocation(lon="+116.6356824", lat="-26.70130064", height=377.0) names = numpy.array(['A%02d' % i for i in range(36)]) mount = numpy.array(['equat' for i in range(36)]) diameter = numpy.array([12 for i in range(36)]) xyz = numpy.array([[-175.233429, +1673.460938, 0.0000], [+261.119019, +796.922119, 0.0000], [-29.2005200, +744.432068, 0.0000], [-289.355286, +586.936035, 0.0000], [-157.031570, +815.570068, 0.0000], [-521.311646, +754.674927, 0.0000], [-1061.114258, +840.541443, 0.0000], [-921.829407, +997.627686, 0.0000], [-818.293579, +1142.272095, 0.0000], [-531.752808, +850.726257, 0.0000], [+81.352448, +790.245117, 0.0000], [+131.126358, +1208.831909, 0.0000], [-1164.709351, +316.779236, 0.0000], [-686.248901, +590.285278, 0.0000], [-498.987305, +506.338226, 0.0000], [-182.249146, +365.113464, 0.0000], [+420.841858, +811.081543, 0.0000], [+804.107910, +1273.328369, 0.0000], [-462.810394, +236.353790, 0.0000], [-449.772339, +15.039755, 0.0000], [+13.791821, +110.971809, 0.0000], [-425.687317, -181.908752, 0.0000], [-333.404053, -503.603394, 0.0000], [-1495.472412, +1416.063232, 0.0000], [-1038.578857, +1128.367920, 0.0000], [-207.151749, +956.312561, 0.0000], [-389.051880, +482.405670, 0.0000], [-434.000000, +510.000000, 0.0000], [-398.000000, +462.000000, 0.0000], [-425.000000, +475.000000, 0.0000], [-400.000000, +3664.000000, 0.0000], [+1796.000000, +1468.000000, 0.0000], [+2600.000000, -1532.000000, 0.0000], [-400.000000, -2336.000000, 0.0000], [-3400.00000, -1532.000000, 0.0000], [-2596.000000, +1468.000000, 0.0000]]) site_config = Configuration(name='ASKAP', data=None, location=obs, names=names, xyz=xyz, mount=mount, frame=None, receptor_frame=ReceptorFrame("linear"), diameter=diameter) antennas = [] for i in range(len(names)): antennas.append( Antenna(i, Stand(names[i], xyz[i, 0], xyz[i, 1], xyz[i, 2]))) # Set baselines and data blList = [] N = len(antennas) antennas2 = antennas for i in range(0, N - 1): for j in range(i + 1, N): blList.append((antennas[i], antennas2[j])) visData = numpy.random.rand(len(blList), len(freq)) visData = visData.astype(numpy.complex64) return { 'freq': freq, 'channel_width': channel_width, 'site': site_config, 'antennas': antennas, 'bl': blList, 'vis': visData }
def __initData(self): """Private function to generate a random set of data for writing a UVFITS file. The data is returned as a dictionary with keys: * freq - frequency array in Hz * site - Observatory object * stands - array of stand numbers * bl - list of baseline pairs in real stand numbers * vis - array of visibility data in baseline x freq format """ if run_ms_tests == False: return # Frequency range freq = numpy.arange(0, 512) * 20e6 / 512 + 40e6 channel_width = numpy.full_like(freq, 20e6 / 512.) # Site and stands obs = EarthLocation(lon="116.76444824", lat="-26.824722084", height=300.0) mount = numpy.array([ 'equat', 'equat', 'equat', 'equat', 'equat', 'equat', 'equat', 'equat', 'equat', 'equat' ]) names = numpy.array([ 'ak02', 'ak04', 'ak05', 'ak12', 'ak13', 'ak14', 'ak16', 'ak24', 'ak28', 'ak30' ]) diameter = numpy.array( [12., 12., 12., 12., 12., 12., 12., 12., 12., 12.]) xyz = numpy.array( [[-2556109.98244348, 5097388.70050131, -2848440.1332423], [-2556087.396082, 5097423.589662, -2848396.867933], [-2556028.60254059, 5097451.46195695, -2848399.83113161], [-2556496.23893101, 5097333.71466669, -2848187.33832738], [-2556407.35299627, 5097064.98390756, -2848756.02069474], [-2555972.78456557, 5097233.65481756, -2848839.88915184], [-2555592.88867802, 5097835.02121109, -2848098.26409648], [-2555959.34313275, 5096979.52802882, -2849303.57702486], [-2556552.97431815, 5097767.23612874, -2847354.29540396], [-2557348.40370367, 5097170.17682775, -2847716.21368966]]) site_config = Configuration(name='ASKAP', data=None, location=obs, names=names, xyz=xyz, mount=mount, frame=None, receptor_frame=ReceptorFrame("linear"), diameter=diameter) antennas = [] for i in range(len(names)): antennas.append( Antenna(i, Stand(names[i], xyz[i, 0], xyz[i, 1], xyz[i, 2]))) # Set baselines and data blList = [] N = len(antennas) antennas2 = antennas for i in range(0, N - 1): for j in range(i + 1, N): blList.append((antennas[i], antennas2[j])) visData = numpy.random.rand(len(blList), len(freq)) visData = visData.astype(numpy.complex64) return { 'freq': freq, 'channel_width': channel_width, 'site': site_config, 'antennas': antennas, 'bl': blList, 'vis': visData }
def create_blockvisibility_from_ms(msname, channum=None, start_chan=None, end_chan=None, ack=False, datacolumn='DATA', selected_sources=None, selected_dds=None): """ Minimal MS to BlockVisibility converter The MS format is much more general than the ARL BlockVisibility so we cut many corners. This requires casacore to be installed. If not an exception ModuleNotFoundError is raised. Creates a list of BlockVisibility's, split by field and spectral window Reading of a subset of channels is possible using either start_chan and end_chan or channnum. Using start_chan and end_chan is preferred since it only reads the channels required. Channum is more flexible and can be used to read a random list of channels. :param msname: File name of MS :param channum: range of channels e.g. range(17,32), default is None meaning all :param start_chan: Starting channel to read :param end_chan: End channel to read :return: """ try: from casacore.tables import table # pylint: disable=import-error except ModuleNotFoundError: raise ModuleNotFoundError("casacore is not installed") try: from processing_components.visibility import msv2 except ModuleNotFoundError: raise ModuleNotFoundError("cannot import msv2") tab = table(msname, ack=ack) log.debug("create_blockvisibility_from_ms: %s" % str(tab.info())) if selected_sources is None: fields = numpy.unique(tab.getcol('FIELD_ID')) else: fieldtab = table('%s/FIELD' % msname, ack=False) sources = fieldtab.getcol('NAME') fields = list() for field, source in enumerate(sources): if source in selected_sources: fields.append(field) assert len(fields) > 0, "No sources selected" if selected_dds is None: dds = numpy.unique(tab.getcol('DATA_DESC_ID')) else: dds = selected_dds log.debug("create_blockvisibility_from_ms: Reading unique fields %s, unique data descriptions %s" % ( str(fields), str(dds))) vis_list = list() for field in fields: ftab = table(msname, ack=ack).query('FIELD_ID==%d' % field, style='') for dd in dds: meta = {'MSV2':{'FIELD_ID': field, 'DATA_DESC_ID':dd}} ms = ftab.query('DATA_DESC_ID==%d' % dd, style='') assert ms.nrows() > 0, "Empty selection for FIELD_ID=%d and DATA_DESC_ID=%d" % (field, dd) log.debug("create_blockvisibility_from_ms: Found %d rows" % (ms.nrows())) # The TIME column has descriptor: # {'valueType': 'double', 'dataManagerType': 'IncrementalStMan', 'dataManagerGroup': 'TIME', # 'option': 0, 'maxlen': 0, 'comment': 'Modified Julian Day', # 'keywords': {'QuantumUnits': ['s'], 'MEASINFO': {'type': 'epoch', 'Ref': 'UTC'}}} otime = ms.getcol('TIME') datacol = ms.getcol(datacolumn, nrow=1) datacol_shape = list(datacol.shape) channels = datacol.shape[-2] log.debug("create_blockvisibility_from_ms: Found %d channels" % (channels)) if channum is None: if start_chan is not None and end_chan is not None: try: log.debug("create_blockvisibility_from_ms: Reading channels from %d to %d" % (start_chan, end_chan)) print("create_blockvisibility_from_ms: Reading channels from %d to %d (inclusive)" % (start_chan, end_chan)) blc = [start_chan, 0] trc = [end_chan, datacol_shape[-1] - 1] channum = range(start_chan, end_chan+1) ms_vis = ms.getcolslice(datacolumn, blc=blc, trc=trc) ms_weight = ms.getcol('WEIGHT') except IndexError: raise IndexError("channel number exceeds max. within ms") else: log.debug("create_blockvisibility_from_ms: Reading all %d channels" % (channels)) try: channum = range(channels) ms_vis = ms.getcol(datacolumn)[:, channum, :] ms_weight = ms.getcol('WEIGHT') channum = range(channels) except IndexError: raise IndexError("channel number exceeds max. within ms") else: log.debug("create_blockvisibility_from_ms: Reading channels %s " % (channum)) channum = range(channels) try: ms_vis = ms.getcol(datacolumn)[:, channum, :] ms_weight = ms.getcol('WEIGHT')[:, :] except IndexError: raise IndexError("channel number exceeds max. within ms") uvw = -1 * ms.getcol('UVW') antenna1 = ms.getcol('ANTENNA1') antenna2 = ms.getcol('ANTENNA2') integration_time = ms.getcol('INTERVAL') # time = Time((time-integration_time/2.0)/86400+ 2400000.5,format='jd',scale='utc').utc.value time = (otime - integration_time / 2.0) start_time = numpy.min(time)/86400.0 end_time = numpy.max(time)/86400.0 log.debug("create_blockvisibility_from_ms: Observation from %s to %s" % (Time(start_time, format='mjd').iso, Time(end_time, format='mjd').iso)) # Now get info from the subtables spwtab = table('%s/SPECTRAL_WINDOW' % msname, ack=False) cfrequency = spwtab.getcol('CHAN_FREQ')[dd][channum] cchannel_bandwidth = spwtab.getcol('CHAN_WIDTH')[dd][channum] nchan = cfrequency.shape[0] # Get polarisation info npol = 4 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') elif numpy.array_equal(corr_type[0], [9]): npol = 1 polarisation_frame = PolarisationFrame('stokesI') else: raise KeyError("Polarisation not understood: %s" % str(corr_type)) # Get configuration anttab = table('%s/ANTENNA' % msname, ack=False) nants = anttab.nrows() 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, :] source = fieldtab.getcol('NAME')[field] phasecentre = SkyCoord(ra=pc[0] * u.rad, dec=pc[1] * u.rad, frame='icrs', equinox='J2000') time_index_row = numpy.zeros_like(time, dtype='int') time_last = time[0] time_index = 0 for row, _ in enumerate(time): if time[row] > time_last + integration_time[row]: assert time[row] > time_last, "MS is not time-sorted - cannot convert" time_index += 1 time_last = time[row] time_index_row[row] = time_index ntimes = time_index + 1 bv_times = numpy.zeros([ntimes]) bv_vis = numpy.zeros([ntimes, nants, nants, nchan, npol]).astype('complex') bv_weight = numpy.zeros([ntimes, nants, nants, nchan, npol]) bv_imaging_weight = numpy.zeros([ntimes, nants, nants, nchan, npol]) bv_uvw = numpy.zeros([ntimes, nants, nants, 3]) bv_integration_time = numpy.zeros([ntimes]) for row, _ in enumerate(time): time_index = time_index_row[row] bv_times[time_index] = time[row] bv_vis[time_index, antenna2[row], antenna1[row], ...] = ms_vis[row, ...] bv_weight[time_index, antenna2[row], antenna1[row], :, ...] = ms_weight[row, numpy.newaxis, ...] bv_imaging_weight[time_index, antenna2[row], antenna1[row], :, ...] = ms_weight[row, numpy.newaxis, ...] bv_uvw[time_index, antenna2[row], antenna1[row], :] = uvw[row, :] bv_integration_time[time_index] = integration_time[row] vis_list.append(BlockVisibility(uvw=bv_uvw, time=bv_times, frequency=cfrequency, channel_bandwidth=cchannel_bandwidth, vis=bv_vis, weight=bv_weight, integration_time = bv_integration_time, imaging_weight=bv_imaging_weight, configuration=configuration, phasecentre=phasecentre, polarisation_frame=polarisation_frame, source=source, meta=meta)) tab.close() return vis_list
def create_blockvisibility_from_uvfits(fitsname, channum=None, ack=False, antnum=None): """ Minimal UVFIT to BlockVisibility converter The UVFITS format is much more general than the ARL BlockVisibility so we cut many corners. Creates a list of BlockVisibility's, split by field and spectral window :param fitsname: File name of UVFITS :param channum: range of channels e.g. range(17,32), default is None meaning all :param antnum: the number of antenna :return: """ def ParamDict(hdul): "Return the dictionary of the random parameters" """ The keys of the dictionary are the parameter names uppercased for consistency. The values are the column numbers. If multiple parameters have the same name (e.g., DATE) their columns are entered as a list. """ pre=re.compile(r"PTYPE(?P<i>\d+)") res={} for k,v in hdul.header.items(): m=pre.match(k) if m : vu=v.upper() if vu in res: res[ vu ] = [ res[vu], int(m.group("i")) ] else: res[ vu ] = int(m.group("i")) return res # Open the file with fits.open(fitsname) as hdul: # Read Spectral Window nspw = hdul[0].header['NAXIS5'] # Read Channel and Frequency Interval freq_ref = hdul[0].header['CRVAL4'] mid_chan_freq = hdul[0].header['CRPIX4'] delt_freq = hdul[0].header['CDELT4'] # Real the number of channels in one spectral window channels = hdul[0].header['NAXIS4'] freq = numpy.zeros([nspw, channels]) # Read Frequency or IF freqhdulname="AIPS FQ" sdhu = hdul.index_of(freqhdulname) if_freq = hdul[sdhu].data['IF FREQ'].ravel() for i in range(nspw): temp = numpy.array([if_freq[i] + freq_ref+delt_freq* ff for ff in range(channels)]) freq[i,:] = temp[:] freq_delt = numpy.ones(channels) * delt_freq if channum is None: channum = range(channels) primary = hdul[0].data # Read time bvtimes = Time(hdul[0].data['DATE'], hdul[0].data['_DATE'], format='jd') bv_times = numpy.unique(bvtimes.jd) ntimes = len(bv_times) # # Get Antenna # blin = hdul[0].data['BASELINE'] antennahdulname="AIPS AN" adhu = hdul.index_of(antennahdulname) try: antenna_name = hdul[adhu].data['ANNAME'] antenna_name = antenna_name.encode('ascii','ignore') except: antenna_name = None antenna_xyz = hdul[adhu].data['STABXYZ'] antenna_mount = hdul[adhu].data['MNTSTA'] try: antenna_diameter = hdul[adhu].data['DIAMETER'] except: antenna_diameter = None # To reading some UVFITS with wrong numbers of antenna if antnum is not None: if antenna_name is not None: antenna_name = antenna_name[:antnum] antenna_xyz = antenna_xyz[:antnum] antenna_mount = antenna_mount[:antnum] if antenna_diameter is not None: antenna_diameter = antenna_diameter[:antnum] nants = len(antenna_xyz) # res= {} # for i,row in enumerate(fin[ahdul].data): # res[row.field("ANNAME") ] = i +1 # Get polarisation info npol = hdul[0].header['NAXIS3'] corr_type = numpy.arange(hdul[0].header['NAXIS3']) - (hdul[0].header['CRPIX3'] - 1) corr_type *= hdul[0].header['CDELT3'] corr_type += hdul[0].header['CRVAL3'] # xx yy xy yx # These correspond to the CASA Stokes enumerations if numpy.array_equal(corr_type, [1, 2, 3, 4]): polarisation_frame = PolarisationFrame('stokesIQUV') elif numpy.array_equal(corr_type, [-1, -2, -3, -4]): polarisation_frame = PolarisationFrame('circular') elif numpy.array_equal(corr_type, [-5, -6, -7, -8]): polarisation_frame = PolarisationFrame('linear') else: raise KeyError("Polarisation not understood: %s" % str(corr_type)) configuration = Configuration(name='', data=None, location=None, names=antenna_name, xyz=antenna_xyz, mount=antenna_mount, frame=None, receptor_frame=polarisation_frame, diameter=antenna_diameter) # Get RA and DEC phase_center_ra_degrees = numpy.float(hdul[0].header['CRVAL6']) phase_center_dec_degrees = numpy.float(hdul[0].header['CRVAL7']) # Get phasecentres phasecentre = SkyCoord(ra=phase_center_ra_degrees * u.deg, dec=phase_center_dec_degrees * u.deg, frame='icrs', equinox='J2000') # Get UVW d=ParamDict(hdul[0]) if "UU" in d: uu = hdul[0].data['UU'] vv = hdul[0].data['VV'] ww = hdul[0].data['WW'] else: uu = hdul[0].data['UU---SIN'] vv = hdul[0].data['VV---SIN'] ww = hdul[0].data['WW---SIN'] _vis = hdul[0].data['DATA'] #_vis.shape = (nchan, ntimes, (nants*(nants-1)//2 ), npol, -1) #self.vis = -(_vis[...,0] * 1.j + _vis[...,1]) row = 0 nchan = len(channum) vis_list = list() for spw_index in range(nspw): bv_vis = numpy.zeros([ntimes, nants, nants, nchan, npol]).astype('complex') bv_weight = numpy.zeros([ntimes, nants, nants, nchan, npol]) bv_uvw = numpy.zeros([ntimes, nants, nants, 3]) for time_index , time in enumerate(bv_times): #restfreq = freq[channel_index] for antenna1 in range(nants-1): for antenna2 in range(antenna1 + 1, nants): for channel_no, channel_index in enumerate(channum): for pol_index in range(npol): bv_vis[time_index, antenna2, antenna1, channel_no,pol_index] = complex(_vis[row,:,:,spw_index,channel_index, pol_index ,0],_vis[row,:,:,spw_index,channel_index,pol_index ,1]) bv_weight[time_index, antenna2, antenna1, channel_no, pol_index] = _vis[row,:,:,spw_index,channel_index,pol_index ,2] bv_uvw[time_index, antenna2, antenna1, 0] = uu[row]* constants.c.value bv_uvw[time_index, antenna2, antenna1, 1] = vv[row]* constants.c.value bv_uvw[time_index, antenna2, antenna1, 2] = ww[row]* constants.c.value row += 1 vis_list.append(BlockVisibility(uvw=bv_uvw, time=bv_times, frequency=freq[spw_index][channum], channel_bandwidth=freq_delt[channum], vis=bv_vis, weight=bv_weight, imaging_weight= bv_weight, 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