;+ ; Name: SPEX_FITINT__DEFINE ; ; Purpose: This object manages the Fit Intervals for OSPEX ; ; Category: OSPEX ; ; Written: 2003, Kim Tolbert ; Modifications: ; 15-Jul-2004, Kim. In process, if no data returned for an interval delete ; that interval (with printed warning to user) ; 16-Jul-2004, Kim. Got rid of extra stuff in plot_setup (like overlaying ; background and fits - should use the gen plot_spectrum method for that. ; 19-Jul-2004, Kim. Added spex_fitint_filter parameter ; 20-Jul-2004, Kim. Added rm_bad_intervals method - calls process, so first ; gets rid of intervals with no data. Then delete any intervals whose ; filter state is unknown (with printed warning to user) ; 12-Aug-2004, Kim. Changed rm_bad_intervals method to find_bad_interval, with ; keyword option /remove. ; 5-Oct-2004, Kim. Added spex_fit_time_used - in process, store newedges there. ; 10-Oct-2004, Kim. Init spex_fit_time_used to -1 ; 11-Apr-2005, Kim. In intervals_pre_hook, use plot_time,/bk_data instead of plot, class=spex_bksub, and ; added /show_filter on time plot ; 21-Jul-2005, Kim. Added /this_class in setunits for speed ; 13-Feb-2006, Kim. In plot_setup, call get_plot_title to get title ; 31-May-2007, Kim. In find_bad_interval, set spex_fitint_filt to [good] elements. ; 17-Sep-2009, Kim. Added computing obsdata, eobsdata, bkdata, and ebkdata and added them ; to setdata structure (these are the observed counts and background and their errors ; binned into the fit time intervals, previously had to bin them manually) ; 26-Sep-2009, Kim. Fixed bug from 17-sep change. In process, if no bk data, skip the binning step for bk. ;- ;--------------------------------------------------------------------------- function spex_fitint::init, source = source, _extra = _extra if not keyword_set( source ) then source = obj_new( 'spex_bksub', _extra=_extra ) ret = self->framework::init( source = source, $ control = spex_fitint_control(), $ info = {spex_fitint_info}, $ _extra = _extra ) self -> set, spex_fitint_filter=-1, spex_fit_time_used=-1 return, ret end ;-------------------------------------------------------------------------- pro spex_fitint::set, $ spex_fit_time_interval=spex_fit_time_interval, $ done=done, not_found=not_found, $ _extra=_extra if keyword_set(spex_fit_time_interval) then time = anytim(spex_fit_time_interval) self->framework::set,spex_fit_time_interval=time, _extra=_extra, done=done, not_found=not_found end ;-------------------------------------------------------------------------- ; data product created is data,edata,ltime structure for data minus background ; for every raw energy bin, binned into fit time interval bins. ; explictly name spex_units keyword to keep it out of _extra pro spex_fitint::process, spex_units=spex_units, _extra = _extra fittime = self -> get(/spex_fit_time_interval) bksub_obj = self -> get(/obj, class='spex_bksub') data = bksub_obj -> getdata(/original_units, _extra=_extra) ;filetime = self -> get(/spex_file_time) ; if fittime is -1 or is outside file times, then set to 1 minute around peak ;if min(fittime) lt filetime[0] or max(fittime) gt filetime[1] then begin ; message, 'spex_fit_time_interval invalid or not set. Setting to 1 min at peak.', /cont ; dummy = max (ftotal (data.data, 1), peakindex) ; peaktime = (self -> getaxis(/ut))[peakindex] ; fit_time = [ (peaktime - 30. > filetime[0]), (peaktime + 30. < filetime[1]) ] ; self -> set, spex_fit_time_interval = fit_time ;endif units_str = bksub_obj -> getunits(/orig) adata = bksub_obj -> bin_data (data=data, $ intervals=fittime, $ units_str=units_str, $ /do_time_bin, $ eresult=eadata, $ ltime=ltime, $ newedges=newedges, $ index=index, $ bad_interval=bad) self -> setunits, units_str, /orig if adata[0] eq -1 then begin msg = 'Error accumulating data.' @spex_message endif if bad[0] ne -1 then begin print,' ' message,'WARNING: Removing the following interval(s) because they contain no data.', /info for i=0,n_elements(bad)-1 do $ print, ' Interval ' + trim(bad[i]) + ' ' + format_intervals(fittime[*,bad[i]],/ut) print,' ' tmp = rem_elem(indgen(n_elements(fittime)/2), bad) fittime = fittime[*,tmp] self -> set, spex_fit_time_interval=fittime endif obs_obj = self -> get(/obj, class='spex_data') obs = obs_obj -> getdata(/original_units, _extra=_extra) units_str = obs_obj -> getunits(/orig) obsdata = obs_obj -> bin_data (data=obs, $ intervals=fittime, $ units_str=units_str, $ /do_time_bin, $ eresult=eobsdata, $ ltime=lobstime) obs_obj -> setunits, units_str, /orig bk_obj = self -> get(/obj, class='spex_bk') bk = bk_obj -> getdata(/original_units, _extra=_extra) if bk.data[0] ne -1 then begin units_str = bk_obj -> getunits(/orig) bkdata = bk_obj -> bin_data (data=bk, $ intervals=fittime, $ units_str=units_str, $ /do_time_bin, $ eresult=ebkdata, $ ltime=lbktime) bk_obj -> setunits, units_str, /orig endif else begin bkdata = -1 ebkdata = -1 endelse fitint_filter = spex_get_filter (self -> get(/spex_interval_filter), index) self -> set, spex_fitint_filter = fitint_filter self -> set, spex_fit_time_used = newedges self -> setdata, {data: adata, edata: eadata, ltime: ltime, $ obsdata: obsdata, eobsdata: eobsdata, $ bkdata: bkdata, ebkdata: ebkdata} end ;-------------------------------------------------------------------------- pro spex_fitint::find_bad_intervals, bad=bad, remove=remove tmp = self -> getdata() fittime = self -> get(/spex_fit_time_interval) fitint_filter = self -> get(/spex_fitint_filter) good = where (fitint_filter ne -99, count, ncomplement=nbad, complement=bad) if nbad gt 0 and keyword_set(remove) then begin self -> set, spex_fit_time_interval = fittime[*, good], spex_fitint_filter=fitint_filter[good] print, ' ' message, /info, 'WARNING: Removing the following interval(s) because they span filter ' + $ 'states (or have unknown filter state).' for i=0,nbad-1 do print, ' Interval ' + trim(bad[i]), ' ', format_intervals(fittime[*,bad[i]],/ut) print, ' ' endif end ;-------------------------------------------------------------------------- function spex_fitint::getunits, orig=orig if keyword_set(orig) then return, self->get(/spex_fitint_origunits) return, self->get(/spex_fitint_units) end ;-------------------------------------------------------------------------- pro spex_fitint::setunits, units, orig=orig if keyword_set(orig) then self -> set, spex_fitint_origunits=units, /this_class else $ self -> set, spex_fitint_units=units, /this_class end ;-------------------------------------------------------------------------- ; Plot_setup method returns plot_params for plots of spectrum of data binned into fitting time intervals. ; this_interval = m or [m,n] for time intervals to plot. Default is interval specified by spex_interval_index ; if photons is set, them drm_eff must also be set, and counts will be converted to photons function spex_fitint::plot_setup, $ photons=photons, $ drm_eff=drm_eff, $ this_interval=this_interval, $ plot_params=plot_params, $ _extra=_extra error_catch = 0 if spex_get_debug() eq 0 then catch, error_catch if error_catch ne 0 then begin catch, /cancel message, !error_state.msg, /cont message,'Error making plot.', /cont return, 0 endif photons = keyword_set(photons) if photons and not keyword_set(drm_eff) then message,'No efficiency factors provided. Cannot display photons.' data = self -> getdata(_extra=_extra) if not is_struct(data) then message, 'No data accumulated.' label = 'Detectors: ' + self -> get(/spex_detectors) energies = self -> getaxis(/ct_energy, /edges_2) times = self -> get(/spex_fit_time_used) if times[0] eq -1 then message, 'No fit time intervals defined yet.' data =data.data checkvar, this_interval, self->get(/spex_interval_index) atimes = format_intervals(times, /ut) ntraces = n_elements(atimes) this_interval = (this_interval > 0) < (ntraces-1) if size(this_interval, /dim) eq 2 then this_interval = this_interval[0] + indgen(this_interval[1]-this_interval[0]+1) dim1_use = this_interval title = self -> get_plot_title(photons=photons) units_str = self -> getunits() if photons then spex_apply_eff, data, drm_eff, units_str=units_str plot_type='xyplot' title = title + ' vs Energy in Fit Intervals' xtitle = 'Energy (keV)' dim1_id = atimes + ' (Data-Bk)' dim1_vals = atimes dim1_sum = 0 dim1_unit = '' xlog = 1 ylog = 1 plot_params = { $ plot_type: plot_type, $ xdata: energies, $ ydata: data, $ id: title, $ label: label, $ data_unit: units_str.data, $ dim1_id: dim1_id, $ dim1_vals: dim1_vals,$ dim1_sum: dim1_sum, $ dim1_unit: dim1_unit, $ dim1_enab_sum: 0, $ dim1_use: dim1_use, $ weighted_sum: units_str.data_type ne 'counts', $ xlog: xlog, $ ylog: ylog, $ xtitle: xtitle $ } return, 1 end ;-------------------------------------------------------------------------- ;; Plot method plots spectrum of data binned into fitting time intervals. ;; this_interval = m or [m,n] for time intervals to plot. Default is interval specified by spex_interval_index ;; no_background = 0/1 means don't / do plot background as well as data ;; overlay_obj is an xyplot object containing the fitted data to be overlaid on plot, ;; (that obj is generated when this is called from spex_fit::plot) ;; if photons is set, them drm_eff must also be set, and counts will be converted to photons ; ;function spex_fitint::plot_setup, $ ; photons=photons, $ ; drm_eff=drm_eff, $ ; this_interval=this_interval, $ ; no_background=no_background, $ ; overlay_obj=overlay_obj, $ ; plot_params=plot_params, $ ; _extra=_extra ; ;error_catch = 0 ;if spex_get_debug() eq 0 then catch, error_catch ;if error_catch ne 0 then begin ; catch, /cancel ; message, !error_state.msg, /cont ; message,'Error making plot.', /cont ; return, 0 ;endif ; ;photons = keyword_set(photons) ;if photons and not keyword_set(drm_eff) then message,'No efficiency factors provided. Cannot display photons.' ; ;acc = self -> getdata(_extra=_extra) ;if not is_struct(acc) then message, 'No data accumulated.' ; ;label = 'Detectors: ' + self -> get(/spex_detectors) ; ;energies = self -> get(/spex_ct_edges) ;times = self -> get(/spex_fit_time_interval) ; ;data =acc.data ; ;checkvar, this_interval, self->get(/spex_interval_index) ;just_one = is_class(overlay_obj,'xyplot',/quiet) ; ;if just_one then begin ; this_interval = this_interval[0] ; data = data[*,this_interval] ; atimes = format_intervals(times[*,this_interval], /ut) ; ntraces=1 ; dim1_use = 0 ;endif else begin ; atimes = format_intervals(times, /ut) ; ntraces = n_elements(atimes) ; this_interval = (this_interval > 0) < (ntraces-1) ; if size(this_interval, /dim) eq 2 then this_interval = this_interval[0] + indgen(this_interval[1]-this_interval[0]+1) ; dim1_use = this_interval ;endelse ;dim1_id = atimes + ' (Data-Bk)' ; ;if not keyword_set(no_background) then begin ; bk_obj = self -> get(/obj, class='spex_bk') ; bk = bk_obj -> getdata(_extra=_extra) ; if bk.data[0] ne -1 then begin ; z = bk_obj -> bin_data (data=bk, intervals=times, er=er, newedges=newedges, /do_time) ; if z[0] ne -1 then begin ; if just_one then z = z[*,this_interval] ; data =[ [data], [z] ] ; dim1_id = [dim1_id, atimes+' (Bk)'] ; dim1_use = [dim1_use, ntraces+dim1_use] ; ;dim1_vals = [[dim1_vals],[dim1_vals]] ; endif ; endif ;endif ; ;units_str = self -> getunits() ;space = photons ? ' Photon' : ' Count' ;case units_str.data_type of ; 'counts': title = 'SPEX ' + units_str.data_name + space + 's' ; 'rate': title = 'SPEX ' + units_str.data_name + space + ' Rate' ; else: title = 'SPEX ' + units_str.data_name + space + ' Flux' ;endcase ; ;if photons then spex_apply_eff, data, drm_eff, units_str=units_str ; ;plot_type='xyplot' ;title = is_class(overlay_obj,'xyplot',/quiet) ? $ ; title + ' vs Energy with Fit Function, Interval ' + trim(this_interval) : $ ; title + ' vs Energy in Fit Intervals' ; ;xtitle = 'Energy (keV)' ;dim1_sum = 0 ;dim1_unit = '' ;xlog = 1 ;ylog = 1 ; ;if not exist(overlay_obj) then overlay_obj = -1 ; ;plot_params = { $ ; plot_type: plot_type, $ ; xdata: energies, $ ; ydata: data, $ ; id: title, $ ; label: label, $ ; data_unit: units_str.data, $ ; dim1_id: dim1_id, $ ; dim1_sum: dim1_sum, $ ; dim1_unit: dim1_unit, $ ; dim1_enab_sum: 0, $ ; dim1_use: dim1_use, $ ; weighted_sum: 1, $ ; xlog: xlog, $ ; ylog: ylog, $ ; xtitle: xtitle, $ ; overlay_obj: overlay_obj $ ; } ; ;return, 1 ;end ;------------------------------------------------------------------------------- ;pro spex_fitint::plot, _extra=_extra ; ;status = self -> plot_setup (plot_params=plot_params, _extra=_extra) ; ;if status then self -> do_plot, plot_params=plot_params, _extra=_extra ; ;end ;------------------------------------------------------------------------------ pro spex_fitint::select_time_int, _extra=_extra self -> intervals, _extra=_extra end ;------------------------------------------------------------------------------ pro spex_fitint::intervals_pre_hook, $ full_options=full_options, $ intervals=intervals, $ valid_range=valid_range, $ title=title, $ type=type, $ abort=abort, $ _extra=_extra ; make sure data has been retrieved for current settings. May be a better way? !!!! data = self -> getdata(class='spex_bksub') if not is_struct(data) then abort = 1 if abort then return intervals = self -> get(/spex_fit_time_interval) valid_range = minmax (self->get(/spex_ut_edges)) title='Select Time Intervals for Analysis' type='Analysis' if not keyword_set(full_options) then $ if not self->valid_plot(/utplot) then self -> plot_time, /bksub, /show_filter end ;------------------------------------------------------------------------------ pro spex_fitint::intervals_post_hook, bins, _extra=_extra old_bins = self -> get(/spex_fit_time_intervals) ; !!! Later - take care of preserving the parameters already stored ; in the right place even if add new intervals. ;old_params = self -> get(/spex_summ_params) if not same_data(bins, old_bin) then begin self -> set, spex_fit_time_interval=bins ; can't do the following here anymore cuz moved the summ params to spex_fit ; nparam = n_elements(self -> get(/fit_comp_param) ) ; self -> set, spex_summ_params = fltarr( nparam, n_elements(bins[0,*]) ) endif end ;--------------------------------------------------------------------------- pro spex_fitint__define dummy = {spex_fitint, $ inherits spex_gen } end