;+ ; IO_SDFITS_LINE is intended for end users wishing to work with spectral line data. It's the child class of IO_SDFITS used for reading, writing, ; navigating sdfits spectrual line files, and for ; translating their info to spectrum data containers. See ; UML for all IO Classes, or ; IO_SDFITS UML for just ; the line and continuum sdfits classes. ; ; ; @file_comments ; IO_SDFITS_LINE is intended for end users wishing to work with spectral line data. It's the child class of IO_SDFITS used for reading, writing, ; navigating sdfits spectrual line files, and for ; translating their info to spectrum data containers. See ; UML for all IO Classes, or ; IO_SDFITS UML for just ; the line and continuum sdfits classes. ; ; @uses LINE_INDEX ; @uses SDFITS ; ; @inherits io_sdfits ; ; @version $Id: io_sdfits_line__define.pro,v 1.32 2005/05/28 15:58:26 paghots Exp $ ;- ;+ ; defines class structure ; @private ;- PRO io_sdfits_line__define compile_opt idl2, hidden io = { io_sdfits_line, inherits io_sdfits, $ online_dir:string(replicate(32B,256)), $ online_proj:string(replicate(32B,256)), $ online_lock_lun:0 $ } END ;+ ; Called upon instantiation of this class. ; @uses IO_SDFITS::init ; @private ;- FUNCTION IO_SDFITS_LINE::init,index_file=index_file compile_opt idl2, hidden r = self->IO_SDFITS::init() if r eq 1 then begin if keyword_set(index_file) then begin self.index = obj_new('line_index',file_name=index_file,version=self.version) endif else begin self.index = obj_new('line_index',file_name='io_sdfits_line_index',version=self.version) endelse self.debug = 0 self.online_dir = "/home/sdfits" get_lun, lun self.online_lock_lun = lun endif return, r END ;+ ; Class destructor ;- PRO IO_SDFITS_LINE::cleanup compile_opt idl2, hidden self->IO_SDFITS::cleanup free_lun, self.online_lock_lun END ;+ ; Reads in all the rows from every extension in the fits file represented by the ; passed in sdfits object, and passes this on to the index object so that the index ; file can be updated. ; @param fits_obj {in}{type=object} sdfits object representing an sdfits file. ; @uses SDFITS::get_and_eval_rows ; @uses SDFITS::get_number_extensions ; @uses SDFITS::get_file_name ; @uses SDFITS::get_extension_header_value ; @uses LINE_INDEX::update_file ; @private ;- PRO IO_SDFITS_LINE::update_index_with_fits_file, fits_obj compile_opt idl2 ; update the index file num_exts = fits_obj->get_number_extensions() for ext = 1, (num_exts) do begin ; for updating an index, we don't need the data column rows = fits_obj->get_and_eval_rows(missing, virtuals, ext=ext, /no_data) project = fits_obj->get_extension_header_value('PROJID') file_name = fits_obj->get_file_name() self.index->update_file, rows, project, file_name, ext, missing, virtuals endfor self.index->read_file self.index_synced = 1 END ;+ ; Groups a collection of rows from the index file by file and extension. ; This method is needed since we will want to access each files extension only once ; to read the pertinent rows (for efficiany reasons). ; @param row_info {in}{type=array} array of structs, where each struct represents a row of the index file ; @returns array of group_row_info structures: rows that share a file and extension ; @private ;- FUNCTION IO_SDFITS_LINE::group_row_info, row_info compile_opt idl2 ; get all files files = row_info.file unique_files = files[uniq(files[sort(files)])] group = {line_sdfits_row_group} for i = 0, (n_elements(unique_files)-1) do begin file_locals = row_info[ where(row_info.file eq unique_files[i]) ] exts = file_locals.extension unique_exts = exts[uniq(exts[sort(exts)])] for j = 0, (n_elements(unique_exts)-1) do begin file_ext_locals = file_locals[ where(file_locals.extension eq unique_exts[j]) ] ; collapse the array into one struct group.file = file_ext_locals[0].file group.extension = file_ext_locals[0].extension group.rows = ptr_new(file_ext_locals.row_num) group.integrations = ptr_new(file_ext_locals.integration) group.if_numbers = ptr_new(file_ext_locals.if_number) group.feed_nums = ptr_new(file_ext_locals.feed_number) group.pol_nums = ptr_new(file_ext_locals.pol_number) group.nsaves = ptr_new(file_ext_locals.nsave) if (i eq 0) and (j eq 0) then groups = [group] else groups = [groups,group] endfor endfor return, groups END ;+ ; This function searches the index file using the keyword parameters passed ; into it, reads the appropriate parts of the sdfits files, and tranlates this ; data into spectrum structures, which are returned. ; ; @keyword _EXTRA {in}{optional} see search_for_row_info for more info ; @param count {out}{optional}{type=long} number of spectra returned ; ; @returns Array of spectrum structures ; ; @examples ;
;; ; @uses LINE_INDEX::search_for_row_info ; @uses SDFITS::get_and_eval_rows ; @uses IO_SDFITS_LINE::rows_to_spectra ; ; @version $Id: io_sdfits_line__define.pro,v 1.32 2005/05/28 15:58:26 paghots Exp $ ;- FUNCTION IO_SDFITS_LINE::get_spectra, _EXTRA=ex, count, indicies compile_opt idl2 if self.index->validate_search_keywords(ex) eq 0 then begin count = 0 return, -1 endif ; if we're online, read in the latest index rows into memory if self.online then self->update ; find the files,extensions, and rows that match the specified criteria row_info = self.index->search_for_row_info(_EXTRA=ex, indicies) if (size(row_info,/dimension) eq 0) then begin if row_info eq -1 then begin count = 0 return, -1 endif endif ; group rows found in index file by filename and extension groups = self->group_row_info(row_info) ; must read each extension seperately becasue they may contain varying data sizes for i = 0, n_elements(groups)-1 do begin sdfits_rows = self->get_and_eval_rows(groups[i], missing, virtuals) ; convert this group of rows to spectra spectra = self->rows_to_spectra(sdfits_rows, *groups[i].integrations, *groups[i].if_numbers, *groups[i].feed_nums, *groups[i].pol_nums, *groups[i].nsaves, missing, virtuals) if (i eq 0) then all_spectra = [spectra] else all_spectra = [temporary(all_spectra),spectra] endfor self->free_group_row_info, groups count = n_elements(all_spectra) return, all_spectra END ;+ ; Handles the translation of several sdfits rows to spectrum data containers. ; Utilizes additional info from the index file, as well as info on keywords in the extension roads are found in, and what ever expected columns were not found in the sdfits file. ; ; @param sdfits_rows {in}{type=array} an array of structures mirroring rows from an sdfits file extension containing spectral line data ; @param integrations {in}{type=array} the integration numbers for these spectra; from index file ; @param if_numbers {in}{type=array} the if numbers for these spectra; from index file ; @param nsaves {in}{type=array} the nsave numbers for these spectra; from index file ; @param missing {in}{type=array} array of column names that were expected in sdfits file extension, but not found. ; @param virtuals {in}{optional}{type=struct} structure containing keywords found in the extension header. ; ; @uses io_sdfits_line::sdfits_row_to_spectrum ; @private ;- FUNCTION IO_SDFITS_LINE::rows_to_spectra, sdfits_rows, integrations, if_numbers, feed_nums, pol_nums, nsaves, missing, virtuals compile_opt idl2 @spectrum num_rows = n_elements(sdfits_rows) spectra = make_array(num_rows,value={spectrum}) for i = 0, (num_rows-1) do begin spectrum = self->sdfits_row_to_spectrum( sdfits_rows[i], integrations[i], if_numbers[i], feed_nums[i], pol_nums[i], nsaves[i], missing, virtuals ) if self.debug then print, "getting spectrum: "+string(i)+" of: "+string(num_rows) spectra[i] = spectrum endfor return, spectra END ;+ ; Handles the translation of an sdfits row to a spectrum data container. ; Utilizes additional info from the index file, as well as info on keywords in the extension roads are found in, and what ever expected columns were not found in the sdfits file. ; ; @param row {in}{type=struct} a structure mirroring a row from an sdfits file extension containing spectral line data ; @param integration {in}{type=long} the integration number of this spectrum; from index file ; @param if_number {in}{type=long} the if number of this spectrum; from index file ; @param nsave {in}{type=long} the nsave number of this spectrum; from index file ; @param missing {in}{type=array} array of column names that were expected in sdfits file extension, but not found. ; @param virtuals {in}{optional}{type=struct} structure containing keywords found in the extension header. ; ; @uses io_sdfits::get_row_value ; @uses io_sdfits_line::format_sdfits_freq_type ; @uses io_sdfits_line::coord_mode_from_types ; @uses io_sdfits_line::translate_sig ; @uses io_sdfits_line::translate_cal ; @uses io_sdfits_line::parse_sdfits_obsmode ; @uses fitsdateparse ; @uses juldate ; @private ;- FUNCTION IO_SDFITS_LINE::sdfits_row_to_spectrum, row, integration, if_number, feed_num, pol_num, nsave, missing, virtuals compile_opt idl2 spec = {spectrum} ;data_new() spec.data_ptr = ptr_new(/allocate_heap) ; check for NO virtual columns if (size(virtuals,/TYPE) eq 3) then virtual_names=-1 else virtual_names=tag_names(virtuals) names = {row:ptr_new(tag_names(row)),missing:ptr_new(missing),virtuals:ptr_new(virtual_names)} ; default values to use for missing cols in sdfits row di = -1L df = 0.0 dd = 0.0D ds = 'default' spec.source = self->get_row_value(row,'OBJECT',virtuals,names,ds) spec.projid = self->get_row_value(row,'PROJID',virtuals,names,ds) spec.backend = self->get_row_value(row,'BACKEND',virtuals,names,ds) spec.observer = self->get_row_value(row,'OBSERVER',virtuals,names,ds) spec.telescope = self->get_row_value(row,'TELESCOP',virtuals,names,ds) spec.bandwidth = self->get_row_value(row,'BANDWID',virtuals,names,dd) date_obs = self->get_row_value(row,'DATE_OBS',virtuals,names,ds) fd = fitsdateparse(date_obs) spec.date = strmid(date_obs,0,10) spec.utc = (fd[3]*60.0+fd[4])*60.0 + fd[5] juldate,fd,mjd ; juldate returnes Reduced Julian Date (RJD): MJD = RJD - 0.5 spec.mjd=mjd - 0.5 spec.exposure = self->get_row_value(row,'EXPOSURE',virtuals,names,dd) spec.duration = self->get_row_value(row,'DURATION',virtuals,names,dd) spec.tsys = self->get_row_value(row,'TSYS',virtuals,names,dd) spec.tsysref = self->get_row_value(row,'TSYSREF',virtuals,names,dd) sitelong = self->get_row_value(row,'SITELONG',virtuals,names,dd) sitelat = self->get_row_value(row,'SITELAT',virtuals,names,dd) siteelev = self->get_row_value(row,'SITEELEV',virtuals,names,dd) ; if this is the GBT, and it's got a positive longitude, its sdfits ver 1.1; ; turn it negative (bug in SDFITS 1.1); this is fixed in ver 1.2 if (spec.telescope eq "NRAO_GBT") and (sitelong gt 0.0) then sitelong = -sitelong spec.site_location = [sitelong, sitelat, siteelev] ; assume row has a data tag name! *spec.data_ptr = row.data spec.units = self->get_row_value(row,'UNIT7',virtuals,names,"") spec.frequency_type = self->format_sdfits_freq_type(self->get_row_value(row,'CTYPE1',virtuals,names,ds)) spec.reference_frequency = self->get_row_value(row,'CRVAL1',virtuals,names,dd) ; ref channel 1-based in sdfits, 0-based in idl spec.reference_channel = self->get_row_value(row,'CRPIX1',virtuals,names,1.0) - 1.0 spec.frequency_interval = self->get_row_value(row,'CDELT1',virtuals,names,dd) ctype2 = self->get_row_value(row,'CTYPE2',virtuals,names,ds) ctype3 = self->get_row_value(row,'CTYPE3',virtuals,names,ds) spec.coordinate_mode = self->coord_mode_from_types(ctype2,ctype3) spec.equinox = self->get_row_value(row,'EQUINOX',virtuals,names,dd) spec.longitude_axis = self->get_row_value(row,'CRVAL2',virtuals,names,dd) spec.latitude_axis = self->get_row_value(row,'CRVAL3',virtuals,names,dd) crval4 = self->get_row_value(row,'CRVAL4',virtuals,names,0) spec.polarization = self->format_sdfits_polarization(crval4[0]) spec.scan_number = self->get_row_value(row,'SCAN',virtuals,names,di) obsmode = self->get_row_value(row,'OBSMODE',virtuals,names,ds) self->parse_sdfits_obsmode,obsmode,proc,swstate,swtchsig spec.procedure = proc spec.switch_state = swstate spec.switch_sig = swtchsig spec.obsid = self->get_row_value(row,'OBSID',virtuals,names,ds) spec.frontend = self->get_row_value(row,'FRONTEND',virtuals,names,ds) spec.beamxoff = self->get_row_value(row,'BEAMXOFF',virtuals,names,dd) spec.beameoff = self->get_row_value(row,'BEAMEOFF',virtuals,names,dd) spec.mean_tcal = self->get_row_value(row,'TCAL',virtuals,names,dd) spec.velocity_definition = self->get_row_value(row,'VELDEF',virtuals,names,ds) spec.frame_velocity = self->get_row_value(row,'VFRAME',virtuals,names,dd) spec.observed_frequency = self->get_row_value(row,'OBSFREQ',virtuals,names,dd) spec.lst = self->get_row_value(row,'LST',virtuals,names,dd) spec.azimuth = self->get_row_value(row,'AZIMUTH',virtuals,names,dd) spec.elevation = self->get_row_value(row,'ELEVATIO',virtuals,names,dd) spec.line_rest_frequency = self->get_row_value(row,'RESTFREQ',virtuals,names,dd) spec.center_frequency = self.index->get_center_frequency(spec.reference_frequency,spec.reference_channel,spec.frequency_interval,n_elements(row.data)) spec.sampler_name = self->get_row_value(row,'SAMPLER',virtuals,names,ds) spec.feed = self->get_row_value(row,'FEED',virtuals,names,di) spec.srfeed = self->get_row_value(row,'SRFEED',virtuals,names,di) spec.sideband = self->get_row_value(row,'SIDEBAND',virtuals,names,ds) spec.subscan = self->get_row_value(row,'PROCSEQN',virtuals,names,0)-1 ; 0-based in idl spec.procsize = self->get_row_value(row,'PROCSIZE',virtuals,names,di) spec.source_velocity = self->get_row_value(row,'VELOCITY',virtuals,names,dd) spec.freq_switch_offset = self->get_row_value(row,'FOFFREF1',virtuals,names,dd) spec.sig_state = self->translate_sig(self->get_row_value(row,'SIG',virtuals,names,'T')) spec.cal_state = self->translate_cal(self->get_row_value(row,'CAL',virtuals,names,'T')) ; additional stuff - all from index file spec.integration = integration spec.if_number = if_number spec.feed_num = feed_num spec.polarization_num = pol_num spec.nsave = nsave ptr_free,names.row ptr_free,names.missing ptr_free,names.virtuals return, spec END ;+ ; Frees the memory referenced by pointers in the passed in structure ; @param row_info {in}{type=struct} contains pointers to row number lists, integration and if number lists ; @private ;- PRO IO_SDFITS_LINE::free_group_row_info, row_info compile_opt idl2 for i=0, (n_elements(row_info)-1) do begin if ptr_valid(row_info[i].rows) then ptr_free, row_info[i].rows if ptr_valid(row_info[i].integrations) then ptr_free, row_info[i].integrations if ptr_valid(row_info[i].if_numbers) then ptr_free, row_info[i].if_numbers if ptr_valid(row_info[i].feed_nums) then ptr_free, row_info[i].feed_nums if ptr_valid(row_info[i].pol_nums) then ptr_free, row_info[i].pol_nums if ptr_valid(row_info[i].nsaves) then ptr_free, row_info[i].nsaves endfor END ;+ ; Creates and returns a line_sdfits object ; @param file_name {in}{type=string} full path file name for sdfits file of with spectral line data ; @private ;- FUNCTION IO_SDFITS_LINE::get_new_fits_obj, file_name, _EXTRA=ex compile_opt idl2 return, obj_new('line_sdfits',file_name,version=self.version,_EXTRA=ex) END ;+ ; ; Determines if any files have grown, and appends new rows to the index file ; ; @uses get_new_row_locations ; @uses group_row_locations ; ; @examples ; >io->set_file, 'filename' ; >io->list ; ; here you see contents of 'filename' ; >io->update ; even though 'filename' hasnt changed ; >'No sdfits file(s) in index need updating' ; ; now new rows are appended to 'filename' (by the online filler perhaps) ; >io->update ; >'Index file updated with 5 rows' ; >io->list ; ; here you see the original contents of 'filname' ; ; plus the extra 5 new rows. ; ; NOTE: the index file was NOT re-created from scatch ; ;- PRO IO_SDFITS_LINE::load_new_sdfits_rows if self.index->is_file_loaded() eq 0 then message, "Cannot update until an index file has been created/loaded" ; for every file in sdfits file, check that its 'nsync files = self.index->get_column_values('file',/unique) for i=0,n_elements(files)-1 do begin status = 0 locations = self->get_new_row_locations(files[i],status) if status then begin ; group the locations by filename-extension to save file I/O time location_groups = self->group_locations(locations) ; use a fits object for accessing the fits file that has our missing rows fits = self->get_fits(files[i]) for j=0,n_elements(location_groups)-1 do begin group = location_groups[j] new_rows = fits->get_and_eval_rows(missing, virtuals, (*group.rows), ext=group.ext) project = fits->get_extension_header_value('PROJID') file_name = fits->get_file_name() startrow = (*group.rows)[0] self.index->update_file, new_rows, project, file_name, group.ext, missing, virtuals, startrow print, "Index file updated with "+string(n_elements(new_rows))+" spectra" ; free memory ptr_free, group.rows endfor ; for each extension endif else begin ; if new rows found print, "No sdfits file(s) in index need updating" endelse endfor ; for each file ; get the new additions into memory self.index->read_file self.index_synced = 1 END ;+ ; Like other group functions in I/O, groups an array of structures by their filename, ; and extension tags. This is used so that rows in the same file-extension can be ; accessed all at once. ; @param locations {in}{required}{type=array} array of structures containing filenames, ext, and row # ; @returns array of structures, each structure giving a filename, extension, and array of row nubmers ; @private ;- FUNCTION IO_SDFITS_LINE::group_locations, locations compile_opt idl2 group = {location_group,filename:string(replicate(32B,256)),ext:0L,rows:ptr_new()} ; get all files files = locations.filename unique_files = files[uniq(files,sort(files))] for i = 0, (n_elements(unique_files)-1) do begin file_locals = locations[ where(locations.filename eq unique_files[i]) ] exts = file_locals.ext unique_exts = exts[uniq(exts,sort(exts))] for j = 0, (n_elements(unique_exts)-1) do begin group = {location_group} group.rows = ptr_new(/allocate_heap) file_ext_locals = file_locals[ where(file_locals.ext eq unique_exts[j]) ] ; collapse the array into one struct group.filename = file_ext_locals[0].filename group.ext = file_ext_locals[0].ext *group.rows = file_ext_locals.row if (i eq 0) and (j eq 0) then groups = [group] else groups = [groups,group] endfor endfor return, groups END ;+ ; Compares index file with sdfits files listed in it, and looks for new rows in the sdfits file. ; @returns array of structures, each giving location of file, extension, and row # of new sdfits row ; @private ;- FUNCTION IO_SDFITS_LINE::get_new_row_locations, filename, status compile_opt idl2, hidden loc = {row_location, filename:string(replicate(32B,256)), ext:0L, row:0L} ; get the fits object for this file fits = self->get_fits(filename) fits->update_properties ; retrieve the extensions in the file file_num_exts = fits->get_number_extensions() file_exts = indgen(file_num_exts)+1 ; collect all index rows for this file index_rows = self.index->search_for_row_info(file=filename) ; collect all the extensions in the index file index_exts = index_rows.extension index_exts = index_exts[uniq(index_exts,sort(index_exts))] ; what extensions does the index not have? for i=0,n_elements(file_exts)-1 do begin ; dont just compare the number of extesions, be more thourogh count = 0 ind = where(file_exts[i] eq index_exts, count) if count eq 0 then begin if n_elements(missing_ext) eq 0 then missing_ext = [file_exts[i]] else missing_ext = [missing_ext, file_exts[i]] endif endfor ; for each extension in file ; recored the locations of all rows in the missing extensions if n_elements(missing_ext) ne 0 then begin for i=0,n_elements(missing_ext)-1 do begin ; get number of rows in this fits file - row numbers are 0-based num_rows = fits->get_ext_num_rows(missing_ext[i]) for j=0,num_rows-1 do begin loc = {row_location} loc.filename = filename loc.ext = missing_ext[i] loc.row = j if n_elements(locs) eq 0 then locs=[loc] else locs=[locs,loc] endfor ; for each missing row number endfor ; for each missing extension endif ; missing rows in index extensions? for i=0,n_elements(index_exts)-1 do begin ; for each extension, compare row's. get the index's ext's rows index_rows = self.index->search_for_row_info(file=filename,ext=index_exts[i]) index_row_nums = index_rows.row_num ; get the fits files rows for this extension file_ext_num_rows = fits->get_ext_num_rows(index_exts[i]) ; although there aren't 'row numbers' in the sdfits files, treat them ; like they are, and don't just compare number of rows missing_rows = [-1] for j=0,file_ext_num_rows-1 do begin count = 0 ind = where(j eq index_row_nums,count) if count eq 0 then begin ; build the list of missing rows for this ext missing_rows = [missing_rows, j] endif endfor ; for each file row number for this extension ; if rows are missing, record their location in the sdfits file if n_elements(missing_rows) gt 1 then begin missing_rows = missing_rows[1:n_elements(missing_rows)-1] for j=0,n_elements(missing_rows)-1 do begin loc = {row_location} loc.filename = filename loc.ext = index_exts[i] loc.row = missing_rows[j] if n_elements(locs) eq 0 then locs=[loc] else locs=[locs,loc] endfor endif ; if rows missing endfor ; for each ext in index if n_elements(locs) eq 0 then begin status = 0 return, -1 endif else begin status = 1 return, locs endelse END ;+ ; Finds the latest files in the online directory. ; @param newest_acs {out}{optional}{type=string} the newest spectrometer fits file in the online directory ; @param newest_dcr {out}{optional}{type=string} the newest dcr fits file in the online directory ; @param newest_sp {out}{optional}{type=string} the newest spectral processor fits file in the online directory ; @param status {out}{optional}{type=boolean} 0 - error, 1 - success ; @returns the newest fits file (of all backends) in the online directory ;- FUNCTION IO_SDFITS_LINE::get_online_files, newest_acs, newest_dcr, newest_sp, status compile_opt idl2 status = 0 ; check if /home/sdfits is visible if file_test(self.online_dir) eq 0 and keyword_set(test) eq 0 then begin message, "Cannot find online files: "+self.online_dir+" not visible", /info return, -1 endif ; get the lastest fits file in the online dir cnt = 0 file_paths = file_search(self.online_dir+'/*.fits',count=cnt) ; dont do anything if there are no file if cnt eq 0 then begin message, "No fits files in: "+self.online_dir, /info return, -1 endif ; find newest files in online dir max_time = 0.0D max_acs_time = 0.0D max_dcr_time = 0.0D max_sp_time = 0.0D newest_file = "" newest_acs = "" newest_dcr = "" newest_sp = "" for i=0,n_elements(file_paths)-1 do begin file = file_paths[i] fi = file_info(file) ; what is the newest of all files? if fi.mtime gt max_time then begin max_time = fi.mtime newest_file = file endif ; what kind of backend is this file parts = strsplit(file,".",/extract) backend = parts[2] ; what is the newest of the backend files? if backend eq "acs" and fi.mtime gt max_acs_time then begin max_acs_time = fi.mtime newest_acs = file endif if backend eq "dcr" and fi.mtime gt max_dcr_time then begin max_dcr_time = fi.mtime newest_dcr = file endif if backend eq "sp" and fi.mtime gt max_sp_time then begin max_sp_time = fi.mtime newest_sp = file endif endfor status = 1 return, newest_file END ;+ ; Connects to a file in the online directory, and sets up object so that ; every time a query of the index file is done, the update method is called. ; This depends on another process(es) that should be updating the sdfits and ; index files for the current project. ; ; @param file_name {in}{required}{type=string} base or full filename to connect to ; @keyword test {in}{optional}{type=bool} if true, this is a test, and the online directory does not need to be visible ; ;- PRO IO_SDFITS_LINE::set_online, file_name, test=test compile_opt idl2 ; check if /home/sdfits is visible if file_test(self.online_dir) eq 0 and keyword_set(test) eq 0 then begin message, "Cannot use online mode: "+self.online_dir+" not visible", /info return endif ; check if path is included or not file_path = file_dirname(file_name) file_name = file_basename(file_name) if file_path eq "." then file_path = self.online_dir ; construct the name of the index we should load parts=strsplit(file_name,'.',/extract) index_file = strjoin(parts[0:n_elements(parts)-2],'.')+'.index' ; construct the name of the project we're connecting to self.online_proj = parts[0] ; for online mode, the daemons really should create it; ; therefore, if this index doesn't exist, raise an error if file_test(file_path+'/'+index_file) eq 0 then begin message, "Cannot use online mode: index file not created yet. Wait until first scan is finished or seek help.", /info return endif ; discard all other fits objects self->free_fits_objs ; set the names of the index file, and where it's located self->set_file_path, file_path self->set_index_file_name, index_file ; add this file, the index should get loaded ; however, some other process might be writing to this index file, so use lock self->lock_file self->add_file, file_name self->unlock_file ; mark this io object as dedicated to one file self.one_file = 1 ; mark the state as online self.online = 1 END ;+ ; Reads the new lines in an index file into memory, if the size of the ; index file has changed. Uses a lock file since other processes might ; be reading/writing the index file. ; @uses INDEX_FILE::read_new_rows ;- PRO IO_SDFITS_LINE::update compile_opt idl2 ; first just look at index file size to see if it's change current_fi = file_info(self.index->get_full_file_name()) old_fi = self.index->get_info() if old_fi.size ne current_fi.size then begin ; the size has changed self.index->set_info, current_fi ; must use lock files incase some other process is trying to read/write this file self->lock_file self.index->read_new_rows, num_new_lines self->unlock_file print, "Online index file has ", num_new_lines, " new lines.", format='(a22,i5,a12)' endif ;else begin ; print, "Online index file has not changed." ;endelse END ;+ ; lock file needed for sharing resources with other processes. ; if lock file already exists, then some other process is using the ; resource, and we wait (no time out). Once file is gone, we ; can lock the resource. ; this method creates the file /home/sdfits/project.lock ;- PRO IO_SDFITS_LINE::lock_file compile_opt idl2 lockfile = self.file_path + '/' + self.online_proj + '.lock' ; if the file exists, we have to wait for the owner to delete it filelocked = file_test(lockfile) while filelocked do begin print, "waiting on for access to project: ", self.online_proj wait, 1.0 filelocked = file_test(lockfile) endwhile if self.debug then print, "creating lockfile: ", lockfile openw, self.online_lock_lun, lockfile END ;+ ; lock file needed for sharing resources with other processes. ; this method destorys the file /home/sdfits/project.lock ;- PRO IO_SDFITS_LINE::unlock_file compile_opt idl2 lockfile = self.file_path + '/' + self.online_proj + '.lock' ; release the lock if self.debug then print, "destroying lockfile" close, self.online_lock_lun file_delete, lockfile END