esrf

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

#%TITLE% KSCAN.MAC
#%NAME%
#   Macros to perform scans on K.
#%DESCRIPTION%
#   This macro set allows to make scans in energy with several
#   regions around an edge.
#   Each region can have different spacing between points as
#   well as to have different collection time per region.
#%SETUP%
#   A pseudo motor energy has to be available.
#   By default a set of parameters is given. This set of parameters
#   can be implemented by a call to the macro *kscan_defaults*.
#   Otherways the parameters can be changed by calling to *kscan_setup*.
#%USAGE%
#
#     kscan <mot> <ene> <>
#
#%EXAMPLE%
#
#     kscan energy_motor 7.111 2
#
#   Performs a kscan of the motor energy_motor whith 7.111 taken as
#   the edge energy (all parameters in kscan are referred to the edge
#   position in order to allow a single profile to be used at different
#   edges).
#%END%

need spec_utils


#%UU%(<k>)
#%MDESC%
#    Given a value of k, returns the corresponding value in energy above
# the edge in eV.
def kscan_calcE(k) '{

    # what is this 0.51242415 ???

	return( pow( (k/0.51242415), 2 ) )
}'


#%UU%(<delta_e_in_eV>)
#%MDESC%
#    Given a value of the energy (in eV above the edge) as input, returns
# the corresponding value in k.
def kscan_calcK(delta_e_in_eV)'{

    # what is this 0.51242415 ???

	return(0.51242415 * sqrt(delta_e_in_eV))
}'


#%UU%
#%MDESC%
#    Interactive definition of the energy regions.
def kscan_setup '{
    local i

    global KSCAN_N_PRE  KSCAN_N_POST # numbers of pre/post regions.
    global KSCAN_PRE  KSCAN_POST
    global KSCAN_EDGE_1  KSCAN_EDGE_2  KSCAN_EDGE_INC  KSCAN_EDGE_T  KSCAN_EDGE_K
    global KSCAN_E0
    global KSCAN_NPTS
    global KSCAN_TIME # time factor


    # energy regions table
    global array KSCAN_E[4000]
    # time regions table
    global array KSCAN_T[4000]


    #### Definition of PRE-egde regions.
    KSCAN_N_PRE = getval("Enter number of pre-edge regions ", KSCAN_N_PRE)
    KSCAN_PRE[0][0] = KSCAN_PRE[0][0]

    for (i=0 ; i<KSCAN_N_PRE ; i++){
        printf("Defining pre-edge region %i\n", i+1)
        KSCAN_PRE [i] [0] = getval("Enter energy relative to edge (in eV)", KSCAN_PRE [i] [0])
        KSCAN_PRE [i] [1] = getval("Enter energy increment (in eV)",        KSCAN_PRE [i] [1])
        KSCAN_PRE [i] [2] = getval("Enter collection time in seconds",      KSCAN_PRE [i] [2])
    }

    KSCAN_EDGE_1   = getval("Enter starting edge region energy (in eV relative to edge):", KSCAN_EDGE_1)
    KSCAN_EDGE_2   = getval("Enter final  edge  region  energy (in eV relative to edge):", KSCAN_EDGE_2)
    KSCAN_EDGE_INC = getval("Enter energy increment in edge region:",                      KSCAN_EDGE_INC)
    KSCAN_EDGE_T   = getval("Enter collection time in seconds:",                           KSCAN_EDGE_T)

    KSCAN_EDGE_K   = kscan_calcK(KSCAN_EDGE_2)


    #### Definition of POST-egde regions.
    KSCAN_N_POST = getval("Enter number of  post-edge regions ", KSCAN_N_POST)
    KSCAN_POST[0][0] = KSCAN_POST[0][0]

    printf("Your edge region ends at k = %f \n", KSCAN_EDGE_K)

    for (i=0 ; i<KSCAN_N_POST ; i++){
        printf("Defining post-edge region %i\n", i+1)
        KSCAN_POST [i] [0] = getval("Enter k end", KSCAN_POST [i] [0])
        KSCAN_POST [i] [1] = getval("Enter k increment", KSCAN_POST [i] [1])
        KSCAN_POST [i] [2] = getval("Enter collection time in seconds", KSCAN_POST [i] [2])
    }

}'


#%UU% <energy_motor> <edge_energy> <time_factor>
#%MDESC%
#    Executes the scan defined with kscan_setup or kscan_defaults.
# The time is a multiplicative factor to apply to the time defined
# in kscan_setup.
#
def kscan '{

    if ($# != 3) {
	    print "Usage: kscan <energy_motor> <edge_energy> <time_factor>"
        exit
    }

    if (motor_valid("$1")){
        _m[0] = motor_num("$1")
    }
    else{
        print "Invalid motor name: " "$1"
        exit
    }

    _nm = 1
    HEADING  = sprintf("$0 $*")
    KSCAN_E0 = $2

    # Make sure we work in eV.
    if(KSCAN_E0 < 100) {
        KSCAN_E0 = KSCAN_E0 * 1000.
    }

    # time factor.
    KSCAN_TIME  = $3

    # Profile calculations.
    _kscan_profile

    _ctime = KSCAN_T [0] * KSCAN_TIME
    print "_ctime = " _ctime

    _kscan
}'


#%IU%
#%MDESC%
#    Calculates a grid in energy and time for the spectrum.
#
def _kscan_profile '{
    local i j e_work k_work

    # First point.
    KSCAN_E [0] = KSCAN_E0 + KSCAN_PRE [0] [0]
    KSCAN_T [0] = KSCAN_PRE [0] [2]

    #### PRE-edge regions profiles.
    i=0
    for (j=0 ; j < KSCAN_N_PRE ; j++) {
        if(j == KSCAN_N_PRE -1) {
            # -> Last of PRE-edge regions.

            # KSCAN_EDGE_1 should be negative.
            e_work = KSCAN_E0 + KSCAN_EDGE_1
        }
        else {
            e_work = KSCAN_E0 + KSCAN_PRE[j+1][0]
        }

        while (KSCAN_E [i] < e_work) {
            i++
            KSCAN_E [i] =  KSCAN_E [i-1] + KSCAN_PRE [j] [1]
            KSCAN_T [i] =  KSCAN_PRE [j] [2]
        }
    }

    #### K-edge region profile.
    KSCAN_E [i] = e_work
    KSCAN_T [i] = KSCAN_EDGE_T  # Acquisition time in EDGE region

    e_work = KSCAN_E0 + KSCAN_EDGE_2

    while (KSCAN_E [i] < e_work) {
        i++
        KSCAN_E [i] =  KSCAN_E [i-1] + KSCAN_EDGE_INC
        KSCAN_T [i] =  KSCAN_EDGE_T
    }

    KSCAN_E [i] = e_work
    KSCAN_T [i] = KSCAN_EDGE_T

    # ?
    k_work = kscan_calcK(e_work - KSCAN_E0)

    #### POST-edge profile.
    for (j=0 ; j<KSCAN_N_POST ; j++) {
        # ??? k_work = kscan_calcK(e_work - KSCAN_E0)
        while (k_work < KSCAN_POST [j] [0]) {
            i++

            # ?
            k_work += KSCAN_POST [j] [1]

            KSCAN_E [i] = KSCAN_E0 + kscan_calcE(k_work)
            KSCAN_T [i] = KSCAN_POST [j] [2]
        }

        e_work = KSCAN_E [i]
    }

    # Total number of points of the scan.
    KSCAN_NPTS = i+1

    # ? Converts energies into keV if needed ?
    if (toupper(substr(PSEUDOE_UNITS, 0, 2)) == "EV") {
        # nothing...
    }
    else {
        for(i=0 ; i<KSCAN_NPTS ; i++){
            KSCAN_E [i] = KSCAN_E [i]/1000.0
        }
    }

    printf("KSCAN : This scan has %g points with %g seconds scanning time ",    \
           KSCAN_NPTS, array_op("cols", KSCAN_T))
    printf("and likely takes %g (2sec deadtime) \n",    \
           array_op("cols", KSCAN_T) + KSCAN_NPTS*2  )

}'


#%IU% [parma]
#%MDESC%
#    
def _kscan '{
    local i

    for (i=0 ; i<_nm ; i++) {
        _bad_lim = 0
        _chk_lim _m[i] KSCAN_E[0]
        _chk_lim _m[i] KSCAN_E[KSCAN_NPTS-1]
        if (_bad_lim) exit;
    }
}

    # _n1++
	_n1=KSCAN_NPTS
	_cols=_nm+_hkl_col
	X_L = motor_name(_m[0])
	Y_L = cnt_name(DET)

    # start / finish
	_s[0] = KSCAN_E [0]
	_f[0] = KSCAN_E [KSCAN_NPTS-1]

	_sx = _s[0]
	_fx = _f[0]
	FPRNT=PPRNT=VPRNT=""
{
    local i
    for (i=0;i<_nm;i++) {
        FPRNT=sprintf("%s%s  ",FPRNT,motor_name(_m[i]))
        PPRNT=sprintf("%s%8.8s ",PPRNT,motor_name(_m[i]))
        VPRNT=sprintf("%s%9.9s ",VPRNT,motor_name(_m[i]))
    }
}

FPRNT=sprintf("%s%s  ",FPRNT,_hkl_sym1)
scan_head
PFMT=sprintf("%%s%%8.%df ",UP)
VFMT=sprintf("%%s%%9.%df ",UP)

def _scan_on \'

	for(;NPTS < KSCAN_NPTS;NPTS++) {
		local i

        # 
		A[_m[0]] = KSCAN_E [NPTS]

		scan_move
        FPRNT=PPRNT=VPRNT=""
        for (i=0;i<_nm;i++) {
            FPRNT=sprintf("%s%.8g ", FPRNT, A[_m[i]])
            PPRNT=sprintf(PFMT, PPRNT, A[_m[i]])
            VPRNT=sprintf(VFMT, VPRNT, A[_m[i]])
        }

        FPRNT=sprintf("%s%s ", FPRNT, _hkl_val)

        # 
        _ctime = KSCAN_T[NPTS] * KSCAN_TIME

        scan_loop
        # data_nput(PL_G, NPTS, A[_m[0]]*UN, S[DET])
        scan_data(NPTS, A[_m[0]])
        scan_plot
    }
scan_tail

\'
_scan_on
'


#%UU%
#%MDESC%
#    This macro sets a profile as default. This profile should be good
# for most of the applications. The profile can always be visualized
# and/or changed with kscan_defaults.
#
def kscan_defaults '{
    global KSCAN_N_PRE KSCAN_N_POST
    global KSCAN_PRE KSCAN_POST
    global KSCAN_EDGE_1 KSCAN_EDGE_2 KSCAN_EDGE_INC KSCAN_EDGE_T KSCAN_EDGE_K
    global KSCAN_E0
    global KSCAN_NPTS KSCAN_TIME

    global array KSCAN_E [4000] KSCAN_T [4000]
    KSCAN_N_PRE = 2
    KSCAN_N_POST = 1
    KSCAN_PRE [0] [0] = -100.0
    KSCAN_PRE [0] [1] =    5.0
    KSCAN_PRE [0] [2] =    1.0
    KSCAN_PRE [1] [0] =  -50.0
    KSCAN_PRE [1] [1] =    2.0
    KSCAN_PRE [1] [2] =    1.0
    KSCAN_EDGE_1 = -20
    KSCAN_EDGE_2 = +20
    KSCAN_EDGE_INC = 0.5
    KSCAN_EDGE_T = 1
    KSCAN_POST [0] [0] =  16.0
    KSCAN_POST [0] [1] =  0.03
    KSCAN_POST [0] [2] =  1
}'

#%MACROS%
#%IMACROS%
#%AUTHOR% V.A.Sole - ID26 - ESRF - Copyright 1999
#%TOC%