esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% GHSCANS.MAC 
#
#%NAME%
#  Macros implementing ghost scans.
#
#%OVERVIEW%
#
#  Ghost scans are motor scans that don't make use of any of the resources 
#  employed by the standard %B%spec%B% scans. They don't write neither in 
#  the data file nor on the screen, they don't modify the variables used by 
#  the standard scans and if they plot, that is optional, they do it in a 
#  different window.%BR%
#  The purpose behind ghost scans is to provide a method to perform motor 
#  scans during the execution of other scans without perturbing them.
#  By using ghost scans one can trigger alignement operations when a ordinary 
#  scan is running. The typical application is to realign some critical
#  component, like a monochromator, either periodically or when an intensity
#  drop is detected.%BR%
#%BR%
#  The scanning macros require the same parameters that the equivalent
#  standard scans. One exception is the %B%ghlineup%B% macro that in addition
#  to the parameters of the standard %dscan% macro accepts an optional
#  threshold value.
#  One can set other options (counters to record, plotting window, etc.) by
#  using the %B%ghopt%B% and %B%ghoptadd%B% macros. Once some options are set
#  in this way they affect all the following ghost scans until they are reset
#  or modified. The available options are:
#  %UL%
#  %LI%%B%counters=<cnt_list>%B% - comma separated list of counters to record.
#  %LI%%B%plot%B% or %B%plot=<n>%B%  - plots the scan data in window <n>.
#  %LI%%B%title=<string>%B% - sets plot title to <string>.
#  %LI%%B%verbose%B% - sets verbode mode.
#  %XUL%
#%BR%
#  One can retrieve information about the last ghost scan in the global array 
#  GHRES[]. The information that is generally available is the following:
#  %UL%
#  %LI%GHRES[%B%"npoints"%B%] - Number of points actually measured.
#  %LI%GHRES[%B%"ncounters"%B%] - Number of counters. 
#  %LI%GHRES[%B%"aborted?"%B%] - flag indicating if the scan was aborted or not.
#  %LI%GHRES[%B%"cnt_mne"%B%][0:ncounters] - counter mnemonics.
#  %XUL%
#  In addition to the previous values, GHRES[] may contain other information
#  specific to the particular scan.%BR%
#  The scan data is stored in the global array GHDATA[npoints][1+ncounters].%BR%
#  %BR%
#  These macros are intended to be used inside other macros and not from
#  the command line. However they should work if used from the command line
#  for testing purposes (see the "verbose" option). They could be also used
#  by people who want to do some alignment without modifying the current data
#  file.
#
#%EXAMPLE%
#
#  %DL%
#  %DT%ghopt counters=det,mon plot
#  %DD%Activates the counters `det' and `mon' and activates plotting.
#  %DT%ghdscan slit -5 5 20 1
#  %DD%performs a dscan in ghost mode.
#  %DT%ghadd plot=3 peak=COM ; ghlineup mono -.01 .01 40 1 .8
#  %DD%Selects the window 3 for plotting, sets the peak criterium to the
#  center of mass (COM) and performs a line up monochromator scan with a
#  threshold of 80%.
#  %XDL%

#%UU% <motor> <star> <finish> <intervals> <time>
#%MDESC%
#  Ghost version of %B%ascan%B%.
#
def ghascan '{
   if ($# != 5) {
      print "Usage:  ghscan  motor start finish intervals time"
      exit
   } 
   _ghchkopt()
   _ghscan("$1", $2, $3, $4, $5)
}'


#%IU% <motor>
#%MDESC% this is here to complie with _check0 redefinition on id28 that is used for hexapode mihexz backlash correction. 
def _ghcheck0 '
        if ("$1" != motor_mne($1) && "$1" != $1) {
                eprint "Invalid motor name:  $1"
                exit
        }
'

#%UU% <motor> <rel_star> <rel_finish> <intervals> <time>
#%MDESC%
#  Ghost version of %B%dscan%B%.%BR%
#  If the macro is interrupted with Ctrl-C, the motor is not moved to the initial position. The initial motor position is stored in GHRES["prev_pos"].
#
def ghdscan '{

   if ($# != 5) {
      print "Usage:  ghdscan  motor start finish intervals time"
      exit
   } 
   _ghchkopt()

   _ghcheck0 "$1"
   waitall
   get_angles
   GHRES["prev_pos"] = A[$1]
   _ghscan("$1", GHRES["prev_pos"]+($2), GHRES["prev_pos"]+($3), $4, $5)
   waitmove
   get_angles
   A[$1]=GHRES["prev_pos"]
   move_em
   move_poll
   get_angles
}'

#%UU% <motor> <rel_star> <rel_finish> <intervals> <time> [<threshold>]
#%MDESC%
#  Ghost version of %B%lineup%B%. The scan runs as a %B%dscan%B% but if a
#  peak is found when the scan is completed, the motor is moved to the peak
#  position. The definition of the peak position can be selected with
#  %B%ghopt%B% or %B%ghoptadd%B% among the following:%BR%
#  %UL%
#  %LI%%B%peak=PK%B% - peak value (this is the default).
#  %LI%%B%peak=CEN%B% - center of the FWHM.
#  %LI%%B%peak=COM%B% - center of mass.
#  %XUL%
#  A threshold level can be optionally defined with a fifth parameter. 
#  The macro considers that a peak is found when the intensity is above such
#  a threshold. If not, the motor is moved to the initial position as if it
#  were a %B%dscan%B%.%BR%
#  If <threshold> is set to a positive value is it is interpreted as a relative
#  value and the actual threshold is calculated as this value multiplied by 
#  the counts at the current position (the counters are run once before
#  starting the scan).
#  If <threshold> is a negative value, its absolute value is taken as actual
#  threshold. If not specified, the threshold is set to zero.%BR%
# %BR%
#  The macro provides information about the alignment in the global array
#  %B%GHRES%B%. The following elements are available:
#  %UL%
#  %LI%GHRES[%B%"counter"%B%] - mnemonic of the counter used for the alignment.
#  %LI%GHRES[%B%"prev_pos"%B%] - initial motor position.
#  %LI%GHRES[%B%"prev_count"%B%] - initial counts (only if a relative threshold is set).
#  %LI%GHRES[%B%"threshold"%B%] - absolute threshold value.
#  %LI%GHRES[%B%"peak"%B%] - peak definition (PK, CEN or COM).
#  %LI%GHRES[%B%"peak_found"%B%] - flag.
#  %LI%GHRES[%B%"peak_pos"%B%] - peak position.
#  %LI%GHRES[%B%"peak_count"%B%] - intensity at the peak position.
#  %XUL%
#
def ghlineup '{
   local threshold myDET msg

   if ($# != 5 && $# != 6) {
      print "Usage:  ghlineup  motor start finish intervals time [threshold]"
      exit
   } 

   _ghchkopt()

   _ghcheck0 "$1"
   waitall
   get_angles
   GHRES["prev_pos"] = A[$1]

   myDET = GHopt["counter"][0]
   GHRES["counter"] = cnt_mne(myDET)

   if ($# > 5) {
      if (($6) > 0) {
#     There is a good reason to comment out the following lines:
#         count $5
         count_em $5
         waitcount
         get_counts
         threshold = ($6) * (GHRES["prev_count"] = S[myDET])
      } else {
         delete GHRES["prev_count"]
         threshold = fabs($6)
      }
      GHRES["threshold"] = threshold
      if (GHopt["verbose"])
         fprintf("tty", "\nPeak threshold for `%s\' (%s): %g\n\n", \
                   cnt_name(myDET), cnt_mne(myDET), threshold)
   } else {
      delete GHRES["threshold"]
      if (GHopt["verbose"])
         fprintf("tty", "\nUsing `%s\' (%s). No peak threshold.\n", \
                   cnt_name(myDET), cnt_mne(myDET))
   }

   _ghscan("$1", GHRES["prev_pos"]+($2), GHRES["prev_pos"]+($3), $4, $5)

   if (GHopt["peak"] == "COM")
      GHRES["peak_pos"] = array_op("com", GHDATA[][0], GHDATA[][1])
   else if (GHopt["peak"] == "CEN")
      GHRES["peak_pos"] = array_op("cfwhm", GHDATA[][0], GHDATA[][1])
   else
      GHRES["peak_pos"] = array_op("x_at_max", GHDATA[][0], GHDATA[][1])

   GHRES["peak_count"] = \
          interpol(GHDATA, 0, 1, array_op("rows", GHDATA), GHRES["peak_pos"])
   GHRES["peak_found"] = (GHRES["peak_count"] > threshold)
   if (GHopt["verbose"]) {
      if (GHRES["peak_found"])
         fprintf("tty", "Peak found: %g at %g.\n", GHRES["peak_count"], GHRES["peak_pos"])
      else
         fprintf("tty", "No peak found.\n")
   }
   waitmove
   get_angles
   A[$1]=(GHRES["peak_found"])? GHRES["peak_pos"] : GHRES["prev_pos"]

   move_em
   move_poll
   get_angles
   if (GHopt["gfilter"] != "") {
      if (GHRES["peak_found"])
         msg = sprintf("Peak found at %g (%s). \`$1\' moved by %g.",\
                            GHRES["peak_pos"], GHopt["peak"],\
                            GHRES["peak_pos"]-GHRES["prev_pos"])
      else
         msg = "Peak not found"
      ghplot(msg)
   }

   if (GHopt["verbose"])
      fprintf("tty", "Motor \`$1\' moved to %g.\n", A[$1])
}'

#%IU% ()
#%MDESC%
#  Checks the options in the current option set and initializes some values.
#
def _ghchkopt() '{
   global GHopt[] GHRES[]
   local aux auxarr[] cnt i
   local filter

   
   for (i in GHopt) delete GHopt[i]
   for (i in GHRES["cnt_mne"]) delete GHRES["cnt_mne"][i]
   GHRES["npoints"] = GHRES["ncounters"] = 0
   GHRES["aborted?"] = 1
   aux = split(GHOPT["counters"], auxarr, ",")
   if (aux) {
      GHopt["ncounters"] = aux
      for (i = 0; i < aux; i++) {
         if ((cnt = cnt_num(auxarr[i])) < 0) {
            print i, "\`"auxarr[i]"\' is not a valid counter."
            exit
         }
         GHopt["counter"][i] = cnt
         GHRES["cnt_mne"][i] = auxarr[i]
      }
   } else {
      GHopt["ncounters"] = 1
      GHopt["counter"][0] = DET
      GHRES["cnt_mne"][0] = cnt_mne(DET)
   }
   GHRES["ncounters"] = GHopt["ncounters"]

   if ( whatis(\'GHOPT["plot"]\') != 0) {
      aux = int(GHOPT["plot"])
      filter = (aux < 1 || aux > 5)? 4 : aux
      GHopt["gfilter"] = "filter" filter
   }

   GHopt["title"] = ("title" in GHOPT)?   \
            GHOPT["title"]:sprintf("%s %d (ghost)", SPEC, filter)
   GHopt["peak"] = ("peak" in GHOPT)? GHOPT["peak"] : "PK"
   GHopt["verbose"] = ("verbose" in GHOPT)
}'


#%IU% (<motor_mne>, <start>, <finish>, <inetrvals>, <time>)
#%MDESC%
#  The macro that does the actual scan.
#

def _ghscan(mot, start, finish, nint, dt) '{
   local delta npts lcnt lplot ltitle
   local motornum nint1 

   if ((motornum=motor_num(mot)) < 0) {
      print "Motor mnemonic not valid"
      exit
   }
   if ((nint1 = int(nint)) <= 0) {
      print "Invalid number of intervals"
      exit
   }
   delta = (finish - start)/nint1

   array GHDATA[nint1+1][GHopt["ncounters"]+1]
   array_op("row_wise", GHDATA, 1)

   waitall; get_angles;
   for (npts = 0; npts <= nint1; npts++) {
      A[motornum] = start + npts * delta
      move_em; move_poll; get_angles
      if (!set_sim(-1) && _sleep) {
          do_sleep _sleep
      }
#     There is a good reason to comment out the following lines:
#     measure0
#     count dt
      count_em dt
      waitcount
      get_counts
      measure1
#      measure2
      GHDATA[npts][0] = A[motornum]
      for (i = 0; i < GHopt["ncounters"]; i++)
         GHDATA[npts][i+1] = S[GHopt["counter"][i]]
      GHRES["npoints"] = npts+1
      if (GHopt["verbose"]) print GHDATA[npts][]

      ghplot(motornum, start, finish, npts)
   } 
   GHRES["aborted?"] = 0
   ghplot(motornum, start, finish, -1, "")
}'


#%IU% (<motor>, <start>, <finish>, <npts>, <label>)
#%MDESC%
#  
#
def ghplot(mot_label, start, finish, npts, text) '{
   local mot label lab_width aux

   if (GHopt["gfilter"] != "") {
      lab_width = 71
      plot_cntl(GHopt["gfilter"])
      if (whatis("mot_label") &  0x00100000) {
         mot = mot_label
         if (npts <= 0) {
            plot_cntl(sprintf("colors=%s",rplot_col))
            plot_cntl("open")
            plot_cntl(sprintf("title=%s",GHopt["title"]))
            plot_cntl("erase")
            plot_cntl("-ebars")
            plot_range(start, finish, YMIN, "auto")
            plot_move(0,2,cnt_name(GHopt["counter"][0]))
            plot_move(0,-1,sprintf("%.8s", motor_name(mot)))

         }
         plot_cntl("addpoint")
         if (npts >= 0) {
            array_plot(GHDATA[:npts][])
            plot_move(9, 2, gh_plot_res(lab_width))
         } else {
            array_plot(GHDATA[][])
            plot_move(9, 1, gh_plot_res(lab_width))
         }
         if (text)
            plot_move(9, 1, text)
      } else {
         label = mot_label
         aux = (lab_width + length(label))/2
         plot_move(9, 2, sprintf("%*s%*s", aux, label, \
                                  lab_width > aux? lab_width-aux:0, ""))
      }
      plot_cntl("filter1")
   }
}'

#%UU% [<option> | <option>=<value>] ...
#%MDESC%
#  Initializes the current option set to the options in the parameter list.
#  Previously defined options are deleted.%BR%
#  The available options are:%BR%
#
def ghopt 'global GHOPT[]; for(i in GHOPT) delete GHOPT[i];; _ghoptadd("$*")'

#%UU% [<option> | <option>=<value>] ...
#%MDESC%
#  Adds options the parameter list to the current set.
#
def ghoptadd '_ghoptadd("$*")'
 
#%IU% (<option_string>)
#%MDESC%
#  Adds the options in <option_string> to the current set.
#
def _ghoptadd(optstr) '{
   global GHOPT[]
   local i iopt opt j

   if (optstr == "") {
      GHOPT[":)"] = 0; delete GHOPT[":)"]
   } else {
      split(optstr, opt)
      for (i in opt) {
         iopt = opt[i]
         if (j = index(iopt, "="))
            GHOPT[substr(iopt,1,j-1)] = substr(iopt,j+1)
         else
            GHOPT[iopt] = ""
      }
   }
}'

#%UU% [<option>] ...
#%MDESC%
#  (Not yet implemented).
#
def ghoptremove '{

}'


def gh_MIN   'array_op("min",      GHDATA[][0], GHDATA[][1])'
def gh_MAX   'array_op("max",      GHDATA[][0], GHDATA[][1])'
def gh_xMIN  'array_op("x_at_min", GHDATA[][0], GHDATA[][1])'
def gh_xMAX  'array_op("x_at_max", GHDATA[][0], GHDATA[][1])'
def gh_SUM   'array_op("sum",      GHDATA[][0], GHDATA[][1])'
def gh_SUMSQ 'array_op("sumsq",    GHDATA[][0], GHDATA[][1])'
def gh_FWHM  'array_op("fwhm",     GHDATA[][0], GHDATA[][1])'
def gh_CFWHM 'array_op("cfwhm",    GHDATA[][0], GHDATA[][1])'
def gh_COM   'array_op("com",      GHDATA[][0], GHDATA[][1])'
def gh_LHMX  'array_op("lhmx",     GHDATA[][0], GHDATA[][1])'
def gh_UHMX  'array_op("uhmx",     GHDATA[][0], GHDATA[][1])'



# 2013/02/08 rh - added local aux / pb in id28 with a global aux[]
#%IU%
#%MDESC%
#
def gh_plot_res(lab_len) '{
   local label, aux;

   label = sprintf(\
        "Peak @ %.5g%s is %.5g  COM @ %.5g%s  FWHM is %.5g%s @ %.5g%s",\
        gh_xMAX,UL,gh_MAX,gh_COM,UL,gh_FWHM,UL,gh_CFWHM,UL)

   if (lab_len > 0) {
      aux = (lab_len + length(label))/2
      return(sprintf("%*s%*s", aux, label, lab_len > aux? lab_len-aux:0, ""))
   } else
      return(label)
}'


#%MACROS%
#%IMACROS%
#%AUTHOR% P.Fajardo, (Original 6/97).
#  $Revision: 3.5 $ / $Date: 2013/02/08 18:29:39 $
#%TOC%