# This glish 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 uses a glish client for loading the contents of a FITS into # a glish record. The scan_info() function 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 same # glish client. # 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 glish prompt: # - include 'scan_info.g' # - scan_info.scan_info('AGBT02A_069_01', 162) include '/users/rfisher/Applications/FitsCode/fits_client.g' func 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 := spaste('/home/gbtdata/', project, '/', device) ls := shell(spaste('ls ', dev_path)) if (len(ls) < 1) { return } file_num := 0 # step through every file in the list for (fn in ls) { sfn := split(fn, '.') # if it's not a FITS file, skip it if (sfn[len(sfn)] == 'fits') { file_num +:= 1 fpn := spaste(dev_path, '/', fn) sn := -1 # load the contents of the FITS file into a record ft := get_fits(fpn) # make sure it's not an incomplete FIT file, then check the scan # number to see if it is the one requested if (has_field(ft.main_header, 'SCAN')) { sn := ft.main_header.SCAN } else { sn := -1 } # if so, gather a few object, date, and time keyword values from # the main header and print them. if (sn == scan_number) { object := ft.main_header.OBJECT # need to use string ID record member notation because of the # '-' character in the name date := ft.main_header['DATE-OBS'] mjd := ft.main_header.UTDATE date_time := split(date, 'T') ut_start := ft.main_header.UTCSTART ut_stop := ft.main_header.UTCSTOP # 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[1], ' UTC:', date_time[2], ' MJD:', mjd print ' Scan length:', as_integer(scan_length), '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) } # and keep looking for files with this scan number } } } # This routine retrieves and prints selected keyword values from the antenna # FITS file, , in the /home/gbtdata//Antenna/ directory. func show_antenna_info ( project, file_name ) { # assemble the file name path and check to see that the file exists fpn := spaste('/home/gbtdata/', project, '/Antenna/', file_name) fs := stat(fpn) if (has_field(fs, 'type')) { # load the contents of the FITS file into a record ft := get_fits(fpn) # make sure it's not an incomplete FIT file, then check the scan # number to see if it is the one requested if (has_field(ft.main_header, 'SCAN')) { sn := ft.main_header.SCAN } else { sn := -1 } if (sn > 0) { # retrieve the outside air temperature, pressure, and humidity # from the main header keywords temp := ft.main_header.AMBTEMP pres := ft.main_header.AMBPRESS humid := ft.main_header.AMBHUMID # retrieve the antenna's position at the beginning of the scan in # two coordinate systems from the DATA block # binary table columns. az := ft.ANTPOSGR.Columns.MNT_AZ[1] el := ft.ANTPOSGR.Columns.MNT_EL[1] ra := ft.ANTPOSGR.Columns.RAJ2000[1] dec := ft.ANTPOSGR.Columns.DECJ2000[1] # print the results. 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 } } # This routine retrieves and prints selected keyword values from the LO # FITS file, , in the /home/gbtdata//LO1A/ directory. func show_lo_info ( project, file_name ) { # assemble the file name path and check to see that the file exists fpn := spaste('/home/gbtdata/', project, '/LO1A/', file_name) fs := stat(fpn) if (has_field(fs, 'type')) { # load the contents of the FITS file into a record ft := get_fits(fpn) # make sure it's not an incomplete FIT file, then check the scan # number to see if it is the one requested if (has_field(ft.main_header, 'SCAN')) { sn := ft.main_header.SCAN } else { sn := -1 } if (sn > 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 := ft.main_header.RESTFRQ if_freq := ft.main_header.IFFREQ pwr_lvl := ft.main_header.POWERLVL sideband := ft.main_header.SIDEBAND # 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 vel := ft.SOUVEL.Columns.VELOCITY[1] lo_freq := ft.LO1TBL.Columns.LO1FREQ[1] vframe := ft.LO1TBL.Columns.VFRAME[1] rvsys := ft.LO1TBL.Columns.RVSYS[1] # print the results. 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 } } # This routine retrieves and prints a few selected keyword values from the # spectral processor FITS file, , in the # /home/gbtdata//SpectralProcessor/ directory. func show_spectral_processor_info ( project, file_name ) { # assemble the file name path and check to see that the file exists fpn := spaste('/home/gbtdata/', project, '/SpectralProcessor/', file_name) fs := stat(fpn) if (has_field(fs, 'type')) { # load the contents of the FITS file into a record ft := get_fits(fpn) # make sure it's not an incomplete FIT file, then check the scan # number to see if it is the one requested if (has_field(ft.main_header, 'SCAN')) { sn := ft.main_header.SCAN } else { sn := -1 } if (sn > 0) { # retrieve the input center frequency, bandwidth, and spectral # processor input sideband from the second HDU binary table columns. iff := ft.RECEIVER.Columns.IFF[1] bw := ft.RECEIVER.Columns.BANDWD[1] sideband := ft.RECEIVER.Columns.IFSIDE[1] # get the number of spectral channels, number of switching states # (cal-on, cal-off, etc.), number of IF inputs, and number of data # records (integrations) from the DATA array dimensions num_chan := ft.DATA.Columns.DATA::shape[1] num_states := ft.DATA.Columns.DATA::shape[2] num_rcvrs := ft.DATA.Columns.DATA::shape[3] num_records := ft.DATA.Columns.DATA::shape[4] # print the results print 'Spectral Processor:' print ' Receivers:', num_rcvrs, ' Records:', num_records print ' Bandwidth:', bw[1] * 1e-6, 'MHz' print ' IF Center Frequency:', iff * 1e-6, 'MHz IF Sideband:', \ sideband[1] print ' Switch States:', num_states, ' Spectral Channels:', \ num_chan } } else { print 'Cannot find SpectralProcessor FITS file:', file_name } } # To test, uncover the scan_info call below and, from the glish # prompt, execute # include 'scan_info.g' scan_info('AGBT02A_069_01', 162)