# This Python module contains a routine for listing a summary of some of the # key parameters for a scan in the /home/gbtdata directory. The required # parameters for this routine are the project ID, scan number, and the back-end # device used for taking the data. The default device is the spectral # processor. Information for all of the files with the same scan number will # be printed to the screen. Antenna position data are retrieved from the # Antenna FITS file and frequency information from the LO1A file for the same # scan. # This code illustrates the use of cfitsio keyword access functions. It # assumes knowledge of the contents of the FITS files, which may be obtained # with a FITS viewer, like 'fv', a text listing utility, like 'more', or the # 'show_fits' function in the get_fits module. Two functions which provide # some sanity checking and automatic type checking to the FITS access, # myfits_get_keyval and myfits_get_colval, are provided at the end of this # file. # We assume that all files of the same scan for the different devices have # the same file name. This is not guaranteed to be the case, but it generally # is, except for the spectrometer, which uses an A, B, C, or D suffix to name # files from different banks. This code presently only looks at antenna, LO # and spectral processor files. # To run from the Python prompt: # >>> import scan_info # >>> scan_info.scan_info('AGBT02A_069_01', 162) # or # >>> from scan_info import * # >>> scan_info('AGBT02A_069_01', 162) import os, string from fitsio import cfitsio def scan_info ( project, scan_number, device='SpectralProcessor' ) : # assemble the directory path name and get a list of file names # from the project/device directory dev_path = '/home/gbtdata/' + project + '/' + device ls = os.listdir(dev_path) if len(ls) < 1 : return file_num = 0 # step through every file in the list for fn in ls : sfn = string.split(fn, '.') # if it's not a FITS file, skip it if sfn[-1] == 'fits' : file_num += 1 fpn = dev_path + '/' + fn sn = -1 # open the file to the cfitsio access module for reading the # back-end fits file status, fits = cfitsio.fits_open_file(fpn, cfitsio.READONLY) # check the scan number to see if it is the one requested if status == 0 : sn = myfits_get_keyval(fits, 1, 'SCAN', cfitsio.TLONG, 0) # if so, gather a few object, date, and time keyword values from # the main header and print them. if sn == scan_number : object = myfits_get_keyval(fits, 1, 'OBJECT', cfitsio.TSTRING) date = myfits_get_keyval(fits, 1, 'DATE-OBS', cfitsio.TSTRING) mjd = myfits_get_keyval(fits, 1, 'UTDATE', cfitsio.TLONG) date_time = string.split(date, 'T') ut_start = myfits_get_keyval(fits, 1, 'UTCSTART', cfitsio.TDOUBLE) ut_stop = myfits_get_keyval(fits, 1, 'UTCSTOP', cfitsio.TDOUBLE) # check for a midnight crossing during the scan if ut_start > ut_stop : ut_stop += 86400.0 scan_length = ut_stop - ut_start + 0.5 print '\nScan:', sn, 'of Object:', object print ' Date:', date_time[0], ' UTC:', date_time[1],\ ' MJD:', mjd print ' Scan length:', scan_length.__int__(), 'seconds' # get and print keyword values from the corresponding antenna # and LO files and more detailed information from the spectral # processor FITS file. show_antenna_info(project, fn) show_lo_info(project, fn) show_spectral_processor_info(project, fn) # close the file cfitsio.fits_close_file(fits) # and move on to the next one return # This routine retrieves and prints selected keyword values from the antenna # FITS file, , in the /home/gbtdata//Antenna/ directory. def show_antenna_info ( project, file_name ) : # assemble the file name path and check to see that the file exists fpn = '/home/gbtdata/' + project + '/Antenna/' + file_name if os.path.isfile(fpn) : # open the file for cfitsio reading status, fits = cfitsio.fits_open_file(fpn, cfitsio.READONLY) if status == 0 : # retrieve the outside air temperature, pressure, and humidity # from the main header keywords temp = myfits_get_keyval(fits, 1, 'AMBTEMP', cfitsio.TDOUBLE) pres = myfits_get_keyval(fits, 1, 'AMBPRESS', cfitsio.TDOUBLE) humid = myfits_get_keyval(fits, 1, 'AMBHUMID', cfitsio.TDOUBLE) # retrieve the antenna's position at the beginning of the scan in # two coordinate systems from the third header data unit's (HDU) # binary table columns. az = myfits_get_colval(fits, 3, 'MNT_AZ', 1, 1, 1) el = myfits_get_colval(fits, 3, 'MNT_EL', 1, 1, 1) ra = myfits_get_colval(fits, 3, 'RAJ2000', 1, 1, 1) dec = myfits_get_colval(fits, 3, 'DECJ2000', 1, 1, 1) # close the antenna file and print the results. cfitsio.fits_close_file(fits) print 'Antenna:' print ' Temperature:', temp, 'Deg. C' print ' Pressure:', pres, 'millibars' print ' Humidity:', humid print ' Azimuth:', az, 'Deg. Elevation:', el, 'Deg.' print ' RA2000:', ra / 15.0, 'Hrs Dec2000:', dec, 'Deg.' else : print 'Cannot find Antenna FITS file:', file_name return # This routine retrieves and prints selected keyword values from the LO # FITS file, , in the /home/gbtdata//LO1A/ directory. def show_lo_info ( project, file_name ) : # assemble the file name path and check to see that the file exists fpn = '/home/gbtdata/' + project + '/LO1A/' + file_name if os.path.isfile(fpn) : # open the file for cfitsio reading status, fits = cfitsio.fits_open_file(fpn, cfitsio.READONLY) if status == 0 : # retrieve the line rest frequency, first IF center frequency, # LO power level sent to the receiver, and the sideband of the # first mixer conversion from the main header keywords rest_freq = myfits_get_keyval(fits, 1, 'RESTFRQ', cfitsio.TDOUBLE) if_freq = myfits_get_keyval(fits, 1, 'IFFREQ', cfitsio.TDOUBLE) pwr_lvl = myfits_get_keyval(fits, 1, 'POWERLVL', cfitsio.TDOUBLE) sideband = myfits_get_keyval(fits, 1, 'SIDEBAND', cfitsio.TSTRING) # retrieve the object's velocity with respect to the selected # reference frame, the LO frequency, the observer's velocity with # respect to the selected reference frame, and the velocity of the # object with respect to the observer at the beginning of the scan # from the third and fourth HDU binary table columns. vel = myfits_get_colval(fits, 3, 'VELOCITY', 1, 1, 1) lo_freq = myfits_get_colval(fits, 4, 'LO1FREQ', 1, 1, 1) vframe = myfits_get_colval(fits, 4, 'VFRAME', 1, 1, 1) rvsys = myfits_get_colval(fits, 4, 'RVSYS', 1, 1, 1) # close the LO file and print the results. cfitsio.fits_close_file(fits) print 'LO1A:' print ' Rest Frequency:', rest_freq * 1e-6, 'MHz' print ' First IF Frequency:', if_freq * 1e-6, 'MHz' print ' Power Level:', pwr_lvl, 'dBm Sideband:', sideband print ' Velocity:', vel * 1e-3, 'km/s' print ' LO Frequency:', lo_freq * 1e-6, 'MHz' print ' Frame Velocity:', vframe * 1e-3, 'km/s' print ' RVsys:', rvsys * 1e-3, 'km/s' else : print 'Cannot find LO1A FITS file:', file_name return # This routine retrieves and prints a few selected keyword values from the # spectral processor FITS file, , in the # /home/gbtdata//SpectralProcessor/ directory. def show_spectral_processor_info ( project, file_name ) : # assemble the file name path and check to see that the file exists fpn = '/home/gbtdata/' + project + '/SpectralProcessor/' + file_name if os.path.isfile(fpn) : # open the file for cfitsio reading status, fits = cfitsio.fits_open_file(fpn, cfitsio.READONLY) if status == 0 : # retrieve the input center frequency, bandwidth, and spectral # processor input sideband from the second HDU binary table columns. iff = myfits_get_colval(fits, 2, 'IFF', 1, 1, 1) bw = myfits_get_colval(fits, 2, 'BANDWD', 1, 1, 1) sideband = myfits_get_colval(fits, 2, 'IFSIDE', 1, 1, 1) # get the number of data records (integration) from the fourth # HDU header. num_records = myfits_get_keyval(fits, 4, 'NAXIS2', cfitsio.TSTRING) # the spectra from the different receivers (IF inputs) and # switching phases, e.g., cal on and cal off are stored in a flat # (one dimensional) array. The TDIMn keyword in the fourth HDU # header gives the real dimensions of this array in an ASCII string, # such as '(1024,2,2)'. The nested replace and split functions # from the Python string module parse the individual digit strings, # which are then converted to integers with the atoi function. dvalstr = myfits_get_keyval(fits, 4, 'TDIM5', cfitsio.TSTRING) dlist = string.split(string.replace(string.replace(dvalstr, \ '(', ''), ')', ''), ',') num_chan = string.atoi(dlist[0]) num_states = string.atoi(dlist[1]) num_rcvrs = string.atoi(dlist[2]) # close the spectral processor file and print the results. cfitsio.fits_close_file(fits) print 'Spectral Processor:' print ' Receivers:', num_rcvrs, ' Records:', num_records print ' Bandwidth:', bw[0] * 1e-6, 'MHz' print ' IF Center Frequency:', iff * 1e-6, 'MHz IF Sideband:', \ sideband[0] print ' Switch States:', num_states, ' Spectral Channels:', \ num_chan else : print 'Cannot find SpectralProcessor FITS file:', file_name return # This function returns a keyword value from the specified HDU header. The # arguments are the cfitsio fits file handle, the HDU number (1 to ...), # the keyword name string, the keyword value data type as coded by the # cfitsio.Txxxx attribute values, and an optional error printing flag, which # can be set to 0 to suppress error printing in cases where a failed access # to a keyword can be tolerated. def myfits_get_keyval ( fits, hdu_num, kw_name, kw_type, print_err=1 ) : # get the number of HDU's in this fits file and check to be sure that # the requested HDU number is within range status, nhdus = cfitsio.fits_get_num_hdus(fits) if status : print 'Error reading number of HDU\'s' return 0 if (hdu_num < 1 or hdu_num > nhdus) : if print_err: print 'HDU number:', hdu_num, 'out of range: 1 to', nhdus return 0 # switch cfitsio's attention to the specified HDU q, qq = cfitsio.fits_movabs_hdu(fits, hdu_num) # use the specified keyword data type to control which retrieval function # to use. (I didn't find a keyword type retrieval function in the Python # interface to CFITSIO, but maybe there is one.) if kw_type == cfitsio.TSTRING : type_str = 'STRING' # the returned value is a tuple containing the status flag, the keyword # value in the appropriate data type, and the comment string from the # keyword line status, val, comment = cfitsio.fits_read_key_str(fits, kw_name) elif (kw_type == cfitsio.TLONG or kw_type == cfitsio.TSHORT or \ kw_type == cfitsio.TINT) : type_str = 'INT, LONG, or SHORT' status, val, comment = cfitsio.fits_read_key_lng(fits, kw_name) elif kw_type == cfitsio.TFLOAT : type_str = 'FLOAT' status, val, comment = cfitsio.fits_read_key_flt(fits, kw_name) elif kw_type == cfitsio.TDOUBLE : type_str = 'DOUBLE' status, val, comment = cfitsio.fits_read_key_dbl(fits, kw_name) else : print 'Unrecognized Keyword type:', kw_type return if status : if print_err: print kw_name, 'keyword of type', type_str,\ 'not found in HDU', hdu_num return 0 return val # This function returns a list value from the specified HDU binary table column # designated by the column name. The arguments are the cfitsio fits file # handle, the HDU number (1 to ...), the column name string, the table row # number, the index (1 to ...) of the first value to be retrieved from the # table row/column entry array, and the number of values to be retrieved. If # num_vals == 0 or larger than the number available, all values from # first_index to the end of the array are retrieved. def myfits_get_colval ( fits, hdu_num, col_name, row_num, first_index, \ num_vals ) : # get the number of HDU's in this fits file and check to be sure that # the requested HDU number is within range status, nhdus = cfitsio.fits_get_num_hdus(fits) if status : print 'Error reading number of HDU\'s' return 0 if (hdu_num < 1 or hdu_num > nhdus) : if print_err: print 'HDU number:', hdu_num, 'out of range: 1 to', nhdus return 0 # switch cfitsio's attention to the specified HDU q, qq = cfitsio.fits_movabs_hdu(fits, hdu_num) # tell cfitsio to use case sensitivity in finding column by name casesens = 1 # get the column number from the column name status, col_num = cfitsio.fits_get_colnum(fits, casesens, col_name) if status : print 'Cannot find', col_name, 'column in HDU number', hdu_num return 0 # get the column's data typeand the number of elements in the array (repeat) status, typecode, repeat, width = cfitsio.fits_get_coltype(fits, col_num, 0) if status : print 'Error reading', col_name, 'column type' return 0 if num_vals < 1 : num_vals = repeat # read to the end of the array if repeat < num_vals : print 'Fewer values (', repeat, ') in', col_name, 'column than the', \ num_vals, 'requested' num_vals = repeat # use the column's data type to control which retrieval function to use if typecode == cfitsio.TDOUBLE : #read the data into val status, val = cfitsio.fits_read_col_dbl(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TFLOAT : status, val = cfitsio.fits_read_col_flt(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TINT : status, val = cfitsio.fits_read_col_int(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TUINT : status, val = cfitsio.fits_read_col_uint(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TLONG : status, val = cfitsio.fits_read_col_lng(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TULONG : status, val = cfitsio.fits_read_col_ulng(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TSHORT : status, val = cfitsio.fits_read_col_sht(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TUSHORT : status, val = cfitsio.fits_read_col_usht(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TSTRING : status, val = cfitsio.fits_read_col_str(fits, col_num, row_num, \ first_index, num_vals, 0) elif typecode == cfitsio.TBYTE : status, val = cfitsio.fits_read_col_byt(fits, col_num, row_num, \ first_index, num_vals, 0) else : print 'Unrecognized', col_name, 'column type:', typecode return 0 if status : print 'Error reading', col_name, 'column in HDU number', hdu_num return 0 return val # To test, uncover the scan_info call below and, from the Python # prompt, execute either # import scan_info # or # reload(scan_info) # scan_info('AGBT02A_069_01', 162)