; $Id: ascii_data__define.pro,v 1.6 2005/02/09 13:38:36 dimeo Exp $
;###############################################################################
;
; NAME:
;  ASCII_DATA__DEFINE
;
; PURPOSE:
;  Class definition for the data in the ascii data reader.
;
; CATEGORY:
;  DAVE, ASCII data reader.
;
; 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:
;        ASCII_DATA__DEFINE.PRO
;
;  PURPOSE:
;
;     Object class definition for an ASCII data set.  This class includes methods
;     for reading in formated 1-d and 2-d data sets and writing out the data
;     as a DAVE pointer.
;
; 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:
;
;     DAVE project, data reduction.
;
;  CALLING SEQUENCE:
;
;     IDL>  odata = OBJ_NEW('ASCII_DATA',filename = 'c:\my_data.txt')
;
;  INPUT PARAMETERS:
;
;     NONE
;
;  INPUT KEYWORDS:
;
;     FILENAME:   Fully path-qualified name of a file containing formatted
;                 ASCII data.  The format of the data is given below.
;
;  REQUIRED PROGRAMS:
;
;     CREATE_DAVE_POINTER.PRO, DREBIN.PRO
;
;  COMMON BLOCKS:
;
;     NONE
;
;  RESTRICTIONS
;
;     IDL 5.5 or higher
;
;  MODIFICATION HISTORY:
;
;     Written by Rob Dimeo, November 5, 2003
;     Modified 11/11/03 (RMD) to read in ASCII files that contain lines with
;        no information on them.
; -
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro ascii_data::cleanup
ptr_free,self.xptr,self.yptr,self.qtyptr,self.dqtyptr,self.treatmentptr
ptr_free,self.xoptr,self.yoptr,self.qtyoptr,self.dqtyoptr,self.descriptr
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::write_dave
if n_elements(*self.descriptr) eq 0 then begin
ret_val = CREATE_DAVE_POINTER($
            DAVE_PTR ,$
            INSTRUMENT = self.instrument,$
            QTY = *self.qtyptr,$
            QTUNITS = self.qtunits,$
            QTLABEL = self.qtlabel,$
            ERR = *self.dqtyptr,$
            XVALS = *self.xptr,$
            XTYPE = self.xtype,$
            XUNITS = self.xunits,$
            XLABEL = self.xlabel,$
            YVALS = *self.yptr,$
            YTYPE = self.ytype,$
            YLABEL = self.ylabel,$
            YUNITS = self.yunits,$
            SPECIFICSTR = {instrument:self.instrument}, $
            TREATMENT = *self.treatmentptr)
endif else begin
ret_val = CREATE_DAVE_POINTER($
            DAVE_PTR ,$
            INSTRUMENT = self.instrument,$
            QTY = *self.qtyptr,$
            QTUNITS = self.qtunits,$
            QTLABEL = self.qtlabel,$
            ERR = *self.dqtyptr,$
            XVALS = *self.xptr,$
            XTYPE = self.xtype,$
            XUNITS = self.xunits,$
            XLABEL = self.xlabel,$
            YVALS = *self.yptr,$
            YTYPE = self.ytype,$
            YLABEL = self.ylabel,$
            YUNITS = self.yunits,$
            DNAME = (*self.descriptr).name,     $
            DUNITS = (*self.descriptr).units,   $
            DLEGEND = (*self.descriptr).legend, $
            DQTY = (*self.descriptr).qty,       $
            DERR = (*self.descriptr).err,       $
            SPECIFICSTR = {instrument:self.instrument}, $
            TREATMENT = *self.treatmentptr)
endelse
return,dave_ptr
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::set_property,  xlabel = xlabel,           $
                                    ylabel = ylabel,           $
                                    zlabel = zlabel,           $
                                    xunits = xunits,           $
                                    yunits = yunits,           $
                                    zunits = zunits,           $
                                    treatment = treatment,     $
                                    xtype = xtype,             $
                                    instrument = instrument,   $
                                    yindex = yindex,           $
                                    descriptr = descriptr,     $
                                    ytype = ytype

if n_elements(descriptr) ne 0 then *self.descriptr = *descriptr
if n_elements(yindex) ne 0 then begin
   zs = size(*self.qtyptr)
   case zs[0] of
   1: begin
         self.yindex = 0L
      end
   2: begin
         ny = n_elements(*self.yptr)
         if yindex gt (ny-1) then self.yindex = (ny-1) else $
            self.yindex = yindex
      end
   else:
   endcase
endif
if n_elements(xlabel) ne 0 then self.xlabel = xlabel
if n_elements(ylabel) ne 0 then self.ylabel = ylabel
if n_elements(zlabel) ne 0 then self.qtlabel = zlabel
if n_elements(xunits) ne 0 then self.xunits = xunits
if n_elements(yunits) ne 0 then self.yunits = yunits
if n_elements(zunits) ne 0 then self.qtunits = zunits
if n_elements(treatment) ne 0 then *self.treatmentptr = treatment
if n_elements(xtype) ne 0 then self.xtype = xtype
if n_elements(ytype) ne 0 then self.ytype = ytype
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::get_property,  xlabel = xlabel,              $
                                    ylabel = ylabel,              $
                                    zlabel = zlabel,              $
                                    xunits = xunits,              $
                                    yunits = yunits,              $
                                    zunits = zunits,              $
                                    treatment = treatment,        $
                                    xtype = xtype,                $
                                    instrument = instrument,      $
                                    filename = filename,          $
                                    xvals = xvals,                $
                                    yvals = yvals,                $
                                    zvals = zvals,                $
                                    dzvals = dzvals,              $
                                    ytype = ytype,                $
                                    yindex = yindex,              $
                                    descriptrstr = descriptrstr,  $
                                    data_type = data_type

if arg_present(descriptr) then begin
   if n_elements(*self.descriptr) ne 0 then begin
      descriptrstr = *self.descriptr
   endif
endif
if arg_present(data_type) then begin
   ds = size(*self.qtyptr)
   case ds[0] of
   0: data_type = 'NONE'
   1: data_type = 'SINGLE'
   2: data_type = 'MULTIPLE'
   else:
   endcase
endif
yindex = self.yindex
if arg_present(xvals) then xvals = *self.xptr
if arg_present(yvals) then yvals = *self.yptr
if arg_present(zvals) then zvals = *self.qtyptr
if arg_present(dzvals) then dzvals = *self.dqtyptr
if arg_present(xlabel) then xlabel = self.xlabel
if arg_present(ylabel) then ylabel = self.ylabel
if arg_present(zlabel) then zlabel = self.qtlabel
if arg_present(xunits) then xunits = self.xunits
if arg_present(yunits) then yunits = self.yunits
if arg_present(zunits) then zunits = self.qtunits
if arg_present(treatment) then treatment = *self.treatmentptr
if arg_present(xtype) then xtype = self.xtype
if arg_present(ytype) then ytype = self.ytype
if arg_present(filename) then filename = self.filename
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::add_treatment,treatment
if n_elements(*self.treatmentptr) eq 0 then begin
   *self.treatmentptr = treatment
endif else begin
   *self.treatmentptr = [*self.treatmentptr,treatment]
endelse
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::restore
*self.xptr = *self.xoptr
*self.yptr = *self.yoptr
*self.qtyptr = *self.qtyoptr
*self.dqtyptr = *self.dqtyoptr
ret = self->add_treatment('Restored data to original binning')
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::rebin,   xlo = xlo,  $
                              xhi = xhi,  $
                              nx = nx,    $
                              err = err,  $
                              emsg = emsg
emsg = ''
err = 0
x = *self.xptr
y = *self.yptr
z = *self.qtyptr & zsize = size(z)
dz = *self.dqtyptr
xmin_s = min(x,max = xmax_s)

if n_elements(xlo) eq 0 then xlo = xmin_s
if n_elements(xhi) eq 0 then xhi = xmax_s
if n_elements(nx) eq 0 then nx = n_elements(x)
ny = n_elements(y)

case zsize[0] of
1: begin
   ; One dimensional data set
      dx = (xhi-xlo)/(nx-1.0)
      xreb = xlo+dx*findgen(nx)
      drebin,x,z,dz,xreb,z_out,dz_out,$
         /points,/to_points,err=err,emsg=emsg
      if err ne 0 then return,0
      *self.xptr = xreb
      *self.qtyptr = z_out
      *self.dqtyptr = dz_out
   end
2: begin
   ; Two dimensional data set
      dx = (xhi-xlo)/(nx-1.0)
      znew = fltarr(nx,ny)
      dznew = fltarr(nx,ny)

      for i = 0,ny-1 do begin
         xreb = xlo+dx*findgen(nx)
         x_in = *self.xptr
         z_in = z[*,i]
         dz_in = dz[*,i]
         drebin,x_in,z_in,dz_in,xreb,z_out,dz_out,$
            /points,/to_points,err=err,emsg=emsg
         if err ne 0 then return,0
         znew[*,i] = z_out
         dznew[*,i] = dz_out
      endfor
      *self.xptr = xreb
      *self.qtyptr = znew
      *self.dqtyptr = dznew
   end
else:
endcase
ret = self->add_treatment('Rebinned data into '+strtrim(string(nx),2)+' channels')
ret = self->add_treatment('XLO='+strtrim(string(xlo),2)+', XHI='+ $
   strtrim(string(xhi),2))
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::plot,_Extra = extra
case (size(*self.qtyptr))[0] of
1: begin
      plot,*self.xptr,*self.qtyptr,_Extra = extra
      errplot,*self.xptr,*self.qtyptr-*self.dqtyptr,*self.qtyptr+*self.dqtyptr,  $
         width = 0.0
   end

2: begin
      x = *self.xptr & y = *self.yptr & z = *self.qtyptr & dz = *self.dqtyptr
      z = z[*,self.yindex] & dz = dz[*,self.yindex]
      plot,x,z, _Extra = extra
      errplot,x,z-dz,z+dz,width = 0.0
   end
else:
endcase

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::read_group_ascii,err = err,emsg = emsg
err = 0
emsg = ''
catch,the_error
if the_error ne 0 then begin
   catch,/cancel
   close,lun
   free_lun,lun,/force
   err = 1
   emsg = !error_state.msg
   return,0
endif
openr,lun,self.filename,/get_lun
s = '' & nx = 0 & ny = 0 & z = 0.0 & dz = 0.0
readf,lun,s
readf,lun,nx   &  x = fltarr(nx)
readf,lun,s
readf,lun,ny   &  y = fltarr(ny)
qty = fltarr(nx,ny) & dqty = fltarr(nx,ny)
readf,lun,s
readf,lun,x
readf,lun,s
readf,lun,y

for i = 0,ny-1 do begin
   readf,lun,s
   for j = 0,nx-1 do begin
      readf,lun,z,dz
      qty[j,i] = z & dqty[j,i] = dz
   endfor
endfor
close,lun
free_lun,lun,/force
*self.xptr = x & *self.yptr = y & *self.qtyptr = qty & *self.dqtyptr = dqty
*self.xoptr = x & *self.yoptr = y & *self.qtyoptr = qty & *self.dqtyoptr = dqty
ret = self->add_treatment('Read in grouped ascii file')
ret = self->add_treatment('Filename: '+strtrim(self.filename))
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::read_other_ascii,err = err,emsg = emsg
d = dave_read_ascii(self.filename,err = err,emsg = emsg)
if err eq 1 then return,0

*self.xptr = d.x & *self.yptr = d.y & *self.qtyptr = d.qty & *self.dqtyptr = d.dqty
*self.xoptr = d.x & *self.yoptr = d.y & *self.qtyoptr = d.qty & *self.dqtyoptr = d.dqty
ret = self->add_treatment('Read in grouped ascii file')
ret = self->add_treatment('Filename: '+strtrim(self.filename))
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::read_three_column_ascii,err = err,emsg = emsg
err = 0
emsg = ''
catch,the_error
if the_error ne 0 then begin
   catch,/cancel
   close,lun
   free_lun,lun,/force
   err = 1
   emsg = !error_state.msg
   return,0
endif
openr,lun,self.filename,/get_lun
dummy = ''
count = 0L
while not eof(lun) do begin
   readf,lun,dummy
   output = strsplit(dummy,/extract)

   if count eq 0L then begin

      if (strpos(dummy,'#'))[0] eq (-1) then begin
         if n_elements(output) gt 1 then begin
            x = float(output[0])
            y = float(output[1])
            if n_elements(output) eq 3 then dy = float(output[2])
            if n_elements(output) gt 3 then begin
               catch,/cancel
               if n_elements(lun) gt 0 then free_lun,lun,/force
               err = 1
               emsg = 'There are more than three columns present'
               return,0
            endif
            count = count + 1L
         endif
      endif

   endif else begin
       if (strpos(dummy,'#'))[0] eq (-1) then begin
         if n_elements(output) gt 1 then begin
            x = [x,float(output[0])]
            y = [y,float(output[1])]
            if n_elements(output) eq 3 then $
               dy = [dy,float(output[2])]
            count = count + 1L
         endif
      endif
   endelse
endwhile
if n_elements(dy) eq 0 then dy = 0.0*findgen(n_elements(x))
; Sort the data
xsort = sort(x)
x = x[xsort]
y = y[xsort]
dy = dy[xsort]
xuniq = uniq(x)
msg = [  'There are overlapping data points.', $
         'Therefore the application will only ', $
         +'use the unique points.']
if n_elements(x) ne n_elements(xuniq) then $
   void = dialog_message(msg)
x = x[xuniq] & y = y[xuniq] & dy = dy[xuniq]

*self.xptr = x
*self.qtyptr = y
*self.dqtyptr = dy
*self.yptr = 0.0
*self.xoptr = x
*self.qtyoptr = y
*self.dqtyoptr = dy
*self.yoptr = 0.0
close,lun
free_lun,lun,/force
ret = self->add_treatment('Read in 3-column ascii file')
ret = self->add_treatment('Filename: '+strtrim(self.filename))
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function ascii_data::init,  filename = filename
; Object initialization routine
self.filename = ''
if n_elements(filename) eq 0 then begin
   self->cleanup
   return,0
endif
if not file_test(filename) then begin
   self->cleanup
   return,0
endif

self.filename = filename
self.dir = ''
delimiter = path_sep()
last_delimiter_pos = strpos(self.filename,delimiter,/reverse_search)
self.dir = strmid(self.filename,0,last_delimiter_pos+1)
self.yindex = 0L
self.xptr = ptr_new(/allocate_heap)
self.yptr = ptr_new(/allocate_heap)
self.qtyptr = ptr_new(/allocate_heap)
self.dqtyptr = ptr_new(/allocate_heap)
self.xoptr = ptr_new(/allocate_heap)
self.yoptr = ptr_new(/allocate_heap)
self.qtyoptr = ptr_new(/allocate_heap)
self.dqtyoptr = ptr_new(/allocate_heap)
self.treatmentptr = ptr_new(/allocate_heap)
self.descriptr = ptr_new(/allocate_heap)
self.xlabel = 'x'
self.ylabel = 'y'
self.qtlabel = 'z'
self.xunits = ''
self.yunits = ''
self.qtunits = ''
self.instrument = ''
self.xtype = 'POINTS'
self.ytype = 'POINTS'
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro ascii_data__define
define = {  ascii_data,                $
            filename:'',               $
            yindex:0L,                 $
            dir:'',                    $
            xptr:ptr_new(),            $
            yptr:ptr_new(),            $
            qtyptr:ptr_new(),          $
            dqtyptr:ptr_new(),         $
            xoptr:ptr_new(),           $
            yoptr:ptr_new(),           $
            qtyoptr:ptr_new(),         $
            dqtyoptr:ptr_new(),        $
            ylabel:'',                 $
            xlabel:'',                 $
            qtlabel:'',                $
            xunits:'',                 $
            yunits:'',                 $
            qtunits:'',                $
            instrument:'',             $
            treatmentptr:ptr_new(),    $
            xtype:'',                  $
            descriptr:ptr_new(),       $
            ytype:''                   }
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;