;$Id: hscn_data__define.pro,v 1.7 2007/06/21 20:12:53 azuah Exp $
;###############################################################################
;
; NAME:
;  HSCN_DATA__DEFINE
;
; PURPOSE:
;  See description below.
;
; CATEGORY:
;  DAVE, HFBS, data reduction
;
; AUTHOR:
;   Robert M. Dimeo, Ph.D.
;   NIST Center for Neutron Research
;   100 Bureau Drive
;   Gaithersburg, MD 20899
;   Phone: (301) 975-8135
;   E-mail: robert.dimeo@nist.gov
;   http://www.ncnr.nist.gov/staff/dimeo
;
; LICENSE:
;  The software in this file is written by an employee of
;  National Institute of Standards and Technology
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used of if the code in this file is
;  included in another product.
;
;###############################################################################
;+
; NAME:
;       HSCN_DATA__DEFINE
;
; PURPOSE:
;
;		Object class for the fixed-window scan flavor of HFBS data.  In short this
;		class allows the user to read in the raw .HSCN data files and access any
;		data contained within.
;
; AUTHOR:
;
;       Robert M. Dimeo, Ph.D.
;		NIST Center for Neutron Research
;       100 Bureau Drive
;		Gaithersburg, MD 20899
;       Phone: (301) 975-8135
;       E-mail: robert.dimeo@nist.gov
;       http://www.ncnr.nist.gov/staff/dimeo
;
; CATEGORY:
;
;       Data reduction, DAVE project, HFBS
;
; CALLING SEQUENCE:
;
;		O = OBJ_NEW("HSCN_DATA",FILE = '20010102_01.HSCN')
;
; PARAMETERS:
;
;		FILE:	fully path qualified file name of the HSCN file
;
; METHODS:
;		INIT (F):		Standard required creation lifecycle method.
;		CLEANUP (P):	Standard destruction lifecycle method.
;		READ_RAW (F):	Reads in the raw .HSCN data. FILENAME is an input parameter.
;		GET (F):		Accessor method to obtain all of the instance data of
;						the object (see INSTANCE DATA below for a list)
;		SET (F):		Accessor method to specify all of the instance data of
;						the object
;		GET_INDEP_VAR (F):	Gets which independent variable will be used in displaying
;							the data. Output keywords are QTY, LABEL, and IDENTITY.
;		SET_INDEP_VAR (F):	Sets which independent variable will be used in displaying
;							the data. Input keywords are TSAMPLE, TCONTROL, and TIME.
;		CLONE (F):		Makes a copy of the existing data object.  CLONED_OBJECT
;						is an output keyword containing the object reference for
;						the cloned object.
;		PLOT (F):		Plots the current detector versus the current independent
;		SPLIT (F):		Splits the data into multiple data objects.  Input is an
;						array of values of the independent variable at which the
;						split will be carried out.  The output is an array of new
;						objects containing the resulting "SPLIT" data.  MSG is an
;						output keyword parameter providing information on any
; 						reason for failure.  Note that if there are N split points
;						specified then there will be N+1 resulting objects returned.
;		CREATE_ADDRUN_DATA_STRUCTURE (F):
;						Creates a data structure that can be manipulated by the
;						function named ADDRUN.
;		STUFF_ADDRUN_DATA_STRUCTURE (F):
;						If the size of the new independent variables match then
;						the relevant instance data of the object is replaced with
;						the contents of the data structure.  DSTRUCT is an input
;						parameter and MSG is an output keyword containing information
;						about why the method failed (if it failed).
;		REBIN (F):		Rebins the data between XLO and XHI with NBINS equally-spaced bins.
;						XLO, XHI, and NBINS are optional keyword parameters.  The output
;						keyword MSG contains information related to any failures of the
;						method.
;		REVERT (F):		Revert from the rebinned data to the original data set.
;		WRITE_DAVE (F):	Writes out a DAVE-format data file.
;		WRITE_HSCN (F):	Writes out a HSCN-format data file.  The keyword argument FILENAME
;						is optional and the default filename is the original filename with
;						_RED appended to the original name.  The optional keyword
;						MSG contains information related to any failures of this method.
; INSTANCE DATA:
;
;			TCONTROL:	Sensor reading of the controlling temperature (GET/SET)
;			TSAMPLE:	Sensor reading of the sample temperature (GET/SET)
;			TIME:		Time (in seconds) at which data was recorded
;						with respect to beginning of data collection. (GET/SET)
;			DATA:		The data array containing all of the counts in each
;						detector (GET/SET)
;			ERROR:		Error bar for DATA (GET/SET)
;			COMMENTS:	Scalar string variable with comments as recorded in
;						file header. (GET/SET)
;			WBM:		White beam monitor (GET/SET)
;			TBM:		Transmitted beam monitor (GET/SET)
;			FC:			Fission chamber (the "beam monitor") (GET/SET)
;			FILENAME:	Name of file with fully-qualified path (GET/SET)
;			DETECTOR:	Index (1-16) specifying the current detector (GET/SET)
;			INDEP_VAR:	Structure containing the information related to the
;						independent variable (QTY, LABEL, IDENTITY) (GET/SET)
;			HEADER:		Header info from the original data file (GET/SET)
;			TITLES:		Column titles from the original data file (GET/SET)
;			LIVETIME:	Time for which data was accrued for each point (GET/SET)
;			Q:			wavevector transfer in units of inverse angstroms (GET/SET)
;			T_OFFSET:	Offset of the time variable (GET/SET)
;			WID:		Widget ID to which this data file is associated (GET/SET)
;			TREATMENT:	String array containing the various steps in reduction (GET/SET)
;			NX:			Number of channels (times, temperatures) (GET)
;			NY:			Number of detectors (always 16) (GET)
;
; COMMON BLOCKS:
;
;		None
;
; REQUIREMENTS:
;
;		HFBS_READHSCN.PRO
;		CREATE_DAVE_POINTER.PRO
;		DREBIN.PRO
;		DATASTRUCT__DEFINE.PRO
;
; MODIFICATION HISTORY:
;
;       Written by Rob Dimeo, July 8, 2003
;		Modified WRITE_DAVE method 08/21/03-RMD
;-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro hscn_data::cleanup
ptr_free,self.pcontrol_temp,self.psample_temp,self.pdata,self.perror
ptr_free,self.ptime,self.pltime,self.ptbm,self.pwbm,self.pfc
ptr_free,(*self.pindep_var).pqty,self.pheader
ptr_free,(*self.pdep_var).pqty,(*self.pdep_var).pdqty,self.ptreatment
ptr_free,self.pindep_var,self.pq,self.ptitles,self.pdep_var
obj_destroy,self.orig_data
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::get,	tcontrol = tcontrol,		$
							tsample = tsample,			$
							time = time,				$
							data = data,				$
							error = error,				$
							comments = comments,		$
							wbm = wbm,					$
							tbm = tbm,					$
							fc = fc,					$
							filename = filename,		$
							path = path,				$
							display_name = display_name,	$
							detector = detector, 		$
							indep_var = indep_var,		$
							dep_var = dep_var,			$
							header = header,			$
							titles = titles,			$
							livetime = livetime,		$
							q = q,						$
							t_offset = t_offset,		$
							wid = wid,					$
							treatment = treatment,		$
							nx = nx,					$
							ny = ny

if arg_present(display_name) then begin
	pos = strlen(self.path)
	self.display_name = strmid(self.filename,pos)
	display_name = self.display_name
endif
if arg_present(path) then path = self.path
if arg_present(treatment) then treatment = *self.ptreatment
if arg_present(dep_var) then dep_var = *self.pdep_var
if arg_present(wid) then wid = self.wid
if arg_present(t_offset) then t_offset = self.t_offset
if arg_present(livetime) then livetime = *self.pltime
if arg_present(titles) then titles = *self.ptitles
if arg_present(header) then header = *self.pheader
if arg_present(q) then q = *self.pq
if arg_present(tcontrol) then tcontrol = *self.pcontrol_temp
if arg_present(tsample) then tsample = *self.psample_temp
if arg_present(data) then data = *self.pdata
if arg_present(error) then error = *self.perror
if arg_present(comments) then comments = self.comments
if arg_present(wbm) then wbm = *self.pwbm
if arg_present(tbm) then tbm = *self.ptbm
if arg_present(fc) then fc = *self.pfc
if arg_present(time) then time = *self.ptime
if arg_present(filename) then filename = self.filename
if arg_present(detector) then detector = self.detector
if arg_present(indep_var) then indep_var = *self.pindep_var
if arg_present(nx) then nx = n_elements(*self.ptime)
if arg_present(ny) then ny = 16
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::set,	tcontrol = tcontrol,		$
							tsample = tsample,			$
							time = time,				$
							data = data,				$
							error = error,				$
							comments = comments,		$
							wbm = wbm,					$
							tbm = tbm,					$
							fc = fc,					$
							filename = filename,		$
							path = path,				$
							display_name = display_name,$
							detector = detector,		$
							header = header,			$
							q = q,						$
							livetime = livetime,		$
							titles = titles,			$
							t_offset = t_offset,		$
							wid = wid,					$
							treatment = treatment,		$
							dep_var = dep_var,			$
							indep_var = indep_var

if n_elements(display_name) ne 0 then self.display_name = display_name
if n_elements(path) ne 0 then self.path = path
if n_elements(treatment) ne 0 then *self.ptreatment = treatment
if n_elements(wid) ne 0 then self.wid = wid
if n_elements(t_offset) ne 0 then self.t_offset = t_offset
if n_elements(livetime) ne 0 then *self.pltime = livetime
if n_elements(titles) ne 0 then *self.ptitles = titles
if n_elements(q) ne 0 then *self.pq = q
if n_elements(header) ne 0 then *self.pheader = header
if n_elements(tcontrol) ne 0 then *self.pcontrol_temp = tcontrol
if n_elements(tsample) ne 0 then *self.psample_temp = tsample
if n_elements(data) ne 0 then *self.pdata = data
if n_elements(error) ne 0 then *self.perror = error
if n_elements(comments) ne 0 then self.comments = comments
if n_elements(wbm) ne 0 then *self.pwbm = wbm
if n_elements(tbm) ne 0 then *self.ptbm = tbm
if n_elements(fc) ne 0 then *self.pfc = fc
if n_elements(time) ne 0 then *self.ptime = time
if n_elements(filename) ne 0 then self.filename = filename
if n_elements(detector) ne 0 then self.detector = detector
if n_elements(indep_var) ne 0 then begin
	*(*self.pindep_var).pqty = *indep_var.pqty
	(*self.pindep_var).label = indep_var.label
	(*self.pindep_var).identity = indep_var.identity
endif
if n_elements(dep_var) ne 0 then begin
	*(*self.pdep_var).pqty = *dep_var.pqty
	*(*self.pdep_var).pdqty = *dep_var.pdqty
	(*self.pdep_var).label = dep_var.label
	(*self.pdep_var).identity = dep_var.identity
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::set_indep_var,	tcontrol = tcontrol,	$
									tsample = tsample,		$
									time = time

if n_elements(tcontrol) eq 0 then tcontrol = 0
if n_elements(tsample) eq 0 then tsample = 0
if n_elements(time) eq 0 then time = 0

if tcontrol ne 0 then begin
	*(*self.pindep_var).pqty = *self.pcontrol_temp
	(*self.pindep_var).identity = 'TCONTROL'
	(*self.pindep_var).label = '!3T!Dcontrol!N'
endif
if tsample ne 0 then begin
	*(*self.pindep_var).pqty = *self.psample_temp
	(*self.pindep_var).identity = 'TSAMPLE'
	(*self.pindep_var).label = '!3T!Dsample!N'
endif
if time ne 0 then begin
	*(*self.pindep_var).pqty = *self.ptime+self.t_offset
	(*self.pindep_var).identity = 'TIME'
	(*self.pindep_var).label = '!3Time (seconds)'
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::set_dep_var,	tcontrol = tcontrol,	$
									tsample = tsample,		$
									time = time,			$
									fc = fc,				$
									wbm = wbm,				$
									tbm = tbm,				$
									detector = detector

if n_elements(tcontrol) eq 0 then tcontrol = 0
if n_elements(tsample) eq 0 then tsample = 0
if n_elements(time) eq 0 then time = 0
if n_elements(tbm) eq 0 then tbm = 0
if n_elements(wbm) eq 0 then wbm = 0
if n_elements(fc) eq 0 then fc = 0
if n_elements(detector) eq 0 then detector = 0
if detector ne 0 then begin
	*(*self.pdep_var).pqty = (*self.pdata)[detector,*]
	*(*self.pdep_var).pdqty = (*self.perror)[detector,*]
	(*self.pdep_var).identity = 'DETECTOR'
	(*self.pdep_var).label = '!3Detector: '+strtrim(string(detector),2)
endif
if tcontrol ne 0 then begin
	*(*self.pdep_var).pqty = *self.pcontrol_temp
	*(*self.pdep_var).pdqty = 0.0*(*self.pcontrol_temp)
	(*self.pdep_var).identity = 'TCONTROL'
	(*self.pdep_var).label = '!3T!Dcontrol!N'
endif
if tsample ne 0 then begin
	*(*self.pdep_var).pqty = *self.psample_temp
	*(*self.pdep_var).pqty = 0.0*(*self.psample_temp)
	(*self.pdep_var).identity = 'TSAMPLE'
	(*self.pdep_var).label = '!3T!Dsample!N'
endif
if time ne 0 then begin
	*(*self.pdep_var).pqty = *self.ptime+self.t_offset
	*(*self.pdep_var).pdqty = 0.0*(*self.ptime+self.t_offset)
	(*self.pdep_var).identity = 'TIME'
	(*self.pdep_var).label = '!3Time (seconds)'
endif
if tbm ne 0 then begin
	ret = self->get(tbm = tbmonitor)
	*(*self.pdep_var).pqty = tbmonitor
	*(*self.pdep_var).pdqty = sqrt(tbmonitor)
	(*self.pdep_var).identity = 'TBM'
	(*self.pdep_var).label = '!3Transmitted Beam Monitor'
endif
if wbm ne 0 then begin
	ret = self->get(wbm = wbmonitor)
	*(*self.pdep_var).pqty = wbmonitor
	*(*self.pdep_var).pdqty = sqrt(wbmonitor)
	(*self.pdep_var).identity = 'WBM'
	(*self.pdep_var).label = '!3White Beam Monitor'
endif
if fc ne 0 then begin
	ret = self->get(fc = fchamber)
	*(*self.pdep_var).pqty = fchamber
	*(*self.pdep_var).pdqty = sqrt(fchamber)
	(*self.pdep_var).identity = 'FC'
	(*self.pdep_var).label = '!3Fission Chamber'
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::get_indep_var,	qty = qty,					$
									identity = identity,		$
									label = label

if n_elements(*(*self.pindep_var).pqty) eq 0 then return,0
qty = *(*self.pindep_var).pqty
identity = (*self.pindep_var).identity
label = (*self.pindep_var).label
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::get_dep_var,	qty = qty,					$
									dqty = dqty,				$
									identity = identity,		$
									label = label

if n_elements(*(*self.pdep_var).pqty) eq 0 then return,0
qty = *(*self.pdep_var).pqty
dqty = *(*self.pdep_var).pdqty
identity = (*self.pdep_var).identity
label = (*self.pdep_var).label
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::write_dave,msg = msg,path = path
msg = ''
if n_elements(*(*self.pdep_var).pqty) eq 0 then begin
	msg = 'No data has been designated as the dependent variable'
	return,0
endif
if n_elements(*(*self.pindep_var).pqty) eq 0 then begin
	msg = 'No data has been designated as the independent variable'
	return,0
endif
; Get the independent variable
ret = self->get_indep_var(qty = xval,label = xlabel,identity = x_id)
; Now we need to determine a few things before filling up the DAVE pointer
case x_id of
'TCONTROL':	xunits = 'temperature:K'
'TSAMPLE':	xunits = 'temperature:K'
'TIME':		xunits = 'time:s'
else:		xunits = 'temperature:K'
endcase
ylabel = '!3Q (!3!sA!r!u!9 %!3!n!E-1!N)'
specificstr = {	wbm_ptr:ptr_new(*self.pwbm),			$
				tbm_ptr:ptr_new(*self.ptbm),			$
				fc_ptr:ptr_new(*self.pfc),				$
				lt_ptr:ptr_new(*self.pltime),			$
				tc_ptr:ptr_new(*self.pcontrol_temp),	$
				ts_ptr:ptr_new(*self.psample_temp),		$
				time_ptr:ptr_new(*self.ptime)			}

qty = transpose(*self.pdata)
err = transpose(*self.perror)
yval = *self.pq
ny = n_elements(yval)
ret_val = CREATE_DAVE_POINTER(	$
								DAVEPTR ,							$
								INSTRUMENT = 'HFBS',				$
								QTY = qty[*,1:ny],		$
								QTUNITS = 'intensity:arb_units',	$
								QTLABEL = 'I (arb units)',			$
								ERR = err[*,1:ny],		$
								XVALS = xval,						$
								XTYPE = 'POINTS',					$
								XUNITS = xunits,					$
								XLABEL = xlabel,					$
								YVALS = yval,					$
								YTYPE = 'POINTS',					$
								YLABEL = ylabel,					$
								YUNITS = 'wavevector:inv_ang',		$
								SPECIFICSTR = specificstr,			$
								TREATMENT = *self.ptreatment,		$
								ERMSG = errmsg						)

if ret eq 0 then begin
	msg = 'Problem creating the DAVE pointer'
	if ptr_valid(daveptr) then heap_free,daveptr
	return,0
endif
;pos = strpos(strupcase(self.filename),'.HSCN')
;init_file = strmid(self.filename,0,pos)+'_scan.dave'
init_file = file_basename(self.filename,'.hscn',/fold_case)+'_scan.dave'
filename = dialog_pickfile(dialog_parent = self.wid, filter = '*.dave', $
	/read,title = 'Type the DAVE filename',file = init_file,path = path)

if filename eq '' then begin
	msg = 'No file selected'
	return,0
endif
save,daveptr,filename = filename
heap_free,daveptr
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::clone,cloned_object = cloned_object,msg = msg
msg = ''
if n_elements(*self.pdata) eq 0 then begin
	msg = ['There is no data currently loaded', $
			'No new object has been created.']
	return,0
endif

cloned_object = obj_new('HSCN_DATA')
ret = cloned_object->set(	tcontrol = *self.pcontrol_temp,			$
							tsample = *self.psample_temp,			$
							time = *self.ptime,						$
							data = *self.pdata,						$
							error = *self.perror,					$
							comments = self.comments,				$
							wbm = *self.pwbm,						$
							tbm = *self.ptbm,						$
							fc = *self.pfc,							$
							detector = self.detector,				$
							filename = self.filename,				$
							path = self.path,						$
							display_name = self.display_name,		$
							header = *self.pheader,					$
							titles = *self.ptitles,					$
							livetime = *self.pltime,				$
							t_offset = self.t_offset,				$
							treatment = *self.ptreatment,			$
							dep_var = *self.pdep_var,				$
							indep_var = *self.pindep_var			)

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::plot,msg = msg,_Extra = extra
msg = ''

if (self.detector gt 23) then begin
	msg = 'Detector selection is out of range'
	return,0
endif
ret = self->get_indep_var(qty = x,label = xlabel)
ret = self->get_dep_var(qty = y,dqty = dy,label = ylabel)

if n_elements(x) gt 1 then begin
	plot,x,y,psym = 4,xtitle = xlabel,_Extra = extra,title = ylabel
	errplot,x,y-dy,y+dy,width = 0.0
endif else begin
	plot,[x],[y],psym = 4,xtitle = xlabel,_Extra = extra
	errplot,[x],[y]-[dy],[y]+[dy],width = 0.0
endelse
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::create_addrun_data_structure
; This function creates a data structure capable of being manipulated
; by the function ADDRUN. Note that this creates a structure with
; pointers that need to be cleaned up externally!
ret = self->get_indep_var(qty = qty)
ret = self->get(data = data,error = error,fc = fc)
x = qty & y = data[self.detector,*] & dy = error[self.detector,*]
mon = fc & dmon = sqrt(fc)
d	=	{datastruct}
d.px = ptr_new(reform(x))
d.py = ptr_new(reform(y))
d.pdy = ptr_new(reform(dy))
d.pmon = ptr_new(reform(mon))
d.pdmon = ptr_new(reform(dmon))
return,d
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::stuff_addrun_data_structure,dstruct,msg = msg
; This function creates loads in the values from an ADDRUN data structure
; (like the one created in the method CREATE_ADDRUN_DATA_STRUCTURE) and
; populates the relevant values of the HSCN data object.  If there is some
; sort of input error then the function returns a 0 and the MSG keyword
; contains a message indicating the error.
;
; Note that this routine will NOT clean up the heap variables contained
; within the data structure!
msg = ''
if n_params() eq 0 then begin
	msg = 'No data structure passed in'
	return,0
endif
ndx = n_elements(*dstruct.px)
ndy = n_elements(*dstruct.py)

ret = self->get(data = data,error = error,fc = fc,indep_var = indep_var)
dsize = size(data)
ny = dsize[1] & nx = dsize[2]
if (nx ne ndx) then begin
	msg = 'Independent variables do not match in length'
	return,0
endif
*indep_var.pqty = *dstruct.px
data[self.detector,*] = *dstruct.y
error[self.detector,*] = *dstruct.dy
ret = self->set(	fc = *dstruct.mon,		$
					data = data,			$
					error = error,			$
					dep_var = dep_var,		$
					indep_var = indep_var	)

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::read_raw,file

hfbs_readhscn,	file,time,ctemp,stemp,data,error,comments,$
    			TBM,FC,header,xout,titles,$
    			WBM = wbm,$
    			norm2Mon = 0,$
    			norm2One = 0,$
    			norm2Time = 0,$
    			liveTime = lTime

*self.ptitles = titles
*self.pheader = header
*self.pcontrol_temp = ctemp
*self.ptime = time
*self.psample_temp = stemp
*self.pwbm = wbm
*self.ptbm = tbm
*self.pfc = fc
*self.pltime = lTime
*self.pdata = data
*self.perror = sqrt(data)
self.comments = comments
ret = self->set_indep_var(/tsample)
ret = self->set_dep_var(detector = 1)
treatment = ['Data read in from the raw file: ',strtrim(file)]
treatment = [treatment,header]
*self.ptreatment = treatment

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::split,split_points,msg = msg
msg = ''
; Check for valid input
if n_params() eq 0 then begin
	msg = 'No split points have been specified'
	return,0
endif
; Check if the split points are in the domain of the currently selected
; independent variable.
n_split = n_elements(split_points)
qty = *(*self.pindep_var).pqty
min_qty = min(qty,max = max_qty)
for i = 0,n_split-1 do begin
	if 	(split_points[i] le min_qty)	or $
		(split_points[i] ge max_qty) then begin
		msg = 'At least one of the split points is out of the data range'
		return,0
	endif
endfor
n_obj = n_split + 1
;	Now get out the relevant data ranges
qty = *(*self.pindep_var).pqty
range_def = [min_qty,split_points,max_qty]
; Cycle through the split points and make sure that there
; is at least one point in the range specified.
for i = 0,n_split do begin
	ok = where((qty ge range_def[i]) and (qty le range_def[i+1]),count_points)
	if count_points lt 0 then begin
		msg = 'There are not enough data points in at least one of the' + $
			' ranges specified'
		return,0
	endif
endfor

o_array = objarr(n_obj)
for i = 0,n_split do begin
;	Create a clone of the "parent" object
	ret = self->clone(cloned_object = o,msg = msg)
	ret = o->get_indep_var(qty = qty)
	ok = where((qty ge range_def[i]) and (qty le range_def[i+1]))
;	Get the pertinent info out of the "parent" object
	ret = o->get(	tcontrol = tcontrol,		$
					tsample = tsample,			$
					time = time,				$
					data = data,				$
					error = error,				$
					wbm = wbm,					$
					tbm = tbm,					$
					livetime = livetime,		$
					fc = fc,					$
					dep_var = dep_var,			$
					treatment = treatment,		$
					display_name = display_name,	$
					indep_var = indep_var		)

	*indep_var.pqty = qty[ok]
	t_min = min(time[ok])
	time[ok] = time[ok]-t_min
	*dep_var.pqty = (*dep_var.pqty)[ok]
	*dep_var.pdqty = (*dep_var.pdqty)[ok]
	treatment = [treatment, 'This file split off from original in '+strtrim(indep_var.identity,2)]
;	Put the data with the relevant ranges into the clone
	ret = o->set(	tcontrol = tcontrol[ok],	$
					tsample = tsample[ok],		$
					time = time[ok],			$
					data = data[*,ok],			$
					error = error[*,ok],		$
					comments = comments,		$
					wbm = wbm[ok],				$
					tbm = tbm[ok],				$
					fc = fc[ok],				$
					livetime = livetime[ok],	$
					dep_var = dep_var,			$
					treatment = treatment,		$
					display_name = display_name,	$
					indep_var = indep_var		)

	o_array[i] = o
endfor

return,o_array
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::write_hscn,filename = filename,msg = msg
; This method returns a .HSCN formatted file suitable for reading into
; the FWS analysis program.
if self.filename eq '' then begin
	msg = 'No data is currently loaded in this object'
	return,0
endif
if n_elements(filename) eq 0 then begin
	filename = strupcase(self.filename)
	pos = strpos(filename,'.HSCN')
	new_filename = strmid(self.filename,0,pos)
	filename = new_filename+'_red.hscn'
endif
this_pos = strpos(filename,'.hscn')
if this_pos eq -1 then filename = filename+'_red.hscn'
; Now get all of the pertinent information out of the object
ret = self->get(	tcontrol = tcontrol,		$
					tsample = tsample,			$
					time = time,				$
					data = data,				$
					error = error,				$
					wbm = wbm,					$
					tbm = tbm,					$
					fc = fc,					$
					header = header,			$
					titles = titles,			$
					livetime = livetime,		$
					comments = comments,		$
					indep_var = indep_var)
; Now reorder the arrangement of data and error to coincide
; with that of the .HSCN data sets.
dsize = size(data)
ny = n_elements(tcontrol)
nx = dsize[1] & ny = dsize[2]
new_data = data
;print,size(tcontrol)
;print,size(tsample)
;print,size(time)
;print,size(data)
;print,size(error)
;print,size(wbm)
;print,size(tbm)
;print,size(fc)
;print,size(livetime)
;return,0
new_data[0,*] = time+self.t_offset
new_data[1,*] = livetime
new_data[2,*] = wbm
new_data[3,*] = tbm
new_data[4,*] = tcontrol	; should be the setpoint but not really necessary
new_data[5,*] = tcontrol
new_data[6,*] = tsample
new_data[7:7+15,*] = data[1:16,*]
new_data[23,*] = fc
new_titles = strmid(titles,1)
header = *self.pheader
; Ok now write the thing out
openw,lun,filename,/get_lun
; Print the header first
for i = 0,n_elements(header)-1 do printf,lun,header[i]
printf,lun,titles
for i = 0,ny-1 do begin
	printf,lun,new_data[*,i],format = '(24f15.5)'
endfor
free_lun,lun,/force
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;function hscn_data::write_dave,filename = filename,msg = msg
;if self.filename eq '' then begin
;	msg = 'No data is currently loaded in this object'
;	return,0
;endif
;if n_elements(filename) eq 0 then begin
;	filename = strupcase(self.filename)
;	pos = strpos(filename,'.HSCN')
;	new_filename = strmid(self.filename,0,pos)
;	filename = new_filename+'.dave'
;endif
;this_pos = strpos(filename,'.dave')
;if this_pos eq -1 then filename = filename+'.dave'
;; Now that we have a valid filename, let's get all of the pertinent
;; information out of the data object and populate the DAVE pointer.
;ret = self->get(	tcontrol = tcontrol,		$
;					tsample = tsample,			$
;					time = time,				$
;					data = data,				$
;					error = error,				$
;					wbm = wbm,					$
;					tbm = tbm,					$
;					fc = fc,					$
;					header = header,			$
;					t_offset = t_offset,		$
;					livetime = livetime,		$
;					treatment = treatment,		$
;					indep_var = indep_var)
;
;x = *indep_var.pqty
;xlabel = indep_var.label
;
;case indep_var.identity of
;	'TCONTROL':	xunits = 'temperature:K'
;	'TSAMPLE':	xunits = 'temperature:K'
;	'TIME':		xunits = 'time:seconds'
;	else:		xunits = 'x:arbitrary'
;endcase
;ylabel = 'Q (!3!sA!r!u!9 %!3!n!E-1!N)'
;specificstr = 	{	wavelength: 6.271,				$
;					tc_ptr:ptr_new(tcontrol),		$
;					ts_ptr:ptr_new(tsample),		$
;					time_ptr:ptr_new(time+t_offset),$
;					fc_ptr:ptr_new(fc),				$
;					header_ptr:ptr_new(header),		$
;					livetime_ptr:ptr_new(livetime),	$
;					q_ptr:ptr_new(q),				$
;					wbm_ptr:ptr_new(wbm)			}
;
;data = transpose(data) & error = transpose(error)
;ret = create_dave_pointer(	$
;							daveptr,					$
;							instrument = 'HFBS',		$
;							qty = data[*,1:16],		$
;							qtunits = 'intensity:arb',	$
;							qtlabel = 'Intensity',		$
;							err = error[*,1:16],		$
;							xvals = x,					$
;							xtype = 'POINTS',			$
;							xunits = xunits,			$
;							xlabel = xlabel,			$
;							yvals = *self.pq,			$
;							ytype = 'POINTS',			$
;							yunits = 'wavevector:A-1',	$
;							ylabel = ylabel,			$
;							specificstr = specificstr,	$
;							treatment = treatment)
;if ret eq 0 then begin
;	msg = 'Problem creating the DAVE pointer'
;	if ptr_valid(daveptr) then heap_free,daveptr
;	return,0
;endif
;; Now save the DAVE pointer
;save,daveptr,filename = filename
;; ...and free all of the heap associated with it.
;heap_free,daveptr
;return,1
;end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::normalize_to_monitor,msg = msg
msg = ''
if n_elements(*self.pdata) eq 0 then begin
	msg = 'No data is currently loaded in this object'
	return,0
endif
data = *self.pdata
error = *self.perror
fc = *self.pfc
nchan = n_elements(fc)
ndet = 16
udet = 1+bytarr(ndet)
data[1:16,*] = data[1:16,*]/(udet#fc)
error[1:16,*] = error[1:16,*]/(udet#fc)
*self.pdata = data
*self.perror = error
ret = self->get(treatment = treatment)
treatment = [treatment,'Normalized to fission chamber']
ret = self->set(treatment = treatment)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::revert
ret = self->get_indep_var(qty = qty)
ret = self.orig_data->get(	tcontrol = tcontrol,		$
							tsample = tsample,			$
							time = time,				$
							data = data,				$
							error = error,				$
							wbm = wbm,					$
							tbm = tbm,					$
							livetime = livetime,		$
							fc = fc,					$
							dep_var = dep_var,			$
							treatment = treatment,		$
							indep_var = indep_var		)

;	Put the data with the relevant ranges into the clone
ret = self->set(		tcontrol = tcontrol,		$
						tsample = tsample,			$
						time = time,				$
						data = data,				$
						error = error,				$
						comments = comments,		$
						wbm = wbm,					$
						tbm = tbm,					$
						fc = fc,					$
						livetime = livetime,		$
						dep_var = dep_var,			$
						treatment = treatment,		$
						indep_var = indep_var		)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::rebin,xlo = xlo,xhi = xhi,nbins = nbins,msg = msg
msg = ''
; Check if any data is loaded into the object
if self.filename eq '' then begin
	msg = 'No data is currently loaded in this object'
	return,0
endif
; Get the current independent variable and determine the default
; range for rebinning
qty = *(*self.pindep_var).pqty
min_qty = min(qty,max = max_qty)
if n_elements(xlo) eq 0 then xlo = min_qty
if n_elements(xhi) eq 0 then xhi = max_qty
if n_elements(nbins) eq 0 then nbins = fix(0.5*n_elements(qty))

; Create the regularly spaced independent variable
dx = (xhi-xlo)/(nbins-1.0) & x_out = xlo+dx*findgen(nbins)

x_in = reform(qty)

ret = self->get(	tcontrol = tcontrol,		$
					tsample = tsample,			$
					time = time,				$
					data = data,				$
					error = error,				$
					wbm = wbm,					$
					tbm = tbm,					$
					fc = fc,					$
					header = header,			$
					livetime = livetime,		$
					dep_var = dep_var,			$
					indep_var = indep_var		)

; Sort everything
ord = uniq(x_in,sort(x_in))
x_in = x_in[ord]
data = data[*,ord]
error = error[*,ord]
wbm = wbm[ord]
tbm = tbm[ord]
time = time[ord]
livetime = livetime[ord]
fc = fc[ord]
tsample = tsample[ord]
tcontrol = tcontrol[ord]
*(*self.pdep_var).pqty = (*(*self.pdep_var).pqty)[ord]
*(*self.pdep_var).pdqty = (*(*self.pdep_var).pdqty)[ord]
; Perform the rebinning. This is a bit disjointed and could really be performed
; in one shot but I'll take the easy (and longer) way out here...
data = transpose(data)
ddata = transpose(error);sqrt(data)
drebin,x_in,data,ddata,x_out,data_out,ddata_out,err=err,emsg=emsg,$
	/points,/to_points
data_out = transpose(data_out)
ddata_out = transpose(ddata_out)
drebin,x_in,wbm,sqrt(wbm),x_out,wbm_out,dwbm_out,err = err,emsg = emsg, $
	/points,/to_points
drebin,x_in,tbm,sqrt(tbm),x_out,tbm_out,dtbm_out,err = err,emsg = emsg, $
	/points,/to_points
drebin,x_in,fc,sqrt(fc),x_out,fc_out,dfc_out,err = err,emsg = emsg, $
	/points,/to_points
drebin,x_in,livetime,sqrt(livetime),x_out,livetime_out,dlivetime_out, $
	err = err,emsg = emsg, /points,/to_points
drebin,x_in,time,sqrt(time),x_out,time_out,dtime_out, $
	err = err,emsg = emsg, /points,/to_points
drebin,x_in,tcontrol,sqrt(tcontrol),x_out,tcontrol_out,dtcontrol_out, $
	err = err,emsg = emsg, /points,/to_points
drebin,x_in,tsample,sqrt(tsample),x_out,tsample_out,dtsample_out, $
	err = err,emsg = emsg, /points,/to_points
; Now populate the instance data of the object.
ret = self->get_indep_var(identity = identity)
*indep_var.pqty = x_out
ret = self->get(dep_var = dep_var)
drebin,x_in,reform(*dep_var.pqty),reform(*dep_var.pdqty),x_out,qty_out,dqty_out,	$
	err = err,emsg = emsg, /points,/to_points
if err ne 0 then print,emsg
*dep_var.pqty = (qty_out)
*dep_var.pdqty = (dqty_out)

ret = self->get(treatment = treatment)
this_treatment = 'Data rebinned between '+strtrim(string(xlo),2)+' and '+ $
	strtrim(string(xhi),2)+' in '+strtrim(string(nbins),2)+' bins'
treatment = [treatment,this_treatment]

ret = self->set(	tcontrol = tcontrol_out,		$
					tsample = tsample_out,			$
					time = time_out,				$
					data = data_out,				$
					error = ddata_out,				$
					wbm = wbm_out,					$
					tbm = tbm_out,					$
					fc = fc_out,					$
					header = header,				$
					livetime = livetime_out,		$
					dep_var = dep_var,				$
					treatment = treatment,			$
					indep_var = indep_var		)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function hscn_data::init,file = file
indep_var_structure = {	label:'',						$
						pqty:ptr_new(/allocate_heap),	$
						identity:''						}
dep_var_structure =   {	label:'',						$
						pqty:ptr_new(/allocate_heap),	$
						pdqty:ptr_new(/allocate_heap),	$
						identity:''						}
detAngles = [14.46,20.98,27.08,32.31,36.0,43.75,51.5,59.25,67.0,$
             74.75,82.5,90.25,98.0,105.75,113.5,121.5]
lamo = 6.27
self.detector = 1
self.ptitles = ptr_new(/allocate_heap)
self.pheader = ptr_new(/allocate_heap)
self.pq = ptr_new((4.0*!pi/lamo)*sin(0.5*!dtor*detAngles))
self.pindep_var = ptr_new(indep_var_structure)
self.pdep_var = ptr_new(dep_var_structure)
self.pcontrol_temp = ptr_new(/allocate_heap)
self.ptime = ptr_new(/allocate_heap)
self.psample_temp = ptr_new(/allocate_heap)
self.pwbm = ptr_new(/allocate_heap)
self.ptbm = ptr_new(/allocate_heap)
self.pfc = ptr_new(/allocate_heap)
self.ptreatment = ptr_new(/allocate_heap)

self.pdata = ptr_new(/allocate_heap)
self.perror = ptr_new(/allocate_heap)
self.pltime = ptr_new(/allocate_heap)
self.comments = ''
self.filename = ''
self.path = ''
self.display_name = ''
self.t_offset = 0.0
self.wid = 0L
if n_elements(file) ne 0 then begin
	ok = file_test(file)
	if not(ok) then begin
		self->cleanup
		return,0
	endif
	self.filename = file
	ret = self->read_raw(self.filename)
	ret = self->clone(cloned_object = myClone,msg = msg)
	self.orig_data = myClone
	if not(ret) then self->cleanup
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro hscn_data__define
define =	{	hscn_data,						$
				filename:'',					$
				path:'',						$
				display_name:'',				$
				t_offset:0.0,					$
				detector:1,						$
				orig_data:obj_new(),			$
				ptreatment:ptr_new(),			$
				ptitles:ptr_new(),				$
				pheader:ptr_new(),				$
				pdep_var:ptr_new(),				$
				pindep_var:ptr_new(),			$
				pcontrol_temp:ptr_new(),		$
				psample_temp:ptr_new(),			$
				ptime:ptr_new(),				$
				pltime:ptr_new(),				$
				pdata:ptr_new(),				$
				perror:ptr_new(),				$
				ptbm:ptr_new(),					$
				pwbm:ptr_new(),					$
				pfc:ptr_new(),					$
				pq:ptr_new(),					$
				comments:'',					$
				user:'',						$
				mode:'',						$
				start_time:'',					$
				wid:0L,							$
				time_per_point:0.0				}

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
