Beispiel #1
0
    def __init__(self, fitsfns):

        from formats import psrfits        

        super(NuppiSplitPsrfitsData, self).__init__(fitsfns)
        self.obstype = 'Nuppi'
	self.beam_id = 0
        # Parse filename to get the scan number
        m = self.fnmatch(fitsfns[0])
        self.scan_num = m.groupdict()['scan']
        self.obs_name = m.groupdict()['source']
        self.num_ifs = self.specinfo.hdus[1].header['NPOL']

	dayfrac = calendar.MJD_to_date(self.timestamp_mjd)[-1]%1
	self.start_ast = int((dayfrac*24)*3600)
	self.start_ast %= 24*3600

        self.specinfo = psrfits.SpectraInfo(self.fns)
        self.original_file = os.path.split(sorted(self.specinfo.filenames)[0])[-1]
        self.project_id = self.specinfo.project_id
        self.observers = self.specinfo.observer
        self.source_name = self.specinfo.source
        self.center_freq = self.specinfo.fctr
        self.num_channels_per_record = self.specinfo.num_channels
        self.channel_bandwidth = self.specinfo.df*1000.0 # In kHz
        self.sample_time = self.specinfo.dt*1e6 # In microseconds
        self.sum_id = int(self.specinfo.summed_polns)
        self.timestamp_mjd = self.specinfo.start_MJD[0]
        self.start_lst = self.specinfo.start_lst 
        self.orig_start_az = self.specinfo.azimuth
        self.orig_start_za = self.specinfo.zenith_ang
        self.ra_deg = self.specinfo.ra2000
        self.dec_deg = self.specinfo.dec2000
        self.right_ascension = float(protractor.convert(self.ra_deg, \
                                        'deg', 'hmsstr')[0].replace(':', ''))
        self.declination = float(protractor.convert(self.dec_deg, \
                                        'deg', 'dmsstr')[0].replace(':', ''))
        l, b = sextant.equatorial_to_galactic(self.ra_deg, self.dec_deg, \
                                            'deg', 'deg', J2000=True)
        self.galactic_longitude = float(l)
        self.galactic_latitude = float(b)

        self.file_size = int(sum([os.path.getsize(fn) for fn in fitsfns]))
        self.observation_time = self.specinfo.T
        self.num_samples = self.specinfo.N
        self.data_size = self.num_samples * \
                            self.specinfo.bits_per_sample/8.0 * \
                            self.num_channels_per_record
        self.num_samples_per_record = self.specinfo.spectra_per_subint
        self.header_version = float(self.specinfo.header_version)
Beispiel #2
0
    def get_correct_positions(self):
        """Reconstruct original wapp filename and check
            for correct beam positions from the coordinates
            table.

            Returns nothing, updates object in place.
        """
        fn0 = os.path.basename(min(self.fns)).lstrip('4bit-').replace(
            's0g0', '').replace('s1g0', '').replace('00100', '00000')
        # Get corrected beam positions
        matches = [line for line in open(config.basic.mock_coords_table, 'r') if \
                        line.replace('s0g0','').startswith(fn0)]
        if len(matches) > 1:
            matches = [matches[0]]

        if len(matches) == 0 and self.timestamp_mjd > 55378:
            # No corrected coords found, but coordinate problem is fixed,
            # so use header values.
            # MJD=55378 is July 1st 2010, it is a recent date by which
            # the coord problem is definitely corrected. (The problem
            # occured from Feb 2009 to Jan 28, 2010).
            self.right_ascension = self.orig_right_ascension
            self.declination = self.orig_declination
            self.ra_deg = self.orig_ra_deg
            self.dec_deg = self.orig_dec_deg
            self.galactic_longitude = self.orig_galactic_longitude
            self.galactic_latitude = self.orig_galactic_latitude
        elif len(matches) == 1:
            # Use values from coords table
            self.posn_corrected = True

            # Format of mock coords table is:
            # <first sub0 filename> <ra deg> <dec deg> <frac year> <lst hrs> <ALFA rot deg>
            split = matches[0].split()
            self.ra_deg = float(split[1])
            self.dec_deg = float(split[2])

            self.correct_ra = protractor.convert(self.ra_deg, 'deg',
                                                 'hmsstr')[0]
            self.correct_decl = protractor.convert(self.dec_deg, 'deg',
                                                   'dmsstr')[0]
            self.right_ascension = float(self.correct_ra.replace(':', ''))
            self.declination = float(self.correct_decl.replace(':', ''))
            l, b = sextant.equatorial_to_galactic(self.ra_deg, self.dec_deg, \
                                    'deg', 'deg', J2000=True)
            self.galactic_longitude = float(l)
            self.galactic_latitude = float(b)
        else:
            raise ValueError("Bad number of matches (%d) in coords table! " \
                             "(Files: %s)" % (len(matches), ", ".join(self.fns)))
Beispiel #3
0
    def get_correct_positions(self):
        """Reconstruct original wapp filename and check
            for correct beam positions from the coordinates
            table.

            Returns nothing, updates object in place.
        """
        wappfn = '.'.join([self.project_id, self.source_name, \
                            "wapp%d" % (self.beam_id/2+1), \
                            "%5d" % int(self.timestamp_mjd), \
                            self.fnmatch(self.original_file).groupdict()['scan']])
        # Get corrected beam positions
        matches = [line for line in open(COORDS_TABLE, 'r') if \
                        line.startswith(wappfn)]
        if len(matches) == 0 and self.timestamp_mjd > 54651:
            # No corrected coords found, but coordinate problem is fixed,
            # so use header values.
            # MJD=54651 is July 4th 2008, it is a recent date by which
            # the coord problem is definitely corrected. (The problem
            # was discovered and fixed in ~2005).
            self.right_ascension = self.orig_right_ascension
            self.declination = self.orig_declination
            self.ra_deg = self.orig_ra_deg
            self.dec_deg = self.orig_dec_deg
            self.galactic_longitude = self.orig_galactic_longitude
            self.galactic_latitude = self.orig_galactic_latitude
        elif len(matches) == 1:
            # Use values from coords table
            self.posn_corrected = True
            if self.beam_id % 2:
                # Even beam number. Use columns 2 and 3.
                self.correct_ra, self.correct_decl = matches[0].split()[1:3]
            else:
                self.correct_ra, self.correct_decl = matches[0].split()[3:5]
            self.right_ascension = float(self.correct_ra.replace(':', ''))
            self.declination = float(self.correct_decl.replace(':', ''))
            self.ra_deg = float(
                protractor.convert(self.correct_ra, 'hmsstr', 'deg')[0])
            self.dec_deg = float(
                protractor.convert(self.correct_decl, 'dmsstr', 'deg')[0])
            l, b = sextant.equatorial_to_galactic(self.correct_ra, self.correct_decl, \
                                    'sexigesimal', 'deg', J2000=True)
            self.galactic_longitude = float(l[0])
            self.galactic_latitude = float(b[0])
        else:
            raise ValueError("Bad number of matches (%d) in coords table!" %
                             len(matches))
Beispiel #4
0
    def get_correct_positions(self):
        """Reconstruct original wapp filename and check
            for correct beam positions from the coordinates
            table.

            Returns nothing, updates object in place.
        """
        import config.basic
        wappfn = '.'.join([self.project_id, self.source_name, \
                            "wapp%d" % (self.beam_id/2+1), \
                            "%5d" % int(self.timestamp_mjd), \
                            self.fnmatch(self.original_file).groupdict()['scan']])
        # Get corrected beam positions
        matches = [line for line in open(config.basic.coords_table, 'r') if \
                        line.startswith(wappfn)]
        if len(matches) == 0 and self.timestamp_mjd > 54651:
            # No corrected coords found, but coordinate problem is fixed,
            # so use header values.
            # MJD=54651 is July 4th 2008, it is a recent date by which
            # the coord problem is definitely corrected. (The problem
            # was discovered and fixed in ~2005).
            self.right_ascension = self.orig_right_ascension
            self.declination = self.orig_declination
            self.ra_deg = self.orig_ra_deg
            self.dec_deg = self.orig_dec_deg
            self.galactic_longitude = self.orig_galactic_longitude
            self.galactic_latitude = self.orig_galactic_latitude
        elif len(matches) == 1:
            # Use values from coords table
            self.posn_corrected = True
            if self.beam_id % 2:
                # Even beam number. Use columns 2 and 3.
                self.correct_ra, self.correct_decl = matches[0].split()[1:3]
            else:
                self.correct_ra, self.correct_decl = matches[0].split()[3:5]
            self.right_ascension = float(self.correct_ra.replace(':', ''))
            self.declination = float(self.correct_decl.replace(':', ''))
            self.ra_deg = float(protractor.convert(self.correct_ra, 'hmsstr', 'deg')[0])
            self.dec_deg = float(protractor.convert(self.correct_decl, 'dmsstr', 'deg')[0])
            l, b = sextant.equatorial_to_galactic(self.correct_ra, self.correct_decl, \
                                    'sexigesimal', 'deg', J2000=True)
            self.galactic_longitude = float(l[0])
            self.galactic_latitude = float(b[0])
        else:
            raise DataFileError("Bad number of matches (%d) in coords table! " \
                             "(Files: %s)" % (len(matches), ", ".join(self.fns)))
Beispiel #5
0
    def __init__(self, fitsfns):
        """PSR fits Header object constructor.
        """
        import psrfits
        #from formats import psrfits

        super(PsrfitsData, self).__init__(fitsfns)
        # Read information from files
        self.specinfo = psrfits.SpectraInfo(self.fns)
        self.original_file = os.path.split(sorted(
            self.specinfo.filenames)[0])[-1]
        self.project_id = self.specinfo.project_id
        self.observers = self.specinfo.observer
        self.source_name = self.specinfo.source
        self.center_freq = self.specinfo.fctr
        self.num_channels_per_record = self.specinfo.num_channels
        self.channel_bandwidth = self.specinfo.df * 1000.0  # In kHz
        self.sample_time = self.specinfo.dt * 1e6  # In microseconds
        self.sum_id = int(self.specinfo.summed_polns)
        self.timestamp_mjd = self.specinfo.start_MJD[0]
        self.start_lst = self.specinfo.start_lst
        self.orig_start_az = self.specinfo.azimuth
        self.orig_start_za = self.specinfo.zenith_ang
        self.orig_ra_deg = self.specinfo.ra2000
        self.orig_dec_deg = self.specinfo.dec2000
        self.orig_right_ascension = float(protractor.convert(self.orig_ra_deg, \
                                        'deg', 'hmsstr')[0].replace(':', ''))
        self.orig_declination = float(protractor.convert(self.orig_dec_deg, \
                                        'deg', 'dmsstr')[0].replace(':', ''))
        l, b = sextant.equatorial_to_galactic(self.orig_ra_deg, self.orig_dec_deg, \
                                            'deg', 'deg', J2000=True)
        self.orig_galactic_longitude = float(l)
        self.orig_galactic_latitude = float(b)
        self.get_correct_positions()

        self.file_size = int(sum([os.path.getsize(fn) for fn in fitsfns]))
        self.observation_time = self.specinfo.T
        self.num_samples = self.specinfo.N
        self.data_size = self.num_samples * \
                            self.specinfo.bits_per_sample/8.0 * \
                            self.num_channels_per_record
        self.num_samples_per_record = self.specinfo.spectra_per_subint
        self.header_version = float(self.specinfo.header_version)
Beispiel #6
0
    def __init__(self, fitsfns):
        """PSR fits Header object constructor.
        """
        from formats import psrfits        
        
        super(PsrfitsData, self).__init__(fitsfns)
        # Read information from files
        self.specinfo = psrfits.SpectraInfo(self.fns)
        self.original_file = os.path.split(sorted(self.specinfo.filenames)[0])[-1]
        self.project_id = self.specinfo.project_id
        self.observers = self.specinfo.observer
        self.source_name = self.specinfo.source
        self.center_freq = self.specinfo.fctr
        self.num_channels_per_record = self.specinfo.num_channels
        self.channel_bandwidth = self.specinfo.df*1000.0 # In kHz
        self.sample_time = self.specinfo.dt*1e6 # In microseconds
        self.sum_id = int(self.specinfo.summed_polns)
        self.timestamp_mjd = self.specinfo.start_MJD[0]
        self.start_lst = self.specinfo.start_lst 
        self.orig_start_az = self.specinfo.azimuth
        self.orig_start_za = self.specinfo.zenith_ang
        self.orig_ra_deg = self.specinfo.ra2000
        self.orig_dec_deg = self.specinfo.dec2000
        self.orig_right_ascension = float(protractor.convert(self.orig_ra_deg, \
                                        'deg', 'hmsstr')[0].replace(':', ''))
        self.orig_declination = float(protractor.convert(self.orig_dec_deg, \
                                        'deg', 'dmsstr')[0].replace(':', ''))
        l, b = sextant.equatorial_to_galactic(self.orig_ra_deg, self.orig_dec_deg, \
                                            'deg', 'deg', J2000=True)
        self.orig_galactic_longitude = float(l)
        self.orig_galactic_latitude = float(b)

        self.file_size = int(sum([os.path.getsize(fn) for fn in fitsfns]))
        self.observation_time = self.specinfo.T
        self.num_samples = self.specinfo.N
        self.data_size = self.num_samples * \
                            self.specinfo.bits_per_sample/8.0 * \
                            self.num_channels_per_record
        self.num_samples_per_record = self.specinfo.spectra_per_subint
        self.header_version = float(self.specinfo.header_version)
Beispiel #7
0
    def __init__(self, wappfns, beamnum):
        """WAPP Data object constructor.
        """
        super(WappData, self).__init__(wappfns)
        # Open wapp files, sort by offset since start of observation
        cmp_offset = lambda w1,w2: cmp(w1.header['timeoff'], w2.header['timeoff'])
        self.wapps = sorted([wapp.wapp(fn) for fn in wappfns], cmp=cmp_offset)
        w0 = self.wapps[0]
        
        # Check WAPP files are from the same observation
        if False in [w0.header['src_name'] == w.header['src_name'] \
                        for w in self.wapps]:
            raise ValueError("Source name is not consistent in all files.")
        if False in [w0.header['obs_date'] == w.header['obs_date'] \
                        for w in self.wapps]:
            raise ValueError("Observation date is not consistent in all files.")
        if False in [w0.header['start_time'] == w.header['start_time'] \
                        for w in self.wapps]:
            raise ValueError("Start time is not consistent in all files.")
        # Divide number of samples by 2 because beams are multiplexed
        # First entry is 0 because first file is start of observation
        sampoffset = np.cumsum([0]+[w.number_of_samples/2 for w in self.wapps])
        if False in [w.header['timeoff']==samps for (w,samps) in \
                        zip(self.wapps, sampoffset)]:
            raise ValueError("Offset since start of observation not consistent.")
        
        self.original_file = os.path.split(w0.filename)[-1]
        matchdict = self.fnmatch(self.original_file).groupdict()
        if 'beam' in matchdict:
            self.beam_id = int(matchdict['beam'])
        else:
            self.beam_id = beamnum
        self.project_id = w0.header['project_id']
        self.observers = w0.header['observers']
        self.start_ast = w0.header['start_ast']
        self.start_lst = w0.header['start_lst']
        self.source_name = w0.header['src_name']
        self.center_freq = w0.header['cent_freq']
        self.num_channels_per_record = w0.header['num_lags']
        # ALFA band is inverted
        self.channel_bandwidth = -abs(w0.header['bandwidth'] / \
                                    float(self.num_channels_per_record))
        self.num_ifs = w0.header['nifs']
        self.sample_time = w0.header['samp_time'] # in micro seconds
        self.sum_id = w0.header['sum']
        
        # Compute timestamp_mjd
        date = date_re.match(w0.header['obs_date']).groupdict()
        time = time_re.match(w0.header['start_time']).groupdict()
        dayfrac = (int(time['hour']) + \
                    (int(time['min']) + \
                    (int(time['sec']) / 60.0)) / 60.0) / 24.0
        day = calendar.date_to_MJD(int(date['year']), int(date['month']), \
                                    int(date['day']))
        self.timestamp_mjd = day + dayfrac

        # Combine obs_name
        scan = matchdict()['scan']
        self.obs_name = '.'.join([self.project_id, self.source_name, \
                                    str(int(self.timestamp_mjd)), \
                                    scan])
        
        # Get beam positions 
        self.beam_id = beamnum
        if beamnum == 7:
            b = 6
        else:
            b = beamnum
        self.orig_start_az = w0.header['alfa_az'][b]
        if w0.header['start_az'] > 360.0 and self.orig_start_az < 360.0:
            self.orig_start_az += 360.0
        self.orig_start_za = w0.header['alfa_za'][b]
        self.orig_ra_deg = w0.header['alfa_raj'][b]*15.0
        self.orig_dec_deg = w0.header['alfa_decj'][b]
        self.orig_right_ascension = float(protractor.convert(self.orig_ra_deg, \
                                        'deg', 'hmsstr')[0].replace(':', ''))
        self.orig_declination = float(protractor.convert(self.orig_dec_deg, \
                                        'deg', 'dmsstr')[0].replace(':', ''))
        l, b = sextant.equatorial_to_galactic(self.orig_ra_deg, self.orig_dec_deg, \
                                            'deg', 'deg', J2000=True)
        self.orig_galactic_longitude = float(l)
        self.orig_galactic_latitude = float(b)
        self.get_correct_positions()
Beispiel #8
0
    def __init__(self, filenames):
        self.filenames = filenames
        self.num_files = len(filenames)
        self.N = 0
        self.user_poln = 0 
        self.default_poln = 0

        # Initialise a few arrays
        self.start_MJD = np.empty(self.num_files)
        self.num_subint = np.empty(self.num_files)
        self.start_subint = np.empty(self.num_files)
        self.start_spec = np.empty(self.num_files)
        self.num_pad = np.empty(self.num_files)
        self.num_spec = np.empty(self.num_files)

        # The following should default to False
        self.need_scale = False
        self.need_offset = False
        self.need_weight = False
        self.need_flipband = False

        for ii, fn in enumerate(filenames):
            if not is_PSRFITS(fn):
                raise ValueError("File '%s' does not appear to be PSRFITS!" % fn)
            
            # Open the PSRFITS file
            hdus = pyfits.open(fn, mode='readonly')
            
            if ii==0:
                self.hdu_names = [hdu.name for hdu in hdus]

            primary = hdus['PRIMARY'].header

            if 'TELESCOP' not in primary.keys():
                telescope = ""
            else:
                telescope = primary['TELESCOP']
                # Quick fix for MockSpec data...
                if telescope == "ARECIBO 305m":
                    telescope = "Arecibo"
            if ii == 0:
                self.telescope = telescope
            else:
                if telescope != self.telescope[0]:
                    warnings.warn("'TELESCOP' values don't match for files 0 and %d!" % ii)

            self.observer = primary['OBSERVER']
            self.source = primary['SRC_NAME']
            self.frontend = primary['FRONTEND']
            self.backend = primary['BACKEND']
            self.project_id = primary['PROJID']
            self.date_obs = primary['DATE-OBS']
            self.poln_type = primary['FD_POLN']
            self.ra_str = primary['RA']
            self.dec_str = primary['DEC']
            self.fctr = primary['OBSFREQ']
            self.orig_num_chan = primary['OBSNCHAN']
            self.orig_df = primary['OBSBW']
            self.beam_FWHM = primary['BMIN']

            # CHAN_DM card is not in earlier versions of PSRFITS
            if 'CHAN_DM' not in primary.keys():
                self.chan_dm = 0.0
            else:
                self.chan_dm = primary['CHAN_DM']

            self.start_MJD[ii] = primary['STT_IMJD'] + (primary['STT_SMJD'] + \
                                    primary['STT_OFFS'])/psr_utils.SECPERDAY
            
            # Are we tracking
            track = (primary['TRK_MODE'] == "TRACK")
            if ii==0:
                self.tracking = track
            else:
                if track != self.tracking:
                    warnings.warn("'TRK_MODE' values don't match for files 0 and %d" % ii)

            # Now switch to the subint HDU header
            subint = hdus['SUBINT'].header
            
            self.dt = subint['TBIN']
            self.num_channels = subint['NCHAN']
            self.num_polns = subint['NPOL']
            
            # PRESTO's 'psrfits.c' has some settings based on environ variables
            envval = os.getenv("PSRFITS_POLN")
            if envval is not None:
                ival = int(envval)
                if ((ival > -1) and (ival < self.num_polns)):
                    print "Using polarisation %d (from 0-%d) from PSRFITS_POLN." % \
                                (ival, self.num_polns-1)
                    self.default_poln = ival
                    self.user_poln = 1

            self.poln_order = subint['POL_TYPE']
            if subint['NCHNOFFS'] > 0:
                warnings.warn("first freq channel is not 0 in file %d" % ii)
            self.spectra_per_subint = subint['NSBLK']
            self.bits_per_sample = subint['NBITS']
            self.num_subint[ii] = subint['NAXIS2']
            self.start_subint[ii] = subint['NSUBOFFS']
            self.time_per_subint = self.dt * self.spectra_per_subint

            # This is the MJD offset based on the starting subint number
            MJDf = (self.time_per_subint * self.start_subint[ii])/psr_utils.SECPERDAY
            # The start_MJD values should always be correct
            self.start_MJD[ii] += MJDf

            # Compute the starting spectra from the times
            MJDf = self.start_MJD[ii] - self.start_MJD[0]
            if MJDf < 0.0:
                raise ValueError("File %d seems to be from before file 0!" % ii)

            self.start_spec[ii] = (MJDf * psr_utils.SECPERDAY / self.dt + 0.5)

            # Now pull stuff from the columns
            subint_hdu = hdus['SUBINT']
            # Identify the OFFS_SUB column number
            if 'OFFS_SUB' not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'OFFS_SUB' column!")
            else:
                colnum = subint_hdu.columns.names.index('OFFS_SUB')
                if ii==0:
                    self.offs_sub_col = colnum 
                elif self.offs_sub_col != colnum:
                    warnings.warn("'OFFS_SUB' column changes between files 0 and %d!" % ii)

            # Identify the data column and the data type
            if 'DATA' not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'DATA' column!")
            else:
                colnum = subint_hdu.columns.names.index('DATA')
                if ii==0:
                    self.data_col = colnum
                    self.FITS_typecode = subint_hdu.columns[self.data_col].format[-1]
                elif self.data_col != colnum:
                    warnings.warn("'DATA' column changes between files 0 and %d!" % ii)

            # Telescope azimuth
            if 'TEL_AZ' not in subint_hdu.columns.names:
                self.azimuth = 0.0
            else:
                colnum = subint_hdu.columns.names.index('TEL_AZ')
                if ii==0:
                    self.tel_az_col = colnum
                    self.azimuth = subint_hdu.data[0]['TEL_AZ']

            # Telescope zenith angle
            if 'TEL_ZEN' not in subint_hdu.columns.names:
                self.zenith_ang = 0.0
            else:
                colnum = subint_hdu.columns.names.index('TEL_ZEN')
                if ii==0:
                    self.tel_zen_col = colnum
                    self.zenith_ang = subint_hdu.data[0]['TEL_ZEN']

            # Observing frequencies
            if 'DAT_FREQ' not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel freq column, 'DAT_FREQ'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_FREQ')
                freqs = subint_hdu.data[0]['DAT_FREQ']
                if ii==0:
                    self.freqs_col = colnum
                    self.df = freqs[1]-freqs[0]
                    self.lo_freq = freqs[0]
                    self.hi_freq = freqs[-1]
                    # Now check that the channel spacing is the same throughout
                    ftmp = freqs[1:] - freqs[:-1]
                    if np.any((ftmp - self.df)) > 1e-7:
                        warnings.warn("Channel spacing changes in file %d!" % ii)
                else:
                    ftmp = np.abs(self.df - (freqs[1]-freqs[0]))
                    if ftmp > 1e-7:
                        warnings.warn("Channel spacing between files 0 and %d!" % ii)
                    ftmp = np.abs(self.lo_freq-freqs[0])
                    if ftmp > 1e-7:
                        warnings.warn("Low channel changes between files 0 and %d!" % ii)
                    ftmp = np.abs(self.hi_freq-freqs[-1])
                    if ftmp > 1e-7:
                        warnings.warn("High channel changes between files 0 and %d!" % ii)

            # Data weights
            if 'DAT_WTS' not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel weights column, 'DAT_WTS'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_WTS')
                if ii==0:
                    self.dat_wts_col = colnum
                elif self.dat_wts_col != colnum:
                    warnings.warn("'DAT_WTS column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]['DAT_WTS'] != 1.0):
                    self.need_weight = True
                
            # Data offsets
            if 'DAT_OFFS' not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel offsets column, 'DAT_OFFS'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_OFFS')
                if ii==0:
                    self.dat_offs_col = colnum
                elif self.dat_offs_col != colnum:
                    warnings.warn("'DAT_OFFS column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]['DAT_OFFS'] != 0.0):
                    self.need_offset = True

            # Data scalings
            if 'DAT_SCL' not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel scalings column, 'DAT_SCL'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_SCL')
                if ii==0:
                    self.dat_scl_col = colnum
                elif self.dat_scl_col != colnum:
                    warnings.warn("'DAT_SCL' column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]['DAT_SCL'] != 1.0):
                    self.need_scale = True

            # Comute the samples per file and the amount of padding
            # that the _previous_ file has
            self.num_pad[ii] = 0
            self.num_spec[ii] = self.spectra_per_subint * self.num_subint[ii]
            if ii>0:
                if self.start_spec[ii] > self.N: # Need padding
                    self.num_pad[ii-1] = self.start_spec[ii] - self.N
                    self.N += self.num_pad[ii-1]
            self.N += self.num_spec[ii]

        # Finished looping through PSRFITS files. Finalise a few things.
        # Convert the position strings into degrees        
        self.ra2000 = protractor.convert(self.ra_str, 'hmsstr', 'deg')
        self.dec2000 = protractor.convert(self.dec_str, 'dmsstr', 'deg')
        
        # Are the polarisations summed?
        if (self.poln_order=="AA+BB") or (self.poln_order=="INTEN"):
            self.summed_polns = True
        else:
            self.summed_polns = False

        # Calculate some others
        self.T = self.N * self.dt
        self.orig_df /= float(self.orig_num_chan)
        self.samples_per_spectra = self.num_polns * self.num_channels
        # Note: the following is the number of bytes that will be in
        #       the returned array.
        if self.bits_per_sample < 8:
            self.bytes_per_spectra = self.samples_per_spectra
        else:
            self.bytes_per_spectra = (self.bits_per_sample * self.samples_per_spectra)/8
        self.samples_per_subint = self.samples_per_spectra * self.spectra_per_subint
        self.bytes_per_subint = self.bytes_per_spectra * self.spectra_per_subint

        # Flip the band?
        if self.hi_freq < self.lo_freq:
            tmp = self.hi_freq
            self.hi_freq = self.lo_freq
            self.lo_freq = tmp
            self.df *= -1.0
            self.need_flipband = True
        # Compute the bandwidth
        self.BW = self.num_channels * self.df
        self.mjd = int(self.start_MJD[0])
        self.secs = (self.start_MJD[0] % 1)*psr_utils.SECPERDAY
Beispiel #9
0
    def __init__(self, filenames, verbose=False):
        self.filenames = filenames
        self.num_files = len(filenames)
        self.N = 0
        self.user_poln = 0
        self.default_poln = 0

        # Initialise a few arrays
        self.start_MJD = np.empty(self.num_files)
        self.num_subint = np.empty(self.num_files)
        self.start_subint = np.empty(self.num_files)
        self.start_spec = np.empty(self.num_files)
        self.num_pad = np.empty(self.num_files)
        self.num_spec = np.empty(self.num_files)

        # The following should default to False
        self.need_scale = False
        self.need_offset = False
        self.need_weight = False
        self.need_flipband = False

        for ii, fn in enumerate(filenames):
            if verbose:
                print "Reading '%s'" % fn
            if not is_PSRFITS(fn):
                raise ValueError("File '%s' does not appear to be PSRFITS!" %
                                 fn)

            # Open the PSRFITS file
            hdus = pyfits.open(fn, mode='readonly', checksum=False)
            self.hdus = hdus

            if ii == 0:
                self.hdu_names = [hdu.name for hdu in hdus]

            primary = hdus['PRIMARY'].header

            if primary.has_key('IBEAM'):
                self.beam_id = primary['IBEAM']
            elif hdus[1].header.has_key('BEAM'):
                self.beam_id = hdus[1].header['BEAM']
            else:
                self.beam_id = None

            if primary.has_key('TELESCOP'):
                telescope = primary['TELESCOP']
                # Quick fix for MockSpec data...
                if telescope == "ARECIBO 305m":
                    telescope = "Arecibo"
            else:
                telescope = ""
            if ii == 0:
                self.telescope = telescope
            else:
                if telescope != self.telescope[0]:
                    warnings.warn(
                        "'TELESCOP' values don't match for files 0 and %d!" %
                        ii)

            self.observer = primary['OBSERVER']
            self.source = primary['SRC_NAME']
            self.frontend = primary['FRONTEND']
            self.backend = primary['BACKEND']
            self.project_id = primary['PROJID']
            self.date_obs = primary['DATE-OBS']
            self.poln_type = primary['FD_POLN']
            self.ra_str = primary['RA']
            self.dec_str = primary['DEC']
            self.fctr = primary['OBSFREQ']
            self.orig_num_chan = primary['OBSNCHAN']
            self.orig_df = primary['OBSBW']
            self.beam_FWHM = primary['BMIN']

            # CHAN_DM card is not in earlier versions of PSRFITS
            if primary.has_key('CHAN_DM'):
                self.chan_dm = primary['CHAN_DM']
            else:
                self.chan_dm = 0.0

            self.start_MJD[ii] = primary['STT_IMJD'] + (primary['STT_SMJD'] + \
                                    primary['STT_OFFS'])/psr_utils.SECPERDAY

            # Are we tracking
            track = (primary['TRK_MODE'] == "TRACK")
            if ii == 0:
                self.tracking = track
            else:
                if track != self.tracking:
                    warnings.warn(
                        "'TRK_MODE' values don't match for files 0 and %d" %
                        ii)

            # Now switch to the subint HDU header
            subint = hdus['SUBINT'].header

            self.dt = subint['TBIN']
            self.num_channels = subint['NCHAN']
            self.num_polns = subint['NPOL']

            # PRESTO's 'psrfits.c' has some settings based on environ variables
            envval = os.getenv("PSRFITS_POLN")
            if envval is not None:
                ival = int(envval)
                if ((ival > -1) and (ival < self.num_polns)):
                    print "Using polarisation %d (from 0-%d) from PSRFITS_POLN." % \
                                (ival, self.num_polns-1)
                    self.default_poln = ival
                    self.user_poln = 1

            self.poln_order = subint['POL_TYPE']
            if subint['NCHNOFFS'] > 0:
                warnings.warn("first freq channel is not 0 in file %d" % ii)
            self.spectra_per_subint = subint['NSBLK']
            self.bits_per_sample = subint['NBITS']
            self.num_subint[ii] = subint['NAXIS2']
            self.start_subint[ii] = subint['NSUBOFFS']
            self.time_per_subint = self.dt * self.spectra_per_subint

            # Now pull stuff from the columns
            subint_hdu = hdus['SUBINT']
            # The following is a hack to read in only the first row
            # from the fits file
            subint_hdu.columns._shape = 1

            # Identify the OFFS_SUB column number
            if 'OFFS_SUB' not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'OFFS_SUB' column!")
            else:
                colnum = subint_hdu.columns.names.index('OFFS_SUB')
                if ii == 0:
                    self.offs_sub_col = colnum
                elif self.offs_sub_col != colnum:
                    warnings.warn(
                        "'OFFS_SUB' column changes between files 0 and %d!" %
                        ii)

                # Read the OFFS_SUB column value for the 1st row
                offs_sub = subint_hdu.data[0]['OFFS_SUB']
                numrows = int((offs_sub - 0.5 * self.time_per_subint) / \
                                self.time_per_subint + 1e-7)
                # Check to see if any rows have been deleted or are missing
                if numrows > self.start_subint[ii]:
                    warnings.warn("Warning: NSUBOFFS reports %d previous rows\n" \
                                  "         but OFFS_SUB implies %s. Using OFFS_SUB.\n" \
                                  "         Will likely be able to correct for this.\n" % \
                                    (self.start_subint[ii], numrows))
                self.start_subint[ii] = numrows

            # This is the MJD offset based on the starting subint number
            MJDf = (self.time_per_subint *
                    self.start_subint[ii]) / psr_utils.SECPERDAY
            # The start_MJD values should always be correct
            self.start_MJD[ii] += MJDf

            # Compute the starting spectra from the times
            MJDf = self.start_MJD[ii] - self.start_MJD[0]
            if MJDf < 0.0:
                raise ValueError("File %d seems to be from before file 0!" %
                                 ii)

            self.start_spec[ii] = (MJDf * psr_utils.SECPERDAY / self.dt + 0.5)

            # Identify the data column and the data type
            if 'DATA' not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'DATA' column!")
                self.FITS_typecode = 0
                self.data_col = 0
            else:
                colnum = subint_hdu.columns.names.index('DATA')
                if ii == 0:
                    self.data_col = colnum
                    self.FITS_typecode = subint_hdu.columns[
                        self.data_col].format[-1]
                elif self.data_col != colnum:
                    warnings.warn(
                        "'DATA' column changes between files 0 and %d!" % ii)

            # Telescope azimuth
            if 'TEL_AZ' not in subint_hdu.columns.names:
                self.azimuth = 0.0
            else:
                colnum = subint_hdu.columns.names.index('TEL_AZ')
                if ii == 0:
                    self.tel_az_col = colnum
                    self.azimuth = subint_hdu.data[0]['TEL_AZ']

            # Telescope zenith angle
            if 'TEL_ZEN' not in subint_hdu.columns.names:
                self.zenith_ang = 0.0
            else:
                colnum = subint_hdu.columns.names.index('TEL_ZEN')
                if ii == 0:
                    self.tel_zen_col = colnum
                    self.zenith_ang = subint_hdu.data[0]['TEL_ZEN']

            # Observing frequencies
            if 'DAT_FREQ' not in subint_hdu.columns.names:
                warnings.warn(
                    "Can't find the channel freq column, 'DAT_FREQ'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_FREQ')
                freqs = subint_hdu.data[0]['DAT_FREQ']
                if ii == 0:
                    self.freqs_col = colnum
                    self.df = freqs[1] - freqs[0]
                    self.lo_freq = freqs[0]
                    self.hi_freq = freqs[-1]
                    # Now check that the channel spacing is the same throughout
                    ftmp = freqs[1:] - freqs[:-1]
                    if np.any((ftmp - self.df)) > 1e-7:
                        warnings.warn("Channel spacing changes in file %d!" %
                                      ii)
                else:
                    ftmp = np.abs(self.df - (freqs[1] - freqs[0]))
                    if ftmp > 1e-7:
                        warnings.warn(
                            "Channel spacing between files 0 and %d!" % ii)
                    ftmp = np.abs(self.lo_freq - freqs[0])
                    if ftmp > 1e-7:
                        warnings.warn(
                            "Low channel changes between files 0 and %d!" % ii)
                    ftmp = np.abs(self.hi_freq - freqs[-1])
                    if ftmp > 1e-7:
                        warnings.warn(
                            "High channel changes between files 0 and %d!" %
                            ii)

            # Data weights
            if 'DAT_WTS' not in subint_hdu.columns.names:
                warnings.warn(
                    "Can't find the channel weights column, 'DAT_WTS'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_WTS')
                if ii == 0:
                    self.dat_wts_col = colnum
                elif self.dat_wts_col != colnum:
                    warnings.warn(
                        "'DAT_WTS column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]['DAT_WTS'] != 1.0):
                    self.need_weight = True

            # Data offsets
            if 'DAT_OFFS' not in subint_hdu.columns.names:
                warnings.warn(
                    "Can't find the channel offsets column, 'DAT_OFFS'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_OFFS')
                if ii == 0:
                    self.dat_offs_col = colnum
                elif self.dat_offs_col != colnum:
                    warnings.warn(
                        "'DAT_OFFS column changes between files 0 and %d!" %
                        ii)
                if np.any(subint_hdu.data[0]['DAT_OFFS'] != 0.0):
                    self.need_offset = True

            # Data scalings
            if 'DAT_SCL' not in subint_hdu.columns.names:
                warnings.warn(
                    "Can't find the channel scalings column, 'DAT_SCL'!")
            else:
                colnum = subint_hdu.columns.names.index('DAT_SCL')
                if ii == 0:
                    self.dat_scl_col = colnum
                elif self.dat_scl_col != colnum:
                    warnings.warn(
                        "'DAT_SCL' column changes between files 0 and %d!" %
                        ii)
                if np.any(subint_hdu.data[0]['DAT_SCL'] != 1.0):
                    self.need_scale = True

            # Comute the samples per file and the amount of padding
            # that the _previous_ file has
            self.num_pad[ii] = 0
            self.num_spec[ii] = self.spectra_per_subint * self.num_subint[ii]
            if ii > 0:
                if self.start_spec[ii] > self.N:  # Need padding
                    self.num_pad[ii - 1] = self.start_spec[ii] - self.N
                    self.N += self.num_pad[ii - 1]
            self.N += self.num_spec[ii]

        # Finished looping through PSRFITS files. Finalise a few things.
        # Convert the position strings into degrees
        self.ra2000 = protractor.convert(self.ra_str, 'hmsstr', 'deg')
        self.dec2000 = protractor.convert(self.dec_str, 'dmsstr', 'deg')

        # Are the polarisations summed?
        if (self.poln_order == "AA+BB") or (self.poln_order == "INTEN"):
            self.summed_polns = True
        else:
            self.summed_polns = False

        # Calculate some others
        self.T = self.N * self.dt
        self.orig_df /= float(self.orig_num_chan)
        self.samples_per_spectra = self.num_polns * self.num_channels
        # Note: the following is the number of bytes that will be in
        #       the returned array.
        if self.bits_per_sample < 8:
            self.bytes_per_spectra = self.samples_per_spectra
        else:
            self.bytes_per_spectra = (self.bits_per_sample *
                                      self.samples_per_spectra) / 8
        self.samples_per_subint = self.samples_per_spectra * self.spectra_per_subint
        self.bytes_per_subint = self.bytes_per_spectra * self.spectra_per_subint

        # Flip the band?
        if self.hi_freq < self.lo_freq:
            tmp = self.hi_freq
            self.hi_freq = self.lo_freq
            self.lo_freq = tmp
            self.df *= -1.0
            self.need_flipband = True
        # Compute the bandwidth
        self.BW = self.num_channels * self.df

        # A few extras
        self.start_lst = primary['STT_LST']

        # Close the psrfits file
        hdus.close()
Beispiel #10
0
    def __init__(self, wappfns, beamnum):
        """WAPP Data object constructor.
        """
        super(WappData, self).__init__(wappfns)
        # Open wapp files, sort by offset since start of observation
        cmp_offset = lambda w1, w2: cmp(w1.header['timeoff'], w2.header[
            'timeoff'])
        self.wapps = sorted([wapp.wapp(fn) for fn in wappfns], cmp=cmp_offset)
        w0 = self.wapps[0]

        # Check WAPP files are from the same observation
        if False in [w0.header['src_name'] == w.header['src_name'] \
                        for w in self.wapps]:
            raise ValueError("Source name is not consistent in all files.")
        if False in [w0.header['obs_date'] == w.header['obs_date'] \
                        for w in self.wapps]:
            raise ValueError(
                "Observation date is not consistent in all files.")
        if False in [w0.header['start_time'] == w.header['start_time'] \
                        for w in self.wapps]:
            raise ValueError("Start time is not consistent in all files.")
        # Divide number of samples by 2 because beams are multiplexed
        # First entry is 0 because first file is start of observation
        sampoffset = np.cumsum([0] +
                               [w.number_of_samples / 2 for w in self.wapps])
        if False in [w.header['timeoff']==samps for (w,samps) in \
                        zip(self.wapps, sampoffset)]:
            raise ValueError(
                "Offset since start of observation not consistent.")

        self.original_file = os.path.split(w0.filename)[-1]
        matchdict = self.fnmatch(self.original_file).groupdict()
        if 'beam' in matchdict:
            self.beam_id = int(matchdict['beam'])
        else:
            self.beam_id = beamnum
        self.project_id = w0.header['project_id']
        self.observers = w0.header['observers']
        self.start_ast = w0.header['start_ast']
        self.start_lst = w0.header['start_lst']
        self.source_name = w0.header['src_name']
        self.center_freq = w0.header['cent_freq']
        self.num_channels_per_record = w0.header['num_lags']
        # ALFA band is inverted
        self.channel_bandwidth = -abs(w0.header['bandwidth'] / \
                                    float(self.num_channels_per_record))
        self.num_ifs = w0.header['nifs']
        self.sample_time = w0.header['samp_time']  # in micro seconds
        self.sum_id = w0.header['sum']

        # Compute timestamp_mjd
        date = date_re.match(w0.header['obs_date']).groupdict()
        time = time_re.match(w0.header['start_time']).groupdict()
        dayfrac = (int(time['hour']) + \
                    (int(time['min']) + \
                    (int(time['sec']) / 60.0)) / 60.0) / 24.0
        day = calendar.date_to_MJD(int(date['year']), int(date['month']), \
                                    int(date['day']))
        self.timestamp_mjd = day + dayfrac

        # Combine obs_name
        scan = matchdict()['scan']
        self.obs_name = '.'.join([self.project_id, self.source_name, \
                                    str(int(self.timestamp_mjd)), \
                                    scan])

        # Get beam positions
        self.beam_id = beamnum
        if beamnum == 7:
            b = 6
        else:
            b = beamnum
        self.orig_start_az = w0.header['alfa_az'][b]
        if w0.header['start_az'] > 360.0 and self.orig_start_az < 360.0:
            self.orig_start_az += 360.0
        self.orig_start_za = w0.header['alfa_za'][b]
        self.orig_ra_deg = w0.header['alfa_raj'][b] * 15.0
        self.orig_dec_deg = w0.header['alfa_decj'][b]
        self.orig_right_ascension = float(protractor.convert(self.orig_ra_deg, \
                                        'deg', 'hmsstr')[0].replace(':', ''))
        self.orig_declination = float(protractor.convert(self.orig_dec_deg, \
                                        'deg', 'dmsstr')[0].replace(':', ''))
        l, b = sextant.equatorial_to_galactic(self.orig_ra_deg, self.orig_dec_deg, \
                                            'deg', 'deg', J2000=True)
        self.orig_galactic_longitude = float(l)
        self.orig_galactic_latitude = float(b)
        self.get_correct_positions()
Beispiel #11
0
    def __init__(self, filenames, verbose=False):
        self.filenames = filenames
        self.num_files = len(filenames)
        self.N = 0
        self.user_poln = 0
        self.default_poln = 0

        # Initialise a few arrays
        self.start_MJD = np.empty(self.num_files)
        self.num_subint = np.empty(self.num_files)
        self.start_subint = np.empty(self.num_files)
        self.start_spec = np.empty(self.num_files)
        self.num_pad = np.empty(self.num_files)
        self.num_spec = np.empty(self.num_files)

        # The following should default to False
        self.need_scale = False
        self.need_offset = False
        self.need_weight = False
        self.need_flipband = False

        for ii, fn in enumerate(filenames):
            if verbose:
                print "Reading '%s'" % fn
            if not is_PSRFITS(fn):
                raise ValueError("File '%s' does not appear to be PSRFITS!" % fn)

            # Open the PSRFITS file
            hdus = pyfits.open(fn, mode="readonly", checksum=False)
            self.hdus = hdus

            if ii == 0:
                self.hdu_names = [hdu.name for hdu in hdus]

            primary = hdus["PRIMARY"].header

            if primary.has_key("IBEAM"):
                self.beam_id = primary["IBEAM"]
            elif hdus[1].header.has_key("BEAM"):
                self.beam_id = hdus[1].header["BEAM"]
            else:
                self.beam_id = None

            if primary.has_key("TELESCOP"):
                telescope = primary["TELESCOP"]
                # Quick fix for MockSpec data...
                if telescope == "ARECIBO 305m":
                    telescope = "Arecibo"
            else:
                telescope = ""
            if ii == 0:
                self.telescope = telescope
            else:
                if telescope != self.telescope[0]:
                    warnings.warn("'TELESCOP' values don't match for files 0 and %d!" % ii)

            self.observer = primary["OBSERVER"]
            self.source = primary["SRC_NAME"]
            self.frontend = primary["FRONTEND"]
            self.backend = primary["BACKEND"]
            self.project_id = primary["PROJID"]
            self.date_obs = primary["DATE-OBS"]
            self.poln_type = primary["FD_POLN"]
            self.ra_str = primary["RA"]
            self.dec_str = primary["DEC"]
            self.fctr = primary["OBSFREQ"]
            self.orig_num_chan = primary["OBSNCHAN"]
            self.orig_df = primary["OBSBW"]
            self.beam_FWHM = primary["BMIN"]

            # CHAN_DM card is not in earlier versions of PSRFITS
            if primary.has_key("CHAN_DM"):
                self.chan_dm = primary["CHAN_DM"]
            else:
                self.chan_dm = 0.0

            self.start_MJD[ii] = primary["STT_IMJD"] + (primary["STT_SMJD"] + primary["STT_OFFS"]) / psr_utils.SECPERDAY

            # Are we tracking
            track = primary["TRK_MODE"] == "TRACK"
            if ii == 0:
                self.tracking = track
            else:
                if track != self.tracking:
                    warnings.warn("'TRK_MODE' values don't match for files 0 and %d" % ii)

            # Now switch to the subint HDU header
            subint = hdus["SUBINT"].header

            self.dt = subint["TBIN"]
            self.num_channels = subint["NCHAN"]
            self.num_polns = subint["NPOL"]

            # PRESTO's 'psrfits.c' has some settings based on environ variables
            envval = os.getenv("PSRFITS_POLN")
            if envval is not None:
                ival = int(envval)
                if (ival > -1) and (ival < self.num_polns):
                    print "Using polarisation %d (from 0-%d) from PSRFITS_POLN." % (ival, self.num_polns - 1)
                    self.default_poln = ival
                    self.user_poln = 1

            self.poln_order = subint["POL_TYPE"]
            if subint["NCHNOFFS"] > 0:
                warnings.warn("first freq channel is not 0 in file %d" % ii)
            self.spectra_per_subint = subint["NSBLK"]
            self.bits_per_sample = subint["NBITS"]
            self.num_subint[ii] = subint["NAXIS2"]
            self.start_subint[ii] = subint["NSUBOFFS"]
            self.time_per_subint = self.dt * self.spectra_per_subint

            # Now pull stuff from the columns
            subint_hdu = hdus["SUBINT"]
            # The following is a hack to read in only the first row
            # from the fits file
            subint_hdu.columns._shape = 1

            # Identify the OFFS_SUB column number
            if "OFFS_SUB" not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'OFFS_SUB' column!")
            else:
                colnum = subint_hdu.columns.names.index("OFFS_SUB")
                if ii == 0:
                    self.offs_sub_col = colnum
                elif self.offs_sub_col != colnum:
                    warnings.warn("'OFFS_SUB' column changes between files 0 and %d!" % ii)

                # Read the OFFS_SUB column value for the 1st row
                offs_sub = subint_hdu.data[0]["OFFS_SUB"]
                numrows = int((offs_sub - 0.5 * self.time_per_subint) / self.time_per_subint + 1e-7)
                # Check to see if any rows have been deleted or are missing
                if numrows > self.start_subint[ii]:
                    warnings.warn(
                        "Warning: NSUBOFFS reports %d previous rows\n"
                        "         but OFFS_SUB implies %s. Using OFFS_SUB.\n"
                        "         Will likely be able to correct for this.\n" % (self.start_subint[ii], numrows)
                    )
                self.start_subint[ii] = numrows

            # This is the MJD offset based on the starting subint number
            MJDf = (self.time_per_subint * self.start_subint[ii]) / psr_utils.SECPERDAY
            # The start_MJD values should always be correct
            self.start_MJD[ii] += MJDf

            # Compute the starting spectra from the times
            MJDf = self.start_MJD[ii] - self.start_MJD[0]
            if MJDf < 0.0:
                raise ValueError("File %d seems to be from before file 0!" % ii)

            self.start_spec[ii] = MJDf * psr_utils.SECPERDAY / self.dt + 0.5

            # Identify the data column and the data type
            if "DATA" not in subint_hdu.columns.names:
                warnings.warn("Can't find the 'DATA' column!")
                self.FITS_typecode = 0
                self.data_col = 0
            else:
                colnum = subint_hdu.columns.names.index("DATA")
                if ii == 0:
                    self.data_col = colnum
                    self.FITS_typecode = subint_hdu.columns[self.data_col].format[-1]
                elif self.data_col != colnum:
                    warnings.warn("'DATA' column changes between files 0 and %d!" % ii)

            # Telescope azimuth
            if "TEL_AZ" not in subint_hdu.columns.names:
                self.azimuth = 0.0
            else:
                colnum = subint_hdu.columns.names.index("TEL_AZ")
                if ii == 0:
                    self.tel_az_col = colnum
                    self.azimuth = subint_hdu.data[0]["TEL_AZ"]

            # Telescope zenith angle
            if "TEL_ZEN" not in subint_hdu.columns.names:
                self.zenith_ang = 0.0
            else:
                colnum = subint_hdu.columns.names.index("TEL_ZEN")
                if ii == 0:
                    self.tel_zen_col = colnum
                    self.zenith_ang = subint_hdu.data[0]["TEL_ZEN"]

            # Observing frequencies
            if "DAT_FREQ" not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel freq column, 'DAT_FREQ'!")
            else:
                colnum = subint_hdu.columns.names.index("DAT_FREQ")
                freqs = subint_hdu.data[0]["DAT_FREQ"]
                if ii == 0:
                    self.freqs_col = colnum
                    self.df = freqs[1] - freqs[0]
                    self.lo_freq = freqs[0]
                    self.hi_freq = freqs[-1]
                    # Now check that the channel spacing is the same throughout
                    ftmp = freqs[1:] - freqs[:-1]
                    if np.any((ftmp - self.df)) > 1e-7:
                        warnings.warn("Channel spacing changes in file %d!" % ii)
                else:
                    ftmp = np.abs(self.df - (freqs[1] - freqs[0]))
                    if ftmp > 1e-7:
                        warnings.warn("Channel spacing between files 0 and %d!" % ii)
                    ftmp = np.abs(self.lo_freq - freqs[0])
                    if ftmp > 1e-7:
                        warnings.warn("Low channel changes between files 0 and %d!" % ii)
                    ftmp = np.abs(self.hi_freq - freqs[-1])
                    if ftmp > 1e-7:
                        warnings.warn("High channel changes between files 0 and %d!" % ii)

            # Data weights
            if "DAT_WTS" not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel weights column, 'DAT_WTS'!")
            else:
                colnum = subint_hdu.columns.names.index("DAT_WTS")
                if ii == 0:
                    self.dat_wts_col = colnum
                elif self.dat_wts_col != colnum:
                    warnings.warn("'DAT_WTS column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]["DAT_WTS"] != 1.0):
                    self.need_weight = True

            # Data offsets
            if "DAT_OFFS" not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel offsets column, 'DAT_OFFS'!")
            else:
                colnum = subint_hdu.columns.names.index("DAT_OFFS")
                if ii == 0:
                    self.dat_offs_col = colnum
                elif self.dat_offs_col != colnum:
                    warnings.warn("'DAT_OFFS column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]["DAT_OFFS"] != 0.0):
                    self.need_offset = True

            # Data scalings
            if "DAT_SCL" not in subint_hdu.columns.names:
                warnings.warn("Can't find the channel scalings column, 'DAT_SCL'!")
            else:
                colnum = subint_hdu.columns.names.index("DAT_SCL")
                if ii == 0:
                    self.dat_scl_col = colnum
                elif self.dat_scl_col != colnum:
                    warnings.warn("'DAT_SCL' column changes between files 0 and %d!" % ii)
                if np.any(subint_hdu.data[0]["DAT_SCL"] != 1.0):
                    self.need_scale = True

            # Comute the samples per file and the amount of padding
            # that the _previous_ file has
            self.num_pad[ii] = 0
            self.num_spec[ii] = self.spectra_per_subint * self.num_subint[ii]
            if ii > 0:
                if self.start_spec[ii] > self.N:  # Need padding
                    self.num_pad[ii - 1] = self.start_spec[ii] - self.N
                    self.N += self.num_pad[ii - 1]
            self.N += self.num_spec[ii]

        # Finished looping through PSRFITS files. Finalise a few things.
        # Convert the position strings into degrees
        self.ra2000 = protractor.convert(self.ra_str, "hmsstr", "deg")
        self.dec2000 = protractor.convert(self.dec_str, "dmsstr", "deg")

        # Are the polarisations summed?
        if (self.poln_order == "AA+BB") or (self.poln_order == "INTEN"):
            self.summed_polns = True
        else:
            self.summed_polns = False

        # Calculate some others
        self.T = self.N * self.dt
        self.orig_df /= float(self.orig_num_chan)
        self.samples_per_spectra = self.num_polns * self.num_channels
        # Note: the following is the number of bytes that will be in
        #       the returned array.
        if self.bits_per_sample < 8:
            self.bytes_per_spectra = self.samples_per_spectra
        else:
            self.bytes_per_spectra = (self.bits_per_sample * self.samples_per_spectra) / 8
        self.samples_per_subint = self.samples_per_spectra * self.spectra_per_subint
        self.bytes_per_subint = self.bytes_per_spectra * self.spectra_per_subint

        # Flip the band?
        if self.hi_freq < self.lo_freq:
            tmp = self.hi_freq
            self.hi_freq = self.lo_freq
            self.lo_freq = tmp
            self.df *= -1.0
            self.need_flipband = True
        # Compute the bandwidth
        self.BW = self.num_channels * self.df

        # A few extras
        self.start_lst = primary["STT_LST"]

        # Close the psrfits file
        hdus.close()