esrf

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

#%TITLE% MAD.MAC
#%NAME%
#  Absorption Edge Scanning commands and utilities used for MAD dadacollection
#%CATEGORY% MX
#
#%LOG%
#$Log: MAD.mac,v $
#Revision 1.28  2014/10/03 10:38:10  witsch
#eliminate occurences of plotlist().
#
#Revision 1.27  2012/05/11 13:34:37  beteva
#changed shstate to shstatus to cope with the new beamshutter software
#
#Revision 1.26  2012/03/19 15:38:18  beteva
#changed max to lmax
#
#Revision 1.25  2011/04/29 15:00:55  beteva
#added test if local_mv_undulator exists. Changed != to fabs() > 0.01
#
#Revision 1.24  2011/04/06 08:35:54  guijarro
#changed return(-1) to exit to trigger cleanup in case the macro is aborted
#
#Revision 1.23  2010/11/16 10:04:09  guijarro
#added _ae_shutters_close if attenuation is not found
#
#Revision 1.22  2010/09/09 08:59:40  beteva
#return beamsize in eV instead of keV to make ISPyB happy
#
#Revision 1.21  2010/02/18 17:18:38  beteva
#set AE_STEP as global (only a bug fix)
#
#Revision 1.20  2010/02/12 10:36:14  blissadm
#fixed typo (pritntf -> printf)
#
#Revision 1.19  2010/02/09 13:40:03  beteva
#do tests for division by zero.
#
#Revision 1.18  2009/12/16 11:54:46  beteva
#changed the attenuation scan to be done form +50 to +30 eV over the edge. Added beamX and beamY
#
#Revision 1.17  2009/11/02 16:46:00  beteva
#changed the reading of the transmission, sizeX and sizeY to be before the cleanup (read by ISPyB).
#
#Revision 1.16  2009/04/08 12:05:32  beteva
#added msopen in the attenuation scan
#
#Revision 1.15  2009/02/19 13:41:51  beteva
#change - move undulators after moving the energy (in case undulator scan to be performed)
#
#Revision 1.14  2008/11/25 16:33:54  beteva
#changed the procedures to use transmission factor instead of attenuators set
#
#Revision 1.13  2008/07/31 06:50:14  rey
#documentation changes
#
#Revision 1.12  2008/07/09 15:15:55  guijarro
#do a check_beam() before energy change
#
#Revision 1.11  2008/07/08 13:34:01  guijarro
#return right parameters at the end of energy scan
#
#Revision 1.10  2008/04/09 11:56:29  spruce
#remove wcadjall from attscan. If this is necessary it should be done elsewhere
#
#Revision 1.9  2008/03/20 12:40:17  guijarro
#removed chooch stuff
#
#Revision 1.8  2008/03/19 14:18:52  guijarro
#changed weird "_ae_moveE" function
#
#Revision 1.7  2008/03/06 16:03:53  spruce
#added backin to prepscan
#
#Revision 1.6  2007/02/12 15:04:08  beteva
#changed moveE & getE to mv energy & get_angles; LAMBDA = A[lambda]
#
#Revision 1.5  2006/06/15 08:21:24  beteva
#ae_local_write_choochfile instead of _ae_write_choochfile;
#COLLECT_SEQ["energy"] set because eprodc_set_mono takes no parameters any more;
#no parameter for ae_local_setatt - transmissions factor used;
#
#Revision 1.4  2006/06/06 15:20:28  beteva
#COLLECT_PARS references swapped for mxutils function calls;
#*_ms_shutter changed to ms*; mattset changet to transmission;
#
#Revision 1.3  2006/02/14 13:55:02  beteva
#added wcadjall for the electrometer gains and ATT_FACTOR calculation for mcCuBE
#
#Revision 1.2  2005/11/17 15:23:05  beteva
#changed Xval to eprodc_energy_status;
#added AE_ESCAN_OFFSET for offset durung the energy scan;
#added test_mad and ESCAN_TST* variables to simulate parts of the procedure
#
#Revision 1.1  2005/10/21 09:35:50  beteva
#Initial revision
#
#%END%

#%UU% ()
#%MDESC% First initialisation.
def ae_init() '{

  global AE_ELEMENT      #element name
  global AE_EDGE         #edge - K,L
  global AE_FILE         #Absorption edge datafile
  global AE_TUNE         #use the parameters fine tunning
  global AE_FEUSE        #use the front end move in the energy scan
  global AE_MCAUSE       #use the mca ROI calculations
  global AE_MCAROIC      #adjust the roi whith this coef [eV]
  global AE_MCAROI       #roi counter mnemonic
  global AE_SCPLOT       #scanplot counter mnemonic
  global AE_ATTUSE       #use the attenuators setup procedure
  global AE_E            #edge energy [KeV]
  global AE_DEAD         #[0] time to count [s] ; [1] min level;
                   #[2] max level; [3] - flag to use deadtime or counts
  global AE_SCAN_TIME    #scan time [s]
  global AE_STEP         #step [ev] for the energy scan
  global AE_UMOT   #Undulator motor(s)
  global AE_UMAX   #Undulator motor(s) max gap value
  global AE_ESCAN_OFFSET #offset for the energyscan from the table values [eV]
  global AE_DEBUG        #nodebug = 0
  global AE_SIMUL        #simulate the hardware if != 0

  global AE_UND_READY  #undulator(s) ready to move OK=0, error=-1
  global AE_MONO_READY #mono ready for the escan OK=0, error=-1
  global AE_ATTSCAN    #attenuation scan status OK=0, error=-1
  global AE_TRANSM     #keep the transmission factor

  global AE_ORG       # data out of the datafile
  constant AE_Elements  18  #Number of elements in AE_ORG
  constant AE_KEN 0
  constant AE_KALPHA1 1
  constant AE_KALPHA2 2
  constant AE_LEN1  3
  constant AE_LEN2  4
  constant AE_LEN3  5
  constant AE_LALPHA1 6
  constant AE_LALPHA2 7
  constant AE_DISCLO  8
  constant AE_DISCHI  9
  constant AE_SCANLO1 10
  constant AE_SCANLO2 11
  constant AE_SCANHI1 12
  constant AE_SCANHI2 13
  constant AE_NOLAM 14
  constant AE_REMOTEK 15
  constant AE_REMOTEL 16
  constant AE_ELNB  17

  global AE_RCM          # Recommended values
  constant AE_RCM_Elements  9  #Number of elements in AE_RCM
  constant AE_RCM_ENERGY    0
  constant AE_RCM_DISCLO    1
  constant AE_RCM_DISCHI    2
  constant AE_RCM_SCANLO1   3
  constant AE_RCM_SCANLO2   4
  constant AE_RCM_SCANHI1   5
  constant AE_RCM_SCANHI2   6
  constant AE_RCM_UND       7

  global AE_ROOT_DIR
  global AE_CHOOCH AE_CHOOCH_FILE

  AE_SIMUL = 0

  AE_MCAUSE = -1
  AE_FEUSE = 0
  AE_ATTUSE = 0
}'

#%UU% [file tune mcaroi attenuators undulator(s)]
#%MDESC% setup the input parameters.
def ae_setup '{
local mne i inp nb

  ae_init()

  if ($# < 2) {
    AE_FILE = getval("Absorption edge datafile", AE_FILE)
    AE_TUNE = yesno("Further setup", AE_TUNE)
    if (AE_TUNE == 1) {
      AE_MCAUSE = getval("Which MCA to use (none=-1)", AE_MCAUSE)
      if (AE_MCAUSE >= 0) {
        AE_MCAROI[0] = getval("ROI counter mnemonic: ", AE_MCAROI[0])
        if (cnt_num(AE_MCAROI[0]) == -1) {
          eprintf ("invalid counter mnemonic, exiting...\n")
          exit
        }
      }
      AE_ATTUSE = yesno("Set the attenuators", AE_ATTUSE)
      if (AE_ATTUSE == 1) {
        ae_att_param
      }
      AE_FEUSE = getval("How many undulators to control (none=0): ", AE_FEUSE)
      if (AE_FEUSE != 0) {
        for (i=0; i<AE_FEUSE; i++) {
          mne = getval("Undulator motor mnemonic: ", motor_mne(AE_UMOT[i]))
          AE_UMOT[i] = motor_num(mne)
          if (AE_UMOT[i] == -1) {
            eprintf ("%s - invalid motor mnemonic, exiting...\n", mne)
            exit
          }
          AE_UMAX[i] = getval("Undulator fully open gap: ", AE_UMAX[i])
        }
      }
      ae_scan_param
    }
  } else {
    nb = split("$*", inp)
    AE_FILE = inp[0]
    AE_TUNE = inp[1]
    if (AE_TUNE == 1) {
      if (nb <= 2) {
  eprintf ("Not enough parameters. Setup not done!\n")
        exit
      }
      AE_MCAUSE = inp[2]
      if (AE_MCAUSE >= 0) {
        AE_MCAROI[0] = inp[3]
        if (cnt_num(AE_MCAROI[0]) == -1) {
          eprintf ("invalid counter mnemonic %s, exiting...\n", AE_MCAROI[0])
          exit
        }
  #_mcapar()
      }
      AE_ATTUSE = inp[4]
      ae_att_param inp[5] inp[6] inp[7]
      AE_FEUSE = inp[8]
      if (AE_FEUSE != 0) {
        for (i=0; i<AE_FEUSE; i++) {
          AE_UMOT[i] = motor_num(inp[9+2*i])
          if (AE_UMOT[i] == -1) {
            eprintf ("%s - invalid motor mnemonic, exiting...\n", inp[9+2*i])
            exit
          }
          AE_UMAX[i] = inp[10+2*i]
        }
      }
    }
  }
  if (file_info(AE_FILE,"-r") == 0) {
   eprintf("Cannot open %s, exiting...\n", AE_FILE)
   exit
  }

  #default counting time 1s
  AE_SCAN_TIME = 1
  #default scan step 1 eV
  AE_STEP[0] = AE_STEP[1] = AE_STEP[2] = 1
  #default plot counter - mcaroi
  AE_SCPLOT = AE_MCAROI[0]
}'

#%UU% [cnt_time ll_dt hl_dt]
#%MDESC% Setup the attenuator scan counting time [s] and low and high
#dead time [percent].
def ae_att_param '{

  if ($# == 3) {
    AE_DEAD[0] = $1
    AE_DEAD[1] = $2
    AE_DEAD[2] = $3
  } else {
    AE_DEAD[0] = getval ("Dead time counted for [s]: ", AE_DEAD[0])
    AE_DEAD[1] = getval("Dead time/counts low level [%]: ", AE_DEAD[1])
    AE_DEAD[2] = getval("Dead time/counts high level [%]: ", AE_DEAD[2])
  }
  if (AE_DEAD[2] > 50)
    AE_DEAD[3] = 1
  else
    AE_DEAD[3] = 0
}'

#%UU% [scan_dir time plot_counter E_step1 E_step2 E_step3]
#%MDESC% Setup the energy scan time/point, plot counter and steps [eV].
def ae_scan_param '{
global AE_STEP[]

  tty_cntl("md")
   print "Running ae_scan_param"
  tty_cntl("me")

  if ($# == 4) {
    AE_ROOT_DIR = "$1"
    AE_SCAN_TIME = $2
    AE_SCPLOT = "$3"
    AE_STEP[0] = AE_STEP[1] = AE_STEP[2] = $4
  } else if ($# > 4) {
    AE_ROOT_DIR = "$1"
    AE_SCAN_TIME = $2
    AE_SCPLOT = "$3"
    AE_STEP[0] = $4
    AE_STEP[1] = $5
    AE_STEP[2] = $6
  } else {
    AE_ROOT_DIR = getval("Directory to keep the scan files: ", AE_ROOT_DIR)
    AE_SCAN_TIME = getval ("Energy scan Time/point [s]: ", AE_SCAN_TIME)
    AE_SCPLOT = getval("Energy scan plot counter mnemonic: ", AE_SCPLOT)
    AE_STEP[0] = getval ("Pre-edge energy step [eV]: ", AE_STEP[0])
    AE_STEP[1] = getval ("Edge energy step [eV]: ", AE_STEP[1])
    AE_STEP[2] = getval ("Post-edge energy step [eV]: ", AE_STEP[2])
  }

  ae_choochparam 1

  if (cnt_num(AE_SCPLOT) == -1) {
    eprintf ("%s - invalid counter mnemonic, exiting...\n", AE_SCPLOT)
    exit
  }
}'

#%UU% [use_chooch]
#%MDESC% Choose to use or not chooch (Yes = 1). Set the chooch data file.
def ae_choochparam '{

  if ($# < 1)
    AE_CHOOCH = getval("Do you want to use chooch (1=YES/0=NO): ", AE_CHOOCH)
  else
    AE_CHOOCH = $1

  if (AE_CHOOCH == 1)
    AE_CHOOCH_FILE = sprintf("%s/data.raw",AE_ROOT_DIR)
}'

#%UU% [element edge]
#%MDESC% Recommended values in function of %B%element%B% and
#%B%edge%B% as foillows:%BR%
#  %B%EDGE:%B%%BR%
# K or L1, L2 and L3 energy%BR%
#  %B%MAD:%B%%BR%
# number of wavelengths and remote energy%BR%
#  %B%MCA:%B%%BR%
# low and high level discriminator settings%BR%
#  %B%SCAN%B%%B%INTERVALS:%B%%BR%
# Pre-edge, Edge and Post-Edge%BR%
#  %B%UNDULATOR%B%%B%SETTINGS:%B%%BR%
# gap and max power.
def ae_getedge '{
local elem edge

  if ($# < 2) {
    elem = getval("Element: ", AE_ELEMENT)
    edge = getval("Edge (K/L): ", AE_EDGE)
  } else {
    elem = "$1"
    edge = "$2"
  }

  if (AE_DEBUG > 0)
    printf ("running _ae_getedge(%s, %s)\n", elem, edge)
  if (_ae_getedge(elem, edge) == -1) {
    eprintf ("Error getting energy values\n")
    exit
  }
}'

#%UI% (elem, edge)
#%MDESC% Calculate the roi, gap and scan parameters, using the
#datafile, as function of the %B%elem%B% and %B%edge%B% parameters .
def _ae_getedge(elem, edge) '{
local i line nb ftemp tmp
local ae_remote gap

  # clean the tables
  for (i=0; i < AE_Elements; i++)
     AE_ORG[i] = -1
  for (i=0; i < AE_RCM_Elements; i++)
     AE_RCM[i] = -1

  i=0
  # read values, print information and fill an array with recommended values
  line = getline(AE_FILE)
  while (line != -1) {
    nb = split(line, ftemp)
    if ((ftemp[1] == elem) && (ftemp[2] == edge)) {
      i++
      break
    }
    line=getline(AE_FILE)
  }
  # close file
  getline(AE_FILE, "close")

  if (i != 1)
    return(-1)

  AE_ELEMENT = elem
  AE_EDGE = edge

  for (i = 0; i<nb-3; i++) {
    sscanf(ftemp[i+3],"%f",tmp)
    AE_ORG[i]=tmp
  }
  AE_ORG[AE_ELNB] = ftemp[0]
  if (edge == "K") {
    AE_RCM[AE_RCM_ENERGY] = AE_ORG[AE_KEN]
    AE_E = AE_ORG[AE_KEN]
    ae_remote = AE_ORG[AE_REMOTEK]
  } else {
    AE_RCM[AE_RCM_ENERGY]=AE_ORG[AE_LEN3]
    AE_E = AE_ORG[AE_LEN3]
    ae_remote = AE_ORG[AE_REMOTEL]
  }
  if (AE_DEBUG > 0)
    ae_printEdgeInfo(elem, edge)

  # Set recommended discriminator values
  AE_RCM[AE_RCM_DISCLO]=AE_ORG[AE_DISCLO]
  AE_RCM[AE_RCM_DISCHI]=AE_ORG[AE_DISCHI]

  # Set recommended scan values
  AE_RCM[AE_RCM_SCANLO1] = AE_ORG[AE_SCANLO1]
  AE_RCM[AE_RCM_SCANLO2] = AE_ORG[AE_SCANLO2] + AE_ESCAN_OFFSET
  AE_RCM[AE_RCM_SCANHI1] = AE_ORG[AE_SCANHI1] + AE_ESCAN_OFFSET
  AE_RCM[AE_RCM_SCANHI2] = AE_ORG[AE_SCANHI2]

  if (AE_FEUSE > 0) {
    for (i=0; i<AE_FEUSE; i++) {
      gap[0] = _ae_wwave(motor_mne(AE_UMOT[i]),AE_E,0)
      if (gap[0]< 0)
        AE_RCM[AE_RCM_UND+i] = AE_UMAX[i]
      else {
        AE_RCM[AE_RCM_UND+i] = gap[0]
        if (ae_remote > 0)
          gap[1] =_ae_wwave(motor_mne(AE_UMOT[i]),ae_remote,1)
        #if (gap[1] < 0)
    #  AE_RCM[AE_RCM_UND+i] = AE_UMAX[i]
      }
    }
    if ((fabs(AE_RCM[AE_RCM_UND] - AE_UMAX[0]) > 0.01) && \
  (fabs(AE_RCM[AE_RCM_UND+1] - AE_UMAX[1]) > 0.01)) {
      AE_RCM[AE_RCM_UND] = AE_UMAX[0]
    }
  }
  return(0)
}'

#%UI% _ae_wwave(umne,le,rem)
#%MDESC% Calculate the undulator %B%ume%B% gap as function of the
#energy (le < 3.5) or the wavelength (le > 1000).
def _ae_wwave(umne,le,rem) '{
  if (le <= 0) {
    return(-1)
  }

  if (le < 3.5) {
    en = hc_over_e*1000/le
  } else {
    if (le > 1000) {
      en=le;
      le=hc_over_e*1000/en
    } else
      return(-1)
  }

  ae_local_wwave motor_num(umne) le rem
  gap = AE_GAP
  if (gap != -1) {
    # plot values if needed
    if (AE_DEBUG == 1) {
      if (rem == 1)
        rem = "remote energy"
      else
        rem = "edge energy"
      printf("-----------------------------------------------------\n")
      printf("\tSUMMARY OF DATA FOR %s %s\n", umne, rem)
      printf("-----------------------------------------------------\n")
      printf(" Gap value  : %6.4f\n", gap)
      printf(" Energy     : %2.3f KeV (wavelength %2.5f )\n",en/1000,le)
    }
  }

  return(gap)
}'

#%UI%(elem,edge)
#%MDESC% Verbose print of information after the getedge calculations.
def ae_printEdgeInfo(elem,edge) '{
global ae_rem
  printf("EDGE INFORMATION -  %s:\n", elem);
  if (edge == "K") {
    printf("\tK edge energy: %2.4f KeV\n", AE_ORG[AE_KEN]/1000)
    ae_rem = AE_ORG[AE_REMOTEK]
  } else {
    printf("\tL3 edge energy: %2.4f\n",AE_ORG[AE_LEN3]/1000)
    printf("\tL2 edge energy: %2.4f\n", AE_ORG[AE_LEN2]/1000)
    printf("\tL1 edge energy: %2.4f\n", AE_ORG[AE_LEN1]/1000)
    ae_rem = AE_ORG[AE_REMOTEL]
  }

  if (AE_MCAUSE >= 0) {
     printf("MCA INFORMATION:\n");
     printf("\tLower level: %6.2f\n", AE_ORG[AE_DISCLO])
     printf("\tHigher level: %6.2f\n", AE_ORG[AE_DISCHI])
    }

  printf ("SCAN INFORMATION:\n")
  if (AE_STEP[0] != AE_STEP[1])
    printf("\tPre-edge : %2.4f to %2.4f KeV, %d eV step\n", AE_ORG[AE_SCANLO1]/1000, AE_ORG[AE_SCANLO2]/1000, AE_STEP[0])
  printf("\tEdge     : %2.4f to %2.4f KeV, %d eV step\n", AE_ORG[AE_SCANLO2]/1000, AE_ORG[AE_SCANHI1]/1000,AE_STEP[1])
  if (AE_STEP[2] != AE_STEP[1])
  printf("\tPost-Edge: %2.4f to %2.4f KeV, %d eV step\n", AE_ORG[AE_SCANHI1]/1000, AE_ORG[AE_SCANHI2]/1000, AE_STEP[2])

  printf("MAD INFORMATION\n");
  printf("\tNumber of wavelengths: %f\n", AE_ORG[AE_NOLAM])
  printf("\tRemote energy        : %3.4f Kev\n", ae_rem)
}'

#%UI% (t,flag)
#%MDESC% Get the deadtime from the mca for count time %B%t%B%. If no flag,
#retun the dead time [s], else return the count rate for the ROI.
def _deadct(t,flag) '{
local double array adcinfo[8]
  if (t <= 0) {
    eprintf("Count time not set, exiting...\n")
    return(-1)
  }
  if (flag == 0) {
    #msopen
    sleep(t)
    #msclose
    esrf_io(mca_spar(AE_MCAUSE, "device_id"), "DevMcaGetAdcInfo",adcinfo)
    #return(MCA_TIMES[AE_MCAUSE]["dead"])
    return(adcinfo[6])
  } else {
    #msopen
    tcount(t); waitcount;get_counts
    #msclose
    return (S[cnt_num(AE_MCAROI[0])]/t)
  }
}'

#%UI% (scan_energy)
#%MDESC% Do energy scan +- 0.1 KeV around %B%scan_energy%B%.
def _deadscan(scan_energy) '{
local lmax
  printf("SCAN AROUND EDGE ENERGY\n")
  msopen
  Escan scan_energy-0.1 scan_energy+0.1 20 0.5
  msclose
  lmax=array_op("max",SCAN_D[][dead+1])
  printf("Max energy in scan: %x\n",lmax)
  return(lmax)
}'

#%UI% ()
#%MDESC% Open all shutters.
def _ae_shutters_open() '{

  if (AE_SIMUL == 0)
    shopen
  if (AE_DEBUG > 0)
    printf("Open the fast shutter\n")
  if (AE_SIMUL == 0)
    msopen
}'

#%UI% ()
#%MDESC% Close all shutters.
def _ae_shutters_close() '{

  if (AE_DEBUG > 0)
    printf("Close the fast shutter\n")
  if (AE_SIMUL == 0)
    msclose

  ae_local_shutters_close
  if (AE_SIMUL == 0)
    shclose
}'

#%UI% ()
#%MDESC% Set the apropriate attenuator set before a scan.
def ae_setattenuator() '{
local i dtc mystr

  #read the present attenuation
  AE_TRANSM = ATT_FACTOR
  # put in max attenuation
  transmission 0

  dtc = _deadct(AE_DEAD[0],AE_DEAD[3])
  if (dtc == -1) {
    egui_logmsg("Cannot read the detector dead time/counts, giving up.")
    return(-1)
  }
  mystr = sprintf("%s",(AE_DEAD[3]==0?"deadtime":"counts"))
  if (dtc > AE_DEAD[2]) {
    egui_logmsg("The detector is saturated, giving up.")
    eprintf ("Saturation %s %g\n", mystr, dtc)
    return (-1)
  }
  printf ("%s %g\n", mystr, dtc)
  for (i=1; i < NR_MATT; i++) {
    # Not enough detection, take out some attenuation
    transmission MATT_TABLE[i]
    mystr = sprintf ("Transmission factor %g\%\n", ATT_FACTOR)
    egui_logmsg(mystr)
    dtc = _deadct(AE_DEAD[0],AE_DEAD[3])
    printf ("%s %g\n", mystr, dtc)
    if (dtc > AE_DEAD[1]) break;
  }

  if (dtc < AE_DEAD[1]) {
    mystr = sprintf("Could not find satisfactory attenuation (is the mca properly set up?), giving up.")
    egui_logmsg(mystr)
    eprintf("%s\n", mystr)
    eval(sprintf ("transmission %f", AE_TRANSM))
    return (-1)
   }
  return (0)
}'

#%UI% (ind)
#%MDESC% Check if the undulator %B%ind%B% can move. Return 0 if OK, -1 if not.
def _ae_checkundulator(ind) '{
global AE_UND_READY

  AE_UND_READY = 0
  eval (sprintf("ae_local_checkundulator %d",ind))
  return(AE_UND_READY)
}'

#%UI% (ind,val)
#%MDESC% Move the undulator %B%ind%B% to the calculated gap %B%val%B%.
def _ae_moveundulator(ind,val) '{
local str

  ESRF_ERR = -1

  if (_ae_checkundulator(ind) == -1) {
    eprintf ("Error with the undulator, will not move\n")
    return(-1)
  }

  printf ("Now will move the undulator %s\n", motor_mne(AE_UMOT[ind]))
  if ((fabs(A[AE_UMOT[ind]] - AE_RCM[val]) > 0.01) && (AE_RCM[val] != 0)) {
    str = sprintf("%s %f",motor_mne(AE_UMOT[ind]),AE_RCM[val])
    if (AE_DEBUG > 0)
      egui_logmsg(sprintf("Moving undulator: mv %s\n", str))
    if (AE_SIMUL == 0) {
      get_angles
      if ((A[AE_UMOT[ind]] < AE_UMAX[ind]) || \
  (fabs(AE_RCM[val] - AE_UMAX[ind]) > 0.01)) {
        A[AE_UMOT[ind]] = AE_RCM[val]
        move_em; move_poll
        if (ESRF_ERR != 0) {
          eprintf ("Cannot move undulator %s\n", str)
          return (-1)
        }
      } else {
        if (ismacro("local_mv_undulator")) {
          eval(sprintf ("local_mv_undulator %d %f", ind, AE_RCM[val]))
        }
      }
    }
  } else {
    printf ("Undulator will not move\n")
  }
  return(0)
}'

#%UI% ()
#%MDESC% Move the undulator(s) to the calculated gaps.
def _ae_moveundulators() '{
local flag stat

  flag = 0

  get_angles
  if (AE_FEUSE == 1) {
    #move one (the first) undulator
    _ae_moveundulator(0,AE_RCM_UND)
  } else if (AE_FEUSE == 2) {
    #move two undulators
    if (AE_RCM[AE_RCM_UND] == AE_UMAX[0]) {
      if (_ae_moveundulator(0,AE_RCM_UND) < 0)
        return(-1)
      flag = 1
    } else if (AE_RCM[AE_RCM_UND+1] == AE_UMAX[1]) {
      if (_ae_moveundulator(1,AE_RCM_UND+1) < 0)
        return(-1)
      flag = 2
    }
    if (AE_DEBUG > 0)
      printf ("should move undulator %d\n",flag)
    if (flag == 1) {
       if (_ae_moveundulator(1,AE_RCM_UND+1) < 0)
         return(-1)
    } else if (flag == 2) {
       if (_ae_moveundulator(0,AE_RCM_UND) < 0)
         return(-1)
    }
  }
  return (0)
}'

#%UI% ()
#%MDESC% Prepare the mono for the escan. Return 0 if OK, -1 if error.
#(set in the AE_MONO_READY variable).
def ae_prepare_mono() '{
global AE_MONO_READY

  AE_MONO_READY = 0
  ae_local_prepare_mono
  return (AE_MONO_READY)
}'

#%UI% ()
#%MDESC% Restore the mono after the escan. Return 0 if OK, -1 if error
#(set in the AE_MONO_READY variable).
def ae_restore_mono() '{
global AE_MONO_READY

  AE_MONO_READY = 0
  ae_local_restore_mono
  return (AE_MONO_READY)
}'

#%UI% (offset)
#%MDESC% Move the mono to the edge+%B%offset%B% energy.
def _ae_moveE(offset) '{
local msg
  msg = sprintf ("Moving to %g+%d eV", AE_E, offset)
  eprodc_energy_scan_status(msg)
  egui_logmsg(msg)
  en = ((AE_E + offset)/1000)
  get_angles
  A[energy]=en
  move_em
  waitmove
  #mv energy en
  #get_angles
  #LAMBDA = A[lambda]
  #if ((hc_over_e/LAMBDA <= en-0.002) || (hc_over_e/LAMBDA > en+0.002)) {
  #  return (-1)
  #}
  #if ((A[energy] <= en-0.002) || (A[energy] > en+0.002)) {
  #  return (-1)
  #}
  return (0)
}'

#%UI% ()
#%MDESC% Prepare the edge scan.
def _ae_prepscan() '{
local en
global OLD_DATAFILE

  OLD_DATAFILE = DATAFILE
  ae_on

  # Move fluorencent detector
  if (AE_DEBUG > 0) {
    printf("Get the backlight out\n")
    printf("Move fluorescence detector\n")
  }
  if (AE_SIMUL == 0) {
    lightout
    fldetin
    backin
    msopen
  }
  if (AE_ATTUSE == 1) {
     en = ((AE_E + 30)/1000)
     eprodc_energy_scan_status("Setting the attenuation..")
     ae_local_setatt
    }

  if (AE_MCAUSE >= 0) {
    plotselect AE_SCPLOT
    if (AE_SIMUL == 0)
     ae_local_mcaroi
    mcaoff
    }
  return(0)
}'

#%UU% ()
#%MDESC% Choose appropriate attenuation. Return 0 if OK, -1 if no
#attenuation found (set in AE_ATTSCAN variable).
def ae_attscan() '{
global AE_ATTSCAN

  AE_ATTSCAN = 0
  ae_local_attscan
  return (AE_ATTSCAN)
}'

#%UI% ()
#%MDESC% Choose appropriate attenuation. Return 0 if OK, -1 if no
#attenuation found (set in AE_ATTSCAN variable).
def _ae_attscan() '{
local en

  # Move fluorencent detector
  if (AE_DEBUG > 0)
    printf("Move fluorescence detector\n")
  if (AE_SIMUL == 0)
    fldetin

  if (AE_MCAUSE >= 0) {
    if (MCA_GUI == 0)
      mcaguion
    mcaon
    ae_local_mcaroi
  }
  #open again the shutter (security feature)
  if (AE_SIMUL == 0)
    msopen

  if (AE_ATTUSE == 1) {
     en = ((AE_E + 30)/1000)
     eprodc_energy_scan_status("Setting the attenuation..")
     if (AE_MCAUSE >= 0)
       mcaclear
     ae_local_setatt
    }

  if (AE_SIMUL == 0) {
    if (AE_ATTUSE == 1) {
      if (ae_setattenuator() == -1) {
  AE_ATTSCAN = -1
        return(-1)
      }
    }
  }
  AE_ATTSCAN = 0
  return(0)
}'

#%UI%()
#%MDESC% Select which counter to plot during the scan.
def ae_plotselect() '{
  if (AE_MCAUSE >= 0) {
    plotselect AE_SCPLOT
  } else {
    ae_local_plotselect
  }
}'

#%UI%()
#%MDESC% Do Escan or XEscan.
def ae_scan() '{
float array params[32]

  if (AE_STEP[0] == 0) {
    eprintf ("Scan step unefined, giving up\n")
    eprodc_energy_scan_status("Scan step unefined, giving up")
    return (-1)
  }
  if (AE_STEP[1] == 0) {
    eprintf ("Scan step unefined, giving up\n")
    eprodc_energy_scan_status("Scan step unefined, giving up")
    return (-1)
  }
  if (AE_STEP[2] == 0) {
    eprintf ("Scan step unefined, giving up\n")
    eprodc_energy_scan_status("Scan step unefined, giving up")
    return (-1)
  }

  params[0] = AE_RCM[AE_RCM_SCANLO1]/1000
  params[1] = AE_RCM[AE_RCM_SCANLO2]/1000
  params[2] = (AE_RCM[AE_RCM_SCANLO2] - AE_RCM[AE_RCM_SCANLO1]) / AE_STEP[0]
  params[3] = AE_RCM[AE_RCM_SCANHI1]/1000
  params[4] = (AE_RCM[AE_RCM_SCANHI1] - AE_RCM[AE_RCM_SCANLO2]) / AE_STEP[1]
  params[5] = AE_RCM[AE_RCM_SCANHI2]/1000
  params[6] = (AE_RCM[AE_RCM_SCANHI2] - AE_RCM[AE_RCM_SCANHI1]) / AE_STEP[2]
  params[7] = AE_SCAN_TIME

  if (AE_SIMUL == 0) {
    DATAFILE = AE_DATAFILE
    eprodc_energy_scan_status("Doing the scan..")
    msopen
    if ((AE_STEP[0] == AE_STEP[1]) && (AE_STEP[0] == AE_STEP[2])) {
      printf("   Edge.....: %6.3f to %6.3f KeV, %4.2f eV step\n", params[1] , params[3], params[4])
      ae_local_Escan params[1] params[3] params[4] params[7]
    } else {
      printf("  Pre-edge.: %6.3f to %6.3f KeV, %4.2f eV step\n", params[0] , params[1], params[2])
      printf("   Edge.....: %6.3f to %6.3f KeV, %4.2f eV step\n", params[1] , params[3], params[4])
      printf("   Post-edge: %6.3f to %6.3f KeV, %4.2feV step\n", params[3] , params[5], params[6])
      XEscanf(params,8)
    }
    DATAFILE = OLD_DATAFILE
    if (AE_CHOOCH ==1)
      ae_local_write_choochfile(AE_CHOOCH_FILE)
  }
}'

#%UI% ()
#%MDESC% To do after the scan.
def _ae_postscan() '{

  if (AE_SIMUL == 0) {
    fldetout
    if (AE_MCAUSE >=0) {
      mcaoff
      mcaguioff
    }
    eval(sprintf ("transmission %f", AE_TRANSM))
  }
  close(DATAFILE)
  close(AE_DATAFILE)
  DATAFILE = OLD_DATAFILE
  return(0)
}'

#%UU%
#%MDESC% To be be called in case of errors in the energy scan.
def ae_cleanup '{
global AE_DOSCAN
  AE_DOSCAN = 0
  eprodc_energy_scan_status("Scan aborted, cleaning up...")
  _ae_shutters_close()
  _ae_postscan()
}'

#%IU%
#%MDESC% Keep the initial motor positions.
def _poskeep() '{
local i
global AE_A[]
  get_angles; waitmove
  for (i=0; i<MOTORS;i++)
    AE_A[i] = A[i]
}'

#%IU%
#%MDESC% Restore the initial motor positions.
def _posrestore() '{
local i
  for (i=0; i<MOTORS;i++)
    A[i] = AE_A[i]
  move_em; waitmove
}'

#%IU% (fname)
#%MDESC% Write a file to be used by autochooch.
def _ae_write_choochfile(fname) '{
local ae_cnt i maxcounts scalefactor curr_x_point

  printf ("Removing choochfile %s\n", fname)
  unix(sprintf("/bin/rm -f %s",fname))

  printf ("Creating new choochfile %s\n", fname)
  open(fname)
  fprintf(fname,"%s on %s\n", HEADING, DATE)
  fprintf(fname,"%d\n",NPTS-1)
  ae_cnt = cnt_num(AE_SCPLOT)+1
  maxcounts = 0
  scalefactor = 1
  maxcounts = array_op("max",SCAN_D[ae_cnt])
  if (maxcounts == 0) {
    close(fname)
    return(-1)
  }
  if (maxcounts < 10)
    scalefactor = 10/maxcounts
  for (i=0; i<NPTS; i++) {
    #just in case the mono motor values are the same, which screws up benny???
    if (curr_x_point - SCAN_D[i][0]*1000 == 0) {
      curr_x_point = SCAN_D[i][0]*1000 + 1
      printf ("Modified energy value for chooch input file\n", curr_x_point)
    } else {
      curr_x_point = SCAN_D[i][0]*1000
    }
    fprintf (fname,"%6.2f    %f\n", curr_x_point,\
  fabs(SCAN_D[i][ae_cnt]*scalefactor))
    curr_x_point = SCAN_D[i][0]*1000
  }
  close(fname)
}'

#%IU% [filename]
#%MDESC% Get a filename for the energy scans.
def ae_newfile '{
global AE_DATAFILE
local fname fn[] ae_file
  if ($# == 0)
    fname = getval("Energy scans filename (name only): ",fname)
  else
    fname = "$1"

  split(date(),fn)
  fname = sprintf ("%s_%s_%s_%s.scan", fname, fn[2], fn[1], fn[4])
  ae_file = sprintf("%s/%s", AE_ROOT_DIR, fname)

  if (file_info(ae_file) == 1) {
    beep
    tty_cntl("md")
    printf("%s already exist !\n", ae_file)
    tty_cntl("me")
  } else {
    close (AE_DATAFILE)
    open(ae_file)
  }
  AE_DATAFILE = ae_file
  tty_cntl("md")
  printf("\nSPEC will save the energy scan data in %s !\n",AE_DATAFILE)
  tty_cntl("me")
}'

#%UU% (edge,prefix)
#%MDESC% Do an energy scan. The %B%edge%B% is a string comprising the
#chemical element and which edege (K or L). Save the scan date in a file
#with %B%prefix%BR name.
def eprodc_do_energy_scan(edge,prefix) '{
local inp[] stat msg
local att
local fn[]
local starte ende exptime
global AE_DATAFILE
global AE_DOSCAN

  check_beam()

  AE_DOSCAN = 1
  ae_on

  eprodc_energy_scan_status("")
  eprodc_energy_scan_status("Checkup procedure")

  # set up the data file for the energy scan
  #(should be in local data file as well)
  split(date(),fn)
  AE_DATAFILE = sprintf("%s/%s_%s_%s_%s.scan", getMxCollectPars("escan_dir"), \
  getMxCollectPars("escan_prefix"), fn[2], fn[1], fn[4])

  AE_ROOT_DIR = getMxCollectPars("escan_dir")
  ae_choochparam 1

  #get the attenuation before the scan
  AE_TRANSM = ATT_FACTOR

  cdef("cleanup_once","ae_cleanup\n","_energy_scan_")

  if (ESCAN_TST_FRONTEND == 0) {
    eprodc_energy_scan_status("Check if hutch searched")

    # Dont waste time if we have not searched the hutch
    stat = shstatus("OPEN")
    if ((stat != "OPEN") && (stat != "CLOSED")) {
      msg = sprintf("Safety shutter disabled, aborted!")
      eprodc_energy_scan_status(msg)
      egui_logmsg(msg)
      exit
    }

    eprodc_energy_scan_status("Check if front end open")
    msg = sprintf ("")
    stat = _check_fe(0)
    if (stat == -1 && AE_SIMUL == 0)
      msg = sprintf ("Front End not open, scan aborted!")
    if (msg != "") {
      eprodc_energy_scan_status(msg)
      egui_logmsg(msg)
      exit
    }
  }

  split(edge,inp)
  eprodc_energy_scan_status("Look up Edge")

  stat = _ae_getedge(inp[0],inp[1])
  if (stat == -1) {
    msg = sprintf("Cannot calculate the scan parameters, scan aborted!")
    eprodc_energy_scan_status(msg)
    egui_logmsg(msg)
    exit
  }

  eprodc_energy_scan_status("Preset scan parameters")
  stat = _ae_prepscan()
  if (stat == -1) {
    msg = sprintf ("Cannot preset the scan parameters, scan aborted!")
    eprodc_energy_scan_status(msg)
    egui_logmsg(msg)
    exit
  }

  msg = sprintf("Moving mono to %g+30 eV",AE_E)
  eprodc_energy_scan_status(msg)

  #move to the remote energy
  COLLECT_SEQ["energy"]=(AE_E+30)/1000.0
  if (eprodc_set_mono() == -1) {
    msg = sprintf("Cannot set the mono to %g eV, scan aborted!", AE_E+30)
    eprodc_energy_scan_status(msg)
    egui_logmsg(msg)
    exit
  }

  if (ESCAN_TST_UND == 0) {
    eprodc_energy_scan_status("Moving undulators")
    stat = _ae_moveundulators()
    if (stat == -1) {
      msg = sprintf ("Cannot move undulators, scan aborted!")
      eprodc_energy_scan_status(msg)
      egui_logmsg(msg)
      exit
    }
  }

  eprodc_energy_scan_status("Setting up the attenuation, please wait")

  _ae_shutters_open()
  if (ESCAN_TST_ATTSCAN == 0) {
    stat = ae_attscan()
    if (stat == -1 && AE_SIMUL == 0) {
      msg = sprintf("Cannot find appropriate attenuation, scan aborted!")
      eprodc_energy_scan_status(msg)
      printf ("%s\n",msg)
      egui_logmsg(msg)
      exit
    }
  }

  msclose

  if (ae_prepare_mono() != 0) {
    msg = sprintf("Mono not ready, procedure aborted!")
    eprodc_energy_scan_status(msg)
    egui_logmsg(msg)
    exit
  }

  ae_plotselect()
  msopen
  eprodc_energy_scan_status("Doing the Escan now, please wait")
  if (ESCAN_TST_ESCAN == 0) {
    stat = ae_scan()
    if (stat == -1) {
      msg = sprintf ("Cannot do the Escan, procedure aborted!")
      eprodc_energy_scan_status(msg)
      egui_logmsg(msg)
      exit
    }
  }
  _ae_shutters_close()

  if (ae_restore_mono() != 0) {
    msg = sprintf("Attention, mono setup not restored!")
    eprodc_energy_scan_status(msg)
    egui_logmsg(msg)
  }

  eprodc_energy_scan_status("Scan successfully completed, cleaning up")

  starte = AE_RCM[AE_RCM_SCANLO2]/1000
  ende = AE_RCM[AE_RCM_SCANHI1]/1000
  exptime = AE_SCAN_TIME * ((AE_RCM[AE_RCM_SCANHI1] - \
  AE_RCM[AE_RCM_SCANLO2]) / AE_STEP[1])

  local af
  af = getMxCurrentTransmission()
  local bsx
  bsx = getMxBeamSizeX()*1000.
  local bsy
  bsy = getMxBeamSizeY()*1000.

  _ae_postscan()

  eprodc_energy_scan_status("")
  egui_logmsg("Energy scan successfully completed")
  AE_DOSCAN = 0
  return ["transmissionFactor":af, "startEnergy":starte, "endEnergy":ende, "exposureTime":exptime, "beamSizeVertical":bsy, "beamSizeHorizontal":bsx, "theoreticalEdge":AE_E]
}'

def test_mad '{
global ESCAN_TST_FRONTEND ESCAN_TST_UND ESCAN_TST_REALIGN
global ESCAN_TST_ATTSCAN ESCAN_TST_ESCAN

  printf ("For testing only, you may choose to simulate the:\n")
  ESCAN_TST_FRONTEND = yesno("\tfront end opening?", ESCAN_TST_FRONTEND)
  ESCAN_TST_UND = yesno("\tundulator(s) moving?", ESCAN_TST_UND)
  ESCAN_TST_REALIGN = yesno("\tquick realignment?", ESCAN_TST_REALIGN)
  ESCAN_TST_ATTSCAN = yesno ("\tattenuation scan?", ESCAN_TST_ATTSCAN)
  ESCAN_TST_ESCAN = yesno("\tenergy scan?", ESCAN_TST_ESCAN)

}'
#%IU% (keyword)
#%MDESC% Return 1 if the macro named %B%keyword%B% exist, 0 otherwise.
def ismacro(keyword) '{
    return ((whatis(keyword)&2)==2)
}'

#%MACROS%
#%IMACROS%

#%DEPENDENCIES%
#%B%fldet.mac%B% - insert/extract the fluorescent detector%BR%
#%B%id.mac%B% - undulators%BR%
#%B%matt.mac%B% - attenuators%BR%
#%B%mxautochooch.mac%B% - chooch functions and calls
#%B%mxcollect.mac%B% - auxilary data collection functions%BR%
#%B%mxutils.mac%B% - Utility macros and functions%BR%
#%B%MAD_id**.mac%B% - local MAD functions%BR%
#%B%multimca.mac%B% - mca%BR%
#%B%wagoct.mac%B% - electrometer gains%BR%
#%B%attfactor.mac%B% - transmission factor%BR%
#%TOC%
#%AUTHOR% A.Beteva/BLISS
#$Revision: 1.28 $$Date: 2014/10/03 10:38:10 $