;+
; FLAGS is the class which handles all flags used by an io_sdfits object. It
; is composed of an array of FLAG_FILE objects for managing separate
; flag files. It is also responsible for converting record number between
; their values for a particular sdfits file, and that for a single index file
; used with multiple sdfits files. See UML fro all IO Classes.
;
; @field files pointer to an array of
; @field flie_index_bases pointer to an array of
; @field flag_files pointer to an array of flag file objects
; @field file_path path to where all flag files can be found
; @field version string indicating the flagging format
; @field flags_section_class string indicating the class to use for the flagging format
; @field param_types pointer to 2-D array of parameter names/types
; @field debug integer flag for printing debug info
;
;-
PRO flags__define
flgs = { FLAGS, $
files:ptr_new(), $
file_index_bases:ptr_new(), $
flag_files:ptr_new(), $
file_path:string(replicate(32B,256)), $
version:string(replicate(32B,3)), $
flags_section_class:string(replicate(32B,256)), $
param_types:ptr_new(), $
flag_ids:ptr_new(), $
debug:0L $
}
END
;+
; Class constructor where pointers are initialized and flag parameter types
; are defined.
;-
FUNCTION FLAGS::init, file_path=file_path, debug=debug
compile_opt idl2, hidden
self.files = ptr_new(/allocate_heap)
self.file_index_bases = ptr_new(/allocate_heap)
self.flag_files = ptr_new(/allocate_heap)
self.param_types = ptr_new(/allocate_heap)
self.flag_ids = ptr_new(/allocate_heap)
self.version = ""
self.flags_section_class = ""
if keyword_set(file_path) then self->set_file_path, file_path
if keyword_set(debug) then self.debug=debug else self.debug = 0
; get the parameter types - must create a flag file obj.
flag_file = obj_new("flag_file")
*self.param_types = flag_file->get_param_types()
if obj_valid(flag_file) then obj_destroy, flag_file
return, 1
END
;+
; Class destructor where pointers and objects are freed.
;-
PRO FLAGS::cleanup
compile_opt idl2, hidden
if ptr_valid(self.files) then ptr_free, self.files
if ptr_valid(self.file_index_bases) then ptr_free, self.file_index_bases
if n_elements(*self.flag_files) ne 0 then begin
for i=0,n_elements(*self.flag_files)-1 do begin
;print, (*self.flag_files)[i]->get_file_name()
if obj_valid((*self.flag_files)[i]) then obj_destroy,(*self.flag_files)[i]
endfor
ptr_free, self.flag_files
endif else begin
ptr_free, self.flag_files
endelse
if ptr_valid(self.param_types) then ptr_free, self.param_types
if ptr_valid(self.flag_ids) then ptr_free, self.flag_ids
END
;+
; One of two main methods for setting flags.
; This sets a flag rule according to observational parameters, such as
; scan number, integration number, feed, polarization, and IF numbers.
; The channels to flag can also be set, along with an idstring for
; identification. The fits filename parameter is used to retrieve the
; flag file object responsible for this file, which does the flagging.
; Flag IDs are reset after this operation.
; @param fits_filename {in}{required}{type=string} the full path name to the fits file that contains the scan to be flagged
; @param scan {in}{required}{type=long} scan number
; @keyword _EXTRA {in}{optional}{type=keywords} includes keywords intnum, fdnum, plnum, ifnum, bchan, echan, idstring.
;-
PRO FLAGS::set_flag, fits_filename, scan, _EXTRA=ex
compile_opt idl2, hidden
flag_filename = self->fits_filename_to_flag_filename(fits_filename)
ff = self->get_flag_file_obj(flag_filename)
ff->set_flag, scan, _EXTRA=ex
ff->append_index_value_recnums, "*"
self->set_flag_ids
END
;+
; One of two main methods for setting flags.
; This sets a flag rule according to index parameters, specifically the
; record number.
; The channels to flag can also be set, along with an idstring for
; identification. The fits filename parameter is used to retrieve the
; flag file object responsible for this file, which does the flagging.
; Flag IDs are reset after this operation.
; @param fits_filename {in}{required}{type=string} the full path name to the fits file that contains the scan to be flagged
; @param index_recnum {in}{required}{type=long} record number to flag
; @keyword _EXTRA {in}{optional}{type=keywords} includes keywords bchan, echan, idstring.
;-
PRO FLAGS::set_flag_rec, fits_filename, index_recnum, _EXTRA=ex
compile_opt idl2, hidden
flag_filename = self->fits_filename_to_flag_filename(fits_filename)
flag_recnum = self->index_recnum_to_flag_recnum(index_recnum,flag_filename)
ff = self->get_flag_file_obj(flag_filename)
ff->set_flag_rec, flag_recnum, _EXTRA=ex
ff->append_index_value_recnums, self->int_array_to_string_list(index_recnum)
self->set_flag_ids
END
;+
; Converts an array of integers to a comma spearated string
; @param int_array {in}{required}{type=long} integer array
; @returns string containing comma separated elements of array
;-
FUNCTION FLAGS::int_array_to_string_list, int_array
compile_opt idl2, hidden
string_list = ""
for i=0,n_elements(int_array)-1 do begin
if i ne 0 then string_list += ","
string_list += strtrim(string(int_array[i]),2)
endfor
return, string_list
END
;+
; Removes a line in a flag file via either its dynamic ID or its IDSTRING.
; @param id {in}{required}{type=long,string} id can be an integer ID
; or string IDSTRING
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @keyword all {in}{optional}{type=boolean} When set, all IDs are
; unflagged and any id argument is ignored.
; @keyword quiet {in}{optional}{type=boolean} When set, suppress the
; warning messages when a specific id is used but not found.
;-
PRO FLAGS::unflag, id, status, all=all, quiet=quiet
compile_opt idl2, hidden
if keyword_set(all) then begin
allIDs = self->get_all_ids(count)
if count gt 0 then begin
for i=(count-1),0,-1 do begin
self->unflag_id, allIDs[i], status
if status ne 1 then break
endfor
endif
endif else begin
idtype = size(id,/type)
if idtype eq 7 then begin
self->unflag_idstring, id, status, quiet=quiet
endif else begin
self->unflag_id, id, status, quiet=quiet
endelse
endelse
END
;+
; Removes a line in a flag file given the flags integer ID.
; Flag IDs are reassigned at the end of this operation.
; @param id {in}{required}{type=long} ID of line to remove
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; unflagged.
; @keyword quiet {in}{optional}{type=boolean} When set, suppress the
; warning message when id was not found.
;-
PRO FLAGS::unflag_id, id, status, quiet=quiet
compile_opt idl2, hidden
; get flag filename and line number for this id
location = self->get_flag_location(id,status)
if status eq 0 then begin
if not keyword_set(quiet) then begin
message, "ID could not be found to unflag: "+string(id), /info
endif
return
endif
; get the object for this filename
ff = (*self.flag_files)[location[0]]
; comment out this line in the flag file
ff->unflag, long(location[1])
; reassign the flag ids
self->set_flag_ids
; recalculate the index value recnums for this flag file
self->calculate_index_value_recnums,ff->get_file_name()
END
;+
; Removes line(s) in a flag file given the flags IDSTRING.
; Flag IDs are reassigned at the end of this operation.
; @param idstring {in}{required}{type=string} IDSTRING of line(s) to remove
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @keyword quiet {in}{optional}{type=boolean} When set, suppress the
; warning message when id was not found.
;-
PRO FLAGS::unflag_idstring, idstring, status, quiet=quiet
compile_opt idl2, hidden
id_found = 0
for i=0,n_elements(*self.flag_files)-1 do begin
ff = (*self.flag_files)[i]
status = 0
inds = ff->search_flags(status,idstring=idstring)
if status ne 0 then begin
ff->unflag, idstring
id_found = 1
; recalculate the index value recnums for this flag file
self->calculate_index_value_recnums,ff->get_file_name()
endif
endfor
if not id_found and not keyword_set(quiet) then message, "IDSTRING could not be found to unflag: "+idstring, /info
; reassign the flag ids
self->set_flag_ids
END
;+
; To be called after flags are added or removed.
; Assigns unique integer IDs to each line in all flag files.
; These IDs are dynamic and only stored in memory.
;-
PRO FLAGS::set_flag_ids
compile_opt idl2, hidden
; how many ids in total are there?
num_ids = 0
for i=0,n_elements(*self.flag_files)-1 do begin
ff = (*self.flag_files)[i]
num_lines = ff->get_num_lines()
num_ids += num_lines
endfor
; create the 3xN array for mapping IDs to locations
if num_ids gt 0 then flag_ids = make_array(3,num_ids,/long)
id = 0
; go through each file and line sequentially
for i=0,n_elements(*self.flag_files)-1 do begin
ff = (*self.flag_files)[i]
;filename = ff->get_file_name()
line_nums = ff->get_line_nums(num_lines)
if num_lines gt 0 then begin
; create separate arrays for IDs, filenames, and line numbers
for j=0,num_lines-1 do begin
flag_ids[0,id] = id
flag_ids[1,id] = i
flag_ids[2,id] = line_nums[j]
id += 1
endfor
endif
endfor
if n_elements(flag_ids) ne 0 then begin
*self.flag_ids = flag_ids
endif else begin
if ptr_valid(self.flag_ids) then ptr_free, self.flag_ids
self.flag_ids = ptr_new(/allocate_heap)
endelse
END
;+
; Checks to make sure that the flag ids pointer is valid.
; Use this before trying to use this pointer.
; @returns 1 - valid flag ids, 0 - no valid flag ids
;-
FUNCTION FLAGS::has_valid_flag_ids
compile_opt idl2, hidden
if ptr_valid(self.flag_ids) then begin
if n_elements(*self.flag_ids) gt 0 then return, 1 else return, 0
endif else begin
return, 0
endelse
END
;+
; Given a flag filename and a line number in this flag file, returns
; the current uniqe ID for this line.
; This method accesses the
; flag id pointer, which points to an array that maps unique IDs
; to there locations in flag files.
; @param flag_filename {in}{required}{type=string} full path name to a flag file
; @param linenum {in}{required}{type=long} line number in the flag file
; @returns the unique integer ID for this line in the flag file.
;-
FUNCTION FLAGS::get_flag_id, flag_filename, linenum
compile_opt idl2, hidden
if not self->has_valid_flag_ids() then return, -1
flag_ids = *self.flag_ids
id = -1
num_ids = self->get_number_of_flag_ids()
if num_ids eq 1 then begin
ff = (*self.flag_files)[flag_ids[1]]
flag_id_filename = strtrim(ff->get_file_name(),2)
if flag_id_filename eq flag_filename and long(flag_ids[2]) eq long(linenum) then id=long(flag_ids[0])
endif else begin
for i=0,num_ids-1 do begin
flag_id = flag_ids[0:2,i]
ff = (*self.flag_files)[flag_id[1]]
flag_id_filename = strtrim(ff->get_file_name(),2)
if flag_id_filename eq flag_filename and long(flag_id[2]) eq long(linenum) then id=long(flag_id[0])
num_ids = self->get_number_of_flag_ids()
endfor
endelse
return, id
END
;+
; Given a unique integer flag ID, returns this ID's location -
; a location being the flag file and the line number in said file.
; This method accesses the
; flag id pointer, which points to an array that maps unique IDs
; to their locations in flag files.
; @param flag_id {in}{required}{type=long} unique integer flag ID
; @param status {out}{optional}{type=long} 1 - success, 0 - failure
; @returns 2 element string array containing file name and line number
;-
FUNCTION FLAGS::get_flag_location, flag_id, status
compile_opt idl2, hidden
status = 1
if not self->has_valid_flag_ids() then begin
status = 0
return, -1
endif
flag_ids = *self.flag_ids
location = -1
num_flag_ids = self->get_number_of_flag_ids()
for i=0,num_flag_ids-1 do begin
id_line = flag_ids[0:2,i]
if id_line[0] eq flag_id then begin
location = id_line[1:2]
break
endif
endfor
if size(location,/n_dim) eq 0 then status = 0
return, location
END
;+
; Get a vector of all of the ID integers currently known.
; Returns, -1 and sets count to 0 if there is nothing flagged.
; @param count {out}{optional}{type=long} The total count, returns 0
; if there are none.
; @returns array of all ID integers known, -1 if none known.
;-
FUNCTION FLAGS::get_all_ids, count
compile_opt idl2, hidden
count = 0
result = -1
if not self->has_valid_flag_ids() then begin
return, result
endif
flag_ids = *self.flag_ids
count = self->get_number_of_flag_ids()
if count gt 0 then begin
result = lonarr(count)
if count eq 1 then begin
result = flag_ids[0]
endif else begin
result = flag_ids[0,0:(count-1)]
endelse
endif
sortResult = result[sort(result)]
return, sortResult
end
;+
; Sets the file path for this object and all managed flag files.
; @param file_path {in}{required}{type=string} path used for all flag files.
;-
PRO FLAGS::set_file_path, file_path
compile_opt idl2, hidden
self.file_path = file_path
if ptr_valid(self.flag_files) then begin
for i=0,n_elements(*self.flag_files)-1 do begin
(*self.flag_files)[i]->set_file_path, file_path
endfor
endif
END
;+
; Returns the types of each parameter for the flag file columns.
; Another words, the scan column takes an integer value, idstring
; takes a string value, etc.
; @returns string array
;-
FUNCTION FLAGS::get_param_types
compile_opt idl2, hidden
return, *self.param_types
END
;+
; Simple function for returning a filename without its extension
; @param filename {in}{required}{type=string} filename with extension
; @returns filename without extension
;-
FUNCTION FLAGS::get_filename_minus_ext, filename
compile_opt idl2, hidden
parts = strsplit(filename,".",/extract)
if n_elements(parts) eq 1 then begin
basename = filename
endif else begin
basename = strjoin(parts[0:n_elements(parts)-2],".")
endelse
return, basename
END
;+
; Converts a *.fits filename to a *.index filename.
; In this case, just the extension is changed.
; @param fits_filename {in}{required}{type=string} fits filename
; @returns index filename
;-
FUNCTION FLAGS::fits_filename_to_index_filename, fits_filename
compile_opt idl2, hidden
return, self->get_filename_minus_ext(fits_filename)+".index"
END
;+
; Converts a *.fits filename to a *.flag filename.
; In this case, just the extension is changed.
; @param fits_filename {in}{required}{type=string} fits filename
; @returns flag filename
;-
FUNCTION FLAGS::fits_filename_to_flag_filename, fits_filename
compile_opt idl2, hidden
return, self->get_filename_minus_ext(fits_filename)+".flag"
END
;+
; Converts a *.index filename to a *.flag filename.
; In this case, just the extension is changed.
; @param index_filename {in}{required}{type=string} index filename
; @returns flag filename
;-
FUNCTION FLAGS::index_filename_to_flag_filename, index_filename
compile_opt idl2, hidden
return, self->get_filename_minus_ext(index_filename)+".flag"
END
;+
; Given the full path name to a flag file, returns a flag file object
; responsible for managing this file.
; If the flag file object has already been created, this object will be
; returned, or it will be created and returned.
; @param flag_filename {in}{required}{type=string} full path to flag file
; @returns flag file object
;-
FUNCTION FLAGS::get_flag_file_obj, flag_filename
compile_opt idl2, hidden
flag_filename = file_basename(flag_filename)
; if there are no flag file objects, create this one
if n_elements(*self.flag_files) eq 0 then begin
if self.debug then print, "creating first flag obj for: ", flag_filename
*self.flag_files = obj_new("flag_file", file_name=flag_filename,file_path=self.file_path,debug=self.debug)
; has the format been set for this object?
if self.version ne "" and self.flags_section_class ne "" then begin
(*self.flag_files)->set_flag_file_version, self.version, self.flags_section_class
endif
return, *self.flag_files
endif else begin
; try and find the object for the file requested
obj_index = -1
for i=0,n_elements(*self.flag_files)-1 do begin
if (*self.flag_files)[i]->get_file_name() eq flag_filename then obj_index = i
endfor
; if found, return it, if not, create it
if obj_index ne -1 then begin
if self.debug then print, "getting flag obj for: ", flag_filename
return, (*self.flag_files)[obj_index]
endif else begin
if self.debug then print, "creating flag obj for: ", flag_filename
ff = obj_new("flag_file",file_name=flag_filename,file_path=self.file_path,debug=self.debug)
; has the format been set for this object?
if self.version ne "" and self.flags_section_class ne "" then begin
ff->set_flag_file_version, self.version, self.flags_section_class
endif
*self.flag_files = [*self.flag_files,ff]
return, ff
endelse
endelse
END
;+
; Reads in a flag file into memory.
; This consists of using/creating a flag file object for the file,
; using this object to read the file, and then assigning unique IDs
; to all the flags managed by this class.
; @param flag_filename {in}{required}{type=string} full path to flag file
;-
PRO FLAGS::load_flag_file, flag_filename
compile_opt idl2, hidden
if self.debug then print, "reading in flag file: ", flag_filename
ff = self->get_flag_file_obj(flag_filename)
ff->read_file
self->calculate_index_value_recnums,flag_filename
self->set_flag_ids
END
;+
; For a given fits filename, make sure that if there is a flag file for it,
; it has been read by a flag file object, and all IDs are up to date.
; @param fits_filename {in}{required}{type=string} full path to flag file
;-
PRO FLAGS::check_flag_file_for_fits_file, fits_filename
compile_opt idl2, hidden
if self.debug then print, "checking for flag file for fits file: ", fits_filename
flag_filename = self->fits_filename_to_flag_filename(fits_filename)
full_flag_filename = self->get_full_file_name(flag_filename)
ff = self->get_flag_file_obj(flag_filename)
is_loaded = ff->is_file_loaded()
if file_test(full_flag_filename) and is_loaded ne 0 then begin
ff->read_file
self->calculate_index_value_recnums,flag_filename
self->set_flag_ids
endif
END
;+
; To be called whenever a flag file is loaded, or all flags are reset, due to
; an unflag command. Takes the record numbers in the flag file, and converts
; them to their new values relative to the current index (remember
; that this is a no-op if there is only one sdfits file).
; These values are stored in each respective flag file object.
; @param flag_filename {in}{required}{type=string} name of the flag file
;-
PRO FLAGS::calculate_index_value_recnums, flag_filename
compile_opt idl2, hidden
ff = self->get_flag_file_obj(flag_filename)
rows = ff->get_row_strcts(status)
if status eq 0 or n_elements(rows) eq 0 then begin
ff->reset_index_value_recnums
endif else begin
all_recnums = strarr(n_elements(rows))
for i=0,n_elements(rows)-1 do begin
flag_recnum_string = rows[i].recnum
if flag_recnum_string ne "*" then begin
index_recnum_string = $
self->flag_recnum_string_to_index_recnum_string(flag_recnum_string,flag_filename)
endif else begin
index_recnum_string = "*"
endelse
all_recnums[i] = index_recnum_string
endfor
ff->set_index_value_recnums, all_recnums
endelse
END
;+
; Add a flag filename to the list of flag files currently begin managed.
; @param flag_filename {in}{required}{type=string} full path to flag file
;-
PRO FLAGS::add_flag_filename, flag_filename
compile_opt idl2, hidden
if n_elements(*self.files) eq 0 then begin
*self.files = flag_filename
endif else begin
*self.files = [*self.files,flag_filename]
endelse
END
;+
; Adds a file index base to the list of these values.
; The file index base values are used for converting a spectrum's index, or
; record number for in a single index file (an index file for one sdfits file),
; to its record number in an index file that manages several fits file.
; This is used in converting record numbers from their values recorded in the flag file to
; their corresponding values for the current index file, which may differ if the index file
; manages multiple fits files.
; @param file_index_base {in}{required}{type=long} value of record number for first spectrum in a multi-sdfits file index file.
;-
PRO FLAGS::add_file_index_base, file_index_base
compile_opt idl2, hidden
if n_elements(*self.file_index_bases) eq 0 then begin
*self.file_index_bases = file_index_base
endif else begin
*self.file_index_bases = [*self.file_index_bases,file_index_base]
endelse
END
;+
; Adds the flag file name and index base to this class's list of these variables.
; The index filename is converted to the flag filename simply by changing the extension.
; This is used in converting record numbers from their values recorded in the flag file to
; their corresponding values for the current index file, which may differ if the index file
; manages multiple fits files.
; @param index_filename {in}{required}{type=string} full path to index file
; @param index_base {in}{required}{type=long} value of record number for first spectrum in a multi-sdfits file index file.
;-
PRO FLAGS::add_index_file_info, index_filename, index_base
compile_opt idl2, hidden
if self.debug then print, "adding index file info: ", index_filename, index_base
self->add_flag_filename, self->index_filename_to_flag_filename(index_filename)
self->add_file_index_base, index_base
END
;+
; Searches the files member variable for a match with given flag filename, and uses this index
; to return the value of record number for first spectrum in a multi-sdfits file index file.
; This is used in converting record numbers from their values recorded in the flag file to
; their corresponding values for the current index file, which may differ if the index file
; manages multiple fits files.
; The returned index base will be zero for the special case of one sdfits file per index file,
; or for the first fits file in a multiple fits file index file.
; @param flag_filename {in}{required}{type=string} full path to flag file
; @returns value of record number for first spectrum in a multi-sdfits file index file.
;-
FUNCTION FLAGS::get_file_index_base, flag_filename
compile_opt idl2, hidden
if not self->has_valid_files() then return, -1
file_index = -1
for i=0,n_elements(*self.files)-1 do begin
if (*self.files)[i] eq flag_filename then file_index = i
endfor
if file_index eq -1 then begin
file_index_base = -1
endif else begin
file_index_base = (*self.file_index_bases)[file_index]
endelse
return, file_index_base
END
;+
; Retrieves the value of record number for first spectrum in a multi-sdfits file index file,
; and subtracts this from the given index number.
; This is used in converting record numbers from their values recorded in the flag file to
; their corresponding values for the current index file, which may differ if the index file
; manages multiple fits files.
; @param index_recnum {in}{required}{type=long} the record number found in the current index file.
; @param flag_filename {in}{required}{type=string} full path to flag file
; @returns the record number found in the fits files index file corresponding to the same spectrum referenced by index_recnum
;-
FUNCTION FLAGS::index_recnum_to_flag_recnum, index_recnum, flag_filename
compile_opt idl2, hidden
file_index_base = self->get_file_index_base(flag_filename)
return, index_recnum - file_index_base
END
;+
; Retrieves the value of record number for first spectrum in a multi-sdfits file index file,
; and adds this to the given record number from the given flag file.
; This is used in converting record numbers from their values recorded in the flag file to
; their corresponding values for the current index file, which may differ if the index file
; manages multiple fits files.
; @param flag_recnum {in}{required}{type=long} the record number found in the flag file.
; @param flag_filename {in}{required}{type=string} full path to flag file
; @returns the record number found in the current index file
;-
FUNCTION FLAGS::flag_recnum_to_index_recnum, flag_recnum, flag_filename
compile_opt idl2, hidden
file_index_base = self->get_file_index_base(flag_filename)
return, flag_recnum + file_index_base
END
;+
; Prints out flag lines in all flag files, either nearly as the appear in the flag file, or
; in a special format.
; @keyword idstring {in}{optional}{type=string} list only flag lines that match this idstring
; @keyword summary {in}{optional}{type=boolean} if set, print in summary format, if not, print in verbose mode.
;-
PRO FLAGS::list, idstring=idstring, summary=summary
compile_opt idl2, hidden
if not self->has_valid_files() then return
if n_elements(summary) eq 0 then begin
self->list_verbose, idstring=idstring
endif else begin
self->list_formatted, idstring=idstring
endelse
END
;+
; Prints the contents of all flag files, nearly in the format they appear in the flag files.
; The Unique IDs are prepended to each line, and the delminators are converted to white space.
; @keyword idstring {in}{optional}{type=string} list only flag lines that match this idstring
;-
PRO FLAGS::list_verbose, idstring=idstring
compile_opt idl2, hidden
if not self->has_valid_files() then begin
print,'No flags for the current dataset.'
return
endif
; get the header - same for all flag files
; place the ID column at the beggining
status = 0
header = self->get_verbose_header(status)
cnt = 0
index_lines = self->get_index_value_lines_with_id(cnt,idstring=idstring)
; replace all the separator chars with blank spaces
index_lines = self->replace_deliminators_in_lines(index_lines, " ")
if cnt ne 0 then begin
; only print the header if there are flag lines to print
if status eq 1 then print, header
for j=0,n_elements(index_lines)-1 do print, index_lines[j]
endif else begin
print,'No flags for the current dataset.'
endelse
END
;+
; Replaces all delminators that appear in the given strings with the given replacement character.
; @param lines {in}{required}{type=string array} lines to adjust
; @param replacement {in}{required}{type=string array} character used to replace deliminators
; @returns the given lines with the deliminators replaced by replacement param.
;-
FUNCTION FLAGS::replace_deliminators_in_lines, lines, replacement
compile_opt idl2, hidden
deliminator = self->get_deliminator(status)
if status eq 0 then return, lines
for i=0,n_elements(lines)-1 do begin
line = lines[i]
while (((j = strpos(line, deliminator))) ne -1) do $
strput, line, replacement, j
lines[i] = line
endfor
return, lines
END
;+
; Returns lines from flag flag files, with record numbers corresponding to
; their values in the current index file, along with their unique ID numbers
; prepended to the begining of each line.
; This is used for listing in verbose mode.
; @param count {out}{optional}{type=long} the number of lines returned
; @keyword idstring {in}{optional}{type=string} get only flag lines that match this idstring
; @returns string array ready for use in listing in verbose mode
;-
FUNCTION FLAGS::get_index_value_lines_with_id, count, idstring=idstring
compile_opt idl2, hidden
; retrieve lines from flag flag files, with record numbers corresponding to
; their values in the current index file
lines = self->get_index_value_lines(count,idstring=idstring)
if count eq 0 then return, -1
; get lines from each file at a time
for i=0,n_elements(*self.flag_files)-1 do begin
; get the raw lines, that start off with the flag recnum
status = 0
lines_and_nums = (*self.flag_files)[i]->get_lines_and_line_nums(idstring=idstring,status)
if status ne 0 then begin
num_dim = size(lines_and_nums,/n_dim)
if num_dim eq 1 then begin
num_lines=1
endif else begin
sz=size(lines_and_nums,/dim)
num_lines = sz[1]
endelse
line_nums = lines_and_nums[1,0:num_lines-1]
dlm = (*self.flag_files)[i]->get_deliminator()
flag_filename = (*self.flag_files)[i]->get_file_name()
; get the flag id for each line
for j=0,n_elements(line_nums)-1 do begin
id = self->get_flag_id(flag_filename, line_nums[j])
if n_elements(ids) eq 0 then ids=[id] else ids=[ids,id]
endfor
endif
endfor
; add the line ids to the flag lines
id_lines = strarr(n_elements(lines))
for i=0,n_elements(lines)-1 do begin
id_lines[i] = strtrim(string(ids[i]),2)+lines[i]
endfor
return, id_lines
END
;+
; Retrieve lines from flag flag files, with record numbers corresponding to
; their values in the current index file
; This is used for listing in verbose mode.
; @param count {out}{optional}{type=long} the number of lines returned
; @keyword idstring {in}{optional}{type=string} get only flag lines that match this idstring
; @returns string array corresponding to lines in flag files, with record number adjusted.
;-
FUNCTION FLAGS::get_index_value_lines, count, idstring=idstring
compile_opt idl2, hidden
count = 0
; get lines from each file at a time
for i=0,n_elements(*self.flag_files)-1 do begin
; get the raw lines, that start off with the flag recnum
status = 0
lines = (*self.flag_files)[i]->get_lines(idstring=idstring,status)
if status ne 0 then begin
count += n_elements(lines)
; convert this flag recnum to an index recnum
dlm = (*self.flag_files)[i]->get_deliminator()
flag_filename = (*self.flag_files)[i]->get_file_name()
index_lines = self->convert_flag_lines_to_index_lines(lines,dlm,flag_filename)
if n_elements(all_index_lines) eq 0 then begin
all_index_lines = index_lines
endif else begin
all_index_lines = [all_index_lines,index_lines]
endelse
endif
endfor
if count ne 0 then return, all_index_lines else return, -1
END
;+
; Given lines from a flag file, returns the same lines, but with the
; record numbers adjusted to reflect the same spectra in the current index file.
; Remember that if the current index file manages multiple sdfits files, the
; record numbers in the flag files must be adjusted.
; @param lines {in}{required}{type=string array} lines from a flag file
; @param deliminator {in}{required}{type=string} character used to deliminate values in a flag file
; @param flag_filename {in}{required}{type=string} full path to flag file
; @returns the same lines passed in, but with their record number adjusted.
;-
FUNCTION FLAGS::convert_flag_lines_to_index_lines, lines, deliminator, flag_filename
compile_opt idl2, hidden
for i=0,n_elements(lines)-1 do begin
line = lines[i]
; get the flag recnum
line_cols = strsplit(line,deliminator,/extract)
flag_recnum_string = strtrim(line_cols[0],2)
if flag_recnum_string ne "*" then begin
; convert the line
index_recnum_string = self->flag_recnum_string_to_index_recnum_string(flag_recnum_string,flag_filename)
index_line = ' '+index_recnum_string + deliminator + $
strjoin(line_cols[1:n_elements(line_cols)-1],deliminator)
endif else begin
; nothing to convert
index_line = line
endelse
if i eq 0 then index_lines=[index_line] else index_lines=[index_lines,index_line]
endfor
return, index_lines
END
;+
; Checks status of flag file pointer
; @returns 1 - valid files, 0 - no valid flag files
;-
FUNCTION FLAGS::has_valid_files
compile_opt idl2, hidden
if ptr_valid(self.flag_files) then begin
if n_elements(*self.flag_files) eq 0 then begin
return, 0
endif else begin
return, 1 ;n_elements(*self.flag_files)
endelse
endif else begin
return, 0
endelse
END
;+
; The format for listing flag file contents in summary mode is stored in
; a flag file object. This method finds and flag file object, and
; retrieves that format.
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @returns The format for listing flag file contents in summary mode
;-
FUNCTION FLAGS::get_values_list_format, status
compile_opt idl2, hidden
i = self->find_file_with_flags()
if i eq -1 then begin
str = ""
status = 0
endif else begin
str = (*self.flag_files)[i]->get_values_list_format()
status = 1
endelse
return, str
END
;+
; The format for listing flag file headers in summary mode is stored in
; a flag file object. This method finds and flag file object, and
; retrieves that format.
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @returns The format for listing flag file headers in summary mode
;-
FUNCTION FLAGS::get_formatted_header, status
compile_opt idl2, hidden
if not self->has_valid_files() then begin
status = 0
return, ""
endif
i = self->find_file_with_flags()
if i eq -1 then begin
header = ""
status = 0
endif else begin
; prepend the ID column
header = (*self.flag_files)[i]->get_formatted_header()
header = "#ID "+strmid(header,1,strlen(header)-1)
status = 1
endelse
return, header
END
;+
; The header used when listing flag file headers in verbose mode is stored in
; a flag file object. This method finds and flag file object, and
; retrieves that header.
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @returns The header used when listing flag file headers in verbose mode
;-
FUNCTION FLAGS::get_verbose_header, status
compile_opt idl2, hidden
i = self->find_file_with_flags()
if i eq -1 then begin
header = ""
status = 0
endif else begin
; prepend the ID column
header = (*self.flag_files)[i]->get_verbose_header()
header = "#ID,"+strmid(header,1,strlen(header)-1)
status = 1
endelse
return, header
END
;+
; Returns the character used for separating values in flag files.
; Foramt info for flag files are stored in flag file objects. One of these
; objects must be retrieved first to get format info.
; @param status {out}{optional}{type=long} 0 - failure, 1 - success
; @returns The character used for separating values in flag files.
;-
FUNCTION FLAGS::get_deliminator, status
compile_opt idl2, hidden
i = self->find_file_with_flags()
if i eq -1 then begin
deliminator = ""
status = 0
endif else begin
deliminator = (*self.flag_files)[i]->get_deliminator()
status = 1
endelse
return, deliminator
END
;+
; Looks for a flag file object that manages a valid flag file.
; @returns the index to the flag file object, or -1 if none found.
;-
FUNCTION FLAGS::find_file_with_flags
compile_opt idl2, hidden
f = -1
for i=0, n_elements(*self.flag_files)-1 do begin
if (*self.flag_files)[i]->has_valid_rows() then f = i
endfor
return, f
END
;+
; Prints contents of flag files in a formatted version.
; Columns have fixed width, and if values are wider then this width
; a symbol is used to denote the truncation of these values.
; @keyword idstring {in}{optional}{type=string} prints only flag lines that match this idstring
;-
PRO FLAGS::list_formatted, idstring=idstring
compile_opt idl2, hidden
if not self->has_valid_files() then begin
print,'No flags for the current dataset.'
return
endif
; get the header - same for all flag files
hstatus = 0
header = self->get_formatted_header(hstatus)
rows_format = self->get_values_list_format(status)
if status eq 0 then begin
print,'No flags for the current dataset.'
return
endif
index_value_rows = self->get_index_value_rows(cnt,ids,useflag=idstring)
; print each formatted line, prepending the ID
if cnt ne 0 then begin
if hstatus eq 1 then print, header
for i=0,n_elements(index_value_rows)-1 do begin
line = self->get_summary_line(index_value_rows[i],rows_format)
id = string(strtrim(ids[i],2),format='(a3)')
print, id+" "+line
endfor
endif else begin
print,'No flags for the current dataset.'
endelse
END
;+
; Given a structure that represents a line form the flag file (with record number already adjusted),
; copy this structure to a line that is ready for printing in summary format.
; This involves going through each structure field and turncating its value to the length
; specified in the given format.
; @param line_strct {in}{required}{type=strct} represents a line form the flag file (with record number already adjusted)
; @param line_format {in}{required}{type=string} string that would print out this structure if used with format keyword
; @returns string ready to print as a line in summary format
;-
FUNCTION FLAGS::get_summary_line, line_strct, line_format
compile_opt idl2, hidden
; get the names of the columns
columns = tag_names(line_strct)
; get the length for each column:
; first strip off the parenthases at each end
stripped_format = strmid(line_format,1,strlen(line_format)-2)
; the format for each column and space is separated by a comma
formats = strsplit(stripped_format,",",/extract)
; get only the formats for each column, ignore the space formats
for i=0,n_elements(formats)-1 do begin
if i MOD 2 eq 0 then begin
f = long(strmid(formats[i],1,strlen(formats[i])-1))
if n_elements(fs) eq 0 then fs=[f] else fs=[fs,f]
endif
endfor
; go through each column, and see if it's beyond the allocated space
for i=0,n_elements(columns)-1 do begin
if fs[i] lt strlen(strtrim(line_strct.(i),2)) then begin
; truncate it, using special symbol to show this
; dont just replace the last character, make sure that
; numbers aren't misreprented
values = strsplit(line_strct.(i),",",/extract)
if n_elements(values) eq 1 then begin
line_strct.(i) = strmid(line_strct.(i),0,fs[i]-1)+'+'
endif else begin
len = 0
line = ""
num_values = 0
while strlen(line) lt fs[i] do begin
oldline = line
line = strjoin(values[0:num_values],",")
num_values +=1
endwhile
line_strct.(i) = oldline+",+"
endelse
endif
endfor
return, string(line_strct, format=line_format)
END
;+
; Returns structures representing desired lines from flag files.
; The desired lines are determined by the optional
; useflag and skipflag keywords.
; @param count {out}{optional}{type=long} number of structures returned
; @param index_recnums {out}{optional}{type=long} the value of the structures' returned record numbers when converted to be relative to the current index file.
; @keyword _EXTRA {in}{optional}{type=strct} useflag and skipflag kewords
; @returns structures representing desired lines from flag files
;-
FUNCTION FLAGS::get_flag_strcts, count, index_recnums, _EXTRA=ex
compile_opt idl2, hidden
count = 0
index_recnums = -1
flags_used_count = 0
; if now flags are being used, the flag structures won't be needed
if self->are_all_flags_off(_EXTRA=ex) then return, -1
if self->are_all_flags_on(_EXTRA=ex) then begin
; retrieve all the flag structures, and index record numbers
index_recnums = self->get_index_value_recnums()
return, self->get_all_row_strcts(count)
endif
; use the useflag and skipflag keywords to determine what the idstrings
; of all flag lines to be used
flags_used = self->get_flag_idstrings_used(_EXTRA=ex, flags_used_count)
if flags_used_count eq 0 then return, -1
; get flag rows only for the flags used
for i=0,n_elements(flags_used)-1 do begin
for j=0,n_elements(*self.flag_files)-1 do begin
status = 0
; get the flag structures from this flag file for a specific flag idstring
rows = (*self.flag_files)[j]->get_row_strcts(idstring=flags_used[i],status,indicies)
file_recnums = (*self.flag_files)[j]->get_index_value_recnums()
if status ne 0 then begin
count += n_elements(rows)
; keep track of only the index valued record numbers used
recnums_used = file_recnums[indicies]
if n_elements(all_rows) eq 0 then begin
all_rows = rows
index_recnums = [recnums_used]
endif else begin
all_rows = [all_rows,rows]
index_recnums = [index_recnums,recnums_used]
endelse
endif
endfor
endfor
if count eq 0 then all_rows = -1
return, all_rows
END
;+
; Now only used when printing in list summary format. This should eventually
; be deprecated so that get_flag_strcts is used (its much faster).
; Returns structures representing desired lines from flag files, with record numbers adjusted
; to their values in the current index file. The desired lines are determined by the optional
; useflag and skipflag keywords.
; @keyword _EXTRA {in}{optional}{type=strct} useflag and skipflag kewords
; @returns structures representing desired lines from flag files, with record numbers adjusted
;-
FUNCTION FLAGS::get_index_value_rows, count, ids, _EXTRA=ex
compile_opt idl2, hidden
count = 0
flags_used_count = 0
if self->are_all_flags_off(_EXTRA=ex) then return, -1
if self->are_all_flags_on(_EXTRA=ex) then begin
ids = self->get_all_flag_ids()
return, self->get_all_index_value_rows(count)
endif
; use the useflag and skipflag keywords to determine what the idstrings
; of all flag lines to be used
flags_used = self->get_flag_idstrings_used(_EXTRA=ex, flags_used_count)
if flags_used_count eq 0 then return, -1
; get ids only for the flags used
ids = self->get_flag_ids_used(flags_used)
; get flag rows only for the flags used
for i=0,n_elements(flags_used)-1 do begin
for j=0,n_elements(*self.flag_files)-1 do begin
status = 0
rows = (*self.flag_files)[j]->get_row_strcts(idstring=flags_used[i],status)
if status ne 0 then begin
; convert this flag recnum to an index recnum
flag_filename = (*self.flag_files)[j]->get_file_name()
index_rows = self->convert_flag_rows_to_index_rows(rows,flag_filename)
count += n_elements(index_rows)
if n_elements(all_index_rows) eq 0 then begin
all_index_rows = index_rows
endif else begin
all_index_rows = [all_index_rows,index_rows]
endelse
endif
endfor
endfor
if count eq 0 then all_index_rows = -1
return, all_index_rows
END
;+
; Returns all the flag IDs, which should just be 0..N, N==number of flag lines.
; @param count {out}{optional}{type=long} number of IDs returned
; @returns array of integer IDs
;-
FUNCTION FLAGS::get_all_flag_ids, count
compile_opt idl2, hidden
count = 0
if not self->has_valid_flag_ids() then return, -1
flag_ids = *self.flag_ids
count = self->get_number_of_flag_ids()
if count eq 1 then begin
return, flag_ids[0]
endif else begin
return, flag_ids[0,0:count-1]
endelse
END
;+
; Simply returns the number of flag ID's. This should be equal to the number of
; all flag lines.
; @returns number of flag IDs
;-
FUNCTION FLAGS::get_number_of_flag_ids
compile_opt idl2, hidden
if not self->has_valid_flag_ids() then return, 0
num_dims = size(*self.flag_ids,/n_dim)
if num_dims eq 1 then begin
return, 1
endif else begin
sz = size(*self.flag_ids)
return, sz[2]
endelse
END
;+
; Returns the unique integer IDs that match flag lines that contain the given IDSTRINGs.
; @param idstrings {in}{required}{type=string array} array of IDSTRINGs.
; @param count {out}{optional}{type=long} number of IDs returned
; @returns the unique integer IDs used by IDSTRINGs.
;-
FUNCTION FLAGS::get_flag_ids_used, idstrings, count
compile_opt idl2, hidden
count = 0
; get flag ids only for the idstrings given
for i=0,n_elements(idstrings)-1 do begin
for j=0,n_elements(*self.flag_files)-1 do begin
status = 0
flag_file_name = (*self.flag_files)[j]->get_file_name()
lines_and_nums = (*self.flag_files)[j]->get_lines_and_line_nums(idstring=idstrings[i],status)
if status ne 0 then begin
num_dim = size(lines_and_nums,/n_dim)
if num_dim eq 1 then begin
num_lines=1
endif else begin
sz=size(lines_and_nums,/dim)
num_lines = sz[1]
endelse
count += num_lines
line_nums = lines_and_nums[1,0:num_lines-1]
; get the corresponding IDs for this flag file and the lines found for the idstring.
for k=0,n_elements(line_nums)-1 do begin
id = self->get_flag_id(flag_file_name, long(line_nums[k]))
if n_elements(ids) eq 0 then ids=[id] else ids=[ids,id]
endfor
endif
endfor ; for each file
endfor ; for each idstring
if n_elements(ids) eq 0 then return, -1 else return, ids
END
;+
; Returns structures representing all lines in all flag files, with the
; record number field adjusted to reflect the correct value in the current index file.
; Remember that if the current index file manages multiple sdfits files, the
; record numbers in the flag files must be adjusted.
; @param count {out}{optional}{type=long} number of structures returned
; @returns array of structures representing all lines in all flag files
;-
FUNCTION FLAGS::get_all_index_value_rows, count
compile_opt idl2, hidden
; get the structures that represent each line for each flag file
for i=0,n_elements(*self.flag_files)-1 do begin
; get the structures that represent each line in flag file
status = 0
rows = (*self.flag_files)[i]->get_row_strcts(status)
if status ne 0 then begin
; convert this flag recnum to an index recnum
flag_filename = (*self.flag_files)[i]->get_file_name()
index_rows = self->convert_flag_rows_to_index_rows(rows,flag_filename)
count += n_elements(index_rows)
if n_elements(all_index_rows) eq 0 then begin
all_index_rows = index_rows
endif else begin
all_index_rows = [all_index_rows,index_rows]
endelse
endif
endfor
if count eq 0 then all_index_rows = -1
return, all_index_rows
END
;+
; Adjusts the record number field in the given structures to match the record number value
; used in the current index file.
; Remember that if the current index file manages multiple sdfits files, the
; record numbers in the flag files must be adjusted.
; @param rows {in}{required}{type=strct array} array of structures representing lines in flag files
; @param flag_filename {in}{required}{type=string} filename of the flag file where these rows came from
; @returns the given rows, with their record number field adjusted
;-
FUNCTION FLAGS::convert_flag_rows_to_index_rows, rows, flag_filename
compile_opt idl2, hidden
for i=0,n_elements(rows)-1 do begin
flag_recnum_string = rows[i].recnum
; nothing to convert if using the NA symbol
if flag_recnum_string ne "*" then begin
rows[i].recnum = self->flag_recnum_string_to_index_recnum_string(flag_recnum_string,flag_filename)
endif
endfor
return, rows
END
;+
; Converts the string found in flag file lines that represent flagged record numbers. This string may
; represent a range of record numbers, compressed using a certain syntax. After decompression, the integer
; values this string represents then must be adjusted to reflect the same spectra in the current index file.
; Remember that if the current index file manages multiple sdfits files, the
; record numbers in the flag files must be adjusted.
; @param flag_filename {in}{required}{type=string} filename of the flag file where the given string came from
; @returns string identical to passed string, except the values have been adjusted for the current index file.
;-
FUNCTION FLAGS::flag_recnum_string_to_index_recnum_string, flag_recnum_string, flag_filename
if not self->has_valid_files() then return, ""
; this could just be a scalar, or a compressed range
; we need to convert string to an integer array, convert it, then
; recreate the appropriate string
decompressed_recnums = decompress_ints(flag_recnum_string)
for j=0,n_elements(decompressed_recnums)-1 do begin
flag_recnum = decompressed_recnums[j]
; convert actual integer values
index_recnum = self->flag_recnum_to_index_recnum(flag_recnum,flag_filename)
if j eq 0 then index_recnums=[index_recnum] else index_recnums=[index_recnums,index_recnum]
endfor
return, compress_ints(index_recnums)
END
;+
; Should change this to get_unique_idstrings.
; Collects all idstrings from all flag files, and returns the sorted, unique idstrings.
; @param count {out}{optional}{type=long} number of structures returned
; @returns unique idstrings found in all flag files
;-
FUNCTION FLAGS::get_unique_ids, count
compile_opt idl2, hidden
for i=0,n_elements(*self.flag_files)-1 do begin
uniq_ids = (*self.flag_files)[i]->get_unique_ids(cnt)
if cnt ne 0 then begin
if n_elements(all_ids) eq 0 then all_ids=[uniq_ids] else all_ids=[all_ids,uniq_ids]
endif
endfor
if n_elements(all_ids) eq 0 then begin
count = 0
return, -1
endif else begin
; find the unique ids from the above collection
unique_ids = all_ids[uniq(all_ids,sort(all_ids))]
count = n_elements(unique_ids)
return, unique_ids
endelse
END
;+
; Should change this to list_unique_idstrings
; Takes the lines returned from get_unique_ids, and prints them
;-
PRO FLAGS::list_ids
compile_opt idl2, hidden
unique_ids = self->get_unique_ids(count)
if count ne 0 then begin
print, "Unique Flag Ids: "
for i=0,n_elements(unique_ids)-1 do begin
print, unique_ids[i]
endfor
endif else begin
print, "No flags for the current dataset."
endelse
END
;+
; If a flag file already exists for the given fits file, this flag file is loaded.
; Also stores information so that record numbers between the index file and flag file
; can be adjusted.
; Remember that if the current index file manages multiple sdfits files, the
; record numbers in the flag files must be adjusted.
; @param fits_name {in}{required}{type=string} filename of the fits file
; @param base_index {in}{required}{type=long} where in the current index file the first spectrum of this fits file appears
;-
PRO FLAGS::update_flags, fits_name, base_index
compile_opt idl2, hidden
if self.debug then print, "update_flags with: ", fits_name, base_index
index_name = self->fits_filename_to_index_filename(fits_name)
flag_file = self->fits_filename_to_flag_filename(fits_name)
self->add_index_file_info, index_name, base_index
; if the file exists, and is not already loaded, load it
flag_file = self->get_full_file_name(flag_file)
file_exists = file_test(flag_file)
flag_file_loaded = self->is_flag_file_loaded(flag_file)
if file_exists and flag_file_loaded eq 0 then begin
self->load_flag_file, flag_file
endif
END
;+
; Is the given flag file name currently loaded in memory?
; @param file_name {in}{required}{type=string} filename of the flag file
; @returns 0 - not loaded; 1 - is loaded
;-
FUNCTION FLAGS::is_flag_file_loaded, file_name
compile_opt idl2, hidden
flag_file = self->get_flag_file_obj(file_name)
return, flag_file->is_file_loaded()
END
;+
; Given a filename, return it full path name, taking into account all possible pertabations.
; @param file_name {in}{required}{type=string} filename
; @returns full path to the given filename
;-
FUNCTION FLAGS::get_full_file_name, file_name
compile_opt idl2, hidden
; if the file_name already has a path attatched to it, don't add to it
if strpos(file_name,'/') eq -1 then begin
if self.file_path eq "" then begin
; no filepath to prepend, return filename as is
full_name = file_name
endif else begin
; look for / at end of file_path
last_char = strmid(self.file_path,strlen(self.file_path)-1,1)
if last_char eq '/' then begin
; get rid of this backslash at the end of the path
file_path = strmid(self.file_path,0,strlen(self.file_path)-1)
endif else begin
file_path = self.file_path
endelse
; full path name is just the path plus the given name.
full_name = file_path +'/'+ file_name
endelse
endif else begin
; the given file name already has a path
full_name = file_name
endelse
return, full_name
END
;+
; Certain values in flag files integer ranges stored as a string. This string
; may use a special syntax for effectively compressing ranges of integers.
; This method takes the string value from part of a line in a flag file, and converts
; it into an integer array by decompressing the string.
; @param flag_string {in}{required}{type=string} string representing integer range using a special syntax
; @returns integer array
;-
FUNCTION FLAGS::get_int_array_from_flag_string, flag_string, count
compile_opt idl2, hidden
if not self->has_valid_files() then begin
count = 0
return, -1
endif
if flag_string ne "*" then begin
int_array = decompress_ints(flag_string)
count = n_elements(int_array)
endif else begin
int_array = -1
count = 0
endelse
return, int_array
END
;+
; Makes object verbose
;-
PRO FLAGS::set_debug_on
compile_opt idl2, hidden
self.debug = 1
self->set_flag_files_debug, 1
END
;+
; Makes object quiet
;-
PRO FLAGS::set_debug_off
compile_opt idl2, hidden
self.debug = 0
self->set_flag_files_debug, 0
END
;+
; Sets debug flag for all flag file objects
; @param debug {in}{required}{type=long} 0 - set debug off, 1 - set debug on
;-
PRO FLAGS::set_flag_files_debug, debug
for i=0,n_elements(*self.flag_files)-1 do begin
if debug eq 1 then begin
(*self.flag_files)[i]->set_debug_on
endif else begin
(*self.flag_files)[i]->set_debug_off
endelse
endfor
END
;+
; For testing purposes only.
; Sets the flag file format version and class that flag files are to use.
; @param version_num {in}{required}{type=string} format version for flag files
; @param version_class {in}{required}{type=string} class to be used to read in rows sections of flag files
;-
PRO FLAGS::set_flag_file_version, version_num, version_class
self.version = version_num
self.flags_section_class = version_class
for i=0,n_elements(*self.flag_files)-1 do begin
(*self.flag_files)[i]->set_flags_section_version, version_num, version_class
endfor
END
;+
; Checks keywords to see if all flags are to be used.
; Useflag keyword takes precedence. If none are set, use all flags.
; @keyword useflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are used; if set to
; a string array, then only those idstrings included are used.
; @keyword skipflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are skipped; if set to
; a string array, then only those idstrings included are skipped.
; @returns 0 - not all flags are used, 1 - all flags are used.
;-
FUNCTION FLAGS::are_all_flags_on, useflag=useflag, skipflag=skipflag
compile_opt idl2, hidden
; useflag keyword takes presidence
if n_elements(useflag) ne 0 then begin
if size(useflag,/type) eq 7 then begin
; certain flags are choosen
return, 0
endif else begin
; use all flags
return, 1
endelse
endif
; if any flags are turned off, then not ALL are used
if n_elements(skipflag) ne 0 then begin
return, 0
endif
; if no keyword set, then default to useflag=1
return, 1
END
;+
; Checks keywords to see if all flags are to be skipped.
; Useflag keyword takes precedence. If none are set, use all flags.
; @keyword useflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are used; if set to
; a string array, then only those idstrings included are used.
; @keyword skipflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are skipped; if set to
; a string array, then only those idstrings included are skipped.
; @returns 0 - some flags are used, 1 - all flags are off.
;-
FUNCTION FLAGS::are_all_flags_off, useflag=useflag, skipflag=skipflag
compile_opt idl2, hidden
; useflag keyword takes presidence - if ANY set, then false
if n_elements(useflag) ne 0 then begin
return, 0
endif
; if any flags are turned off
if n_elements(skipflag) ne 0 then begin
if size(skipflag,/type) eq 7 then begin
; only certain flags are turned off, not all
return, 0
endif else begin
return, 1
endelse
endif
; if no keyword set, then default to useflag=1
return, 0
END
;+
; Returns the idstrings of all flag lines that match the criteria of the given keywords.
; @keyword useflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are used; if set to
; a string array, then only those idstrings included are used.
; @keyword skipflag {in}{optional}{type=boolean, string array} if set to 1, then all flags are skipped; if set to
; a string array, then only those idstrings included are skipped.
; @param count {out}{optional}{type=long} number of idstrings returned
;-
FUNCTION FLAGS::get_flag_idstrings_used, useflag=useflag, skipflag=skipflag, count
compile_opt idl2, hidden
all_flag_ids = self->get_unique_ids(cnt)
if cnt eq 0 then begin
count = 0
return, -1
endif
; useflag keyword takes precedence
if n_elements(useflag) ne 0 then begin
if size(useflag,/type) ne 7 then begin
count = cnt
return, all_flag_ids
endif else begin
; check that the flags passed in exist before returning them
count = 0
for i=0,n_elements(useflag)-1 do begin
ind = where(strtrim(useflag[i],2) eq all_flag_ids, flag_matches)
if flag_matches ne 0 then begin
if count eq 0 then flag_ids_used=[all_flag_ids[ind]] else $
flag_ids_used=[flag_ids_used,all_flag_ids[ind]]
count += 1
endif
endfor
if count eq 0 then return, -1 else return, flag_ids_used
endelse
endif
; process skipflag keyword if useflag keyword was not used
if n_elements(skipflag) ne 0 then begin
if size(skipflag,/type) ne 7 then begin
; skipflag = 1
count = 0
return, -1
endif else begin
; check that the flags passed in exist
count = 0
for i=0,n_elements(skipflag)-1 do begin
ind = where(strtrim(skipflag[i],2) eq all_flag_ids, flag_matches)
if flag_matches ne 0 then begin
if count eq 0 then flags_not_used=[all_flag_ids[ind]] else $
flags_not_used=[flags_not_used,all_flag_ids[ind]]
count += 1
endif
endfor
if count eq 0 then begin
; none of the skipflags actually exist, so use all flags
count = n_elements(all_flag_ids)
return, all_flag_ids
endif else begin
count = 0
; remove the flags not used
for i=0,n_elements(all_flag_ids)-1 do begin
ind = where(strtrim(all_flag_ids[i],2) eq flags_not_used, cnt)
if cnt eq 0 then begin
if count eq 0 then flag_ids_used=[all_flag_ids[i]] else $
flag_ids_used=[flag_ids_used,all_flag_ids[i]]
count += 1
endif
endfor
if count eq 0 then return, -1 else return, flag_ids_used
endelse
endelse
endif
; if no keywords set, then use all ids
count = n_elements(all_flag_ids)
return, all_flag_ids
END
;+
; Returns an array for all the record numbers in all the flag files, with
; their values given with respect to the current index file.
; @param status {out}{optional}{type=bool} 0 - failure, 1 - success
;-
FUNCTION FLAGS::get_index_value_recnums, status
status = 1
index_value_recnums = -1
num_flags = self->get_num_flags()
if self->has_valid_files() eq 0 or num_flags eq 0 then begin
status = 0
return, -1
endif
index_value_recnums = strarr(num_flags)
; optimize for performance if there is only one file
if n_elements(*self.flag_files) eq 1 then begin
return, (*self.flag_files)[0]->get_index_value_recnums(status)
endif else begin
allStatus = 0
r = -1
for i=0,n_elements(*self.flag_files)-1 do begin
recnums = (*self.flag_files)[i]->get_index_value_recnums(status)
if status then begin
if allStatus then r=[r,recnums] else r=[recnums]
allStatus = 1
endif
endfor
return, r
endelse
END
;+
; Returns the sum of all the flags in all flag files
; @returns the sum of all the flags in all flag files
;-
FUNCTION FLAGS::get_num_flags
compile_opt idl2, hidden
if not self->has_valid_files() then begin
return, 0
endif else begin
cnt = 0
for i=0,n_elements(*self.flag_files)-1 do begin
cnt += (*self.flag_files)[i]->get_num_lines()
endfor
return, cnt
endelse
END
;+
; Method for returning structures that represent all the flags in all the
; flag files.
; @param count {out}{optional}{type=long}
; @returns structures that represent all the flags in all flag files, -1 if none
;-
FUNCTION FLAGS::get_all_row_strcts, count
if not self->has_valid_files() then begin
count = 0
return, -1
endif
; to optimize performance, if there is just one file, just
; return its rows...
if n_elements(*self.flag_files) eq 1 then begin
count = (*self.flag_files)[0]->get_num_lines()
return, (*self.flag_files)[0]->get_row_strcts()
endif else begin
for i=0,n_elements(*self.flag_files)-1 do begin
rows = (*self.flag_files)[i]->get_row_strcts(status)
if status ne 0 then begin
if n_elements(all_rows) eq 0 then all_rows=[rows] else all_rows=[all_rows,rows]
endif
endfor
count = n_elements(all_rows)
if count ne 0 then return, all_rows else return, -1
endelse
END
;+
; Uses keyword inheritance to intercept the channel keywords and test
; them for valid usage.
; Relevant keywords are : bchan, echan, chans, chanwidth
; bchan and echan are exclusive to chans and chanwidth.
; If bchan or echan are greater then one, then they must have the
; same length.
; chanwidth will default to 1.
; @returns 0 - keywords not valid, 1 - keywords valid
;-
FUNCTION FLAGS::check_channels_range, _EXTRA=ex
compile_opt idl2, hidden
; convert tags of the extra structure to keywords
if n_elements(ex) eq 0 then return,1
keywords = tag_names(ex)
for i=0,n_elements(keywords)-1 do begin
if keywords[i] eq "BCHAN" then bchan = ex.(i)
if keywords[i] eq "ECHAN" then echan = ex.(i)
if keywords[i] eq "CHANS" then chans = ex.(i)
if keywords[i] eq "CHANWIDTH" then chanwidth = ex.(i)
endfor
; either bchan or echan are set, then chan and widths should not
if n_elements(bchan) ne 0 or n_elements(echan) then begin
if n_elements(chans) ne 0 or n_elements(chanwidth) ne 0 then begin
message, "bchan and echan keywords are exclusive to chans and chanwidth keywords", /info
return, 0
endif
endif
; chanwidth cant be set without chans
if n_elements(chanwidth) ne 0 and n_elements(chans) eq 0 then begin
message, "chans must be specified with chanwidth keyword", /info
return, 0
endif
; if chans is set, use this to set bchan and echan
if n_elements(chans) ne 0 then begin
; what is the width?
if n_elements(chanwidth) eq 0 then begin
width=1
endif else begin
; width MUST be an odd number
if chanwidth MOD 2 eq 0 then begin
message, "chanwidth must be an odd number.", /info
return, 0
endif
endelse
endif else begin
; just bchan and/or echan must be set
; if only one begin or end channel is specified, the other end
; will default to the max or min range.
; if there is only one begining channel, then there must
; one or less end channels
if n_elements(bchan) eq 1 then begin
if n_elements(echan) gt 1 then begin
message, "bchan and echan must have equal lengths if more then one range is to be specified", /info
return, 0
endif
endif
; if there is only one end channel, then there must
; one or less begining channels
if n_elements(echan) eq 1 then begin
if n_elements(bchan) gt 1 then begin
message, "bchan and echan must have equal lengths if more then one range is to be specified", /info
return, 0
endif
endif
; when specifying more then one channel range, bchan and echan must
; be of same length
if n_elements(bchan) gt 1 or n_elements(echan) gt 1 then begin
if n_elements(bchan) ne n_elements(echan) then begin
message, "when specifying more then one range, bchan and echan must have equal lengths.", /info
return, 0
endif
endif
endelse
; nifty trick to inherit keywords
if 0 then self->set_flag, 0, _EXTRA=ex
return, 1
END
PRO FLAGS::show_state
compile_opt idl2
if ptr_valid(self.flag_files) then begin
for i=0,n_elements(*self.flag_files)-1 do begin
(*self.flag_files)[i]->show_state
endfor
endif else begin
print,"no valid flag files in flags"
endelse
end