;+ ; Child class of INDEX_FILE, contains special functionality for dealing with continuum data. ; This mostly entails the translation of sdfits data into contents of the index file. ; See UML for all IO Classes, or ; INDEX UML for just index classes. ; This class is responsible for establishing the correct class for managing the ; row section of the index file, the translation between sdfits and index rows, ; and provides the search gateway. ; @file_comments ; Child class of INDEX_FILE, contains special functionality for dealing with continuum data. ; This mostly entails the translation of sdfits data into contents of the index file. ; See UML for all IO Classes, or ; INDEX UML for just index classes. ; This class is responsible for establishing the correct class for managing the ; row section of the index file, the translation between sdfits and index rows, ; and provides the search gateway. ; @private_file ;- PRO cntm_index__define cif = { CNTM_INDEX, inherits INDEX_FILE } END FUNCTION CNTM_INDEX::init, _EXTRA=ex compile_opt idl2, hidden self.rows_class = "cntm_index_section" r = self->INDEX_FILE::init(_EXTRA=ex) return, r END ;+ ; Returns the specail structure needed for continuum data ; @returns cntm_row_info_strct structure ; @private ; - FUNCTION CNTM_INDEX::get_row_info_strct @cntm_row_info return, {cntm_row_info_strct} END ;+ ; This method searches the rows in the index file using the optional keywords. ; Not using any keywords returns all rows. Use of more then one keyword is like ; using an AND. ; ; @param start {in}{optional}{type=long} where to start the range to search in ; @param finish {in}{optional}{type=long} where to stop the range to search in ; ; @keyword index {in}{optional}{type=long} What index # to search for ; @keyword project {in}{optional}{type=string} What projects to search for ; @keyword file {in}{optional}{type=string} What sdfits files to search for ; @keyword extension {in}{optional}{type=long} What sdfits extension numbers to search for ; @keyword start_rows {in}{optional}{type=long} What sdfits row numbers to search for ; @keyword num_rows {in}{optional}{type=long} What number of rows to search for ; @keyword stride {in}{optional}{type=long} What stride to search for ; @keyword source {in}{optional}{type=string} What source names to search for ; @keyword procedure {in}{optional}{type=string} What procecures to search for ; @keyword scan {in}{optional}{type=long }What M&C scan numbers to search for ; @keyword subscan {in}{optional}{type=long }What M&C sub scan numbers to search for ; @keyword e2escan {in}{optional}{type=long }What e2e scan numbers to search for (not yet supported) ; @keyword ifnum {in}{optional}{type=long }What if numbers to search for ; @keyword polarization {in}{optional}{type=string} What polarizations to search for ; @keyword sig {in}{optional}{type=string} What sig states to search for ; @keyword cal {in}{optional}{type=string} What cal states to search for ; ; @returns Array of structures, each element corresponding to a line of the index file that matches the search ; ;- FUNCTION CNTM_INDEX::search_index, start, finish, SEARCH=search, INDEX=index, PROJECT=project, FILE=file, EXTENSION=extension, START_ROWS=start_rows, NUM_ROWS=num_rows, STRIDE=stride, SOURCE=source, PROCEDURE=procedure, SCAN=scan, SUBSCAN=subscan, E2ESCAN=e2escan, POLARIZATION=polarization, IFNUM=ifnum, SIG=sig, CAL=cal, NSAVE=nsave if (self.file_loaded eq 0) then begin print, 'File not loaded, cannot search index. Use read_file method' return, -1 endif if n_elements(SEARCH) eq 0 then begin ; init the search result to include all row indicies search_result = indgen(n_elements(*self.row_lines),/LONG) endif else begin ; init the search to include only previous results passed in search_result = search endelse ; if the start and finish parameters have been used, use them for limiting our search to a range. search_result = self->search_range(start,finish,search_result) ; for each keyword, par down the search result for each criteria if n_elements(INDEX) ne 0 then begin self->find_values_plus_and,(*self.row_lines).index,index,search_result endif if n_elements(PROJECT) ne 0 then begin self->find_values_plus_and,(*self.row_lines).project,project,search_result endif if n_elements(FILE) ne 0 then begin self->find_values_plus_and,(*self.row_lines).file,file,search_result endif if n_elements(EXTENSION) ne 0 then begin self->find_values_plus_and,(*self.row_lines).extension,extension,search_result endif if n_elements(start_rows) ne 0 then begin self->find_values_plus_and,(*self.row_lines).start_row,start_rows,search_result endif if n_elements(source) ne 0 then begin self->find_values_plus_and,(*self.row_lines).source,source,search_result endif if n_elements(procedure) ne 0 then begin self->find_values_plus_and,(*self.row_lines).procedure,procedure,search_result endif if n_elements(scan) ne 0 then begin self->find_values_plus_and,(*self.row_lines).mc_scan,scan,search_result endif if n_elements(subscan) ne 0 then begin self->find_values_plus_and,(*self.row_lines).subscan,subscan,search_result endif if n_elements(e2escan) ne 0 then begin self->find_values_plus_and,(*self.row_lines).scan,e2escan,search_result endif if n_elements(polarization) ne 0 then begin self->find_values_plus_and,(*self.row_lines).polarization,polarization,search_result endif if n_elements(ifnum) ne 0 then begin self->find_values_plus_and,(*self.row_lines).if_number,ifnum,search_result endif if n_elements(sig) ne 0 then begin self->find_values_plus_and,(*self.row_lines).sig_state,sig,search_result endif if n_elements(cal) ne 0 then begin self->find_values_plus_and,(*self.row_lines).cal_state,cal,search_result endif if n_elements(nsave) ne 0 then begin self->find_values_plus_and,(*self.row_lines).nsave,nsave,search_result endif return, search_result END ;+ ; Appends row info to an index file, given a group of rows from sdfits files. Used ; for first loading in an sdfits file ; @param first_row {in}{type=struct} represents the first row in the sdfits file of the scan ; @param proj {in}{type=string} project for scan ; @param file_name {in}{type=string} file location ; @param ext {in}{type=long} extension location ; @param start_row {in}{type=long} where this scan starts in the extension ; @param n_data {in}{type=long} length of a continuum in this scan ; @param samplers {in}{type=array} array of sampler names used in this scan ; @param sigs {in}{type=array} array of unique signal states in scan ; @param cals {in}{type=array} array of unique cal states in scan ; @param pols {in}{type=array} array of polarizations for each sampler ; @uses CNTM_INDEX::parse_scan_info ; @uses CNTM_INDEX::update_index_file ;- PRO CNTM_INDEX::update_file_with_scan, first_row, proj,file_name, ext, start_row, n_data, samplers, sigs, cals, pols info_rows = self->parse_scan_info(first_row, proj,file_name,ext, start_row, n_data, samplers, sigs, cals, pols) self->update_index_file, info_rows END ;+ ; Takes in information about a continuum scan, and converts that to several rows in the index ; file. A single scan may have several continua (or rows in index) depending on the switching type, receiver type, etc... ; @param first_row {in}{type=struct} represents the first row in the sdfits file of the scan ; @param proj {in}{type=string} project for scan ; @param file_name {in}{type=string} file location ; @param ext {in}{type=long} extension location ; @param start_row {in}{type=long} where this scan starts in the extension, should be zero for the first scan ; @param n_data {in}{type=long} length of a continuum in this scan ; @param unique_samplers {in}{type=array} array of sampler names used in this scan ; @param sigs {in}{type=array} array of unique signal states in scan ; @param cals {in}{type=array} array of unique cal states in scan ; @param sampler_pols {in}{type=array} array of polarizations for each sampler ; returns array of structures representing new rows for the index file (all for just this scan) ; @private ;- FUNCTION CNTM_INDEX::parse_scan_info,first_row,proj, file_name, ext, start_row, n_data, unique_samplers, sigs, cals, sampler_pols compile_opt idl2 row_info = self->get_row_info_strct() n_samplers = n_elements(unique_samplers) n_sigs = n_elements(sigs) n_cals = n_elements(cals) count = 0 ;row_number = self.current_rows row_number = self.rows->get_num_rows() current_rows = self.rows->get_num_rows() ; total data points per polarization ;data_per_sampler = n_elements(data)/n_samplers data_per_sampler = n_data/n_samplers index_len = (n_data/(n_samplers*n_sigs*n_cals)) if (index_len eq 0) then index_len = 1 seed_index = indgen(index_len) seed_index = seed_index*n_sigs*n_cals ; make the array where each element will be a row in the index file info_rows = make_array((n_samplers*n_sigs*n_cals),value= self->get_row_info_strct()) if self.debug then help, info_rows ; cycle through pols for i_sampler=0,n_samplers-1 do begin pol_index = seed_index + (data_per_sampler*i_sampler) pol = sampler_pols[i_sampler] sampler = unique_samplers[i_sampler] ; cycle through sigs for i_sig=0,n_sigs-1 do begin sig_index = pol_index + (2*i_sig) ; what's the sig? if (i_sig eq 0) then sig = 'T' else sig = 'F' ; cycle throuh cals for i_cal=0,n_cals-1 do begin index = sig_index + i_cal ; what's the cal? if (i_cal eq 0) then cal = 'F' else cal = 'T' if self.debug then print, "count: "+string(count)+"sampler: "+string(i_sampler)+" sig: "+string(i_sig)+" cal: "+string(i_cal) ; get info to put in index file start_row_in_file = start_row + index[0] num_rows = n_elements(index) if (num_rows gt 1) then begin stride = index[1] - index[0] endif else begin stride = 1 endelse ; this structure represents a line in the index file row_info = self->get_row_info_strct() row_info.start_row = start_row_in_file row_info.num_rows = num_rows row_info.stride = stride row_info.index = current_rows row_info.project = proj row_info.file = file_name row_info.extension = ext row_info.mc_scan = first_row.scan row_info.source = strtrim(first_row.object,2) row_info.procedure = self->get_procedure_from_obsmode(first_row.obsmode[0]) row_info.subscan = first_row.procseqn[0] row_info.polarization = self->translate_polarization(pol) row_info.sig_state = sig row_info.cal_state = cal row_info.nsave = -1 if self.debug then help, row_info, /str info_rows[count] = row_info count = count + 1 current_rows = current_rows + 1 endfor ; for each cal endfor ; for each sig endfor ; for each sampler return, info_rows END ;+ ; Checks basic file properties to see if they agree with what the index file has listed. ; @param file_name {in}{type=string} sdfits file to check ; @param expanded {in}{optional}{type=boolean} has this file been expanded since its listing in the index file? ; @keyword verbose {in}{optional}{type=boolean} print out details of errors? ; @returns 0,1 ; @private ;- FUNCTION CNTM_INDEX::check_file_properties, file_name, expanded, verbose=verbose if (n_params() eq 2) then checking_expansion = 1 else checking_expansion = 0 if checking_expansion then expanded = 0 if keyword_set(verbose) then loud =1 else loud = 0 ; get the number of extensions and rows/ext. according to the index file self->get_file_properties_in_index, file_name, index_exts, index_rows ; open this fits file and get same properties fits = obj_new('fits',self->get_full_file_name(file_name)) file_exts = indgen(fits->get_number_extensions())+1 file_rows = make_array(n_elements(file_exts),value=0L) for i=0,n_elements(file_rows)-1 do begin file_rows[i] = fits->get_ext_num_rows(file_exts[i]) endfor obj_destroy, fits ; check number of extensions if (n_elements(index_exts) ne n_elements(file_exts)) then begin ; if the file has more extensions then index, its expandable if (index_exts lt file_exts) and checking_expansion then expanded = 1 if loud then print, 'file: '+file_name+' does not have same number of extensions as index reports' return, 0 endif ; file properties match index return, 1 END ;+ ; Returns a structure that contains info about the scan number given, such ; as scan number, procedure name, number of integrations, ifs, etc.. ; ; @param scan_number {in}{type=long} scan number information is queried for ; ; @returns Structure containing info on scan ; ;- FUNCTION CNTM_INDEX::get_scan_info, scan_number compile_opt idl2 rows = self->search_for_row_info(scan=scan_number) if (size(rows,/dimension) eq 0) then message, 'Scan number not found: '+string(scan_number) scan_info = {scan_info} ; this info is constant for scan scan_info.scan = rows[0].mc_scan scan_info.subscan = rows[0].subscan scan_info.procedure = rows[0].procedure ; scan_info.n_subscans = n_elements(self->get_uniques(rows.procsize)) ; collect info about scan scan_info.n_integrations = 1 scan_info.n_feeds = 1 scan_info.n_ifs = n_elements(self->get_uniques(rows.if_number)) n_sigs = n_elements(self->get_uniques(rows.sig_state)) n_cals = n_elements(self->get_uniques(rows.cal_state)) scan_info.n_switching_states = n_sigs*n_cals return, scan_info END ;+ ; Finds the number and sizes of extensions for a file listed in the index file, according to the index file. ; @param file_name {in}{type=string} file whose properties are being queried ; @param extensions {out}{type=long} number of extensions for this file ; @param num_rows {out}{type=array} array showing how many rows in each extension for this file ; @uses INDEX_FILE::search_for_row_info ; @private ;- PRO CNTM_INDEX::get_file_properties_in_index, file_name, extensions, num_rows compile_opt idl2 ; get all rows for this file name row_info = self->search_for_row_info( file=file_name ) ; get the unique extension numbers for this file exts = row_info.extension s_exts = exts[sort(exts)] unique_exts = s_exts[uniq(s_exts)] ; set the output parameters extensions = unique_exts num_rows = make_array(n_elements(extensions),value=0L) ; gather the number of rows for each extension for i=0,n_elements(extensions)-1 do begin ext = extensions[i] row_info = self->search_for_row_info( file=file_name, ext=ext ) num_rows[i] = n_elements(row_info) endfor return END