;+
; IO_SDFITS_WRITER is intended for use by users who wish to write spectral line data to sdfits.
; See UML for all IO Classes, or IO_SDFITS UML for just the line and continuum sdfits classes.
;
; @field sdfits_def sdfits object used just for getting the definition of an sdfits row
; @field output_file the name of the file to be written to.
;
; @inherits io_sdfits_line
;
; @file_comments
; IO_SDFITS_WRITER is intended for use by users who wish to write spectral line data to sdfits.
; See UML for all IO Classes, or IO_SDFITS UML for just the line and continuum sdfits classes.
;
;-
PRO io_sdfits_writer__define
compile_opt idl2, hidden
io4 = { io_sdfits_writer, inherits io_sdfits_line, $
sdfits_def:obj_new(), $
output_file:string(replicate(32B,256)) $
}
END
;+
; Class Constructor
; @private
;-
FUNCTION IO_SDFITS_WRITER::init
compile_opt idl2
self.sdfits_def = obj_new('sdfits',version=self.version)
r = self->IO_SDFITS_LINE::init(index_file='io_sdfits_writer_index')
return, r
END
;+
; Class Destructor
; @private
;-
PRO IO_SDFITS_WRITER::cleanup
compile_opt idl2
if obj_valid(self.sdfits_def) then obj_destroy, self.sdfits_def
self->IO_SDFITS_LINE::cleanup
END
;+
; Sets the name of the output file, and if the file exists, creates an
; sdfits object for it
; @param file_name {in}{type=string} full path name to the file to write to
; @uses IO::file_exists
; @uses IO_SDFITS::add_fits_obj
;-
PRO IO_SDFITS_WRITER::set_output_file, file_name
compile_opt idl2
self.output_file = file_name
if self->file_exists(file_name) then begin
if self.debug then print, "output file exists, creating fits object"
if ptr_valid(self.fits_files) then obj_destroy, *self.fits_files
self->add_fits_obj, file_name
endif
END
;+
; Sets the file which this object will exclusively be writing to and reading from.
; Acts much like IO_SDFITS::set_file in the way it forces creation of a new index file
; @param file_name {in}{type=string} file name (full path or not) of file to use exclusively
; @keyword file_path {in}{optinal}{type=string} file path where file_name is found
; @keyword index_name {in}{optinal}{type=string} name to use for the index file
; @uses IO_SDFITS::set_file_path
; @uses IO_SDFITS_LINE::set_file
; @uses IO_SDFITS::set_index_file_name
; @uses IO_SDFITS::free_fits_objs
;-
PRO IO_SDFITS_WRITER::set_file, file_name, file_path=file_path, index_name=index_name
compile_opt idl2
if (self.one_file ne 0) then message, "this object is commited to using only one file"
if keyword_set(file_path) then file_path_set=1 else file_path_set=0
if keyword_set(index_name) then index_name_set=1 else index_name_set=0
; see if file path is inlcuded seperately
if file_path_set then begin
self->set_file_path, file_path
file_base=file_name
endif else begin
; see if file path is inlcuded in file name or not
if (strpos(file_name,'/') ne -1) then begin
self->set_file_path, file_dirname(file_name)
file_base = file_basename(file_name)
endif else begin
file_base = file_name
endelse
endelse
; now that self.file_path and file_base have been established
; check if this file exists
if (self->file_exists(self->get_full_file_name(file_base)) eq 1) then begin
; in this case, we can use the superclass's method
if (file_path_set eq 0) then file_path = 0
if (index_name_set eq 0) then index_name = 0
self->IO_SDFITS_LINE::set_file, file_name, file_path=file_path, index_name=index_name
self.output_file = file_name
endif else begin
; we can't use the superclass's method, we need a special implementation
; index file name == to file, or keyword?
if index_name_set then begin
index_file=index_name
endif else begin
parts=strsplit(file_base,'.',/extract)
index_file = strjoin(parts[0:n_elements(parts)-2],'.')+'.index'
endelse
self->set_index_file_name, index_file
; discard all other fits objects
self->free_fits_objs
; record the file to be written to
self->set_output_file, file_name
; mark this io object as dedicated to one file
self.one_file = 1
endelse
END
;+
; Writes a single spectrum to the sdfits file, saving an NSAVE number
; in the index file corresponding to this spectrum
;
; @param spectrum {in}{required}{type=struct} the spectral line data container to be written
; @param nsave {in}{required}{type=long} the integer identifier to associate with this spectrum
; @param status {in}{optional}{type=long} set to 0 or 1 for failure or success
;
; @uses set_nsave
; @uses get_nsave_index
; @uses write_spectra
; @uses overwrite_spectra
;
;-
PRO IO_SDFITS_WRITER::nsave_spectrum, spectrum, nsave, status
compile_opt idl2, hidden
; are we creating a new nsave number, or is it already in the index?
; what is the nsave numbers location in the index file
nsave_index = self.index->get_nsave_index(nsave)
if nsave_index eq -1 then begin
; this must be a new nsave number
spectrum.nsave = nsave
; append the spectrum to the output file and update the index file
self->write_spectra, spectrum
; since all new spectra are appended, this latest spectrum will
; have the highest index number.
index_num = max(self.index->get_column_values("INDEX"))
self.index->set_nsave, index_num, nsave
if n_elements(status) ne 0 then status = 1
endif else begin
; are we allowed to overwrite previously nsaved spectra?
if self.index->get_sprotect() eq 0 then begin
spectrum.nsave = nsave
; overwrite the pre-existing specturm with this new one
self->overwrite_spectrum, nsave_index, spectrum
; set the nsave number in the index file for this spectrum
self.index->set_nsave, nsave_index, nsave
if n_elements(status) ne 0 then status = 1
endif else begin
message, "Cannot nsave spectrum: index file's nsave protection set. Use set_sprotect_on", /info
if n_elements(status) ne 0 then status = 0
endelse
endelse
END
FUNCTION IO_SDFITS_WRITER::get_nsave_index, nsave
; get all nsave values
nsaves = self.index->get_column_values("NSAVE",/unique)
; is the one we're looking for in there?
cnt = 0
nsave_index = where(nsaves eq nsave,cnt)
; multiple nsave numbers is a blatant error
if cnt gt 1 then message, "nsave numbers in index file must be unique: "+string(nsave)
return, nsave_index
END
PRO IO_SDFITS_WRITER::overwrite_spectrum, index, spectrum
compile_opt idl2, hidden
; get the location, and other info abou the spectrum to be overwritten
row_info = self.index->search_for_row_info(index=index)
; will this spectrum fit in the current spot?
; first get the data size for the extension of this index
spectrum_size = n_elements(*spectrum.data_ptr)
; then get the size of the extension that this row is located in
full_file_name = self->get_full_file_name(row_info.file)
fits = obj_new("sdfits",full_file_name,version=self.version)
ext_data_size = fits->get_extension_data_size(row_info.extension)
if obj_valid(fits) then obj_destroy,fits
; if they don't agree, raise an error for now
if spectrum_size ne ext_data_size then message, "Cannot overwrite spectrum of size "+string(ext_data_size)+" with spectrum of size "+string(spectrum_size)
; this spectrum can fit in this extension, overwrite the old one
sdfits_row = self->spectra_to_rows(spectrum, virtuals)
; check if we have a fits writer object for this file
fw = self->get_fits(self.output_file)
; we are only allowed to write to sdfits files that were created by idl
if self->is_gbtidl_sdfits(fw->get_sdfits_version()) eq 0 then $
message, "This file was not created by gbtidl, we cannot modify it: "+self.output_file
; finally, overwrite the row in the fits file AND the index
fw->modify_rows, row_info.extension, row_info.row_num+1, sdfits_row
self.index->replace_with_spectrum, index, spectrum, row_info.file, row_info.extension, row_info.row_num
END
;+
; Writes given spectra to an sdfits file. The spectra are translated to their proper
; form for sdfits, and the rows are written to the output file in extensions based off
; the data size of each spectrum.
; @param spectra {in}{type=array} array of spectrum data containers to write to disk
; @keyword file_name {in}{optinal}{type=string} if passed in, this is the name of the output file
; @uses IO_SDFITS_WRITER::set_output_file
; @uses IO_SDFITS_WRITER::check_spectrum_size_uniformity
; @uses IO_SDFITS_WRITER::spectra_to_rows
; @uses IO_SDFITS_WRITER::write_rows_to_extension
; @uses IO_SDFITS_WRITER::update_index_with_spectra
;-
PRO IO_SDFITS_WRITER::write_spectra, spectra, file_name=file_name
compile_opt idl2
if keyword_set(file_name) then self->set_output_file, file_name
uniformity = self->check_spectrum_size_uniformity(spectra)
if (uniformity eq 1) then begin
; all the spectra have the same data size, we can write them at once
sdfits_rows = self->spectra_to_rows(spectra, virtuals)
self->write_rows_to_extension, sdfits_rows, virtuals, ext, start
self->update_index_with_spectra, spectra, ext, start
endif else begin
; not all spectra have same data length, they need separate extensions
; group spectra by data size
spectrum = spectra[0]
data_size = n_elements(*spectrum.data_ptr)
group_size = data_size
spectrum_group = [spectrum]
for i = 1, n_elements(spectra)-1 do begin
spectrum = spectra[i]
data_size = n_elements(*spectrum.data_ptr)
if (group_size eq data_size) then begin
spectrum_group = [spectrum_group,spectrum]
endif else begin
; data size has changed
; write current group, and start a new one
sdfits_rows = self->spectra_to_rows(spectrum_group, virtuals)
self->write_rows_to_extension, sdfits_rows, virtuals, ext, start
self->update_index_with_spectra, spectrum_group, ext, start
; start a new group
start_ext = i
group_size = data_size
spectrum_group = [spectrum]
endelse
endfor
; write last spectrum group
sdfits_rows = self->spectra_to_rows(spectrum_group, virtuals)
self->write_rows_to_extension, sdfits_rows, virtuals, ext, start
self->update_index_with_spectra, spectrum_group, ext, start
endelse
END
;+
; Writes sdfits rows to the output file, managing wether to create new extension, or append to current one
; @param rows {in}{type=array} array of structs mirroring sdfits rows to be written
; @param virtuals {in}{type=struct} structure containing keyword-values of keywords in extension header to be written
; @param ext {out}{type=long} extension that these rows get written to
; @param start_row {out}{type=long} row at which these new rows will start getting written to in the extension, equal to the number of rows in extension before new rows are written
; @private
;-
PRO IO_SDFITS_WRITER::write_rows_to_extension, rows, virtuals, ext, start_row
compile_opt idl2
; HACK HACK HACK - are these constant over all rows?
observer = rows[0].observer
project = rows[0].projid
backend = rows[0].backend
start_row = 0
full_output_name = self->get_full_file_name(self.output_file)
if (self->file_exists(full_output_name) eq 0) then begin
if self.debug then print, "creating new fits object for non-existent output file"
; create new file and object for file
self->add_fits_obj, self.output_file, /new
fw = self->get_fits(self.output_file)
fw->create_sdfits_file, full_output_name
fw->write_rows_new_extension, rows, virtuals
fw->update_file_properties
extension = fw->get_number_extensions()
endif else begin
; check if we have a fits writer object for this file
fw = self->get_fits(self.output_file)
if (obj_valid(fw) eq 0) then begin
if self.debug then print, "creating new fits object for pre-existing output file"
fw = self->get_new_fits_obj(self.output_file)
if (obj_valid(fw) eq 0) then message, "Could not create valid sdfits object to update fits file: "+self.output_file
endif
fw->update_file_properties
fw->update_last_extension_properties
; check if we are allowed to write to this file
version = fw->get_sdfits_version()
if self->is_gbtidl_sdfits(version) eq 0 then begin
message, "Cannot write to this sdfits file, was not created by GBTIDL: "+version+" "+self.output_file, /info
return
endif
extension = fw->get_number_extensions()
; check if we append to existing table or create new one
current_data_size = fw->get_last_extension_data_size()
new_data_size = n_elements(rows[0].data)
if (current_data_size eq new_data_size) then begin
; before appending to an extension, we need to double check that the rows
; are completely compatible with the current extension, i.e. the column types agree
if fw->row_compatible_with_extension(rows[0],extension) then begin
if self.debug then print, "appending to extension"
; how many rows already in this table?
start_row = fw->get_ext_num_rows(extension)
; append to this table
fw->append_rows_to_extension, rows
endif else begin
if self.debug then print, "rows differ from extension definition: writing to new extension"
; time to write a new extension table
fw->write_rows_new_extension, rows, virtuals
endelse
endif else begin
if self.debug then print, "writing new extension"
; time to write a new extension table
fw->write_rows_new_extension, rows, virtuals
endelse
endelse
ext = fw->get_number_extensions()
END
;+
; If these spectra have just been written to the output file-extension, then call this
; function to update the index file with the latest info
; @param spectra {in}{type=array} array of spectrum data containers that were just written to the output file
; @param extension {in}{type=long} the extension that just got written to
; @param start_row {in}{type=long} the row that the spectra started getting written to, should equal the current number of rows in extension
; @uses IO_SDFITS_WRITER::get_uniques_string
; @uses INDEX_FILE::is_file_loaded
; @uses INDEX_FILE::new_file
; @uses LINE_INDEX::udpate_with_spectra
; @uses INDEX_FILE::read_file
; @private
;-
PRO IO_SDFITS_WRITER::update_index_with_spectra, spectra, extension, start_row
compile_opt idl2
if (n_params() eq 3) then start = start_row else start = 0
observers = self->get_uniques_string(spectra.observer)
backends = self->get_uniques_string(spectra.backend)
if (self.index->is_file_loaded() eq 0) then begin
self.index->new_file, observers, backends, 'unknown', self.file_path
endif
;for i=0,n_elements(spectra)-1 do begin
; self.index->update_with_spectra, spectra[i]
;endfor
self.index->update_with_spectra, spectra, file_basename(self.output_file), extension, start
self.index->read_file
self.index_synced = 1
END
;+
; Sorts input array, and then reduces sorted array to unique values.
; Unique values are then put in a comma separated string
; @param arr {in}{type=array} array to find uniques of
; @returns comma separated string of unique values in input array
; @private
;-
FUNCTION IO_SDFITS_WRITER::get_uniques_string, arr
s = arr[sort(arr)]
u = s[uniq(s)]
u_str = ''
for i=0,n_elements(u)-1 do begin
if (i eq 0) then u_str=u[i] else u_str=u_str+','+u[i]
endfor
return, u_str
END
;+
; Goes through array of spectrum data containers and checks to see if they
; all have the same data length.
; @param spectra {in}{type=array} array of spectrum data containers
; @returns 0,1
; @private
;-
FUNCTION IO_SDFITS_WRITER::check_spectrum_size_uniformity, spectra
compile_opt idl2
i = 0
uniform = 1
first_data_size = n_elements(*spectra[0].data_ptr)
while (uniform eq 1) and (i lt n_elements(spectra)) do begin
data_size = n_elements(*spectra[i].data_ptr)
if (data_size ne first_data_size) then uniform = 0 else i = i + 1
endwhile
return, uniform
END
;+
; Translates an array of spectra into sdfits rows
; @param spectra {in}{type=array} array of spectrum data containers
; @param virtuals {out}{type=struct} keywords to be written to the file-extension header
; @returns array of structures that mirror the sdfits rows to be written
; @uses IO_SDFITS_WRITER::define_sdfits_row
; @uses IO_SDFITS_WRITER::spectrum_to_row
; @private
;-
FUNCTION IO_SDFITS_WRITER::spectra_to_rows, spectra, virtuals
compile_opt idl2
num_specs = n_elements(spectra)
data_size = n_elements(*(spectra[0]).data_ptr)
rows = make_array(num_specs, value=self->define_sdfits_row(data_size))
for i = 0, (num_specs-1) do begin
row = self->spectrum_to_row(spectra[i],virtuals)
rows[i] = row
endfor
return, rows
END
;+
; Translates a spectrum data container into a structure that mirrors the sdfits (v1.2) row to be written
; @param spec {in}{type=struct} spectrum data container to translate
; @param virtuals {out}{type=struct} keywords to be written to the sdfits extension header
; @keyword data_mode {in}{optional}{type=long} determines what data mode sdfits to be written in (not set uses raw mode)
; @returns structure that mirrors the sdfits row to be written
; @uses IO_SDFITS_WRITER::define_sdfits_row
; @uses IO_SDFITS_WRITER::get_sdfits_row_sizes
; @uses IO_SDFITS_WRITER::buffer_string
; @uses IO_SDFITS_WRITER::frequency_type_to_ctype1
; @uses IO_SDFITS_WRITER::coord_types_from_mode
; @uses IO_SDFITS_WRITER::pol_to_sdfits
; @uses IO_SDFITS_WRITER::create_obsmode
; @uses IO_SDFITS_WRITER::translate_bool_int
; makefitsdate
; @private
;-
FUNCTION IO_SDFITS_WRITER::spectrum_to_row, spec, virtuals, data_mode=data_mode
compile_opt idl2
; virtuals are keywords to be written to the binary ext. header
; if data containers from different projects, or even different telescopes
; are to be written to the same fits file extension, then many of the virtuals
; from an sdfits-filled fits file need to be columns with a gbtidl-filled one.
virtuals = { $
;backend:spec.backend, $
;projid:spec.projid, $
;telescop:'NRAO_GBT', $
extname:'SINGLE DISH', $
ctype4:'STOKES' $
;sitelong:spec.site_location[0], $
;sitelat:spec.site_location[1], $
;siteelev:spec.site_location[2] $
}
data_points = n_elements(*spec.data_ptr)
row = self->define_sdfits_row(data_points)
sizes = self->get_sdfits_row_sizes()
tdim7 = '('+strtrim(string(data_points),2)+',1,1,1)'
row.tdim7 = self->buffer_string(tdim7,sizes.tdim7)
row.object = self->buffer_string(spec.source,sizes.object)
row.observer = self->buffer_string(spec.observer,sizes.observer)
row.obsid = self->buffer_string(spec.obsid,sizes.obsid)
row.bandwid = spec.bandwidth
fdate = makefitsdate(spec.mjd,precision=2)
row.date_obs = self->buffer_string(fdate,sizes.date_obs)
row.exposure = spec.exposure
row.duration = spec.duration
row.tsys = spec.tsys
;row.tsysref = spec.tsysref
row.data = *spec.data_ptr
row.tunit7 = self->buffer_string(spec.units,sizes.tunit7)
ctype1 = self->frequency_type_to_ctype1(spec.frequency_type)
row.ctype1 = self->buffer_string(ctype1,sizes.ctype1)
row.crval1 = spec.reference_frequency
; ref channel 1-based in sdfits, 0-based in idl
row.crpix1 = spec.reference_channel + 1.0
row.cdelt1 = spec.frequency_interval
types = self->coord_types_from_mode(spec.coordinate_mode)
row.ctype2 = self->buffer_string(types[0],sizes.ctype2)
row.ctype3 = self->buffer_string(types[1],sizes.ctype3)
row.equinox = spec.equinox
row.crval2 = spec.longitude_axis
row.crval3 = spec.latitude_axis
row.crval4 = self->pol_to_sdfits(spec.polarization)
row.scan = spec.scan_number
obsmode = self->create_obsmode(spec.procedure,spec.switch_state, spec.switch_sig)
row.obsmode = self->buffer_string(obsmode,sizes.obsmode)
row.frontend = self->buffer_string(spec.frontend,sizes.frontend) ; frontend
row.tcal =spec.mean_tcal
row.veldef = self->buffer_string(spec.velocity_definition,sizes.veldef)
row.vframe = spec.frame_velocity
row.obsfreq = spec.observed_frequency
row.azimuth = spec.azimuth
row.elevatio = spec.elevation
row.lst = spec.lst
row.restfreq = spec.line_rest_frequency
row.sampler = self->buffer_string(spec.sampler_name,sizes.sampler)
row.feed = spec.feed
row.srfeed = spec.srfeed
row.sideband = spec.sideband
row.procseqn = spec.subscan
row.procsize = spec.procsize
row.velocity = spec.source_velocity
row.beamxoff = spec.beamxoff
row.beameoff = spec.beameoff
row.foffref1 = spec.freq_switch_offset
row.sig = self->translate_bool_int(spec.sig_state)
row.cal = self->translate_bool_int(spec.cal_state)
; the below columns are keywords in an sdfits-filled fits file
row.backend = self->buffer_string(spec.backend,sizes.backend)
row.projid = self->buffer_string(spec.projid,sizes.projid)
row.telescop = self->buffer_string('NRAO_GBT',sizes.telescop)
row.sitelong = spec.site_location[0]
row.sitelat = spec.site_location[1]
row.siteelev = spec.site_location[2]
; the below are only found in gbtidl-filled sdfits files
row.nsave = spec.nsave
return, row
END
;+
; Returns sizes needed for ASCII columns in sdfits.
; Problems: this exists here AND in IO_SDFITS_WRITER.
; @returns structure with sizes for ASCII columsn in sdfits
; @private
;-
FUNCTION IO_SDFITS_WRITER::get_sdfits_row_sizes
compile_opt idl2
return, self.sdfits_def->get_sdfits_row_sizes()
END
;+
; Defines an anonymous structure that can be used with mrdfits to write an sdfits row
; @param data_points {in}{type=long} the size of the data array in data column
; @uses SDFITS::define_sdfits_row
; @returns anonymous structure that can be used with mrdfits to write an sdfits row
; @private
;-
FUNCTION IO_SDFITS_WRITER::define_sdfits_row, data_points
compile_opt idl2
return, self.sdfits_def->define_sdfits_row(data_points)
END
;+
; Crops or pads the input string to exactly the length specified
; @param str {in}{type=string} string to buffer
; @param length {in}{type=long} length that string should be buffered to
; @returns The input string, cropped or padded to specified length
; @private
;-
FUNCTION IO_SDFITS_WRITER::buffer_string, str, length
compile_opt idl2
new_str = str
current_length = strlen(new_str)
; if string is exact length, nothing to do
if (current_length eq length) then return, new_str
; if string is too long, trim it
if (current_length gt length) then begin
new_str = strmid(new_str,0,length)
endif
; if string is too short, buffer on the right with white space
if (current_length lt length) then begin
new_str = new_str + string(replicate(32B,(length - current_length)))
endif
return, new_str
END
;+
; Creates sdfits obsmode column value from the procedure, switch state, and switch signal
; obsmode = 'procedure:switchstate:swtchsig'
; @param proc {in}{type=string} procedure
; @param swstate {in}{type=string} switch state
; @param swtchsig {in}{type=string} switch signal
; @returns obsmode
; @private
;-
FUNCTION IO_SDFITS_WRITER::create_obsmode, proc, swstate, swtchsig
proc = strtrim(proc,2)
swstate = strtrim(swstate,2)
swtchsig = strtrim(swtchsig,2)
obsmode = proc+':'+swstate+':'+swtchsig
return, obsmode
END
;+
; Tranlate coordinate mode to the two values needed for long. type and lat. type
; @examples
; case mode of
; 'RADEC': value = ['RA ','DEC ']
; 'GALACTIC': value = ['GLON','GLAT']
; 'HADEC': value = ['HA ','DEC ']
; 'AZEL': value = ['AZ ','EL ']
; 'OTHER': value = ['OLON','OLAT']
; else: value = ['OLON','OLAT']
; endcase
; @private
;-
FUNCTION IO_SDFITS_WRITER::coord_types_from_mode, mode
compile_opt idl2
mode = strtrim(strupcase(mode),2)
case mode of
'RADEC': value = ['RA ','DEC ']
'GALACTIC': value = ['GLON','GLAT']
'HADEC': value = ['HA ','DEC ']
'AZEL': value = ['AZ ','EL ']
'OTHER': value = ['OLON','OLAT']
else: value = ['OLON','OLAT']
endcase
return, value
END
;+
; converts spectrums integer value for columns such as cal or sig
; to ascii value used in sdfits
; @param bool_int {in}{type=long} 0 or 1
; @returns 'T' or 'F'
; @private
;-
FUNCTION IO_SDFITS_WRITER::translate_bool_int, bool_int
compile_opt idl2
if (bool_int eq 1) then return, 'T' else return, 'F'
END
;+
; Translates char polarization used by spectrum data container to integer
; values used by sdfits
; @param pol {in}{type=string} char representation of polarization
; @returns integer rep of polarization
; @private
;-
FUNCTION IO_SDFITS_WRITER::pol_to_sdfits, pol
compile_opt idl2
case pol of
'I': value = 1
'Q': value = 2
'U': value = 3
'V': value = 4
'RR': value = -1
'LL': value = -2
'RL': value = -3
'LR': value = -4
'XX': value = -5
'YY': value = -6
'XY': value = -7
'YX': value = -8
else: value = 0
endcase
return, value
END
;+
; Translates spectrum data container representation of frequency type
; to rep used by sdfits. See comments in IO_SDFITS_LINE::ctype1_to_freq_type
; @param freq_type {in}{type=string} rep of frequency type
; @returns sdfits rep of frequency type (ctype1)
; @private
;-
FUNCTION IO_SDFITS_WRITER::frequency_type_to_ctype1, freq_type
compile_opt idl2
if freq_type eq 'TOPO' then begin
ctype1 = 'FREQ-OBS'
endif else begin
if (where(codes eq freq_type) ne -1) then begin
ctype1 = 'FREQ-'+strtrim(freq_type,2)
endif else begin
ctype1 = 'unknown'
endelse
endelse
return, ctype1
END
;+
; Sets index file so nsave numbers cannot be overwritten
;-
PRO IO_SDFITS_WRITER::set_sprotect_on
compile_opt idl2, hidden
self.index->set_sprotect_on
END
;+
; Sets index file so nsave numbers can be overwritten
;-
PRO IO_SDFITS_WRITER::set_sprotect_off
compile_opt idl2, hidden
self.index->set_sprotect_off
END
;+
; Retrieves the state of nsave protection
; @returns 0 - nsave numbers cannot be overwritten; 1 - they cannot be overwritten
;-
FUNCTION IO_SDFITS_WRITER::get_sprotect
compile_opt idl2, hidden
return, self.index->get_sprotect()
END
;+
; Does the passed in version string start with 'GBTIDL'?
; Only fits files with primary header keyword 'SDFITVER' values that
; are of the form 'GBTIDL ver#.#' are allowed to be written to.
; This is the value that is used when GBTIDL creates an sdfits file.
; @param version string value for the keyword 'SDFITVER' in primary header
; @returns 1 - file was written by gbtidl, 0 - file was not
;-
FUNCTION IO_SDFITS_WRITER::is_gbtidl_sdfits, version
compile_opt idl2, hidden
if strmid(version,0,6) eq 'GBTIDL' then return, 1 else return, 0
END