; $Id: create_dave_pointer.pro,v 1.8 2005/02/03 18:04:12 azuah Exp $
;+
; NAME:
;       CREATE_DAVE_POINTER
;
; PURPOSE:
;
;		This function creates a DAVE pointer if one does not already exist, and/or
;		fills it with data of the user's choice.  If successful, the function returns
;		a 1 else it returns 0.  Note that the user must specify DAVEPTR (which can be
;		undefined when it is called) and QTY at the minimum.
;
; 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:
;
;       Utility, DAVE project
;
; CALLING SEQUENCE:
;
;
;	ret_val = CREATE_DAVE_POINTER(	$
;								DAVEPTR ,					$
;								INSTRUMENT = instrument,	$
;								QTY = qty,					$
;								QTUNITS = qtunits,			$
;								QTLABEL = qtlabel,			$
;								ERR = err,					$
;								XVALS = xvals,				$
;								XTYPE = xtype,				$
;								XUNITS = xunits,			$
;								XLABEL = xlabel,			$
;								YVALS = yvals,				$
;								YTYPE = ytype,				$
;								YLABEL = ylabel,			$
;								YUNITS = yunits,			$
;								SPECIFICSTR = specificstr,	$
;								TREATMENT = treatment,		$
;								DNAME = dname,				$
;								DUNITS = dunits,			$
;								DLEGEND = dlegend,			$
;								DQTY = dqty,				$
;								DERR = derr,				$
;								ERMSG = errmsg				)
;
; PARAMETERS (REQUIRED)
;
;	DAVEPTR:	This can either be an input or output pointer.  If it is an input
;				parameter then it must be a properly defined DAVE pointer as defined
;				in DAVE.PRO for instance.
;
;
; REQUIRED INPUT KEYWORDS
;
;	QTY:		Double of float array containing the data variable.  Can be one or two
;				dimensional where the size can be one of the following
;				(nx,ny), (nx+1,ny), (nx,ny+1),	(nx+1,ny+1),(nx),(nx+1) where
;				nx is the length of the first independent variable and ny is the
;				length of the second independent variable.
;
;  OPTIONAL INPUT KEYWORDS
;
;	ERR:		Double of float array containing the error associated with the measured
;				quantity, QTY.  ERR must have the same dimension and size as QTY.
;	INSTRUMENT:	String variable describing instrument.
;	XVALS:		Double or float array containing the first independent variable for
;				QTY.  If not provided then a simple index array is determined based
;				on the size of QTY.
;	YVALS:		Double or float array containing the second independent variable for
;				QTY.  If not provided then a simple index array is determined based
;				on the size of QTY.
;	QTUNITS:	string variable specifying the units of QTY
;	QTLABEL:	string variable specifying the plot label for QTY
;	XTYPE:		String variable specifying if the first independent variable, XVALS,
;				is "POINTS" or "HISTO".
;	YTYPE:		String variable specifying if the second independent variable, YVALS,
;				is "POINTS" or "HISTO".
;	XLABEL:		string variable specifying the plot label for the first independent
;				variable, XVALS.
;	YLABEL:		string variable specifying the plot label for the second independent
;				variable, YVALS.
;	XUNITS:		string variable specifying the units of XVALS
;	YUNITS:		string variable specifying the units of YVALS
;	SPECIFICSTR:	structure containing any instrument specific information the
;					user wishes to include in the DAVE pointer.  Can contain any
;					variable type in its fields.
;	TREATMENT:	string array of any length containing the treatment of the data.
;
;	DNAME:		string name of the variable/parameter to be described in the
;				descriptive pointer in the DAVEPTR called DESCRIPTR.
;	DUNITS:		string variable specifying the units of the descriptive variable.
;	DLEGEND:	string variable specifying a description of the variable
;	DQTY:		value of the descriptive variable.
;	DERR:		value specifying the uncertainty of the descriptive variable.
;
;
; OPTIONAL OUTPUT KEYWORDS
;
;	ERMSG:		string variable specifying the cause of an error in which the function
;				returns 0.
;
; COMMON BLOCKS:
;
;		None
;
;
; EXAMPLE USAGE:
;
;	(a). As a first simple case, consider creating a one-dimensional data set "from scratch".
;
;		xlo = -10.0 & xhi = 10.0 & nx = 100 & dx = (xhi-xlo)/(nx-1.0)
;		x = xlo+dx*findgen(nx)
;		n = 1.e3
;		gamma = 1.0 & center = 0.0
;		bg = 0.1*n
;		z = bg + (n*gamma/!pi)/((x-center)^2+gamma^2)
;		qty = fltarr(nx)
;		for i = 0,nx-1 do begin
;			qty[i] = randomn(s,1,poisson = z[i])
;		endfor
;		err = sqrt(qty)
;		plot,x,qty,psym = 4
;		errplot,x,qty-err,qty+err,width = 0.0
;
;		RET = CREATE_DAVE_POINTER(	DAVEPTR,					$
;									QTY = qty,					$
;									ERR = err,					$
;									XVALS = x,					$
;									ERMSG = ermsg)
;		print,'Error message:',ermsg
;
;	(b). On HFBS we can assume that we have already defined qty, err, energy, temperature
;		 and q.  Therefore we can simply call the function as follows:
;
;	RET_VAL = CREATE_DAVE_POINTER(	DAVEPTR,						$
;									INSTRUMENT = 'HFBS',			$
;									QTY = qty,						$
;									ERR = err,						$
;									XVALS = energy,					$
;									XUNITS = 'energy:uev',			$
;									XTYPE = 'POINTS',				$
;									YVALS = q,						$
;									YUNITS = 'wavevector:A-1',		$
;									YTYPE = 'POINTS',				$
;									TREATMENT = ['Converted from time to energy',$
;												'Normalized to beam monitor'],	$
;									DNAME = 'T',					$
;									DUNITS = 'temperature:K',		$
;									DLEGEND = 'Temperature',		$
;									DQTY = 2.30,						$
;									DERR = 0.05	)
;
;###############################################################################
;
; 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.
;
;###############################################################################
;
;
; MODIFICATION HISTORY:
;
;       Written by Rob Dimeo, March 18, 2003
;		Wrote documentation for function-RMD (03/19/03)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function create_dave_pointer,	$
							daveptr,					$
							instrument = instrument,	$
							qty = qty,					$
							qtunits = qtunits,			$
							qtlabel = qtlabel,			$
							err = err,					$
							xvals = xvals,				$
							xtype = xtype,				$
							xunits = xunits,			$
							xlabel = xlabel,			$
							yvals = yvals,				$
							ytype = ytype,				$
							yunits = yunits,			$
							ylabel = ylabel,			$
							specificstr = specificstr,	$
							treatment = treatment,		$
							dname = dname,				$
							dunits = dunits,			$
							dlegend = dlegend,			$
							dqty = dqty,				$
							derr = derr,				$
							ermsg = errmsg
errmsg = 'No errors'
; Was a DAVE pointer set as a parameter?
if n_params() eq 0 then begin
	errmsg = 'DAVEPTR is a required parameter (either input or output)'
	return,0
endif

if n_elements(qty) eq 0 then begin
	errmsg = 'QTY is a required keyword'
	return,0
endif

if n_elements(err) eq 0 then begin
	err = 0.0*qty
endif

; Check the dimensions of QTY and ERR and do some error handling
; here.
qty_size = size(qty) & err_size = size(err)
if qty_size[0] eq 2 and n_elements(yvals) eq 0 then begin
	yvals = findgen(qty_size[2])
endif
if n_elements(xvals) eq 0 then xvals = findgen(qty_size[1])

nxvals = n_elements(xvals) & nyvals = n_elements(yvals)
if qty_size[0] ne err_size[0] then begin
	errmsg = 'Dimensions of QTY and ERR are incompatible'
	return,0
endif
case qty_size[0] of
1:	begin
		nx = qty_size[1]
		if (err_size[1] ne nx) then begin
			errmsg = 'QTY and ERR must be the same size'
			return,0
		endif
		if (nxvals+1) eq qty_size[1] then xtype = 'HISTO' else xtype = 'POINTS'
		ytype = ''
	end
2:	begin
		nx = qty_size[1] & ny = qty_size[2]
		if (err_size[1] ne nx) or (err_size[2] ne ny) then begin
			errmsg = 'QTY and ERR must be the same size'
			return,0
		endif
		if (nxvals+1) eq qty_size[1] then xtype = 'HISTO' else xtype = 'POINTS'
		if (nyvals+1) eq qty_size[2] then ytype = 'HISTO' else ytype = 'POINTS'
	end
else:	$
	begin
		errmsg = 'QTY must be 1 or 2 dimensional'
		return,0
	end
endcase

; Fill in some default values if the user has not filled them in.
if n_elements(yvals) eq 0 then yvals = 0.0
if n_elements(treatment) eq 0 then $
	treatment = 'Created a DAVE pointer on: ' + systime()
if n_elements(qtunits) eq 0 then qtunits = 'arbitrary units'
if n_elements(xunits) eq 0 then xunits = 'index:number'
if n_elements(yunits) eq 0 then yunits = 'index:number'
if n_elements(xlabel) eq 0 then xlabel = 'x index'
if n_elements(ylabel) eq 0 then ylabel = 'y index'
if n_elements(qtlabel) eq 0 then qtlabel = 'Counts (arb units)'
if n_elements(instrument) eq 0 then instrument = 'No instrument specified'

;================;
; If daveptr is a valid pointer then use de-referencing to populate it
if ptr_valid(daveptr) then begin
	hist = {x:xvals,y:yvals,qty:qty,err:err}
	*(*(*daveptr).datastrptr).commonstr.histptr = hist
	(*(*daveptr).datastrptr).commonstr.histunits = qtunits
	(*(*daveptr).datastrptr).commonstr.instrument = instrument
	(*(*daveptr).datastrptr).commonstr.histlabel = qtlabel
	(*(*daveptr).datastrptr).commonstr.xunits = xunits
	(*(*daveptr).datastrptr).commonstr.yunits = yunits
	(*(*daveptr).datastrptr).commonstr.xlabel = xlabel
	(*(*daveptr).datastrptr).commonstr.ylabel = ylabel
	*(*(*daveptr).datastrptr).commonstr.treatmentptr = treatment
	if n_elements(specificstr) ne 0 then $
		*(*(*daveptr).datastrptr).specificptr = specificstr
	if	(n_elements(dname) ne 0) and (n_elements(dunits) ne 0) and $
		(n_elements(dlegend) ne 0) and (n_elements(dqty) ne 0) and $
		(n_elements(derr) ne 0) then begin
		description = 	{	descriptrstr,	$
							name:'',		$
							units:'',		$
							legend:'',		$
							qty:0.0,		$
							err:0.0			$
						}

		if	(n_elements(dname) ne 0) and (n_elements(dunits) ne 0) and $
			(n_elements(dlegend) ne 0) and (n_elements(dqty) ne 0) and $
			(n_elements(derr) ne 0) then begin
			description.name = dname
			description.units = dunits
			description.legend = dlegend
			description.qty = dqty
			description.err = derr
		endif

		(*daveptr).descriptr = ptr_new(description,/no_copy)
	endif
	return,1
endif

;================;
; The DAVE pointer must not be valid.  Therefore we will create it from
; scratch.
histptr = ptr_new(/allocate_heap)
*histptr = 	{	qty:qty,				$
				err:err,				$
				x:xvals,				$
				y:yvals					}

treatmentptr = ptr_new(treatment,/no_copy)

commonstr = {	histptr:histptr,		$
				instrument:instrument,	$
				xlabel:xlabel,			$
				ylabel:ylabel,			$
				xtype:xtype,			$
				xunits:xunits,			$
				ytype:ytype,			$
				yunits:yunits,			$
				histlabel:qtlabel,	$
				histunits:qtunits,	$
				treatmentptr:treatmentptr,	$
				commonstrptr:ptr_new()	}
specificptr = ptr_new(/allocate_heap)

if n_elements(specificstr) ne 0 then $
		*specificptr = specificstr
datastr = {commonstr:commonstr,specificptr:specificptr}
datastrptr = ptr_new(datastr,/no_copy)

description = 	{	descriptrstr,	$
					name:'',		$
					units:'',		$
					legend:'',		$
					qty:0.0,		$
					err:0.0			$
				}
daveStr =    {davePtrStr, $
              dataStrPtr:dataStrPtr, $
              descriPtr:ptr_new(description,/no_copy)}

; Do all of the error checking for the contents of DESCRIPTR
if	(n_elements(dname) ne 0) and (n_elements(dunits) ne 0) and $
	(n_elements(dlegend) ne 0) and (n_elements(dqty) ne 0) and $
	(n_elements(derr) ne 0) then begin
	(*davestr.descriptr).name = dname
	(*davestr.descriptr).units = dunits
	(*davestr.descriptr).legend = dlegend
	(*davestr.descriptr).qty = dqty
	(*davestr.descriptr).err = derr
endif

daveptr = ptr_new(davestr,/no_copy)

; Return a 1 if successful
return,1
end
