;+
; 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