esrf

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

#%TITLE% id9eds.mac
#%NAME% Macros for Energy dispersive scattering 
#%CATEGORY% Scans, Beamlines
#%DESCRIPTION% 
# This macro set is used on beamline ID9 for High Pressure Work for
# the moment. The reciprocal space is searched for reflections. 
# Utilities to index this reflections and find other reflections are provided
#%OVERVIEW%
#%DL%
#%DT% Initializing the macro package %DD%
#   %UL%
#   %LI% You initialize the eds macros with %B%edssetup%B%
#   %XUL%
#%DT% Searching for reflections %DD%
#   %UL%
#   %LI% Searching for reflections in the chi , theta space can be
#          done with %B%edssearch%B%
#   %XUL%
#%DT% Entering the crystal parameters %DD%
#   %UL%
#   %LI% You can enter the crystal parameters by hand with %B%setlat%B%     
#   %LI% You can calculate the lattice and OM with %B%autoindex%B%
#   %XUL%
#%DT% Finding the OM %DD%
#   %UL%
#   %LI% You can create an index file by hand with %B%editlist%B%     
#   %LI% Calculate the OM and put it into spec with %B%indexcell%B%
#   %XUL%
#   Another posibility is to enter the OM by hand
#   %UL%
#   %LI% Enter the OM by hand with %B%enterUB%B%
#   %LI% List the OM with %B%listUB%B%
#   %XUL%
#%DT% Refining the OM %DD%
#   %UL%
#   %LI% You can refine the OM with %B%leastsquares%B%     
#   %XUL%
#%DT% Working with the OM %DD%
#   %UL%
#   %LI% You can go to an angle specified by hkl with %B%angles%B%.
#   %LI% You can calculate hkl for a specific set of angles with %B%hkl%B%.
#   %LI% You can index a complete reflection file with %B%indexfile%B% 
#   %LI% You can create all the accessible reflections and put them
#            into a file with %B%calcall%B% 
#   %LI% You can move to all these reflections easily with
#        %B%nextref%B%
#   %XUL%
#%DT% File format %DD%
# The following file format for reflection files is used : %BR%
#   %5d %5.2f %5.2f %5.2f %7.2f %10.4f %10.4f %10.4f %7d %6.3f %1d %3d %BR%
#   <Reflection number> , <H> , <K> , <L> , <Energy in keV>, <Omega in degree>,
#   <Chi in degree>, <Phi in degree>, <Intensity in integr. counts>, 
#   <FWHM in keV> <Flag for multiplett> <flag if selected> %BR%
#   Reflections have flag=1 after search procedure, flag=16 means
#   that the reflaction is selected. 
#%XDL%
#%ATTENTION%
# Do not forget to select reflections (flag set to 16), for those reflections
# you would like to use in the different external programs (like
# calculating the OM , auoindexing, ...)
#	
#%UU% [two-theta minth maxth] 
#%MDESC% This macro initializes the global variables and ask the user
# for some values which will not change later. It has to be called 
# before doing anything else. The user is asked to enter the two-theta
# angle, where he would like to carry out the measurement and limits
# for the theta movement.
def edssetup '
{
global EDSSEARCHFILE EDSAN0 EDSAN1 EDSAN2 EDSMNE EDSSPEED
global EDSOLDSPEED EDSOLDBASE EDS_WA EDS_WB EDSSNO EDSMNE EDS_LINES EDS_MAXNO
global EDS_RESGROUP EDS_ED EDS_TTH EDS_COMMENT EDSMNO
global EDS_INDth EDS_INDtth EDS_INDchi 
global EDS_MINC EDS_MAXC EDS_PEAKS
global MIN_EN MAX_EN MIN_INT EDSREFLFILE
global EDS_IPR EDS_MINTHT EDS_MAXTHT EDSREFLECTIONS

# Initialize global variables

EDS_IPR=12 # Number of items per data record
EDS_MINC=0 # min channel to read
EDS_MAXC=4095 # max channel

double array EDS_RES[2048][EDS_IPR]

EDSMNO = 2 ;  EDSMNE[0]="mchi" ; EDSMNE[1]="mth" ; EDSMNE[2]="twot"

if ($# != 3) {
  EDS_TTH=getval("Two Theta",EDS_TTH)
  EDS_MINTHT=getval("Minimum Value of theta",EDS_MINTHT)
  EDS_MAXTHT=getval("Maximum Value of theta",EDS_MAXTHT)
} else {
  EDS_TTH=$1 ; EDS_MINTHT=$2 ; EDS_MAXTHT=$3
}

EDS_ED=12.398/2/sin(EDS_TTH/2*PI/180)

EDS_INDchi = motor_num(EDSMNE[0]) ; EDS_INDth = motor_num(EDSMNE[1])
EDS_INDtth = motor_num(EDSMNE[2])

if ((EDS_INDchi == -1) || (EDS_INDth == -1) || (EDS_INDtth == -1)) {
  printf ("ERROR: %s, %s and %s must be defined!\n",\
     EDSMNE[0],EDSMNE[1],EDSMNE[2])
  exit 
  }

EDSOLDSPEED=motor_par(EDS_INDth,"velocity")
EDSOLDBASE=motor_par(EDS_INDth,"base_rate")

}
'

#%IU%
#%MDESC%
# This macro is called from edssearch to ask the user for the parameters
# of the search to be carried out.

def edssearchinput '
{
local range
EDSSEARCHFILE=getval("Filename of the search result file",EDSSEARCHFILE)
EDSSPEED=getval("Theta scan speed in seconds per degree ",EDSSPEED)
printf("FWHM = sqr[a^2 + b*E + (c*E)^2]\n")
EDS_WA=getval("Term (a) in keV",EDS_WA)
EDS_WB=getval("Term (b) in keV",EDS_WB)
EDS_WC=getval("Term (c)       ",EDS_WC)
MIN_EN=getval("Minimum Energy to save",MIN_EN)
MAX_EN=getval("Maximum Energy to save",MAX_EN)
MIN_INT=getval("Minimum Intensity to save",MIN_INT)

for (ii=0;ii<EDSMNO;ii++) {
  EDSAN0[ii]=getval(sprintf("From %s",EDSMNE[ii]),EDSAN0[ii])
  EDSAN1[ii]=getval(sprintf("To %s",EDSMNE[ii]),EDSAN1[ii])
  EDSAN2[ii]=getval(sprintf("Step size %s",EDSMNE[ii]),EDSAN2[ii])
  }

# Prepare file EDSSEARCHFILE (delete if user wants to and write header
# for new file
EDSSNO=0
if (!unix(sprintf("test -r %s",EDSSEARCHFILE))) {
  edsreadfile EDSSEARCHFILE 1
  EDSSNO =EDS_MAXNO+1
  if (yesno(sprintf("Delete the existing file %s",EDSSEARCHFILE),0)) {
    close(EDSSEARCHFILE)
    unix(sprintf("/bin/rm -f %s",EDSSEARCHFILE))
    EDSSNO = 0
    }
  }

if (!EDSSNO) {
  EDS_COMMENT=getval("Enter Description of Experiment ",EDS_COMMENT)
  eds_fileheader EDSSEARCHFILE "edssearch" 1
}

}'


#%IU%
#%MDESC% Move eds two theta motor to EDS_TTH
def eds_movetth '
    waitmove ; eds_getangles ; A[EDS_INDtth] = EDS_TTH ; move_em ; waitmove
'

#%IU%
#%MDESC% Move eds theta motor to EDS_AN0[1] and chi to EDS_AN0[0]+nchi*chistep
def eds_movechi '
    waitmove ; eds_getangles
    A[EDS_INDchi] = EDSAN0[0]+nchi*chistep ; A[EDS_INDth] = EDSAN0[1]
    move_em ; waitmove
'

#%IU%
#%MDESC% Starts the theta motor
def eds_startmoveth '
    waitmove ; eds_getangles ; A[EDS_INDth] = EDSAN0[1]+nth*thstep ; move_em
'

#%IU% 
#%MDESC% Calculates thcen and thdelta. In the old version the search
#subdivided the th steps to get better resolution. As this was not
#used it is removed in this version
def eds_getthdth '
  thcen = A[EDS_INDth] - thstep/2
  thdelta = thstep/2
'


#%IU%
#%MDESC% 
# A get_angles with printing the motor positions on the screen.
#
def eds_getangles '
   get_angles
   printf ("Chi: %10.4f Theta: %10.4f\r",A[EDS_INDchi],A[EDS_INDth]) 
'


#%IU%
#%MDESC%
# Moves theta motor slowly and aquires data on the mca
def eds_searchth '
{
  waitmove

  eds_slow 
  eds_mcaacqstart
  eds_startmoveth

  # This part counts on the MCA during motor movement
  eds_mcaacqstop

  eds_fast
}'

#%IU%
#%MDESC% 
# Searches for peaks in the energy spectrum, plots the spectrum and
# writes the result into the file and on the screen.
def eds_findpeak '
  eds_psearch
  eds_plotspectrum
  eds_writeinfile
'

#%UU%
#%MDESC% This macro initiates the actual search procedure. The user
# is asked to specify the necessary parameters and the search is
# started. The following questions are asked:
# %PRE%
# Filename of the search result file        All output will go to this file
# Theta scan speed in seconds per degree 
#   FWHM = sqr[a^2 + b*E + (c*E)^2]        These parameters are used for
#     Term (a) in keV                      the peak search (in the Energy
#     Term (b) in keV                      spectrum).
#     Term (c) 
# Minimum Energy to save                   These parameter allow to
# Maximum Energy to save                   restrict the peaks which will
# Minimum Intensity to save                be accepted
#    and for every angle
# From <angle>                             A step scan in chi and a continous
# To <angle>                               scan in theta will be carried 
# Step size <angle>                        out.
# %PRE%
# The following procedure is used to search for scans :
# %UL%
#   %LI% Move two theta angle to the user specified value
#   %LI% Make a step scan in chi
#   %LI% At every point in chi move theta slowly (speed asked above) 
#        to the next theta point. During this time acquire on the MCA.
#   %LI% If peaks in the energy spectrum are found which satisfy the 
#        user conditions, they are written to the file
# %XUL%

def edssearch '
{ 
  local manchi chistep manth 
  edssearchinput
  eds_fast
  eds_initmca 

  # Calculate nb of steps and stepsize for chi (manchi,chistep) ,
  # and th (manth,thstep)
  manchi=int(fabs(EDSAN1[0]-EDSAN0[0])/EDSAN2[0])+1
  chistep = (EDSAN1[0]-EDSAN0[0]) / (manchi-1)
  manth=int(fabs(EDSAN1[1]-EDSAN0[1])/EDSAN2[1])+1
  thstep = (EDSAN1[1]-EDSAN0[1]) / (manth-1)

  # The main loop
  eds_movetth
  for (nchi=0; nchi<manchi; nchi++) {
    eds_movechi
    for (nth=1; nth<manth; nth++) {
      eds_searchth
      eds_findpeak
    }
  }

}
'


#%IU%
#%MDESC% Sets the velocity and base rate of the theta motor to the
# saved normal speeds EDSOLDSPEED and EDSOLDBASE
def eds_fast '
  motor_par(EDS_INDth,"velocity",EDSOLDSPEED) 
  motor_par(EDS_INDth,"base_rate",EDSOLDBASE)
'


#%IU%
#%MDESC% Sets the velocity and base rate to the slow EDSSPEED (in
# s/degree) 
def eds_slow '
{
  stepsize=fabs(motor_par(EDS_INDth,"step_size"))
  motor_par(EDS_INDth,"velocity",stepsize/EDSSPEED) 
  motor_par(EDS_INDth,"base_rate",stepsize/EDSSPEED) 
}
'

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Attention this parts uses mca macros
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

def eds_mcaacqstart '
   mcaclear 
   mcastart 0
'

def eds_mcaacqstop '
   while (chk_move) {
      mca_read EDS_MINC EDS_MAXC
   } 
   mcastop
   mca_read EDS_MINC EDS_MAXC
'

def eds_initmca '
  # prepare step scans
  # Turn ON energy Mode if calibrated
  if (MCA_EB <= 0) {
    p "ERROR: MCA is not calibrated in Energy - You have to do that first"
    exit
  }
  MCA_ENERGY=1 
'

def eds_plotspectrum '
   mca_plotit MCA_AUTO MCA_AUTO MCA_AUTO MCA_AUTO
'

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Attention - this part uses the psearch macros
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

def eds_psearch '
mca_tops  # Will update PS_EA PS_EB PS_EC calibration parameters from interface
EDS_PEAKS = pssearch (MCA_DATA[][1],0,MCA_MEMGRPSIZE, \
			EDS_WA, EDS_WB, EDS_WC, 1, MIN_INT,0)
'

def eds_getpeakvalue '
{
idx = $1
if (idx < EDS_PEAKS) {
  p_energy = PS_PEAKS[idx][5] # [1] is the position in channels 
  p_intens = PS_PEAKS[idx][2]
  p_fwhm =   PS_PEAKS[idx][6] # [3] is the fwhm in channels
  p_multi =  PS_PEAKS[idx][4] ? 1 : 0 ; 
  p_no_more_peaks = 0
} else {
  p_no_more_peaks = 1
}
}'

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# File in/output
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#%IU%
#%MDESC% Writes the result from the peak search together with the
# current angles to the search file 
def eds_writeinfile '
   
   waitmove ; eds_getangles

   for(jj=0;;jj++) {
     local p_energy p_fwhm p_multi p_intens 
     local omega thcen thdelta

     eds_getpeakvalue jj
     if (p_no_more_peaks) break;

     eds_getthdth
     omega = thcen - A[EDS_INDtth]/2

     if ((p_energy > MIN_EN) && (!MAX_EN || p_energy < MAX_EN) \
			       && (!MIN_INT || p_intens > MIN_INT)) { 
     printf(\
 	"%5d %7.2f %10.4f %10.4f %5.2f %7d %6.3f %1d \n",\
  	++EDSSNO,p_energy,thcen,A[EDS_INDchi],0.,\
	p_intens,p_fwhm,p_multi)     
     fprintf(EDSSEARCHFILE,\
      "%5d %5.2f %5.2f %5.2f %7.2f %10.4f %10.4f %10.4f %7d %6.3f %1d %3d\n",\
  	EDSSNO,0,0,0,p_energy,omega,A[EDS_INDchi],0.,\
	p_intens,p_fwhm,p_multi,1)     
     }
}'

#%IU% [filename] [print-flag]
#%MDESC% Reads file with EDS_IPR items per line and comment lines
# in the array EDS_RES. If print-flag is true, every line will
# be printed on the screen. %BR%
# EDS_LINES will hold the number of data lines and EDS_MAXNO will have
# the maximum value in the first column (The peak number).

def edsreadfile '
{
  local _f 
  if ($# > 0) {_f=$1} else {_f=getval("Filename to read reflections","")}

  if (file_info(_f,"-r") == 1) {
#    array_read dows not return the number of lines just ignore
#    EDS_LINES=array_read(_f, EDS_RES)
    EDS_RES[][0]=0
    array_read(_f, EDS_RES)
    EDS_LINES=array_op("sum",(EDS_RES[][0] != 0))
    EDS_MAXNO=array_op("max",EDS_RES[:EDS_LINES][0])
    printf("%d datapoints read from file %s\n",EDS_LINES,_f)
  } else {
    print "File ",_f,"does not exist"
    exit
  }
}'

#%IU% [filename] [macro name for comment]
#%MDESC% Writes file with reflections with data from EDS_RES
# EDS_LINES holds the number of data lines.
# 
def edswritefile '{
  local _f cnt
  if ($# > 0) {
    _f=$1 
  } else {
    _f=getval("Filename to save reflections","")
  }
  
  if (file_info(_f,"-r") == 1) {
    close (_f)
    unix(sprintf("mv %s %s.bak",_f,_f))
  }

  # Save group to file with comments      
  eds_fileheader _f "$2"
	
# Format: no H K L E/tth omega chi phi I fwhm multi flag

  for(ii=0,cnt=1; ii<EDS_LINES; ii++) {
    if (EDS_RES[ii][0]) fprintf(_f,\
      "%5d %5.2f %5.2f %5.2f %7.2f %10.4f %10.4f %10.4f %7d %6.3f %1d %3d\n",\
      cnt++,EDS_RES[ii][1],EDS_RES[ii][2],EDS_RES[ii][3], \
      EDS_RES[ii][4],EDS_RES[ii][5],EDS_RES[ii][6],EDS_RES[ii][7], \
      EDS_RES[ii][8],EDS_RES[ii][9],EDS_RES[ii][10],EDS_RES[ii][11])
  }
  close(_f)
} '

def eds_listrefl '{
  local ii
  for(ii=0;ii<EDS_LINES;ii++) {
    if (EDS_RES[ii][0]) 
      printf(\
       "%5d %5.2f %5.2f %5.2f %7.2f %10.4f %10.4f %10.4f %7d %6.3f %1d %3d\n",\
        EDS_RES[ii][0],EDS_RES[ii][1],EDS_RES[ii][2],EDS_RES[ii][3], \
        EDS_RES[ii][4],EDS_RES[ii][5],EDS_RES[ii][6],EDS_RES[ii][7], \
        EDS_RES[ii][8],EDS_RES[ii][9],EDS_RES[ii][10],EDS_RES[ii][11])
  }
}'


#%IU% <filename> <macro name for comment> [no geo parameters]
#%MDESC% Saves information in the file header for reflection list and
#other files, The header includes USER, SPEC, date(), EDS_COMMENT,
#lattice const, UB. The third parameter can be set to 1 if no
#geometric parameters like OM and lattice should be in the header.


def eds_fileheader ' {
  local _fn
  _fn = $1
  fprintf(_fn,"#C %20s %20s %30s\n","User","Version","Date")
  fprintf(_fn,"#H %20s %20s %30s\n",USER,SPEC,date())
  fprintf(_fn,"#U Description: %-55s\n",EDS_COMMENT)
  if ($3 == 0) {
    fprintf(_fn,"#U Lattice Constants: %8.4f %8.4f %8.4f %7.3f %7.3f %7.3f\n",\
      g_aa,g_bb,g_cc,g_al,g_be,g_ga)
    fprintf(_fn,"#U OM1: %10.6f %10.6f %10.6f\n",UB[0]/PI2,UB[3]/PI2,UB[6]/PI2)
    fprintf(_fn,"#U OM2: %10.6f %10.6f %10.6f\n",UB[1]/PI2,UB[4]/PI2,UB[7]/PI2)
    fprintf(_fn,"#U OM3: %10.6f %10.6f %10.6f\n",UB[2]/PI2,UB[5]/PI2,UB[8]/PI2)
  }
  fprintf(_fn,"#C Created by : $2\n")
  fprintf(_fn,"#C Two Theta : %f Theta Limits: %f - %f\n", \
		EDS_TTH,EDS_MINTHT,EDS_MAXTHT)
  fprintf(_fn,"#C No H K L E Omega Chi Phi I FWHM Multi Flag\n")
} ' 


#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This section is for the geometric calculations
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#%IU%
#%MDESC% This macro does something very tricky 
#  be able to load the OM into SPEC. The problem is that SPEC has a
#  Flag set either if it starts up or if somebody calls calcG that the
#  OM should be recalculated on the next calcA from the primary and
#  secondary orientations. So all what I can think of is to force a
#  recalculation before loading the matrix.
def eds_preloadmatrix '
 H=1; K=0; L=0; calcA
'

#%UU% [E chi th]
#%MDESC% This macros calculates the HKL for a given E,th,chi pair.

def hkl '{
  local l_chi l_E l_om l_thy
  if ($#) {
    l_E   = $1
    l_chi = $2
    l_th  = $3
  } else {
    get_angles
    l_E   = getval("Energy of the reflection [keV]",35)
    l_chi = getval("Chi of the reflection",A[EDS_INDchi])
    l_th  = getval("Theta of the reflection",A[EDS_INDth])
  }
  l_om = l_th - EDS_TTH/2
  eds_eds2hkl l_E l_om l_chi
  printf("H K L =  %.5g  %.5g  %.5g\n",H,K,L)
  printf("\n%9.9s %9.9s %9.9s\n","E","chi","th")
  printf("%9.4f %9.4f %9.4f\n",l_E,l_chi,l_th)
}'


#%UU%
#%MDESC% Indexes a reflection list by using spec`s orientation matrix. 
#The old hkl from the reflection list will be deleted from the file.

def indexlist '
{
  local ii 

  EDSINDEXFILE = getval("Name of the file to index",EDSINDEXFILE)

  edsreadfile EDSINDEXFILE 0
  for (ii=0;ii<EDS_LINES;ii++) {
    eds_eds2hkl EDS_RES[ii][4] EDS_RES[ii][5] EDS_RES[ii][6]
    EDS_RES[ii][1] = H ; EDS_RES[ii][2] = K ;EDS_RES[ii][3] = L 
  }

  edswritefile EDSINDEXFILE "indexlist"
  printf("Indexing completed.\n")
}'

#%IU% <E> <omega> <chi> 
#%MDESC% This macro calculates the fourc angles from the eds "angles"
# E omega chi. The fourc values are returned in the variables 
# ftth, fth, fchi, and fphi. It uses the LAMBDA and EDS_ED.

def eds_eds2fourc '
{
  fphi = 0
  fchi = $3
  ftth = asin(LAMBDA*0.5/EDS_ED*$1)*360/PI
  fth = $2+0.5*ftth
} '


#%IU% <E> <omega> <chi> 
#%MDESC% This macro calculates hkl given in H K L from the eds
# "angles" E omega chi

def eds_eds2hkl '
{
  local ftth fth fchi fphi 
  eds_eds2fourc $1 $2 $3 
  get_angles ; A[tth]=ftth ; A[th]=fth ; A[chi]=fchi ; A[phi]=fphi
  calcHKL
} '



#********************************************************
#%UU%
#%MDESC%
# Asks user to enter the Orientation matrix in the UB array
# Rows have to be entered, separated by space.

def enterUB ' {
  local x
  print "Enter Orientation Matrix by Row"
  eds_preloadmatrix
  x = getval("Row 1:",sprintf("%f %f %f",UB[0]/PI2,UB[3]/PI2,UB[6]/PI2))
  sscanf(x,"%f %f %f",UB[0],UB[3],UB[6])
  x = getval("Row 2:",sprintf("%f %f %f",UB[1]/PI2,UB[4]/PI2,UB[7]/PI2))
  sscanf(x,"%f %f %f",UB[1],UB[4],UB[7])
  x = getval("Row 3:",sprintf("%f %f %f",UB[2]/PI2,UB[5]/PI2,UB[8]/PI2))
  sscanf(x,"%f %f %f",UB[2],UB[5],UB[8])
  eds_multUB2PI
}'

#%IU%
#%MDESC% Multiplies Spec UB by 2 * PI
def  eds_multUB2PI '
{ 
 local ii
 for (ii=0;ii<9;ii++) {
   UB[ii] *= PI2
 } 
}'

def PI2 '(PI*2)'


#********************************************************
#%UU%
#%MDESC%
# Prints the UB matrix on the screen
def listUB '
  {
  print "Orientation Matrix by Row:"
  print ""
  printf("Row 1: %10.5f %10.5f %10.5f\n",UB[0]/PI2,UB[3]/PI2,UB[6]/PI2)
  printf("Row 2: %10.5f %10.5f %10.5f\n",UB[1]/PI2,UB[4]/PI2,UB[7]/PI2)
  printf("Row 3: %10.5f %10.5f %10.5f\n",UB[2]/PI2,UB[5]/PI2,UB[8]/PI2)
  }
'

#%UU%
#%MDESC% 
# This macro calls the external program refine_cell_spec to do a least
# square fit on all the selected (with flag bit 0x10 set to 1) reflections
# in a file.

def leastsquares '
{
  global EDSINDEXFILE
  local res ftemp lat ff

  EDSINDEXFILE=getval("Index file name (for least square fit)",EDSINDEXFILE)

  res=data_pipe("refine_cell_spec",sprintf("%s %f",EDSINDEXFILE,EDS_ED),0,0)
  if (split(res,ftemp) == 15) {
    eds_preloadmatrix
    for (i=0;i<9;i++) { 
      UB[i]=ftemp[i]*PI2 # det(OM) = 2 Pi in spec , 1 in calc_om_spec
    }
    
    for (i=9;i<15;i++) { 
      ff[i-9]=ftemp[i]+0.0
    }
    setlat ff[0] ff[1] ff[2] ff[3] ff[4] ff[5] 
  
  } else {
    print "Error in refining cell"
  }
}
'
#%UU%
#%MDESC% 
# This macro calls the external program autoindex_spec to try to find
# the indexes of the selected (with flag bit 0x10 set to 1) reflections
# in a file.

def autoindex '
{
  global EDSINDEXFILE
  local res ftemp lat ff

  EDSINDEXFILE=getval("Index file name (for least square fit)",EDSINDEXFILE)

  res=data_pipe("autoindex_spec",sprintf("%s %f",EDSINDEXFILE,EDS_ED),0,0)
  if (split(res,ftemp) == 15) {
    eds_preloadmatrix
    for (i=0;i<9;i++) { 
      UB[i]=ftemp[i]*PI2 # det(OM) = 2 Pi in spec , 1 in calc_om_spec
    }
    
    for (i=9;i<15;i++) { 
      ff[i-9]=ftemp[i]+0.0
    }
    setlat ff[0] ff[1] ff[2] ff[3] ff[4] ff[5] 
  
  } else {
    print "Error in autoindexing"
  }
}
'


#********************************************************
#%UU% 
#%MDESC% The macro calls the external program calc_om_spec to
# calculate the orientation matrix from reflections in a file
# (default EDSINDEXFILE). The user selects the reflections and enters
# at the keyboard the hkl values. The orientation matrix is calculated
# and inserted into spec. 

def indexcell '
  {
  global EDS_UB EDSINDEXFILE
  local i ii file ftemp lat 
  lat=sprintf("%f %f %f %f %f %f %f",EDS_ED,g_aa,g_bb,g_cc,g_al,g_be,g_ga)

  EDSINDEXFILE = getval("Index file name (to calc. OM)",EDSINDEXFILE)

  res = data_pipe("calc_om_spec",sprintf("%s %s",EDSINDEXFILE,lat),0,0)
  if (split(res,ftemp) == 9) {
    eds_preloadmatrix
    for (i=0;i<9;i++) { 
      UB[i]=ftemp[i]*PI2 # det(OM) = 2 Pi in spec , 1 in calc_om_spec
    }
  } else {
    print "Error in indexing cell"
  }
}
'

#%UU% <h> <k> <l>
#%MDESC% Calculates E, theta (omega), chi for the given h k l and
# offers the user a choice to move the motors to this position

def angles '
{ 
  local ftemp h k l v_omega v_chi v_energy v_theta
  h=$1 ; k=$2 ; l=$3

  if ($# < 3) {
     printf("Usage: angles h k l\n")
     exit
  }

  eds_calcangles h k l

  if (v_theta > EDS_MAXTHT || v_theta < EDS_MINTHT ) {
     printf("Out of Bounds (%f < th < %f)\n",EDS_MINTHT,EDS_MAXTHT)
  } else { 
     printf(" Energy: %10.4f; Theta: %10.4f; Chi: %10.4f\n" \
		,v_energy,v_theta,v_chi)

     if (yesno("Drive to Position",0)) {
        get_angles
        A[EDS_INDth] = v_theta
        A[EDS_INDchi] = v_chi
        move_em
	_update2 EDS_INDth EDS_INDchi
     }
  }
}
'

#%UU%
#%MDESC% Add reflections to a list of reflection, edit reflection
# list. Very primitive for the moment. Should be replaced with an
# editor later. For the moment you can enter the following commands:
# %DL%
# %DT% L %DD% List all reflections. This is the default action when you
#             just type ENTER. 
# %DT% D %DD% Delete one reflection. You will be asked for a reflection 
#             number. The reflections will be renumbered only when written 
#             to disk. 
# %DT% A %DD% Add a reflection by hand. You will be asked to enter the 
#             energy, th and chi where you found the reflection.
# %DT% M %DD% Mark a reflection so it will be used by further programs (like
#             autoindexing, least square fitting or index cell). Marked 
#             lines will have a 16 in the last column.
# %DT% M %DD% Restore all reflections from the index file. All your changes
#             will be lost.
# %DT% E %DD% Call the editor (specified in the global variable EDITOR) to
#             edit the reflection list. You will not be editing the index
#             file directly , but a temporary file. Only when you write 
#             the changes back to the index file when you quit, will you make
#             your changes permanent.
# %DT% Q %DD% Quit the editor. You will be asked if you want to save your 
#             changes. The default answer is yes. If you do not save your 
#             changes, then they will be lost.
# %XDL%

def editlist '{

  global EDS_UB EDSINDEXFILE
  local _f ii idx g v_ene v_chi v_theta i 
  global EDS_GR_MOD

  rdef cleanup \'
    undef cleanup
    eds_savegroup
  \'

  EDS_GR_MOD=0

  EDSINDEXFILE = getval("Index file name (to edit)",EDSINDEXFILE)

  if (file_info(EDSINDEXFILE,"-r") == 1) {
    edsreadfile EDSINDEXFILE 1
  } else {
    p "File",EDSINDEXFILE,"does not exit (will be created)"
    EDS_LINES = 0
  }
 
  while (1) {
    cho = getval(\
	"(L)ist (D)elete (A)dd (M)ark Refl., (R)estore, (E)dit, (Q)uit","l");

    if (cho == "x" || cho == "q") 
      break;
    
    if (cho == "l") {
      eds_listrefl
      continue;
    }

    if (cho == "r") {
      edsreadfile EDSINDEXFILE 0
      EDS_GR_MOD=0
    }

    if (cho == "e") {
      tempf = sprintf("/tmp/,editl_%s_%s.tmp",SPEC,USER)  
      unix (sprintf("/bin/rm -f %s",tempf))
      edswritefile tempf "editlist" 
      unix (sprintf("%s %s",EDITOR,tempf))	
      edsreadfile tempf 0 
      EDS_GR_MOD=1
    }

    if (cho == "m") {
      rno = getval("Enter reflection number to mark",rno)
      for (idx = -1, ii=0; ii<EDS_LINES; ii++) 
	if (EDS_RES[ii][0] == rno) { 
	  idx = ii;
          break;
        }
      if (idx != -1) {
        EDS_RES[ii][EDS_IPR-1] = 16 
        EDS_GR_MOD=1
      }
    }

    if (cho == "d") {
      rno = getval("Enter reflection number to delete",rno)
      for (idx = -1, ii=0; ii<EDS_LINES; ii++) 
	if (EDS_RES[ii][0] == rno) { 
	  idx = ii;
          break;
        }
      if (idx != -1) {
        EDS_RES[ii][0] = 0
        EDS_GR_MOD=1
      }
    }

    if (cho == "a") {
      ii=EDS_LINES++

      # ask user
      v_ene=getval("Energy of peak",v_ene)
      v_chi=getval("Chi of peak",A[EDS_INDchi])
      v_theta=getval("Theta of peak",A[EDS_INDth])
      
      # Put in array
      v_omega=v_theta-EDS_TTH/2
      for(i=0;i<EDS_IPR;i++) {
        EDS_RES[ii][i] = 0
      }
      EDS_RES[ii][0] = EDS_LINES
      EDS_RES[ii][EDS_IPR-1] = 16  # select this peak for calc_om and ....
      EDS_RES[ii][4] = v_ene; EDS_RES[ii][5] = v_omega; EDS_RES[ii][6] = v_chi
      EDS_GR_MOD=1
    }
  }
}
cleanup
'

#%IU%
#%MDESC% Saves group into file if EDS_GR_MOD is true. Will be called
#from cleanup. Used in editlist.
 
def eds_savegroup '
  if (EDS_GR_MOD) {
    if (yesno(sprintf("Save your changes to file (%s)",EDSINDEXFILE),1)) {
       print "Saving modified group to file .. "
      edswritefile EDSINDEXFILE "editlist" 
    }
  }
'

#%UU%
#%MDESC% Calculates all possible reflections up to a certain energy.
# Only reflections are included which can not be divided by 2 or 3.
# (These reflections are at the same chi/th with twice (three times) 
# the energy)

def calcall '
{
  global EDSREFLECTIONS EDS_REF_FILE_OPEN EDS_EMAX
  local ftemp h k l _f emax ihmax ikmax ilmax dinv energy chi omega
  local ncalc ninrange hdiv_2 hdiv_3 hkdiv_2 hkdiv_3 hkldiv_2 hkldiv_3
  printf("Generate Entire Reflection List\n")
  EDSREFLECTIONS = getval("Enter Name of Reflection File",EDSREFLECTIONS)

  _f = EDSREFLECTIONS
  if (open(_f)) {
  } else {
    close(_f)
    unix(sprintf("mv %s %s.bak",_f,_f))
  }

  eds_fileheader EDSREFLECTIONS "calcall"

  EDS_EMAX=getval("Maximum Reflection Energy to Generate",EDS_EMAX)

  # h,k,l max from length of col vector of UB (/2Pi because of spec convent)
  efund=EDS_ED*sqrt((UB[0]*UB[0]+UB[3]*UB[3]+UB[6]*UB[6]))/PI2
  ihmax=int(EDS_EMAX/efund)+1  
  efund=EDS_ED*sqrt((UB[1]*UB[1]+UB[4]*UB[4]+UB[7]*UB[7]))/PI2
  ikmax=int(EDS_EMAX/efund)+1  
  efund=EDS_ED*sqrt((UB[2]*UB[2]+UB[5]*UB[5]+UB[8]*UB[8]))/PI2
  ilmax=int(EDS_EMAX/efund)+1

  ncalc=0 ; ninrange=0  # numb. of refl calculated and numb. in th range

  # triple loop : loop 0<h<ihmax , -ikmax<k<ikmax , -ilmax<l<ilmax  
  for (h=0; h<=ihmax; h++) {
    hdiv_2 = h%2 ; hdiv_3 = h%3  # true if h can not be divided by 2 (3)
    for (k=-ikmax; k<=ikmax; k++) {
      hkdiv_2= hdiv_2 ? 1 : fabs(k)%2  ; hkdiv_3= hdiv_3 ? 1 : fabs(k)%3 ;
      for (l=-ilmax; l<ilmax; l++) {
	hkldiv_2 = hkdiv_2 ? 1:fabs(l)%2  ; hkldiv_3 = hkdiv_3 ? 1:fabs(l)%3 ; 
	# if hkl can be divided by 2 (3) then do not include
        if ( hkldiv_2 == 0 || hkldiv_3 == 0 ) continue
        if (h == 0 && k == 0 && l == 0) continue  
        eds_calcangles h k l
	if (v_energy > 0 && v_energy <= EDS_EMAX) {
	  ncalc++
	
	  dobs = EDS_ED/v_energy
	  if (v_theta > EDS_MAXTHT || v_theta < EDS_MINTHT) {
	  } else { 
	         fprintf(_f,\
      "%5d %5.2f %5.2f %5.2f %7.2f %10.4f %10.4f %10.4f %7d %6.3f %1d %3d\n",\
      ninrange+1,h,k,l,v_energy,v_omega,v_chi,0.,0.,0.,0,0)
	     ninrange++
	  }
	}
      }
    }
  }
  close(_f)
  printf("%7d Refl. within Energy range. (E < %f)\n",ncalc,EDS_EMAX)
  printf("%7d Refl. within Theta Limits. (%f < t < %f) \n",ninrange,\
	EDS_MINTHT,EDS_MAXTHT)

  EDS_REF_FILE_OPEN = 0
}
'


#%IU% h k l
#%MDESC% Used to calculate chi, omega, and theta from h k l
# The output variable names are fixed to v_chi, v_omega v_theta v_energy  

def eds_calcangles '
  ftemp[0]=(UB[0]*$1 + UB[1]*$2 + UB[2]*$3)/PI2
  ftemp[1]=(UB[3]*$1 + UB[4]*$2 + UB[5]*$3)/PI2
  ftemp[2]=(UB[6]*$1 + UB[7]*$2 + UB[8]*$3)/PI2
  dinv = sqrt(ftemp[0]*ftemp[0]+ftemp[1]*ftemp[1]+ftemp[2]*ftemp[2])
  v_energy = EDS_ED * dinv
  if (ftemp[0] == 0) {
     v_chi = 0
  } else {
     v_chi=atan(ftemp[2]/ftemp[0])*180/PI
     if (ftemp[0] <0) {v_chi=v_chi-180}
     if (v_chi < -180) { v_chi=v_chi+360}
  }
  v_omega=asin(ftemp[1]/dinv)*180/PI
  v_theta=v_omega+EDS_TTH/2
'

#%UU% [force_new_file_flag]
#%MDESC% This macro goes to the next reflection from a user specified 
# reflection file. The angles are calculated from (hkl) in the file.
# If a parameter is given, it will ask the file name , otherwise it will
# ask the file name only the first time it is called.

def nextref'
{
  global EDSREFLECTIONS EDS_NEXTREFL EDS_REF_FILE_OPEN
  local _f line ftemp hh kk ll 

  if ($# != 0 || EDS_REF_FILE_OPEN == 0) {
    EDSREFLECTIONS = getval("Enter Name of Reflection File",EDSREFLECTIONS)
    edsreadfile EDSREFLECTIONS 0
    EDS_NEXTREFL = 0  
    EDS_REF_FILE_OPEN = 1
  }
  
  if (EDS_NEXTREFL >= EDS_LINES) {
    printf("End of Reflection file (%s) reached\n",EDSREFLECTIONS)
    EDS_REF_FILE_OPEN = 0
    exit
  } 
 
  hh = EDS_RES[EDS_NEXTREFL][1]
  kk = EDS_RES[EDS_NEXTREFL][2]
  ll = EDS_RES[EDS_NEXTREFL][3]
  printf("** Reflection %d from file %s\n",++EDS_NEXTREFL,EDSREFLECTIONS)

  angles hh kk ll
} '

#%MACROS%
#%IMACROS%
#%BUGS%
# There are some bugs or questions to be fixed 
# %PRE%
#  * Why are all the reflections ignored which can be divided by 2 or 3
#    in calcall. Not all people might want to have that.
#  * Autoindexing finds sometimes no suitable cr. and put metric tensor
#    to 0
#  * the interaction with psearch and mca has been isolated but that is
#    probably not good enough
# %PRE% 
#%AUTHOR% Larry Finger, Jorg Klora 93/94/95/96
#%TOC%