#%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%
|