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)
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)))
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))
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)))
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)
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)
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()
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
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()
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()
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()