Example #1
0
    def read_beamfits(self, filename, run_check=True, check_extra=True,
                      run_check_acceptability=True):
        """
        Read the data from a beamfits file.

        Args:
            filename: The beamfits file to write to.
            run_check: Option to check for the existence and proper shapes of
                required parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as
                required ones. Default is True.
            run_check_acceptability: Option to check acceptability of the values of
                required parameters after reading in the file. Default is True.
        """
        F = fits.open(filename)
        primary_hdu = F[0]
        primary_header = primary_hdu.header.copy()
        hdunames = uvutils.fits_indexhdus(F)  # find the rest of the tables

        data = primary_hdu.data

        # only support simple antenna_types for now.
        # support for phased arrays should be added
        self.set_simple()

        self.beam_type = primary_header.pop('BTYPE', None)
        if self.beam_type is not None:
            self.beam_type = self.beam_type.lower()
        else:
            bunit = primary_header.pop('BUNIT', None)
            if bunit is not None and bunit.lower().strip() == 'jy/beam':
                self.beam_type = 'power'

        if self.beam_type == 'intensity':
            self.beam_type = 'power'

        n_dimensions = primary_header.pop('NAXIS')
        ctypes = [primary_header[ctype] for ctype in (key for key in primary_header
                                                      if 'ctype' in key.lower())]

        self.pixel_coordinate_system = primary_header.pop('COORDSYS', None)
        if self.pixel_coordinate_system is None:
            if ctypes[0] == 'Pix_Ind':
                self.pixel_coordinate_system = 'healpix'
            else:
                for cs, coords in self.coordinate_system_dict.iteritems():
                    if coords == ctypes[0:2]:
                        coord_list = ctypes[0:2]
                        self.pixel_coordinate_system = cs
        else:
            if self.pixel_coordinate_system == 'healpix':
                if ctypes[0] != 'Pix_Ind':
                    raise ValueError('First axis must be "Pix_Ind" for healpix beams')
            else:
                coord_list = ctypes[0:2]
                if coord_list != self.coordinate_system_dict[self.pixel_coordinate_system]:
                    raise ValueError('Coordinate axis list does not match coordinate system')

        if self.pixel_coordinate_system == 'healpix':
            # get pixel values out of HPX_IND extension
            hpx_hdu = F[hdunames['HPX_INDS']]
            self.Npixels = hpx_hdu.header['NAXIS2']
            hpx_data = hpx_hdu.data
            self.pixel_array = hpx_data['hpx_inds']

            ax_nums = hpx_primary_ax_nums
            self.nside = primary_header.pop('NSIDE', None)
            self.ordering = primary_header.pop('ORDERING', None)
            data_Npixels = primary_header.pop('NAXIS' + str(ax_nums['pixel']))
            if data_Npixels != self.Npixels:
                raise ValueError('Number of pixels in HPX_IND extension does '
                                 'not match number of pixels in data array')
        else:
            ax_nums = reg_primary_ax_nums
            self.Naxes1 = primary_header.pop('NAXIS' + str(ax_nums['img_ax1']))
            self.Naxes2 = primary_header.pop('NAXIS' + str(ax_nums['img_ax2']))

            self.axis1_array = uvutils.fits_gethduaxis(primary_hdu, ax_nums['img_ax1'])
            self.axis2_array = uvutils.fits_gethduaxis(primary_hdu, ax_nums['img_ax2'])

        n_efield_dims = max([ax_nums[key] for key in ax_nums])

        if self.beam_type == 'power':
            self.data_array = data
            if primary_header.pop('CTYPE' + str(ax_nums['feed_pol'])).lower().strip() == 'stokes':
                self.Npols = primary_header.pop('NAXIS' + str(ax_nums['feed_pol']))
            self.polarization_array = np.int32(uvutils.fits_gethduaxis(primary_hdu,
                                                                       ax_nums['feed_pol']))
            self.set_power()
        elif self.beam_type == 'efield':
            self.set_efield()
            if n_dimensions < n_efield_dims:
                raise (ValueError, 'beam_type is efield and data dimensionality is too low')
            complex_arrs = np.split(data, 2, axis=0)
            self.data_array = np.squeeze(complex_arrs[0] + 1j * complex_arrs[1], axis=0)
            if primary_header.pop('CTYPE' + str(ax_nums['feed_pol'])).lower().strip() == 'feedind':
                self.Nfeeds = primary_header.pop('NAXIS' + str(ax_nums['feed_pol']))
            feedlist = primary_header.pop('FEEDLIST', None)
            if feedlist is not None:
                self.feed_array = np.array(feedlist[1:-1].split(', '))
        else:
            raise ValueError('Unknown beam_type: {type}, beam_type should be '
                             '"efield" or "power".'.format(type=self.beam_type))

        self.data_normalization = primary_header.pop('NORMSTD', None)

        self.telescope_name = primary_header.pop('TELESCOP')
        self.feed_name = primary_header.pop('FEED', None)
        self.feed_version = primary_header.pop('FEEDVER', None)
        self.model_name = primary_header.pop('MODEL', None)
        self.model_version = primary_header.pop('MODELVER', None)

        # shapes
        if primary_header.pop('CTYPE' + str(ax_nums['freq'])).lower().strip() == 'freq':
            self.Nfreqs = primary_header.pop('NAXIS' + str(ax_nums['freq']))

        if n_dimensions > ax_nums['spw'] - 1:
            if primary_header.pop('CTYPE' + str(ax_nums['spw'])).lower().strip() == 'if':
                self.Nspws = primary_header.pop('NAXIS' + str(ax_nums['spw']), None)
                # subtract 1 to be zero-indexed
                self.spw_array = uvutils.fits_gethduaxis(primary_hdu, ax_nums['spw']) - 1

        if n_dimensions > ax_nums['basisvec'] - 1:
            if primary_header.pop('CTYPE' + str(ax_nums['basisvec'])).lower().strip() == 'vecind':
                self.Naxes_vec = primary_header.pop('NAXIS' + str(ax_nums['basisvec']), None)

        if (self.Nspws is None or self.Naxes_vec is None) and self.beam_type == 'power':
            if self.Nspws is None:
                self.Nspws = 1
                self.spw_array = np.array([0])
            if self.Naxes_vec is None:
                self.Naxes_vec = 1

            # add extra empty dimensions to data_array as appropriate
            while len(self.data_array.shape) < n_efield_dims - 1:
                self.data_array = np.expand_dims(self.data_array, axis=0)

        self.freq_array = uvutils.fits_gethduaxis(primary_hdu, ax_nums['freq'])
        self.freq_array.shape = (self.Nspws,) + self.freq_array.shape

        self.history = str(primary_header.get('HISTORY', ''))
        if not uvutils.check_history_version(self.history, self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str
        while 'HISTORY' in primary_header.keys():
            primary_header.remove('HISTORY')

        # remove standard FITS header items that are still around
        std_fits_substrings = ['SIMPLE', 'BITPIX', 'EXTEND', 'BLOCKED',
                               'GROUPS', 'PCOUNT', 'BSCALE', 'BZERO', 'NAXIS',
                               'PTYPE', 'PSCAL', 'PZERO', 'CTYPE', 'CRVAL',
                               'CRPIX', 'CDELT', 'CROTA', 'CUNIT']
        for key in primary_header.keys():
            for sub in std_fits_substrings:
                if key.find(sub) > -1:
                    primary_header.remove(key)

        # find all the remaining header items and keep them as extra_keywords
        for key in primary_header:
            if key == 'COMMENT':
                self.extra_keywords[key] = str(primary_header.get(key))
            elif key != '':
                self.extra_keywords[key] = primary_header.get(key)

        if self.beam_type == 'efield':
            # read BASISVEC HDU
            basisvec_hdu = F[hdunames['BASISVEC']]
            self.basis_vector_array = basisvec_hdu.data
            basisvec_header = basisvec_hdu.header

            if self.pixel_coordinate_system == 'healpix':
                basisvec_ax_nums = hxp_basisvec_ax_nums
                if basisvec_header['CTYPE' + str(basisvec_ax_nums['pixel'])] != 'Pix_Ind':
                    raise ValueError('First axis in BASISVEC HDU must be "Pix_Ind" for healpix beams')

                basisvec_Npixels = basisvec_header.pop('NAXIS' + str(basisvec_ax_nums['pixel']))

                if basisvec_Npixels != self.Npixels:
                    raise ValueError('Number of pixels in BASISVEC HDU does not match '
                                     'primary HDU')
            else:
                basisvec_ax_nums = reg_basisvec_ax_nums
                basisvec_coord_list = [basisvec_header['CTYPE' + str(basisvec_ax_nums['img_ax1'])],
                                       basisvec_header['CTYPE' + str(basisvec_ax_nums['img_ax2'])]]
                basisvec_axis1_array = uvutils.fits_gethduaxis(basisvec_hdu,
                                                               basisvec_ax_nums['img_ax1'])
                basisvec_axis2_array = uvutils.fits_gethduaxis(basisvec_hdu,
                                                               basisvec_ax_nums['img_ax2'])
                if not np.all(basisvec_axis1_array == self.axis1_array):
                    raise ValueError('First image axis in BASISVEC HDU does not match '
                                     'primary HDU')
                if not np.all(basisvec_axis2_array == self.axis2_array):
                    raise ValueError('Second image axis in BASISVEC HDU does not '
                                     'match primary HDU')
                if basisvec_coord_list != coord_list:
                    raise ValueError('Pixel coordinate list in BASISVEC HDU does not '
                                     'match primary HDU')

            basisvec_Naxes_vec = basisvec_header['NAXIS' + str(basisvec_ax_nums['basisvec'])]

            basisvec_cs = basisvec_header['COORDSYS']
            if basisvec_cs != self.pixel_coordinate_system:
                raise ValueError('Pixel coordinate system in BASISVEC HDU does '
                                 'not match primary HDU')

            if basisvec_Naxes_vec != self.Naxes_vec:
                raise ValueError('Number of vector coordinate axes in BASISVEC '
                                 'HDU does not match primary HDU')

        # check to see if BANDPARM HDU exists and read it out if it does
        if 'BANDPARM' in hdunames:
            bandpass_hdu = F[hdunames['BANDPARM']]
            bandpass_header = bandpass_hdu.header.copy()
            self.reference_input_impedance = bandpass_header.pop('refzin', None)
            self.reference_output_impedance = bandpass_header.pop('refzout', None)

            freq_data = bandpass_hdu.data
            columns = [c.name for c in freq_data.columns]
            self.bandpass_array = freq_data['bandpass']
            self.bandpass_array = self.bandpass_array[np.newaxis, :]

            if 'rx_temp' in columns:
                self.receiver_temperature_array = freq_data['rx_temp']
                self.receiver_temperature_array = self.receiver_temperature_array[np.newaxis, :]
            if 'loss' in columns:
                self.loss_array = freq_data['loss']
                self.loss_array = self.loss_array[np.newaxis, :]
            if 'mismatch' in columns:
                self.mismatch_array = freq_data['mismatch']
                self.mismatch_array = self.mismatch_array[np.newaxis, :]
            if 's11' in columns:
                s11 = freq_data['s11']
                s12 = freq_data['s12']
                s21 = freq_data['s21']
                s22 = freq_data['s22']
                self.s_parameters = np.zeros((4, 1, len(s11)))
                self.s_parameters[0, 0, :] = s11
                self.s_parameters[1, 0, :] = s12
                self.s_parameters[2, 0, :] = s21
                self.s_parameters[3, 0, :] = s22
        else:
            # no bandpass information, set it to an array of ones
            self.bandpass_array = np.zeros((self.Nspws, self.Nfreqs)) + 1.

        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)
Example #2
0
    def read_fhd(self,
                 filelist,
                 use_model=False,
                 run_check=True,
                 check_extra=True,
                 run_check_acceptability=True):
        """
        Read in data from a list of FHD files.

        Args:
            filelist: The list of FHD save files to read from. Must include at
                least one polarization file, a params file and a flag file.
            use_model: Option to read in the model visibilities rather than the
                dirty visibilities. Default is False.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.
        """
        datafiles = {}
        params_file = None
        flags_file = None
        settings_file = None
        if use_model:
            data_name = '_vis_model_'
        else:
            data_name = '_vis_'
        for file in filelist:
            if file.lower().endswith(data_name + 'xx.sav'):
                datafiles['xx'] = xx_datafile = file
            elif file.lower().endswith(data_name + 'yy.sav'):
                datafiles['yy'] = yy_datafile = file
            elif file.lower().endswith(data_name + 'xy.sav'):
                datafiles['xy'] = xy_datafile = file
            elif file.lower().endswith(data_name + 'yx.sav'):
                datafiles['yx'] = yx_datafile = file
            elif file.lower().endswith('_params.sav'):
                params_file = file
            elif file.lower().endswith('_flags.sav'):
                flags_file = file
            elif file.lower().endswith('_settings.txt'):
                settings_file = file
            else:
                continue

        if len(datafiles) < 1:
            raise StandardError('No data files included in file list')
        if params_file is None:
            raise StandardError('No params file included in file list')
        if flags_file is None:
            raise StandardError('No flags file included in file list')
        if settings_file is None:
            warnings.warn('No settings file included in file list')

        # TODO: add checking to make sure params, flags and datafiles are
        # consistent with each other

        vis_data = {}
        for pol, file in datafiles.iteritems():
            this_dict = readsav(file, python_dict=True)
            if use_model:
                vis_data[pol] = this_dict['vis_model_ptr']
            else:
                vis_data[pol] = this_dict['vis_ptr']
            this_obs = this_dict['obs']
            data_shape = vis_data[pol].shape

        obs = this_obs
        bl_info = obs['BASELINE_INFO'][0]
        meta_data = obs['META_DATA'][0]
        astrometry = obs['ASTR'][0]
        fhd_pol_list = []
        for pol in obs['POL_NAMES'][0]:
            fhd_pol_list.append(pol.decode("utf-8").lower())

        params_dict = readsav(params_file, python_dict=True)
        params = params_dict['params']

        flag_file_dict = readsav(flags_file, python_dict=True)
        # The name for this variable changed recently (July 2016). Test for both.
        vis_weights_data = {}
        if 'flag_arr' in flag_file_dict:
            weights_key = 'flag_arr'
        elif 'vis_weights' in flag_file_dict:
            weights_key = 'vis_weights'
        else:
            raise ValueError(
                'No recognized key for visibility weights in flags_file.')
        for index, w in enumerate(flag_file_dict[weights_key]):
            vis_weights_data[fhd_pol_list[index]] = w

        self.Ntimes = int(obs['N_TIME'][0])
        self.Nbls = int(obs['NBASELINES'][0])
        self.Nblts = data_shape[0]
        self.Nfreqs = int(obs['N_FREQ'][0])
        self.Npols = len(vis_data.keys())
        self.Nspws = 1
        self.spw_array = np.array([0])
        self.vis_units = 'JY'

        lin_pol_order = ['xx', 'yy', 'xy', 'yx']
        linear_pol_dict = dict(zip(lin_pol_order, np.arange(5, 9) * -1))
        pol_list = []
        for pol in lin_pol_order:
            if pol in vis_data:
                pol_list.append(linear_pol_dict[pol])
        self.polarization_array = np.asarray(pol_list)

        self.data_array = np.zeros(
            (self.Nblts, self.Nspws, self.Nfreqs, self.Npols),
            dtype=np.complex_)
        self.nsample_array = np.zeros(
            (self.Nblts, self.Nspws, self.Nfreqs, self.Npols), dtype=np.float_)
        self.flag_array = np.zeros(
            (self.Nblts, self.Nspws, self.Nfreqs, self.Npols), dtype=np.bool_)
        for pol, vis in vis_data.iteritems():
            pol_i = pol_list.index(linear_pol_dict[pol])
            self.data_array[:, 0, :, pol_i] = vis
            self.flag_array[:, 0, :, pol_i] = vis_weights_data[pol] <= 0
            self.nsample_array[:, 0, :, pol_i] = np.abs(vis_weights_data[pol])

        # In FHD, uvws are in seconds not meters!
        self.uvw_array = np.zeros((self.Nblts, 3))
        self.uvw_array[:, 0] = params['UU'][0] * const.c.to('m/s').value
        self.uvw_array[:, 1] = params['VV'][0] * const.c.to('m/s').value
        self.uvw_array[:, 2] = params['WW'][0] * const.c.to('m/s').value

        # bl_info.JDATE (a vector of length Ntimes) is the only safe date/time
        # to use in FHD files.
        # (obs.JD0 (float) and params.TIME (vector of length Nblts) are
        #   context dependent and are not safe
        #   because they depend on the phasing of the visibilities)
        # the values in bl_info.JDATE are the JD for each integration.
        # We need to expand up to Nblts.
        int_times = bl_info['JDATE'][0]
        bin_offset = bl_info['BIN_OFFSET'][0]
        if self.Ntimes != len(int_times):
            warnings.warn(
                'Ntimes does not match the number of unique times in the data')
        self.time_array = np.zeros(self.Nblts)
        if self.Ntimes == 1:
            self.time_array.fill(int_times)
        else:
            for ii in range(0, len(int_times)):
                if ii < (len(int_times) - 1):
                    self.time_array[
                        bin_offset[ii]:bin_offset[ii + 1]] = int_times[ii]
                else:
                    self.time_array[bin_offset[ii]:] = int_times[ii]

        # Note that FHD antenna arrays are 1-indexed so we subtract 1
        # to get 0-indexed arrays
        self.ant_1_array = bl_info['TILE_A'][0] - 1
        self.ant_2_array = bl_info['TILE_B'][0] - 1

        self.Nants_data = int(
            len(
                np.unique(self.ant_1_array.tolist() +
                          self.ant_2_array.tolist())))

        self.antenna_names = bl_info['TILE_NAMES'][0].tolist()
        self.Nants_telescope = len(self.antenna_names)
        self.antenna_numbers = np.arange(self.Nants_telescope)

        self.baseline_array = \
            self.antnums_to_baseline(self.ant_1_array,
                                     self.ant_2_array)
        if self.Nbls != len(np.unique(self.baseline_array)):
            warnings.warn(
                'Nbls does not match the number of unique baselines in the data'
            )

        if len(bl_info['FREQ'][0]) != self.Nfreqs:
            warnings.warn(
                'Nfreqs does not match the number of frequencies in the data')
        self.freq_array = np.zeros((self.Nspws, len(bl_info['FREQ'][0])),
                                   dtype=np.float_)
        self.freq_array[0, :] = bl_info['FREQ'][0]

        if not np.isclose(obs['OBSRA'][0], obs['PHASERA'][0]) or \
                not np.isclose(obs['OBSDEC'][0], obs['PHASEDEC'][0]):
            warnings.warn('These visibilities may have been phased '
                          'improperly -- without changing the uvw locations')

        self.set_phased()
        self.phase_center_ra_degrees = np.float(obs['OBSRA'][0])
        self.phase_center_dec_degrees = np.float(obs['OBSDEC'][0])

        # this is generated in FHD by subtracting the JD of neighboring
        # integrations. This can have limited accuracy, so it can be slightly
        # off the actual value.
        # (e.g. 1.999426... rather than 2)
        self.integration_time = float(obs['TIME_RES'][0])
        self.channel_width = float(obs['FREQ_RES'][0])

        # # --- observation information ---
        self.telescope_name = str(obs['INSTRUMENT'][0].decode())

        # This is a bit of a kludge because nothing like object_name exists
        # in FHD files.
        # At least for the MWA, obs.ORIG_PHASERA and obs.ORIG_PHASEDEC specify
        # the field the telescope was nominally pointing at
        # (May need to be revisited, but probably isn't too important)
        self.object_name = 'Field RA(deg): ' + str(obs['ORIG_PHASERA'][0]) + \
                           ', Dec:' + str(obs['ORIG_PHASEDEC'][0])
        # For the MWA, this can sometimes be converted to EoR fields
        if self.telescope_name.lower() == 'mwa':
            if np.isclose(obs['ORIG_PHASERA'][0], 0) and \
                    np.isclose(obs['ORIG_PHASEDEC'][0], -27):
                object_name = 'EoR 0 Field'

        self.instrument = self.telescope_name
        self.telescope_location_lat_lon_alt_degrees = (float(obs['LAT'][0]),
                                                       float(obs['LON'][0]),
                                                       float(obs['ALT'][0]))

        self.set_lsts_from_time_array()

        # history: add the first few lines from the settings file
        if settings_file is not None:
            history_list = ['fhd settings info']
            with open(settings_file) as f:
                # TODO Make this reading more robust.
                head = list(islice(f, 11))
            for line in head:
                newline = ' '.join(str.split(line))
                if not line.startswith('##'):
                    history_list.append(newline)
            self.history = '    '.join(history_list)
        else:
            self.history = ''
        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str

        self.phase_center_epoch = astrometry['EQUINOX'][0]

        # TODO Once FHD starts reading and saving the antenna table info from
        #    uvfits, that information should be read into the following optional
        #    parameters:
        # 'xyz_telescope_frame'
        # 'x_telescope'
        # 'y_telescope'
        # 'z_telescope'
        # 'antenna_positions'
        # 'GST0'
        # 'RDate'
        # 'earth_omega'
        # 'DUT1'
        # 'TIMESYS'

        try:
            self.set_telescope_params()
        except ValueError, ve:
            warnings.warn(str(ve))
Example #3
0
    def read_ms(self,
                filepath,
                run_check=True,
                check_extra=True,
                run_check_acceptability=True,
                data_column='DATA',
                pol_order='AIPS'):
        '''
        read in a casa measurement set

        Args:
            filepath: name of the measurement set folder
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check the values of parameters
                after reading in the file. Default is True.
            data_column: specify which CASA measurement set data column to read from (can be 'DATA','CORRECTED', or 'MODEL')
            pol_order: use 'AIPS' or 'CASA' ordering of polarizations?
        '''
        # make sure user requests a valid data_column
        if data_column != 'DATA' and data_column != 'CORRECTED_DATA' and data_column != 'MODEL':
            raise ValueError(
                'Invalid data_column value supplied. Use \'Data\',\'MODEL\' or \'CORRECTED_DATA\''
            )
        if not os.path.exists(filepath):
            raise (IOError, filepath + ' not found')
        # set visibility units
        if (data_column == 'DATA'):
            self.vis_units = "UNCALIB"
        elif (data_column == 'CORRECTED_DATA'):
            self.vis_units = "JY"
        elif (data_column == 'MODEL'):
            self.vis_units = "JY"
        # limit length of extra_keywords keys to 8 characters to match uvfits & miriad
        self.extra_keywords['DATA_COL'] = data_column
        # get frequency information from spectral window table
        tb_spws = tables.table(filepath + '/SPECTRAL_WINDOW')
        freqs = tb_spws.getcol('CHAN_FREQ')
        self.freq_array = freqs
        self.Nfreqs = int(freqs.shape[1])
        self.channel_width = float(tb_spws.getcol('CHAN_WIDTH')[0, 0])
        self.Nspws = int(freqs.shape[0])
        if self.Nspws > 1:
            raise ValueError('Sorry.  Files with more than one spectral' +
                             'window (spw) are not yet supported. A ' +
                             'great project for the interested student!')

        self.spw_array = np.arange(self.Nspws)
        tb_spws.close()
        # now get the data
        tb = tables.table(filepath)
        # check for multiple subarrays. importuvfits does not appear to preserve subarray information!
        subarray = np.unique(np.int32(tb.getcol('ARRAY_ID')) - 1)
        if len(set(subarray)) > 1:
            raise ValueError('This file appears to have multiple subarray '
                             'values; only files with one subarray are '
                             'supported.')
        times_unique = time.Time(np.unique(tb.getcol('TIME') / (3600. * 24.)),
                                 format='mjd').jd
        self.Ntimes = int(len(times_unique))
        data_array = tb.getcol(data_column)
        self.Nblts = int(data_array.shape[0])
        flag_array = tb.getcol('FLAG')
        # CASA stores data in complex array with dimension NbltsxNfreqsxNpols
        if (len(data_array.shape) == 3):
            data_array = np.expand_dims(data_array, axis=1)
            flag_array = np.expand_dims(flag_array, axis=1)
        self.data_array = data_array
        self.flag_array = flag_array
        self.Npols = int(data_array.shape[-1])
        self.uvw_array = tb.getcol('UVW')
        self.ant_1_array = tb.getcol('ANTENNA1').astype(np.int32)
        self.ant_2_array = tb.getcol('ANTENNA2').astype(np.int32)
        self.Nants_data = len(
            np.unique(
                np.concatenate((np.unique(self.ant_1_array),
                                np.unique(self.ant_2_array)))))
        self.baseline_array = self.antnums_to_baseline(self.ant_1_array,
                                                       self.ant_2_array)
        self.Nbls = len(np.unique(self.baseline_array))
        # Get times. MS from cotter are modified Julian dates in seconds (thanks to Danny Jacobs for figuring out the proper conversion)
        self.time_array = time.Time(tb.getcol('TIME') / (3600. * 24.),
                                    format='mjd').jd
        # Polarization array
        tbPol = tables.table(filepath + '/POLARIZATION')
        # list of lists, probably with each list corresponding to SPW.
        polList = tbPol.getcol('CORR_TYPE')[0]
        self.polarization_array = np.zeros(len(polList), dtype=np.int32)
        for polnum in range(len(polList)):
            self.polarization_array[polnum] = int(polDict[polList[polnum]])
        tbPol.close()
        # Integration time
        # use first interval and assume rest are constant (though measurement set has all integration times for each Nblt )
        # self.integration_time=tb.getcol('INTERVAL')[0]
        # for some reason, interval ends up larger than the difference between times...
        self.integration_time = float(times_unique[1] -
                                      times_unique[0]) * 3600. * 24.
        # open table with antenna location information
        tbAnt = tables.table(filepath + '/ANTENNA')
        tbObs = tables.table(filepath + '/OBSERVATION')
        self.telescope_name = tbObs.getcol('TELESCOPE_NAME')[0]
        self.instrument = tbObs.getcol('TELESCOPE_NAME')[0]
        tbObs.close()
        # Use Telescopes.py dictionary to set array position
        full_antenna_positions = tbAnt.getcol('POSITION')
        xyz_telescope_frame = tbAnt.getcolkeyword('POSITION',
                                                  'MEASINFO')['Ref']
        antFlags = np.empty(len(full_antenna_positions), dtype=bool)
        antFlags[:] = False
        for antnum in range(len(antFlags)):
            antFlags[antnum] = np.all(full_antenna_positions[antnum, :] == 0)
        if (xyz_telescope_frame == 'ITRF'):
            self.telescope_location = np.array(
                np.mean(full_antenna_positions[np.invert(antFlags), :],
                        axis=0))
        if self.telescope_location is None:
            try:
                self.set_telescope_params()
            except ValueError:
                warnings.warn(
                    'Telescope frame is not ITRF and telescope is not '
                    'in known_telescopes, so telescope_location is not set.')

        # antenna names
        ant_names = tbAnt.getcol('STATION')
        ant_diams = tbAnt.getcol('DISH_DIAMETER')

        self.antenna_diameters = ant_diams[ant_diams > 0]

        self.Nants_telescope = len(antFlags[np.invert(antFlags)])
        test_name = ant_names[0]
        names_same = True
        for antnum in range(len(ant_names)):
            if (not (ant_names[antnum] == test_name)):
                names_same = False
        if (not (names_same)):
            # cotter measurement sets store antenna names in the NAMES column.
            self.antenna_names = ant_names
        else:
            # importuvfits measurement sets store antenna names in the STATION column.
            self.antenna_names = tbAnt.getcol('NAME')
        self.antenna_numbers = np.arange(len(self.antenna_names)).astype(int)
        nAntOrig = len(self.antenna_names)
        ant_names = []
        for antNum in range(len(self.antenna_names)):
            if not (antFlags[antNum]):
                ant_names.append(self.antenna_names[antNum])
        self.antenna_names = ant_names
        self.antenna_numbers = self.antenna_numbers[np.invert(antFlags)]

        relative_positions = np.zeros_like(full_antenna_positions)
        relative_positions = full_antenna_positions - self.telescope_location.reshape(
            1, 3)
        self.antenna_positions = relative_positions[np.invert(antFlags), :]

        tbAnt.close()
        tbField = tables.table(filepath + '/FIELD')
        if (tbField.getcol('PHASE_DIR').shape[1] == 2):
            self.phase_type = 'drift'
            self.set_drift()
        elif (tbField.getcol('PHASE_DIR').shape[1] == 1):
            self.phase_type = 'phased'
            # MSv2.0 appears to assume J2000. Not sure how to specifiy otherwise
            self.phase_center_epoch = float(
                tb.getcolkeyword('UVW', 'MEASINFO')['Ref'][1:])
            self.phase_center_ra = float(tbField.getcol('PHASE_DIR')[0][0][0])
            self.phase_center_dec = float(tbField.getcol('PHASE_DIR')[0][0][1])
            self.set_phased()
        # set LST array from times and itrf
        self.set_lsts_from_time_array()
        # set the history parameter
        _, self.history = self._ms_hist_to_string(
            tables.table(filepath + '/HISTORY'))
        # CASA weights column keeps track of number of data points averaged.

        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str
        self.nsample_array = tb.getcol('WEIGHT_SPECTRUM')
        if (len(self.nsample_array.shape) == 3):
            self.nsample_array = np.expand_dims(self.nsample_array, axis=1)
        self.object_name = tbField.getcol('NAME')[0]
        tbField.close()
        tb.close()
        # order polarizations
        self.order_pols(pol_order)
        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)
Example #4
0
    def read_uvh5(self,
                  filename,
                  run_check=True,
                  check_extra=True,
                  run_check_acceptability=True):
        """
        Read in data from a UVH5 file.

        Args:
            filename: The file name to read.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.

        Returns:
            None
        """
        import h5py
        if not os.path.exists(filename):
            raise (IOError, filename + ' not found')

        # open hdf5 file for reading
        f = h5py.File(filename, 'r')

        # extract header information
        header = f['/Header']

        # get telescope information
        latitude = header['latitude'].value
        longitude = header['longitude'].value
        altitude = header['altitude'].value
        self.telescope_location_lat_lon_alt = (latitude, longitude, altitude)
        self.instrument = header['instrument'].value

        # get source information
        self.object_name = header['object_name'].value

        # set history appropriately
        self.history = header['history'].value
        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str

        # check for vis_units
        if 'vis_units' in header:
            self.vis_units = header['vis_units'].value
        else:
            # default to uncalibrated data
            self.vis_units = 'UNCALIB'

        # check for optional values
        if 'dut1' in header:
            self.dut1 = float(header['dut1'].value)
        if 'earth_omega' in header:
            self.earth_omega = float(header['earth_omega'].value)
        if 'gst0' in header:
            self.gst0 = float(header['gst0'].value)
        if 'rdate' in header:
            self.rdate = header['rdate'].value
        if 'timesys' in header:
            self.timesys = header['timesys'].value
        if 'x_orientation' in header:
            self.x_orientation = header['x_orientation'].value
        if 'telescope_name' in header:
            self.telescope_name = header['telescope_name'].value
        if 'antenna_positions' in header:
            self.antenna_positions = header['antenna_positions'].value
        if 'antenna_diameters' in header:
            self.antenna_diameters = header['antenna_diameters'].value
        if 'uvplane_reference_time' in header:
            self.uvplane_reference_time = int(
                header['uvplane_reference_time'].value)

        # check for phasing information
        self.phase_type = header['phase_type'].value
        if self.phase_type == 'phased':
            self.set_phased()
            self.phase_center_ra = float(header['phase_center_ra'].value)
            self.phase_center_dec = float(header['phase_center_dec'].value)
            self.phase_center_epoch = float(header['phase_center_epoch'].value)
        elif self.phase_type == 'drift':
            self.set_drift()
            self.zenith_dec = header['zenith_dec'].value
            self.zenith_ra = header['zenith_ra'].value
        else:
            self.set_unknown_phase_type()

        # get antenna arrays
        # cast to native python int type
        self.Nants_data = int(header['Nants_data'].value)
        self.Nants_telescope = int(header['Nants_telescope'].value)
        self.ant_1_array = header['ant_1_array'].value
        self.ant_2_array = header['ant_2_array'].value
        self.antenna_names = list(header['antenna_names'].value)
        self.antenna_numbers = header['antenna_numbers'].value

        # get baseline array
        self.baseline_array = self.antnums_to_baseline(self.ant_1_array,
                                                       self.ant_2_array)
        self.Nbls = len(np.unique(self.baseline_array))

        # get uvw array
        self.uvw_array = header['uvw_array'].value

        # get time information
        self.time_array = header['time_array'].value
        self.integration_time = float(header['integration_time'].value)
        self.lst_array = header['lst_array'].value

        # get frequency information
        self.freq_array = header['freq_array'].value
        self.channel_width = float(header['channel_width'].value)
        self.spw_array = header['spw_array'].value

        # get polarization information
        self.polarization_array = header['polarization_array'].value

        # get data shapes
        self.Nfreqs = int(header['Nfreqs'].value)
        self.Npols = int(header['Npols'].value)
        self.Ntimes = int(header['Ntimes'].value)
        self.Nblts = int(header['Nblts'].value)
        self.Nspws = int(header['Nspws'].value)

        # get extra_keywords
        if "extra_keywords" in header:
            self.extra_keywords = {}
            for key in header["extra_keywords"].keys():
                self.extra_keywords[key] = header["extra_keywords"][key].value

        # read data array
        dgrp = f['/Data']
        self.data_array = dgrp['visdata'].value

        # read the flag array
        self.flag_array = dgrp['flags'].value

        # get sample information
        self.nsample_array = dgrp['nsample_array'].value

        # check if the object has all required UVParameters
        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)

        return
Example #5
0
    def read_uvfits(self,
                    filename,
                    antenna_nums=None,
                    antenna_names=None,
                    ant_str=None,
                    ant_pairs_nums=None,
                    frequencies=None,
                    freq_chans=None,
                    times=None,
                    polarizations=None,
                    blt_inds=None,
                    read_data=True,
                    read_metadata=True,
                    run_check=True,
                    check_extra=True,
                    run_check_acceptability=True):
        """
        Read in header, metadata and data from a uvfits file. Supports reading
        only selected portions of the data.

        Args:
            filename: The uvfits file to read from.
            antenna_nums: The antennas numbers to include when reading data into
                the object (antenna positions and names for the excluded antennas
                will be retained). This cannot be provided if antenna_names is
                also provided. Ignored if read_data is False.
            antenna_names: The antennas names to include when reading data into
                the object (antenna positions and names for the excluded antennas
                will be retained). This cannot be provided if antenna_nums is
                also provided. Ignored if read_data is False.
            ant_pairs_nums: A list of antenna number tuples (e.g. [(0,1), (3,2)])
                specifying baselines to include when reading data into the object.
                Ordering of the numbers within the tuple does not matter.
                Ignored if read_data is False.
            ant_str: A string containing information about what antenna numbers
                and polarizations to include when reading data into the object.
                Can be 'auto', 'cross', 'all', or combinations of antenna numbers
                and polarizations (e.g. '1', '1_2', '1x_2y').
                See tutorial for more examples of valid strings and
                the behavior of different forms for ant_str.
                If '1x_2y,2y_3y' is passed, both polarizations 'xy' and 'yy' will
                be kept for both baselines (1,2) and (2,3) to return a valid
                pyuvdata object.
                An ant_str cannot be passed in addition to any of the above antenna
                args or the polarizations arg.
                Ignored if read_data is False.
            frequencies: The frequencies to include when reading data into the
                object. Ignored if read_data is False.
            freq_chans: The frequency channel numbers to include when reading
                data into the object. Ignored if read_data is False.
            times: The times to include when reading data into the object.
                Ignored if read_data is False.
            polarizations: The polarizations to include when reading data into
                the object. Ignored if read_data is False.
            blt_inds: The baseline-time indices to include when reading data into
                the object. This is not commonly used. Ignored if read_data is False.
            read_data: Read in the visibility and flag data. If set to false,
                only the basic header info and metadata (if read_metadata is True)
                will be read in. Results in an incompletely defined object
                (check will not pass). Default True.
            read_metadata: Read in metadata (times, baselines, uvws) as well as
                basic header info. Only used if read_data is False
                (metadata will be read if data is read). If both read_data and
                read_metadata are false, only basic header info is read in. Default True.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
                Ignored if read_data is False.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True. Ignored if read_data is False.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.
                Ignored if read_data is False.
        """
        if not read_data:
            run_check = False

        hdu_list = fits.open(filename, memmap=True)
        vis_hdu = hdu_list[
            0]  # assumes the visibilities are in the primary hdu
        vis_hdr = vis_hdu.header.copy()
        hdunames = uvutils.fits_indexhdus(
            hdu_list)  # find the rest of the tables

        # First get everything we can out of the header.
        self.set_phased()
        # check if we have an spw dimension
        if vis_hdr['NAXIS'] == 7:
            if vis_hdr['NAXIS5'] > 1:
                raise ValueError('Sorry.  Files with more than one spectral'
                                 'window (spw) are not yet supported. A '
                                 'great project for the interested student!')

            self.Nspws = vis_hdr.pop('NAXIS5')

            self.spw_array = np.int32(uvutils.fits_gethduaxis(vis_hdu, 5)) - 1

            # the axis number for phase center depends on if the spw exists
            self.phase_center_ra_degrees = np.float(vis_hdr.pop('CRVAL6'))
            self.phase_center_dec_degrees = np.float(vis_hdr.pop('CRVAL7'))
        else:
            self.Nspws = 1
            self.spw_array = np.array([0])

            # the axis number for phase center depends on if the spw exists
            self.phase_center_ra_degrees = np.float(vis_hdr.pop('CRVAL5'))
            self.phase_center_dec_degrees = np.float(vis_hdr.pop('CRVAL6'))

        # get shapes
        self.Nfreqs = vis_hdr.pop('NAXIS4')
        self.Npols = vis_hdr.pop('NAXIS3')
        self.Nblts = vis_hdr.pop('GCOUNT')

        self.freq_array = uvutils.fits_gethduaxis(vis_hdu, 4)
        self.freq_array.shape = (self.Nspws, ) + self.freq_array.shape
        self.channel_width = vis_hdr.pop('CDELT4')
        self.polarization_array = np.int32(uvutils.fits_gethduaxis(vis_hdu, 3))

        # other info -- not required but frequently used
        self.object_name = vis_hdr.pop('OBJECT', None)
        self.telescope_name = vis_hdr.pop('TELESCOP', None)
        self.instrument = vis_hdr.pop('INSTRUME', None)
        latitude_degrees = vis_hdr.pop('LAT', None)
        longitude_degrees = vis_hdr.pop('LON', None)
        altitude = vis_hdr.pop('ALT', None)
        self.x_orientation = vis_hdr.pop('XORIENT', None)
        self.history = str(vis_hdr.get('HISTORY', ''))
        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str

        while 'HISTORY' in vis_hdr.keys():
            vis_hdr.remove('HISTORY')

        self.vis_units = vis_hdr.pop('BUNIT', 'UNCALIB')
        self.phase_center_epoch = vis_hdr.pop('EPOCH', None)

        # remove standard FITS header items that are still around
        std_fits_substrings = [
            'SIMPLE', 'BITPIX', 'EXTEND', 'BLOCKED', 'GROUPS', 'PCOUNT',
            'BSCALE', 'BZERO', 'NAXIS', 'PTYPE', 'PSCAL', 'PZERO', 'CTYPE',
            'CRVAL', 'CRPIX', 'CDELT', 'CROTA', 'CUNIT', 'DATE-OBS'
        ]
        for key in vis_hdr.keys():
            for sub in std_fits_substrings:
                if key.find(sub) > -1:
                    vis_hdr.remove(key)

        # find all the remaining header items and keep them as extra_keywords
        for key in vis_hdr:
            if key == 'COMMENT':
                self.extra_keywords[key] = str(vis_hdr.get(key))
            elif key != '':
                self.extra_keywords[key] = vis_hdr.get(key)

        # Next read the antenna table
        ant_hdu = hdu_list[hdunames['AIPS AN']]

        # stuff in the header
        if self.telescope_name is None:
            self.telescope_name = ant_hdu.header['ARRNAM']

        self.gst0 = ant_hdu.header['GSTIA0']
        self.rdate = ant_hdu.header['RDATE']
        self.earth_omega = ant_hdu.header['DEGPDY']
        self.dut1 = ant_hdu.header['UT1UTC']
        if 'TIMESYS' in ant_hdu.header.keys():
            self.timesys = ant_hdu.header['TIMESYS']
        else:
            # CASA misspells this one
            self.timesys = ant_hdu.header['TIMSYS']

        if 'FRAME' in ant_hdu.header.keys():
            xyz_telescope_frame = ant_hdu.header['FRAME']
        else:
            warnings.warn('Required Antenna frame keyword not set, '
                          'setting to ????')
            xyz_telescope_frame = '????'

        # get telescope location and antenna positions.
        # VLA incorrectly sets ARRAYX/ARRAYY/ARRAYZ to 0, and puts array center
        # in the antenna positions themselves
        if (np.isclose(ant_hdu.header['ARRAYX'], 0)
                and np.isclose(ant_hdu.header['ARRAYY'], 0)
                and np.isclose(ant_hdu.header['ARRAYZ'], 0)):
            x_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 0])
            y_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 1])
            z_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 2])
            self.antenna_positions = (
                ant_hdu.data.field('STABXYZ') -
                np.array([x_telescope, y_telescope, z_telescope]))

        else:
            x_telescope = ant_hdu.header['ARRAYX']
            y_telescope = ant_hdu.header['ARRAYY']
            z_telescope = ant_hdu.header['ARRAYZ']
            # AIPS memo #117 says that antenna_positions should be relative to
            # the array center, but in a rotated ECEF frame so that the x-axis
            # goes through the local meridian.
            rot_ecef_positions = ant_hdu.data.field('STABXYZ')
            latitude, longitude, altitude = \
                uvutils.LatLonAlt_from_XYZ(np.array([x_telescope, y_telescope, z_telescope]))
            self.antenna_positions = uvutils.ECEF_from_rotECEF(
                rot_ecef_positions, longitude)

        if xyz_telescope_frame == 'ITRF':
            self.telescope_location = np.array(
                [x_telescope, y_telescope, z_telescope])
        else:
            if latitude_degrees is not None and longitude_degrees is not None and altitude is not None:
                self.telescope_location_lat_lon_alt_degrees = (
                    latitude_degrees, longitude_degrees, altitude)

        # stuff in columns
        ant_names = ant_hdu.data.field('ANNAME').tolist()
        self.antenna_names = []
        for name in ant_names:
            self.antenna_names.append(name.replace('\x00!', ''))

        # subtract one to get to 0-indexed values rather than 1-indexed values
        self.antenna_numbers = ant_hdu.data.field('NOSTA') - 1

        self.Nants_telescope = len(self.antenna_numbers)

        if 'DIAMETER' in ant_hdu.columns.names:
            self.antenna_diameters = ant_hdu.data.field('DIAMETER')

        try:
            self.set_telescope_params()
        except ValueError, ve:
            warnings.warn(str(ve))
Example #6
0
    def read_calfits(self,
                     filename,
                     run_check=True,
                     check_extra=True,
                     run_check_acceptability=True,
                     strict_fits=False):
        """
        Read data from a calfits file.

        Args:
            filename: The calfits file to read to.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.
        strict_fits: boolean
            If True, require that the data axes have cooresponding NAXIS, CRVAL,
            CDELT and CRPIX keywords. If False, allow CRPIX to be missing and
            set it equal to zero and allow the CRVAL for the spw directions to
            be missing and set it to zero. This keyword exists to support old
            calfits files that were missing many CRPIX and CRVAL keywords.
            Default is False.
        """
        F = fits.open(filename)
        data = F[0].data
        hdr = F[0].header.copy()
        hdunames = uvutils.fits_indexhdus(F)

        anthdu = F[hdunames['ANTENNAS']]
        self.Nants_telescope = anthdu.header['NAXIS2']
        antdata = anthdu.data
        self.antenna_names = map(str, antdata['ANTNAME'])
        self.antenna_numbers = map(int, antdata['ANTINDEX'])
        self.ant_array = np.array(map(int, antdata['ANTARR']))
        if np.min(self.ant_array) < 0:
            # ant_array was shorter than the other columns, so it was padded with -1s.
            # Remove the padded entries.
            self.ant_array = self.ant_array[np.where(self.ant_array >= 0)[0]]

        self.channel_width = hdr.pop('CHWIDTH')
        self.integration_time = hdr.pop('INTTIME')
        self.telescope_name = hdr.pop('TELESCOP')
        self.history = str(hdr.get('HISTORY', ''))

        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            if self.history.endswith('\n'):
                self.history += self.pyuvdata_version_str
            else:
                self.history += '\n' + self.pyuvdata_version_str

        while 'HISTORY' in hdr.keys():
            hdr.remove('HISTORY')
        self.time_range = map(float, hdr.pop('TMERANGE').split(','))
        self.gain_convention = hdr.pop('GNCONVEN')
        self.x_orientation = hdr.pop('XORIENT')
        self.cal_type = hdr.pop('CALTYPE')
        if self.cal_type == 'delay':
            self.freq_range = map(float, hdr.pop('FRQRANGE').split(','))
        else:
            if 'FRQRANGE' in hdr:
                self.freq_range = map(float, hdr.pop('FRQRANGE').split(','))
        if 'OBSERVER' in hdr:
            self.observer = hdr.pop('OBSERVER')
        if 'ORIGCAL' in hdr:
            self.git_origin_cal = hdr.pop('ORIGCAL')
        if 'HASHCAL' in hdr:
            self.git_hash_cal = hdr.pop('HASHCAL')

        # generate polarization and time array for either cal_type.
        self.Njones = hdr.pop('NAXIS2')
        self.jones_array = uvutils.fits_gethduaxis(F[0],
                                                   2,
                                                   strict_fits=strict_fits)
        self.Ntimes = hdr.pop('NAXIS3')
        self.time_array = uvutils.fits_gethduaxis(F[0],
                                                  3,
                                                  strict_fits=strict_fits)

        # get data.
        if self.cal_type == 'gain':
            self.set_gain()
            self.gain_array = data[:, :, :, :, :,
                                   0] + 1j * data[:, :, :, :, :, 1]
            self.flag_array = data[:, :, :, :, :, 2].astype('bool')
            if hdr.pop('NAXIS1') == 5:
                self.input_flag_array = data[:, :, :, :, :, 3].astype('bool')
                self.quality_array = data[:, :, :, :, :, 4]
            else:
                self.quality_array = data[:, :, :, :, :, 3]

            self.Nants_data = hdr.pop('NAXIS6')

            self.Nspws = hdr.pop('NAXIS5')
            # add this for backwards compatibility when the spw CRVAL wasn't recorded
            try:
                spw_array = uvutils.fits_gethduaxis(
                    F[0], 5, strict_fits=strict_fits) - 1
                if spw_array[0] == 0:
                    # XXX: backwards compatibility: if array is already (erroneously) zero-
                    #      indexed, do nothing
                    self.spw_array = spw_array
                else:
                    # subtract 1 to be zero-indexed
                    self.spw_array = uvutils.fits_gethduaxis(
                        F[0], 5, strict_fits=strict_fits) - 1
            except (KeyError):
                if not strict_fits:
                    _warn_oldcalfits(filename)
                    self.spw_array = np.array([0])
                else:
                    raise

            # generate frequency array from primary data unit.
            self.Nfreqs = hdr.pop('NAXIS4')
            self.freq_array = uvutils.fits_gethduaxis(F[0],
                                                      4,
                                                      strict_fits=strict_fits)
            self.freq_array.shape = (self.Nspws, ) + self.freq_array.shape

        if self.cal_type == 'delay':
            self.set_delay()
            try:
                # delay-style should have the same number of axes as gains
                self.Nants_data = hdr.pop('NAXIS6')
                self.Nspws = hdr.pop('NAXIS5')
                ax_spw = 5
                old_delay = False
            except (KeyError):
                _warn_olddelay(filename)
                self.Nants_data = hdr.pop('NAXIS5')
                self.Nspws = hdr.pop('NAXIS4')
                ax_spw = 4
                old_delay = True

            if old_delay:
                self.delay_array = data[:, :, np.newaxis, :, :, 0]
                self.quality_array = data[:, :, np.newaxis, :, :, 1]
            else:
                self.delay_array = data[:, :, :, :, :, 0]
                self.quality_array = data[:, :, :, :, :, 1]
            sechdu = F[hdunames['FLAGS']]
            flag_data = sechdu.data
            flag_hdr = sechdu.header
            if sechdu.header['NAXIS1'] == 2:
                self.flag_array = flag_data[:, :, :, :, :, 0].astype('bool')
                self.input_flag_array = flag_data[:, :, :, :, :,
                                                  1].astype('bool')
            else:
                self.flag_array = flag_data[:, :, :, :, :, 0].astype('bool')

            # add this for backwards compatibility when the spw CRVAL wasn't recorded
            try:
                spw_array = uvutils.fits_gethduaxis(F[0],
                                                    ax_spw,
                                                    strict_fits=strict_fits)
                if spw_array[0] == 0:
                    # XXX: backwards compatibility: if array is already (erroneously) zero-
                    #      indexed, do nothing
                    self.spw_array = spw_array
                else:
                    # subtract 1 to be zero-indexed
                    self.spw_array = spw_array - 1
            except (KeyError):
                if not strict_fits:
                    _warn_oldcalfits(filename)
                    self.spw_array = np.array([0])
                else:
                    raise

            # generate frequency array from flag data unit (no freq axis in primary).
            self.Nfreqs = sechdu.header['NAXIS4']
            self.freq_array = uvutils.fits_gethduaxis(sechdu,
                                                      4,
                                                      strict_fits=strict_fits)
            self.freq_array.shape = (self.Nspws, ) + self.freq_array.shape

            # add this for backwards compatibility when the spw CRVAL wasn't recorded
            try:
                spw_array = uvutils.fits_gethduaxis(
                    sechdu, 5, strict_fits=strict_fits) - 1
            except (KeyError):
                if not strict_fits:
                    _warn_oldcalfits(filename)
                    spw_array = np.array([0])
                else:
                    raise
            if not np.allclose(spw_array, self.spw_array):
                raise ValueError(
                    'Spectral window values are different in FLAGS HDU than in primary HDU'
                )

            time_array = uvutils.fits_gethduaxis(sechdu,
                                                 3,
                                                 strict_fits=strict_fits)
            if not np.allclose(time_array,
                               self.time_array,
                               rtol=self._time_array.tols[0],
                               atol=self._time_array.tols[0]):
                raise ValueError(
                    'Time values are different in FLAGS HDU than in primary HDU'
                )

            jones_array = uvutils.fits_gethduaxis(sechdu,
                                                  2,
                                                  strict_fits=strict_fits)
            if not np.allclose(jones_array,
                               self.jones_array,
                               rtol=self._jones_array.tols[0],
                               atol=self._jones_array.tols[0]):
                raise ValueError(
                    'Jones values are different in FLAGS HDU than in primary HDU'
                )

        # remove standard FITS header items that are still around
        std_fits_substrings = [
            'SIMPLE', 'BITPIX', 'EXTEND', 'BLOCKED', 'GROUPS', 'PCOUNT',
            'BSCALE', 'BZERO', 'NAXIS', 'PTYPE', 'PSCAL', 'PZERO', 'CTYPE',
            'CRVAL', 'CRPIX', 'CDELT', 'CROTA', 'CUNIT'
        ]
        for key in hdr.keys():
            for sub in std_fits_substrings:
                if key.find(sub) > -1:
                    hdr.remove(key)

        # find all the remaining header items and keep them as extra_keywords
        for key in hdr:
            if key == 'COMMENT':
                self.extra_keywords[key] = str(hdr.get(key))
            elif key != '':
                self.extra_keywords[key] = hdr.get(key)

        # get total quality array if present
        if 'TOTQLTY' in hdunames:
            totqualhdu = F[hdunames['TOTQLTY']]
            self.total_quality_array = totqualhdu.data

            # add this for backwards compatibility when the spw CRVAL wasn't recorded
            try:
                spw_array = uvutils.fits_gethduaxis(
                    totqualhdu, 4, strict_fits=strict_fits) - 1
            except (KeyError):
                if not strict_fits:
                    _warn_oldcalfits(filename)
                    spw_array = np.array([0])
                else:
                    raise
            if not np.allclose(spw_array, self.spw_array):
                raise ValueError(
                    'Spectral window values are different in TOTQLTY HDU than in primary HDU'
                )

            if self.cal_type != 'delay':
                # delay-type files won't have a freq_array
                freq_array = uvutils.fits_gethduaxis(totqualhdu,
                                                     3,
                                                     strict_fits=strict_fits)
                freq_array.shape = (self.Nspws, ) + freq_array.shape
                if not np.allclose(freq_array,
                                   self.freq_array,
                                   rtol=self._freq_array.tols[0],
                                   atol=self._freq_array.tols[0]):
                    raise ValueError(
                        'Frequency values are different in TOTQLTY HDU than in primary HDU'
                    )

            time_array = uvutils.fits_gethduaxis(totqualhdu,
                                                 2,
                                                 strict_fits=strict_fits)
            if not np.allclose(time_array,
                               self.time_array,
                               rtol=self._time_array.tols[0],
                               atol=self._time_array.tols[0]):
                raise ValueError(
                    'Time values are different in TOTQLTY HDU than in primary HDU'
                )

            jones_array = uvutils.fits_gethduaxis(totqualhdu,
                                                  1,
                                                  strict_fits=strict_fits)
            if not np.allclose(jones_array,
                               self.jones_array,
                               rtol=self._jones_array.tols[0],
                               atol=self._jones_array.tols[0]):
                raise ValueError(
                    'Jones values are different in TOTQLTY HDU than in primary HDU'
                )

        else:
            self.total_quality_array = None

        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)
Example #7
0
    def read_fhd_cal(self,
                     cal_file,
                     obs_file,
                     settings_file=None,
                     raw=True,
                     extra_history=None,
                     run_check=True,
                     check_extra=True,
                     run_check_acceptability=True):
        """
        Read data from an FHD cal.sav file.

        Args:
            cal_file: The cal.sav file to read from.
            obs_file: The obs.sav file to read from.
            settings_file: The settings_file to read from. Optional, but very
                useful for provenance.
            raw: Option to use the raw (per antenna, per frequency) solution or
                to use the fitted (polynomial over phase/amplitude) solution.
                Default is True (meaning use the raw solutions).
            extra_history: Optional string or list of strings to add to the
                object's history parameter. Default is None.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.
        """

        this_dict = readsav(cal_file, python_dict=True)
        cal_data = this_dict['cal']

        this_dict = readsav(obs_file, python_dict=True)
        obs_data = this_dict['obs']

        self.Nspws = 1
        self.spw_array = np.array([0])

        self.Nfreqs = int(cal_data['n_freq'][0])
        self.freq_array = np.zeros((self.Nspws, len(cal_data['freq'][0])),
                                   dtype=np.float_)
        self.freq_array[0, :] = cal_data['freq'][0]
        self.channel_width = float(np.mean(np.diff(self.freq_array)))

        # FHD only calculates one calibration over all the times.
        # cal_data.n_times gives the number of times that goes into that one
        # calibration, UVCal.Ntimes gives the number of separate calibrations
        # along the time axis.
        self.Ntimes = 1
        time_array = obs_data['baseline_info'][0]['jdate'][0]
        self.integration_time = np.round(
            np.mean(np.diff(time_array)) * 24 * 3600, 2)
        self.time_array = np.array([np.mean(time_array)])

        self.Njones = int(cal_data['n_pol'][0])
        # FHD only has the diagonal elements (jxx, jyy) and if there's only one
        # present it must be jxx
        if self.Njones == 1:
            self.jones_array = np.array([-5])
        else:
            self.jones_array = np.array([-5, -6])

        self.telescope_name = obs_data['instrument'][0]

        self.Nants_data = int(cal_data['n_tile'][0])
        self.Nants_telescope = int(cal_data['n_tile'][0])
        self.antenna_names = np.array(cal_data['tile_names'][0].tolist())
        self.antenna_numbers = np.arange(self.Nants_telescope)
        self.ant_array = np.arange(self.Nants_data)

        self.set_sky()
        self.sky_field = 'phase center (RA, Dec): ({ra}, {dec})'.format(
            ra=obs_data['orig_phasera'][0], dec=obs_data['orig_phasedec'][0])
        self.sky_catalog = cal_data['skymodel'][0]['catalog_name'][0]
        self.ref_antenna_name = cal_data['ref_antenna_name'][0]
        self.Nsources = int(cal_data['skymodel'][0]['n_sources'][0])
        self.baseline_range = [
            float(cal_data['min_cal_baseline'][0]),
            float(cal_data['max_cal_baseline'][0])
        ]

        galaxy_model = cal_data['skymodel'][0]['galaxy_model'][0]
        if galaxy_model == 0:
            galaxy_model = None
        else:
            galaxy_model = 'gsm'

        diffuse_model = cal_data['skymodel'][0]['diffuse_model'][0]
        if diffuse_model == '':
            diffuse_model = None
        else:
            diffuse_model = os.path.basename(diffuse_model)

        if galaxy_model is not None:
            if diffuse_model is not None:
                self.diffuse_model = galaxy_model + ' + ' + diffuse_model
            else:
                self.diffuse_model = galaxy_model
        elif diffuse_model is not None:
            self.diffuse_model = diffuse_model

        self.gain_convention = 'divide'
        self.x_orientation = 'east'

        self.set_gain()
        fit_gain_array_in = cal_data['gain'][0]
        fit_gain_array = np.zeros(self._gain_array.expected_shape(self),
                                  dtype=np.complex_)
        for jones_i, arr in enumerate(fit_gain_array_in):
            fit_gain_array[:, 0, :, 0, jones_i] = arr
        if raw:
            res_gain_array_in = cal_data['gain_residual'][0]
            res_gain_array = np.zeros(self._gain_array.expected_shape(self),
                                      dtype=np.complex_)
            for jones_i, arr in enumerate(fit_gain_array_in):
                res_gain_array[:, 0, :, 0, jones_i] = arr
            self.gain_array = fit_gain_array + res_gain_array
        else:
            self.gain_array = fit_gain_array

        # FHD doesn't really have a chi^2 measure. What is has is a convergence measure.
        # The solution converged well if this is less than the convergence
        # threshold ('conv_thresh' in extra_keywords).
        self.quality_array = np.zeros_like(self.gain_array, dtype=np.float)
        convergence = cal_data['convergence'][0]
        for jones_i, arr in enumerate(convergence):
            self.quality_array[:, 0, :, 0, jones_i] = arr

        # array of used frequencies (1: used, 0: flagged)
        freq_use = obs_data['baseline_info'][0]['freq_use'][0]
        # array of used antennas (1: used, 0: flagged)
        ant_use = obs_data['baseline_info'][0]['tile_use'][0]
        # array of used times (1: used, 0: flagged)
        time_use = obs_data['baseline_info'][0]['time_use'][0]

        time_array_use = time_array[np.where(time_use > 0)]
        self.time_range = [np.min(time_array_use), np.max(time_array_use)]

        # Currently this can't include the times because the flag array
        # dimensions has to match the gain array dimensions. This is somewhat artificial...
        self.flag_array = np.zeros_like(self.gain_array, dtype=np.bool)
        flagged_ants = np.where(ant_use == 0)[0]
        for ant in flagged_ants:
            self.flag_array[ant, :] = 1
        flagged_freqs = np.where(freq_use == 0)[0]
        for freq in flagged_freqs:
            self.flag_array[:, :, freq] = 1

        # currently don't have branch info. may change in future.
        self.git_origin_cal = 'https://github.com/EoRImaging/FHD'
        self.git_hash_cal = obs_data['code_version'][0]

        self.extra_keywords['autoscal'] = \
            '[' + ', '.join(str(d) for d in cal_data['auto_scale'][0]) + ']'
        self.extra_keywords['nvis_cal'] = cal_data['n_vis_cal'][0]
        self.extra_keywords['time_avg'] = cal_data['time_avg'][0]
        self.extra_keywords['cvgthres'] = cal_data['conv_thresh'][0]
        if 'DELAYS' in obs_data.dtype.names:
            if obs_data['delays'][0] is not None:
                self.extra_keywords['delays'] = \
                    '[' + ', '.join(str(int(d)) for d in obs_data['delays'][0]) + ']'

        if not raw:
            self.extra_keywords['polyfit'] = cal_data['polyfit'][0]
            self.extra_keywords['bandpass'] = cal_data['bandpass'][0]
            self.extra_keywords['mode_fit'] = cal_data['mode_fit'][0]
            self.extra_keywords['amp_deg'] = cal_data['amp_degree'][0]
            self.extra_keywords['phse_deg'] = cal_data['phase_degree'][0]

        if settings_file is not None:
            self.history, self.observer = get_fhd_history(settings_file,
                                                          return_user=True)
        else:
            warnings.warn('No settings file, history will be incomplete')
            self.history = ''

        if extra_history is not None:
            if isinstance(extra_history, (list, tuple)):
                self.history += '\n' + '\n'.join(extra_history)
            else:
                self.history += '\n' + extra_history

        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            if self.history.endswith('\n'):
                self.history += self.pyuvdata_version_str
            else:
                self.history += '\n' + self.pyuvdata_version_str

        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)
Example #8
0
    def read_uvfits(self,
                    filename,
                    run_check=True,
                    check_extra=True,
                    run_check_acceptability=True):
        """
        Read in data from a uvfits file.

        Args:
            filename: The uvfits file to read from.
            run_check: Option to check for the existence and proper shapes of
                parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                parameters after reading in the file. Default is True.
        """
        F = fits.open(filename)
        D = F[0]  # assumes the visibilities are in the primary hdu
        hdr = D.header.copy()
        hdunames = uvutils.fits_indexhdus(F)  # find the rest of the tables

        # astropy.io fits reader scales date according to relevant PZER0 (?)
        time0_array = D.data['DATE']
        try:
            # uvfits standard is to have 2 DATE parameters, both floats:
            # DATE (full day) and _DATE (fractional day)
            time1_array = D.data['_DATE']
            self.time_array = (time0_array.astype(np.double) +
                               time1_array.astype(np.double))
        except (KeyError):
            # cotter uvfits files have one DATE that is a double
            self.time_array = time0_array
            if np.finfo(time0_array[0]).precision < 5:
                raise ValueError('JDs in this file are not precise to '
                                 'better than a second.')
            if (np.finfo(time0_array[0]).precision > 5
                    and np.finfo(time0_array[0]).precision < 8):
                warnings.warn('The JDs in this file have sub-second '
                              'precision, but not sub-millisecond. '
                              'Use with caution.')

        self.Ntimes = len(np.unique(self.time_array))

        # if antenna arrays are present, use them. otherwise use baseline array
        try:
            # Note: uvfits antennas are 1 indexed,
            # need to subtract one to get to 0-indexed
            self.ant_1_array = np.int32(D.data.field('ANTENNA1')) - 1
            self.ant_2_array = np.int32(D.data.field('ANTENNA2')) - 1
            subarray = np.int32(D.data.field('SUBARRAY')) - 1
            # error on files with multiple subarrays
            if len(set(subarray)) > 1:
                raise ValueError('This file appears to have multiple subarray '
                                 'values; only files with one subarray are '
                                 'supported.')
        except (KeyError):
            # cannot set this to be the baseline array because it uses the
            # 256 convention, not our 2048 convention
            bl_input_array = np.int64(D.data.field('BASELINE'))

            # get antenna arrays based on uvfits baseline array
            self.ant_1_array, self.ant_2_array = \
                self.baseline_to_antnums(bl_input_array)
        # check for multi source files
        try:
            source = D.data.field('SOURCE')
            if len(set(source)) > 1:
                raise ValueError('This file has multiple sources. Only single '
                                 'source observations are supported.')
        except (KeyError):
            pass

        # get self.baseline_array using our convention
        self.baseline_array = \
            self.antnums_to_baseline(self.ant_1_array,
                                     self.ant_2_array)
        self.Nbls = len(np.unique(self.baseline_array))

        # initialize internal variables based on the antenna lists
        self.Nants_data = int(
            len(
                np.unique(self.ant_1_array.tolist() +
                          self.ant_2_array.tolist())))

        self.set_phased()
        # check if we have an spw dimension
        if hdr.pop('NAXIS') == 7:
            if hdr['NAXIS5'] > 1:
                raise ValueError('Sorry.  Files with more than one spectral' +
                                 'window (spw) are not yet supported. A ' +
                                 'great project for the interested student!')
            self.data_array = (D.data.field('DATA')[:, 0, 0, :, :, :, 0] +
                               1j * D.data.field('DATA')[:, 0, 0, :, :, :, 1])
            self.flag_array = (D.data.field('DATA')[:, 0, 0, :, :, :, 2] <= 0)
            self.nsample_array = np.abs(
                D.data.field('DATA')[:, 0, 0, :, :, :, 2])
            self.Nspws = hdr.pop('NAXIS5')
            assert (self.Nspws == self.data_array.shape[1])

            # the axis number for phase center depends on if the spw exists
            # subtract 1 to be zero-indexed
            self.spw_array = np.int32(uvutils.fits_gethduaxis(D, 5)) - 1

            self.phase_center_ra_degrees = np.float(hdr.pop('CRVAL6'))
            self.phase_center_dec_degrees = np.float(hdr.pop('CRVAL7'))
        else:
            # in many uvfits files the spw axis is left out,
            # here we put it back in so the dimensionality stays the same
            self.data_array = (D.data.field('DATA')[:, 0, 0, :, :, 0] +
                               1j * D.data.field('DATA')[:, 0, 0, :, :, 1])
            self.data_array = self.data_array[:, np.newaxis, :, :]
            self.flag_array = (D.data.field('DATA')[:, 0, 0, :, :, 2] <= 0)
            self.flag_array = self.flag_array[:, np.newaxis, :, :]
            self.nsample_array = np.abs(D.data.field('DATA')[:, 0, 0, :, :, 2])
            self.nsample_array = (self.nsample_array[:, np.newaxis, :, :])

            # the axis number for phase center depends on if the spw exists
            self.Nspws = 1
            self.spw_array = np.array([0])

            self.phase_center_ra_degrees = np.float(hdr.pop('CRVAL5'))
            self.phase_center_dec_degrees = np.float(hdr.pop('CRVAL6'))

        # get shapes
        self.Nfreqs = hdr.pop('NAXIS4')
        self.Npols = hdr.pop('NAXIS3')
        self.Nblts = hdr.pop('GCOUNT')

        # read baseline vectors in units of seconds, return in meters
        self.uvw_array = (np.array(
            np.stack(
                (D.data.field('UU'), D.data.field('VV'), D.data.field('WW'))))
                          * const.c.to('m/s').value).T

        self.freq_array = uvutils.fits_gethduaxis(D, 4)
        self.channel_width = hdr.pop('CDELT4')

        try:
            self.integration_time = float(D.data.field('INTTIM')[0])
        except (KeyError):
            if self.Ntimes > 1:
                self.integration_time = \
                    float(np.diff(np.sort(list(set(self.time_array))))
                          [0]) * 86400
            else:
                raise ValueError('integration time not specified and only '
                                 'one time present')

        self.freq_array.shape = (self.Nspws, ) + self.freq_array.shape

        self.polarization_array = np.int32(uvutils.fits_gethduaxis(D, 3))

        # other info -- not required but frequently used
        self.object_name = hdr.pop('OBJECT', None)
        self.telescope_name = hdr.pop('TELESCOP', None)
        self.instrument = hdr.pop('INSTRUME', None)
        latitude_degrees = hdr.pop('LAT', None)
        longitude_degrees = hdr.pop('LON', None)
        altitude = hdr.pop('ALT', None)
        self.x_orientation = hdr.pop('XORIENT', None)
        self.history = str(hdr.get('HISTORY', ''))
        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str

        while 'HISTORY' in hdr.keys():
            hdr.remove('HISTORY')

        # if 'CASAHIST' in hdr.keys():
        #    self.casa_history=hdr.pop('CASAHIST',None)
        self.vis_units = hdr.pop('BUNIT', 'UNCALIB')
        self.phase_center_epoch = hdr.pop('EPOCH', None)

        # remove standard FITS header items that are still around
        std_fits_substrings = [
            'SIMPLE', 'BITPIX', 'EXTEND', 'BLOCKED', 'GROUPS', 'PCOUNT',
            'BSCALE', 'BZERO', 'NAXIS', 'PTYPE', 'PSCAL', 'PZERO', 'CTYPE',
            'CRVAL', 'CRPIX', 'CDELT', 'CROTA', 'CUNIT', 'DATE-OBS'
        ]
        for key in hdr.keys():
            for sub in std_fits_substrings:
                if key.find(sub) > -1:
                    hdr.remove(key)

        # find all the remaining header items and keep them as extra_keywords
        for key in hdr:
            if key == 'COMMENT':
                self.extra_keywords[key] = str(hdr.get(key))
            elif key != '':
                self.extra_keywords[key] = hdr.get(key)

        # READ the antenna table
        ant_hdu = F[hdunames['AIPS AN']]

        # stuff in the header
        if self.telescope_name is None:
            self.telescope_name = ant_hdu.header['ARRNAM']

        self.gst0 = ant_hdu.header['GSTIA0']
        self.rdate = ant_hdu.header['RDATE']
        self.earth_omega = ant_hdu.header['DEGPDY']
        self.dut1 = ant_hdu.header['UT1UTC']
        try:
            self.timesys = ant_hdu.header['TIMESYS']
        except (KeyError):
            # CASA misspells this one
            self.timesys = ant_hdu.header['TIMSYS']

        try:
            xyz_telescope_frame = ant_hdu.header['FRAME']
        except (KeyError):
            warnings.warn('Required Antenna frame keyword not set, '
                          'setting to ????')
            xyz_telescope_frame = '????'

        # get telescope location and antenna positions.
        # VLA incorrectly sets ARRAYX/ARRAYY/ARRAYZ to 0, and puts array center
        # in the antenna positions themselves
        if (np.isclose(ant_hdu.header['ARRAYX'], 0)
                and np.isclose(ant_hdu.header['ARRAYY'], 0)
                and np.isclose(ant_hdu.header['ARRAYZ'], 0)):
            x_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 0])
            y_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 1])
            z_telescope = np.mean(ant_hdu.data['STABXYZ'][:, 2])
            self.antenna_positions = (
                ant_hdu.data.field('STABXYZ') -
                np.array([x_telescope, y_telescope, z_telescope]))

        else:
            x_telescope = ant_hdu.header['ARRAYX']
            y_telescope = ant_hdu.header['ARRAYY']
            z_telescope = ant_hdu.header['ARRAYZ']
            # AIPS memo #117 says that antenna_positions should be relative to
            # the array center, but in a rotated ECEF frame so that the x-axis
            # goes through the local meridian.
            rot_ecef_positions = ant_hdu.data.field('STABXYZ')
            latitude, longitude, altitude = \
                uvutils.LatLonAlt_from_XYZ(np.array([x_telescope, y_telescope, z_telescope]))
            self.antenna_positions = uvutils.ECEF_from_rotECEF(
                rot_ecef_positions, longitude)

        if xyz_telescope_frame == 'ITRF':
            self.telescope_location = np.array(
                [x_telescope, y_telescope, z_telescope])
        else:
            if latitude_degrees is not None and longitude_degrees is not None and altitude is not None:
                self.telescope_location_lat_lon_alt_degrees = (
                    latitude_degrees, longitude_degrees, altitude)

        # stuff in columns
        ant_names = ant_hdu.data.field('ANNAME').tolist()
        self.antenna_names = []
        for name in ant_names:
            self.antenna_names.append(name.replace('\x00!', ''))

        # subtract one to get to 0-indexed values rather than 1-indexed values
        self.antenna_numbers = ant_hdu.data.field('NOSTA') - 1

        self.Nants_telescope = len(self.antenna_numbers)

        try:
            self.antenna_diameters = ant_hdu.data.field('DIAMETER')
        except (KeyError):
            pass

        del (D)

        try:
            self.set_telescope_params()
        except ValueError, ve:
            warnings.warn(str(ve))
Example #9
0
    def read_cst_beam(self,
                      filename,
                      beam_type='power',
                      feed_pol='x',
                      rotate_pol=True,
                      frequency=None,
                      telescope_name=None,
                      feed_name=None,
                      feed_version=None,
                      model_name=None,
                      model_version=None,
                      history='',
                      run_check=True,
                      check_extra=True,
                      run_check_acceptability=True):
        """
        Read in data from a cst file.

        Args:
            filename: The cst file to read from.
            beam_type: what beam_type to read in ('power' or 'efield'). Defaults to 'power'.
            feed_pol: what feed or polarization the files correspond to.
                Defaults to 'x' (meaning x for efield or xx for power beams).
            rotate_pol: If True, assume the structure in the simulation is symmetric under
                90 degree rotations about the z-axis (so that the y polarization can be
                constructed by rotating the x polarization or vice versa). Default: True.
            frequency: the frequency corresponding to the filename.
                If not passed, the code attempts to parse it from the filename.
            telescope_name: the name of the telescope corresponding to the filename.
            feed_name: the name of the feed corresponding to the filename.
            feed_version: the version of the feed corresponding to the filename.
            model_name: the name of the model corresponding to the filename.
            model_version: the version of the model corresponding to the filename.
            history: A string detailing the history of the filename.
            run_check: Option to check for the existence and proper shapes of
                required parameters after reading in the file. Default is True.
            check_extra: Option to check optional parameters as well as required
                ones. Default is True.
            run_check_acceptability: Option to check acceptable range of the values of
                required parameters after reading in the file. Default is True.
        """
        self.telescope_name = telescope_name
        self.feed_name = feed_name
        self.feed_version = feed_version
        self.model_name = model_name
        self.model_version = model_version
        self.history = history
        if not uvutils.check_history_version(self.history,
                                             self.pyuvdata_version_str):
            self.history += self.pyuvdata_version_str

        if beam_type is 'power':
            self.Naxes_vec = 1

            if feed_pol is 'x':
                feed_pol = 'xx'
            elif feed_pol is 'y':
                feed_pol = 'yy'

            if rotate_pol:
                rot_pol_dict = {'xx': 'yy', 'yy': 'xx', 'xy': 'yx', 'yx': 'xy'}
                pol2 = rot_pol_dict[feed_pol]
                self.polarization_array = np.array(
                    [uvutils.polstr2num(feed_pol),
                     uvutils.polstr2num(pol2)])
            else:
                self.polarization_array = np.array(
                    [uvutils.polstr2num(feed_pol)])

            self.Npols = len(self.polarization_array)
            self.set_power()
        else:
            self.Naxes_vec = 2
            self.Ncomponents_vec = 2
            if rotate_pol:
                if feed_pol is 'x':
                    self.feed_array = np.array(['x', 'y'])
                else:
                    self.feed_array = np.array(['y', 'x'])
            else:
                if feed_pol is 'x':
                    self.feed_array = np.array(['x'])
                else:
                    self.feed_array = np.array(['y'])
            self.Nfeeds = len(self.feed_array)
            self.set_efield()

        self.data_normalization = 'physical'
        self.antenna_type = 'simple'

        self.Nfreqs = 1
        self.Nspws = 1
        self.freq_array = np.zeros((self.Nspws, self.Nfreqs))
        self.bandpass_array = np.zeros((self.Nspws, self.Nfreqs))

        self.spw_array = np.array([0])
        self.pixel_coordinate_system = 'az_za'
        self.set_cs_params()

        out_file = open(filename, 'r')
        line = out_file.readline().strip()  # Get the first line
        out_file.close()
        raw_names = line.split(']')
        raw_names = [raw_name for raw_name in raw_names if not raw_name == '']
        column_names = []
        units = []
        for raw_name in raw_names:
            column_name, unit = tuple(raw_name.split('['))
            column_names.append(''.join(column_name.lower().split(' ')))
            units.append(unit.lower().strip())

        data = np.loadtxt(filename, skiprows=2)

        theta_col = np.where(np.array(column_names) == 'theta')[0][0]
        phi_col = np.where(np.array(column_names) == 'phi')[0][0]

        if 'deg' in units[theta_col]:
            theta_data = np.radians(data[:, theta_col])
        else:
            theta_data = data[:, theta_col]
        if 'deg' in units[phi_col]:
            phi_data = np.radians(data[:, phi_col])
        else:
            phi_data = data[:, phi_col]

        theta_axis = np.sort(np.unique(theta_data))
        phi_axis = np.sort(np.unique(phi_data))
        if not theta_axis.size * phi_axis.size == theta_data.size:
            raise ValueError('Data does not appear to be on a grid')

        theta_data = theta_data.reshape((theta_axis.size, phi_axis.size),
                                        order='F')
        phi_data = phi_data.reshape((theta_axis.size, phi_axis.size),
                                    order='F')

        delta_theta = np.diff(theta_axis)
        if not np.isclose(np.max(delta_theta), np.min(delta_theta)):
            raise ValueError(
                'Data does not appear to be regularly gridded in zenith angle')
        delta_theta = delta_theta[0]

        delta_phi = np.diff(phi_axis)
        if not np.isclose(np.max(delta_phi), np.min(delta_phi)):
            raise ValueError(
                'Data does not appear to be regularly gridded in azimuth angle'
            )
        delta_phi = delta_phi[0]

        self.axis1_array = phi_axis
        self.Naxes1 = self.axis1_array.size
        self.axis2_array = theta_axis
        self.Naxes2 = self.axis2_array.size

        if self.beam_type == 'power':
            # type depends on whether cross pols are present (if so, complex, else float)
            self.data_array = np.zeros(self._data_array.expected_shape(self),
                                       dtype=self._data_array.expected_type)
        else:
            self.data_array = np.zeros(self._data_array.expected_shape(self),
                                       dtype=np.complex)

        if frequency is not None:
            self.freq_array[0] = frequency
        else:
            self.freq_array[0] = self.name2freq(filename)

        if rotate_pol:
            # for second polarization, rotate by pi/2
            rot_phi = phi_data + np.pi / 2
            rot_phi[np.where(rot_phi >= 2 * np.pi)] -= 2 * np.pi
            roll_rot_phi = np.roll(rot_phi,
                                   int((np.pi / 2) / delta_phi),
                                   axis=1)
            if not np.allclose(roll_rot_phi, phi_data):
                raise ValueError('Rotating by pi/2 failed')

            # theta should not be affected by the rotation
            rot_theta = theta_data
            roll_rot_theta = np.roll(rot_theta,
                                     int((np.pi / 2) / delta_phi),
                                     axis=1)
            if not np.allclose(roll_rot_theta, theta_data):
                raise ValueError('Rotating by pi/2 failed')

        # get beam
        if self.beam_type is 'power':
            data_col = np.where(np.array(column_names) == 'abs(v)')[0][0]
            power_beam1 = data[:, data_col].reshape(
                (theta_axis.size, phi_axis.size), order='F')**2.

            self.data_array[0, 0, 0, 0, :, :] = power_beam1

            if rotate_pol:
                # rotate by pi/2 for second polarization
                power_beam2 = np.roll(power_beam1,
                                      int((np.pi / 2) / delta_phi),
                                      axis=1)
                self.data_array[0, 0, 1, 0, :, :] = power_beam2
        else:
            self.basis_vector_array = np.zeros(
                (self.Naxes_vec, self.Ncomponents_vec, self.Naxes2,
                 self.Naxes1))
            self.basis_vector_array[0, 0, :, :] = 1.0
            self.basis_vector_array[1, 1, :, :] = 1.0

            theta_mag_col = np.where(
                np.array(column_names) == 'abs(theta)')[0][0]
            theta_phase_col = np.where(
                np.array(column_names) == 'phase(theta)')[0][0]
            phi_mag_col = np.where(np.array(column_names) == 'abs(phi)')[0][0]
            phi_phase_col = np.where(
                np.array(column_names) == 'phase(phi)')[0][0]

            theta_mag = data[:, theta_mag_col].reshape(
                (theta_axis.size, phi_axis.size), order='F')
            phi_mag = data[:, phi_mag_col].reshape(
                (theta_axis.size, phi_axis.size), order='F')
            if 'deg' in units[theta_phase_col]:
                theta_phase = np.radians(data[:, theta_phase_col])
            else:
                theta_phase = data[:, theta_phase_col]
            if 'deg' in units[phi_phase_col]:
                phi_phase = np.radians(data[:, phi_phase_col])
            else:
                phi_phase = data[:, phi_phase_col]
            theta_phase = theta_phase.reshape((theta_axis.size, phi_axis.size),
                                              order='F')
            phi_phase = phi_phase.reshape((theta_axis.size, phi_axis.size),
                                          order='F')

            theta_beam = theta_mag * np.exp(1j * theta_phase)
            phi_beam = phi_mag * np.exp(1j * phi_phase)

            self.data_array[0, 0, 0, 0, :, :] = phi_beam
            self.data_array[1, 0, 0, 0, :, :] = theta_beam

            if rotate_pol:
                # rotate by pi/2 for second polarization
                theta_beam2 = np.roll(theta_beam,
                                      int((np.pi / 2) / delta_phi),
                                      axis=1)
                phi_beam2 = np.roll(phi_beam,
                                    int((np.pi / 2) / delta_phi),
                                    axis=1)
                self.data_array[0, 0, 1, 0, :, :] = phi_beam2
                self.data_array[1, 0, 1, 0, :, :] = theta_beam2

        self.bandpass_array[0] = 1

        if frequency is None:
            warnings.warn('No frequency provided. Detected frequency is: '
                          '{freqs} Hz'.format(freqs=self.freq_array))

        if run_check:
            self.check(check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)