;+ ; IO_SDFITS_CNTM is intended for end users wishing to work with continuum data. It's the child class of IO_SDFITS used for reading, writing, ; navigating sdfits continuum files, and for ; translating their info to continuum data containers. See ; UML for all IO Classes, or ; IO_SDFITS UML for just ; the line and continuum sdfits classes. ; ; ; @file_comments ; IO_SDFITS_LINE is intended for end users wishing to work with continuum data. It's the child class of IO_SDFITS used for reading, writing, ; navigating sdfits continuum line files, and for ; translating their info to continuum data containers. See ; UML for all IO Classes, or ; IO_SDFITS UML for just ; the line and continuum sdfits classes. ; ; @uses LINE_INDEX ; @uses SDFITS ; ; @inherits io_sdfits ; ; @version $Id: io_sdfits_cntm__define.pro,v 1.19 2005/04/21 15:10:23 paghots Exp $ ;- ;+ ; @private ;- PRO io_sdfits_cntm__define compile_opt idl2, hidden ioc = { io_sdfits_cntm, inherits io_sdfits } END ;+ ; Constructor ; @uses IO_SDFITS::init ; @private ;- FUNCTION IO_SDFITS_CNTM::init compile_opt idl2 r = self->IO_SDFITS::init() if (r ne 1) then return, r self.index = obj_new('cntm_index',file_name='io_sdfits_cntm_index',version=self.version) self.debug = 0 return, 1 END ;+ ; This function searches the index file using the keyword parameters passed ; into it, reads the appropriate parts of the sdfits files, and tranlates this ; data into continuum structures, which are returned. ; ; @keyword _EXTRA {in}{optional} see search_for_row_info for more info ; @param count {out}{optional}{type=long} number of continua returned ; ; @returns Array of spectrum structures ; ; @examples ;
;; ; @uses CNTM_INDEX::search_for_row_info ; @uses IO_SDFITS_CNTM::get_continua_from_group ; ; @version $Id: io_sdfits_cntm__define.pro,v 1.19 2005/04/21 15:10:23 paghots Exp $ ;- FUNCTION IO_SDFITS_CNTM::get_continua, _EXTRA=ex, count, indicies if self.index->validate_search_keywords(ex) eq 0 then begin count = 0 return, -1 endif row_info = self.index->search_for_row_info(_EXTRA=ex, indicies) ;pol='XX') if (size(row_info,/dimension) eq 0) then begin count = 0 return, -1 endif groups = self->group_row_info(row_info) for i=0,n_elements(groups)-1 do begin group = groups[i] continua = self->get_continua_from_group(group) if (i eq 0) then all_cntm=[continua] else all_cntm=[all_cntm,continua] endfor self->free_group_row_info, groups count = n_elements(continua) return, continua END ;+ ; Retrieves Continua data containers from a group of sdfits rows from the same extension. ; ; @param group {in}{type=struct} structure that contains all the info needed for extracting continua from sdfits. ; ; @private ;- FUNCTION IO_SDFITS_CNTM::get_continua_from_group, group @continuum start_rows=*group.start_rows num_rows=*group.num_rows strides=*group.strides if_numbers=*group.if_numbers ; get the fits object for reading from fits = self->get_fits(group.file) ; how many continnua will we be getting? continua = make_array(n_elements(start_rows),value={continuum}) for i=0,n_elements(start_rows)-1 do begin ; structure for passing data ptrs around data = { data:ptr_new(/allocate_heap), $ azimuth:ptr_new(/allocate_heap), $ elevation:ptr_new(/allocate_heap), $ longitude:ptr_new(/allocate_heap), $ latitude:ptr_new(/allocate_heap), $ lst:ptr_new(/allocate_heap), $ date_obs:ptr_new(/allocate_heap) $ } ; get the first row, and all the columns that vary row = fits->get_cntm_data( group.extension, start_rows[i], num_rows[i], strides[i], data, missing, virtuals ) ; translate the data to a data container cnt = self->cntm_data_to_cntm_container(row, data, missing, virtuals, if_numbers[i]) if self.debug then begin print, 'retrieved continuum:' print, cnt.scan_number, cnt.procedure, cnt.polarization, cnt.sig_state, cnt.cal_state, format='(i5,2x,16a,2x,2a,2x,i3,2x,i3)' endif ; append the new continuum to the array continua[i]=cnt ; don't clean up ALL the 'data' struct: it's pointers are used by the continnua if ptr_valid(data.date_obs) then ptr_free, data.date_obs ;if ptr_valid(data.lst) then ptr_free, data.lst endfor return, continua END ;+ ; Translates continuum data derived from an sdfits file and index file into a Continuum data container. ; @param row {in}{type=struct} struct mirroring the first row that this continuum starts at ; @param data {in}{type=struct} struct containing pointers to the continuum data: data, az, el, etc. ; @param missing {in}{type=array} array of column names expected in sdfits and not found ; @param virtuals {in}{type=struct} struct containg extension header keywords ; @param if_number {in}{type=long} if number from index file for this continuum ; ; @uses IO_SDFITS::get_row_value ; @uses fitsdateparse ; @uses mjd ; @uses juldate ; @uses IO_SDFITS::coord_mode_from_types ; @uses IO_SDFITS::format_sdfits_polarization ; @uses IO_SDFITS::format_sdfits_procedure ; @uses IO_SDFITS::translate_sig ; @uses IO_SDFITS::translate_cal ; ; @private ;- FUNCTION IO_SDFITS_CNTM::cntm_data_to_cntm_container, row, data, missing, virtuals, if_number compile_opt idl2 cnt = {continuum} names = {row:ptr_new(tag_names(row)),missing:ptr_new(missing),virtuals:ptr_new(tag_names(virtuals))} ; pass over the data pointers of varying columns cnt.data_ptr = data.data cnt.azimuth = data.azimuth cnt.elevation = data.elevation cnt.longitude_axis = data.longitude cnt.latitude_axis = data.latitude ; date cnt.date = ptr_new(strmid(*data.date_obs,0,10)) ; note that the sign in the current sdfits output of SITELONG is probably ; wronge - it should be degrees east of Greenwich ; make sure this came from NRAO_GBT before fixing that. ; eventually, when sdfits is fixed, this will need to check the FITSVER sitelong = self->get_row_value(row,'SITELONG',virtuals,names,0.0) sitelat = self->get_row_value(row,'SITELAT',virtuals,names,0.0) siteelev = self->get_row_value(row,'SITEELEV',virtuals,names,0.0) cnt.site_location = [sitelong, sitelat, siteelev] if (cnt.telescope eq "NRAO_GBT") then cnt.site_location[0] = -cnt.site_location[0] ; utc, mjd and ltc utc = dblarr(n_elements(*data.date_obs)) mjd = dblarr(n_elements(*data.date_obs)) lst = dblarr(n_elements(*data.date_obs)) for i=0,n_elements(*data.date_obs)-1 do begin fd = fitsdateparse((*data.date_obs)[i]) utc[i] = (fd[3]*60.0+fd[4])*60.0 + fd[5] juldate,fd,thismjd ; juldate sets Reduced Julian Date (RJD). MJD = RJD - 0.5 mjd[i] = thismjd - 0.5 ;print, i, mjd[i], mjd[i]-mjd[0], thismjd, fd, (*data.date_obs)[i] ;ct2lst,lst[i],cnt.site_location[1],0,(mjd[i]+2400000.5) ;lst[i] = lst[i] * 3600.0 endfor cnt.utc = ptr_new(utc) cnt.mjd = ptr_new(mjd) ;cnt.lst = ptr_new(lst) cnt.lst = data.lst ; pass on the rest of the const info cnt.source = self->get_row_value(row,'OBJECT',virtuals,names,'default') cnt.projid = self->get_row_value(row,'PROJID',virtuals,names,'default') cnt.backend = self->get_row_value(row,'BACKEND',virtuals,names,'default') cnt.observer = self->get_row_value(row,'OBSERVER',virtuals,names,'default') cnt.telescope = self->get_row_value(row,'TELESCOP',virtuals,names,'default') cnt.bandwidth = self->get_row_value(row,'BANDWID',virtuals,names,'default') cnt.exposure = self->get_row_value(row,'EXPOSURE',virtuals,names,'default') cnt.tsys = self->get_row_value(row,'TSYS',virtuals,names,'default') cnt.tsysref = self->get_row_value(row, 'TSYSREF',virtuals,names, 1.0) ctype2 = self->get_row_value(row,'CTYPE2',virtuals,names,'default') ctype3 = self->get_row_value(row,'CTYPE3',virtuals,names,'default') cnt.coordinate_mode = self->coord_mode_from_types(ctype2,ctype3) crval4 = self->get_row_value(row,'CRVAL4',virtuals,names,'default') cnt.polarization = self->format_sdfits_polarization(crval4[0]) cnt.scan_number = self->get_row_value(row,'SCAN',virtuals,names,'default') cnt.procedure = self->format_sdfits_procedure(self->get_row_value(row,'OBSMODE',virtuals,names,'default')) cnt.obsid = self->get_row_value(row,'OBSID',virtuals,names,'default') cnt.frontend = self->get_row_value(row,'FRONTEND',virtuals,names,'default') cnt.beamxoff = self->get_row_value(row,'BEAMXOFF',virtuals,names,'default') cnt.beameoff = self->get_row_value(row,'BEAMEOFF',virtuals,names,'default') cnt.mean_tcal = self->get_row_value(row,'TCAL',virtuals,names,'default') cnt.observed_frequency = self->get_row_value(row,'OBSFREQ',virtuals,names,'default') cnt.sampler_name = self->get_row_value(row,'SAMPLER',virtuals,names,'default') cnt.feed = self->get_row_value(row,'FEED',virtuals,names,'default') cnt.srfeed = self->get_row_value(row,'SRFEED',virtuals,names,'default') cnt.sideband = self->get_row_value(row,'SIDEBAND',virtuals,names,'default') cnt.subscan = self->get_row_value(row,'PROCSEQN',virtuals,names,'default') cnt.procsize = self->get_row_value(row,'PROCSIZE',virtuals,names,'default') cnt.sig_state = self->translate_sig(self->get_row_value(row,'SIG',virtuals,names,'T')) cnt.cal_state = self->translate_cal(self->get_row_value(row,'CAL',virtuals,names,'T')) ; additional stuff cnt.if_number = if_number ; from index file ptr_free,names.row ptr_free,names.missing ptr_free,names.virtuals return, cnt END ;+ ; Groups rows from index file according to file-extension ; @param row_info {in}{type=array} array of structs mirroring rows of index file ; @returns same structures passed in, but grouped by file-extension ; @private ;- FUNCTION IO_SDFITS_CNTM::group_row_info, row_info ;row_group = {sdfits_row_group} ; get all files files = row_info.file unique_files = files[uniq(files[sort(files)])] group = {cntm_sdfits_row_group} for i = 0, (n_elements(unique_files)-1) do begin file_locals = row_info[ where(row_info.file eq unique_files[i]) ] exts = file_locals.extension unique_exts = exts[uniq(exts[sort(exts)])] for j = 0, (n_elements(unique_exts)-1) do begin file_ext_locals = file_locals[ where(file_locals.extension eq unique_exts[j]) ] ; collapse the array into one struct group.file = file_ext_locals[0].file group.extension = file_ext_locals[0].extension group.start_rows = ptr_new(file_ext_locals.start_row) group.num_rows = ptr_new(file_ext_locals.num_rows) group.strides = ptr_new(file_ext_locals.stride) ;group.integrations = ptr_new(file_ext_locals.integration) group.if_numbers = ptr_new(file_ext_locals.if_number) if (i eq 0) and (j eq 0) then groups = [group] else groups = [groups,group] endfor endfor return, groups END ;+ ; Updates the index file with all the information from the passed in sdfits file ; @param fits {in}{type=object} object that represents sdfits files whose info is feed to index file ; @uses CNTM_SDFITS::get_cntm_scan_properties ; @uses CNTM_INDEX::update_index_with_scan ; @uses INDEX_FILE::read_file ; @private ;- PRO IO_SDFITS_CNTM::update_index_with_fits_file, fits compile_opt idl2 num_exts = fits->get_number_extensions() ; go through each extension, skipping the primary one for ext = 1, num_exts do begin num_rows = fits->get_ext_num_rows(ext) scan_starts = fits->get_scan_starts(ext) ; use the scan start info to load each scan for i=0,n_elements(scan_starts)-1 do begin ; get the beginning and end of each scan start = scan_starts[i] if (i ne n_elements(scan_starts)-1) then begin end_row = scan_starts[i+1] - 1 endif else begin end_row = num_rows endelse ; get key properties of this scan from the fits file row = fits->get_cntm_scan_properties(ext, start, end_row, project, samplers, sigs, cals, sampler_pols) if self.debug then begin print, "update_index_with_fits_file:" print, "start:end - ",start,end_row,format="(20a,2x,i5,2x,i5)" print, samplers print, sigs print, cals print, sampler_pols endif ; how many total data points for scan n_data = end_row - start + 1 ; total data points per polarization data_per_sampler = n_data/n_elements(samplers) ;if self.debug then begin ; print, "start row: "+string(start) ; print, "end row: "+string(end_row) ; print, "n_data: "+string(n_data) ; print, "data/sampler: "+string(data_per_sampler) ;endif file_name = fits->get_file_name() self.index->update_file_with_scan, row, project, file_name, ext, start, n_data, samplers, sigs, cals, sampler_pols endfor ; for each scan endfor ; for each extension self.index->read_file self.index_synced = 1 END ;+ ; frees the memory in each element of this array ; @param row_info {in}{type=array} array of structures ; @private ;- PRO IO_SDFITS_CNTM::free_group_row_info, row_info compile_opt idl2 for i=0, (n_elements(row_info)-1) do begin if ptr_valid(row_info[i].start_rows) then ptr_free, row_info[i].start_rows if ptr_valid(row_info[i].num_rows) then ptr_free, row_info[i].num_rows if ptr_valid(row_info[i].strides) then ptr_free, row_info[i].strides if ptr_valid(row_info[i].if_numbers) then ptr_free, row_info[i].if_numbers endfor END ;+ ; creates and returns a new object to represent an sdfits continuum file ; @param file_name {in}{type=string} full path name to the file to be represented by object ; @returns object of cntm_sdfits class ; @private ;- FUNCTION IO_SDFITS_CNTM::get_new_fits_obj, file_name, _EXTRA=ex compile_opt idl2 return, obj_new('cntm_sdfits',file_name,version=self.version,_EXTRA=ex) END ;+ ; Stub method for updating the index file. TBD. ;- PRO IO_SDFITS_CNTM::load_new_sdfits_rows compile_opt idl2 message, "load_new_sdfits_rows not implemented yet for continuum", /info END ;+ ; Stub method for updating the index file. TBD. ;- PRO IO_SDFITS_CNTM::update compile_opt idl2 message, "update not implemented yet for continuum", /info END ;+ ; Stub method for updating the index file. TBD. ;- PRO IO_SDFITS_CNTM::set_online, file_name compile_opt idl2 message, "online mode not implemented yet for continuum", /info END