esrf

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

#%TITLE% EBPM.MAC
#
#%NAME%
#  EBPM.MAC - Macros for reading the machine electron BPM's
#
#%OVERVIEW%
#  This macro set allows to read the information provided by the
#  electron BPM's installed in the machine.
#  %BR%
#  All position and angles can be loaded in %B%spec%B% pseudocounters.
#  %BR%
#  An interactive macro %B%efbpm%B% can be used to read, display and save
#  the spectral distribution of the beam position and angle provided by
#  the machine eBPM's.
#  %BR%
#
#%EXAMPLE%
#  %DL%
#  %DT%ebpmsetup id3 x=hp x'=hang z=vp
#  %DD%Configures three spec counters to be loaded with different values
#      from the eBPM's in section 3. Counters \"hp\" and \"hang\" will be
#      loaded with the horizontal position and angle respectively from
#      the slow BPM's. Counter \"vp\" will take its value from the vertical
#      position provide by the eBPMs.
#  %DT%efbpm id30
#  %DD%Starts an interactive macro to display and save the frequency
#      spectrum of the fast electron beam position in the straight section 30.
#  %XDL%
#
#%SETUP%
# The %B%ebpmsetup%B% macro must be included in the setup file to declare
# the apropriate pseudocounters.%BR%
# The %B%efbpm%B% macro requires an instance of the %B%SpecfitServer%B% 
# module running in the same computer
#%BR% The SpecfitServer device must be define in the setup file using the macro %B%specfit_define%B%
#%BR%ex: specfit_define //gwenn/id24/specfit/bpm.
#%BR%and has to be set at tcp mode
#%BR%ex: taco_io("//gwenn/id24/specfit/bpm","tcp")
#%END%

#%HISTORY%
#$Log: ebpm.mac,v $
#Revision 1.9  2019/10/10 08:04:53  ohlsson
#Disabled version
#Since it use Taco
#
#Revision 1.6  2012/07/04 14:11:01  domingue
#now uses specfit_ebpm.mac
#
#Revision 1.5  2012/07/04 13:05:55  domingue
#remove the need of specfit.mac
#
#Revision 1.4  2012/07/04 12:58:53  domingue
#with tango ebpm server
#
#Revision 1.2  2005/04/28 16:49:39  fajardo
#Correction in the units for the slow ebpm pseudocounters.
#
#Revision 1.1  2004/10/11 11:32:40  fajardo
#Initial revision
#
#
#
#%END%

jtdo("specfit_ebpm")


#%UU% <idname> [<signal>=<mnemonic> ...]
#%MDESC%
#  Declares pseudocounters associates to the eBPM's corresponding to idname.
#  The available signals are:
#  %UL%
#  %LI%%B%x%B%- Horizontal position from the eBPM
#  %LI%%B%x'%B%- Horizontal angle from the eBPM
#  %LI%%B%z%B%- Vertical position from the eBPM
#  %LI%%B%z'%B%- Vertical angle from the eBPM
#  %XUL%
def ebpmsetup '{
   local retval

   if ($# == 0 || (retval = _ebpmsetup("$*"))) {
      if (SETUP) print "Error in line: $0 $*"

      print "Usage:  $0 idname [parameter=value ...]"
      if (yesno("\nDisplay online help", 0)) eval("help local ebpm")
   } 
}'

def _ebpmsetup(args) '{
   global EBPM[]

   local i nparam auxlist0[] auxlist1[] larr 
   local idname idnumber dev hdev vdev
   local chmne[] 

   nparam = split(args, auxlist0)
   for (i = 0; i < nparam; i++) {
      if (split(auxlist0[i], larr, "=") > 1){
         delete auxlist0[i]
         auxlist1[larr[0]] = larr[1]
      } else if (i > 1) {
         delete auxlist0[i]
         auxlist1[larr[0]] = "yes"
      }
   }
   if (!(0 in auxlist0)) {
      printf("Bad parameters\n")
      return(-1)
   }
   idname = auxlist0[0]
   sscanf(idname, "id%d", idnumber)
   if (idnumber <= 0 || idnumber > 32) {
      printf("Bad id name.\n")
      return(-1)
   }

   dev = "//orion:10000/sr/d-fbpm/" idname
   tango_get(dev, "State")
   if (TANGO_ERR != "0") {
      print "No eFBPM accessible at " idname
      print_tango_err()
      return(-1)
   }
   
   if (EBPM["setup_n"] != SETUP_N) {
      list_init EBPM
      EBPM["setup_n"] = SETUP_N
   }

   if (list_add(EBPM, idname) <= 0) {
      printf("Invalid efbpm name: %s\n", idname)
      return(-1)
   }

   EBPM[idname]["dev"] = dev
   EBPM[idname]["setup"] = "ebpmsetup " args

   if (!(EBPM["fitdev"] = specfit_start(1))) {
      printf("No SpecfitServer found running in the system.\n")
      return(-1)
   }
   EBPM["signal"][1] = "x"
   EBPM["signal"][2] = "z"
   EBPM["signal"][3] = "x\'"
   EBPM["signal"][4] = "z\'"
   EBPM["color"][1] = 2
   EBPM["color"][2] = 7
   EBPM["color"][3] = 4
   EBPM["color"][4] = 9

   # to avoid calling a macro from another file
   # anyway, it was hard-coded
   #EBPM["npts"] = specfit_par("maxfftpts")
   EBPM["npts"] = 8192
   
   float array efbpm_pos[5][EBPM["npts"]]
   array_op("fill", efbpm_pos[0][], 1 / 10)

   float array efbpm_fft[9][EBPM["npts"] / 2]
   array_op("fill", efbpm_fft[0][], 10 * 1000 / EBPM["npts"])
   efbpm_fft[0][] += efbpm_fft[0][1]


   if (!EBPM[idname]["filter"]) EBPM[idname]["filter"] = 10
   EBPM[idname]["plotfilter"] = 1
   if (!EBPM[idname]["Fmin"])   EBPM[idname]["Fmin"] = "auto"
   if (!EBPM[idname]["Fmax"])   EBPM[idname]["Fmax"] = "auto"
   if (!EBPM[idname]["Tmin"])   EBPM[idname]["Tmin"] = "auto"
   if (!EBPM[idname]["Tmax"])   EBPM[idname]["Tmax"] = "auto"
   if (!EBPM[idname]["plot"])   EBPM[idname]["plot"] = 15
   if (!EBPM[idname]["mode"])   EBPM[idname]["mode"] = "freq"

   ebpm_addgetcounts(idname, auxlist1)

   if ("updateT" in auxlist1)
      EBPM[idname]["updateT"] = (auxlist1["updateT"] + 0)
   else
      EBPM[idname]["updateT"] = 3
   delete auxlist1["updateT"]
   EBPM[idname]["nextT"] = 0

   setup_tail("ebpm", idname)

   i = ""
   for (i in auxlist1) {
      print "Invalid parameter: " i "=" auxlist1[i]
   } 
   if (i != "")
      return(-1)
   else
      return(0)
}'

def ebpm_addgetcounts(idname, auxlist1) '{
   local i num mne chname chid
   local nchan macrodef key

   nchan = 0
   macrodef = "\"" idname "\""
   for (i = 1; i <= 4; i++) {

      chname = EBPM["signal"][i]
      num = (chname in auxlist1)? cnt_num(mne = auxlist1[chname]) : -1
      delete auxlist1[chname]
      if (num >= 0 && counter_par(num, "controller") == "NONE") {
         nchan++
      } else
         mne = ""

      macrodef = macrodef ", \"" mne "\""
      EBPM[idname][chname] = mne
   }

   key = "ebpm-" idname
   if (nchan) {
      macrodef = "ebpm_getcounts(" macrodef ")\n"
      cdef("user_getcounts", macrodef, key)
   } else {
      cdef("user_getcounts", "", key, "delete")
   }
}'

def ebpmunsetup '{
   local idname key

   idname = "$1"
   key = "ebpm-" idname
   cdef("", "", key, "delete")

   list_remove(EBPM, idname)
   if (list_n(EBPM) <= 0)
      unglobal EBPM
}'

def efbpm_update(idname) '{
   local update_flag

   update_flag = 0

   efbpm_getdata(idname)
   if (efbpm_doFFT() < 0) {
      local fitdev

      print "No SpecfitServer is running now in the system."
      if (fitdev = specfit_start(1)) {
         EBPM["fitdev"] = fitdev
         if (efbpm_doFFT() < 0)
            print "The problem persists ..."
         else
            print "Now it seems ok."
      } else {
         print "The problem persists ..."
      }
      update_flag = 1
   }
   efbpm_filter(idname)
   efbpm_plot(idname)

   return(update_flag)
}'

def efbpm_getgetbuff(idname, commd, data) '{
   tango_get(EBPM[idname]["dev"], commd, data)
   if (TANGO_ERR != "0") {
      print "Error reading eBPM data at " idname
      print_tango_err() 
      return(-1)
   }
}'

def efbpm_getdata(idname) '{
   float array datX[10140]
   float array datZ[10140]
   float array datXp[10140]
   float array datZp[10140]

   efbpm_pos[1:4][] = 0
   if (efbpm_getgetbuff(idname, "XPosBuffer", datX) != 0) return(-1)
   if (efbpm_getgetbuff(idname, "ZPosBuffer", datZ) != 0) return(-1)
   if (efbpm_getgetbuff(idname, "XAngleBuffer", datXp) != 0) return(-1)
   if (efbpm_getgetbuff(idname, "ZAngleBuffer", datZp) != 0) return(-1)
   efbpm_pos[1][] = datX
   efbpm_pos[2][] = datZ
   efbpm_pos[3][] = datXp
   efbpm_pos[4][] = datZp
}'
 
def efbpm_filter(idname) '{
   local filt_n

   filt_n = EBPM[idname]["filter"]
   efbpm_fft[5:8][] *= (1 - 1 / filt_n) 
   efbpm_fft[5:8][] += efbpm_fft[1:4][] / filt_n
}'

def efbpm_reset_filter '{
   efbpm_fft[5:8][] = 0
}'

def efbpm_doFFT() '{
   local i error npts

   npts = EBPM["npts"]
   float array fftdat[2][npts]

   error = 0
   for (i = 1; i <= 4; i++) {
#      TACO_ERR=-1
      TACO_ERR_MSG = ""
      if (taco_io(EBPM["fitdev"], "SpecfitFFTArray", efbpm_pos[i], fftdat) < 0) 
         error = -1
      efbpm_fft[i][] = sqrt(fftdat[0][1:npts/2] * fftdat[0][1:npts/2] + \
                            fftdat[1][1:npts/2] * fftdat[1][1:npts/2])
   }
   return(error)
}'

def efbpm_getcounts(idname, x, z, xp, zp) '{
   if (time() < EBPM[idname]["nextT"])
      return

   efbpm_getdata(idname)
   if (x  != "") S[cnt_num(x)]  = array_op("sum", efbpm_pos[1]) / 1024
   if (z  != "") S[cnt_num(z)]  = array_op("sum", efbpm_pos[2]) / 1024
   if (xp != "") S[cnt_num(xp)] = array_op("sum", efbpm_pos[3]) / 1024
   if (zp != "") S[cnt_num(zp)] = array_op("sum", efbpm_pos[4]) / 1024

   EBPM[idname]["nextT"] = time() + EBPM[idname]["updateT"]
}'

def ebpm_getcounts(idname, x, z, xp, zp) '{
   dev = EBPM[idname]["dev"]
   if (x  != "") S[cnt_num(x)]  = tango_get(dev, "XPosition") / 1000
   if (xp != "") S[cnt_num(xp)] = tango_get(dev, "XAngle")
   if (z  != "") S[cnt_num(z)]  = tango_get(dev, "ZPosition") / 1000
   if (zp != "") S[cnt_num(zp)] = tango_get(dev, "ZAngle")
}'

def efbpm_head '{
   local i j z s

   printf("\n#S %d  %s\n#D %s\n",++SCAN_N,HEADING,DATE)

   _head_par G 0
   _head_par U 1
   _head_par UB 3
   _head_par Q 4

   printf("#Q %s\n", _hkl_val)

   for (i=0; i<MOTORS; i+= 8) {
      s = sprintf("#P%d ",i/8)
      for (j=i; j<i+8 && j<MOTORS;) {
         if (motor_name(mA[j]) != "unused")
            s = s sprintf("%.8g", A[mA[j]])
         if (j%8 == 7)
            break
         s = s " "
         j++
      }
      print s
   }
   Fheader
   user_Fheader
}'

def efbpm_tail '{
   user_scan_tail
   Ftail
}'

def efbpm_save(idname) '{
   ond; offt
   if (EBPM[idname]["mode"] == "freq") {
      HEADING = " eFBPM spectral density - " idname
      efbpm_head

      printf("#N 9\n")
      printf("#L  Frequency")
      for (i = 1; i <= 8; i++) {
         local colname

         colname = EBPM["signal"][((i - 1) % 4) + 1]
         if (EBPM[idname][colname] != "")
             colname = cnt_name(cnt_num(EBPM[idname][colname]))
         else {
             colname = idname "_" colname
         }
         if (i > 4)
            colname = colname " (filt)"
         printf("  %s", colname)
      }
      printf("\n")

      array_dump(efbpm_fft, "%1")

   } else {
      HEADING = " eFBPM time record - " idname
      efbpm_head

      printf("#N 5\n")
      printf("#L  Time")
      for (i = 1; i <= 4; i++) {
         local colname mne

         colname = EBPM["signal"][i]
         if ((mne = EBPM[idname][colname]) != "")
             colname = cnt_name(cnt_num(mne))
         else {
             colname = idname "_" colname
         }
         printf("  %s", colname)
      }
      printf("\n")

      array_dump(efbpm_pos, "%1")
   }
   efbpm_tail
   offd; ont
}'

def efbpm_pcols(idname) '{
   local pcol_list[] n i

   if (EBPM[idname]["allcases"])
      n = split("1 2 4 8 3 12 5 10 15", pcol_list)
   else
      n = split("5 10 15", pcol_list)
   for (i = 0; i < n; i++) {
      if (EBPM[idname]["plot"] == pcol_list[i]) {
         i = (i + 1) % n
         break
      }
   }
   if (i < n) 
      EBPM[idname]["plot"] = pcol_list[i]
   else
      EBPM[idname]["plot"] = 15
}'


def efbpm_plot(idname) '{
   local i col ncol datacols
   local title colors filtered
   local min max

   plot_cntl("filter5")
   colors = "colors=47:49:9:3"
   plot_cntl(colors)
   plot_cntl("open")
   plot_cntl("erase")

   filtered = EBPM[idname]["plotfilter"] && (EBPM[idname]["mode"] == "freq")
   datacols = ""
   for (ncol = 0, i = 1; i <= 4; i++) {
      if (EBPM[idname]["plot"] & (1 << (i-1))) {
         col = i + (filtered? 4 : 0)
         if (!ncol)
            datacols = col
         else
            datacols = datacols "," col
         plot_move(ncol * 3, 1, EBPM["signal"][i],  EBPM["color"][i])
         colors = colors ":" EBPM["color"][i]
         ncol++
      }
   }
   plot_cntl(colors)
   plot_cntl("-dots,-ebars,xexact")

   min = array_op("min", efbpm_fft[datacols][1:])
   max = array_op("max", efbpm_fft[datacols][1:])

   if (EBPM[idname]["mode"] == "freq") {


      title = "title=eFBPM Frequency spectrum - " idname
      plot_cntl(title)
      plot_cntl("ylog")
      if (EBPM[idname]["plotfilter"])
         plot_move(24,0, sprintf("Filtered spectra - (filter value = %s)", EBPM[idname]["filter"]))
      else
         plot_move(-50,0, "Non filtered spectra")
      plot_move(0,-1,"f(Hz)")
   
      if (max > 0 && min > 0) {
         max = pow(10, int(log10(max)) + 1)

         plot_range(EBPM[idname]["Fmin"], EBPM[idname]["Fmax"], min, max)
         array_plot(efbpm_fft[0], efbpm_fft[datacols])

      } else {

         plot_range(EBPM[idname]["Fmin"], EBPM[idname]["Fmax"], "auto", "auto")
         array_plot(efbpm_fft[0], efbpm_fft[datacols])
         plot_cntl("colors=:2:3")
         plot_move(40, 10, "BAD DATA")
      }

   } else {
      title = "title=eFBPM time record - " idname
      plot_cntl(title)
      plot_cntl("-ylog")
      plot_move(-50,0, "Time record")
      plot_range(EBPM[idname]["Tmin"], EBPM[idname]["Tmax"], "auto", "auto")
      plot_move(0,-1,"t(ms)")

      array_plot(efbpm_pos[0], efbpm_pos[datacols])
   }
   plot_cntl("filter1")
}'

#%UU% [<idname>]
#%MDESC%
#  Starts the interactive macro to display and save the time or frequency
#  records from the fast eBPM's.
def efbpm '{
   local idname options

   idname = $#? "$1": ""
   if (!$# || list_check(EBPM, idname) > 0){
      if (efbpm_setdefault(idname)) {
         idname = EBPM["default"]
         EBPM[idname]["prompt"] = "(" EBPM["default"] ")"
      }
   } else
      _ebpmsetup(idname)

   if (list_check(EBPM, idname) <= 0 ) {
      print "Usage: $0 idname" 
      if (yesno("\nDisplay online help", 0))
         eval("help local ebpm")

   } else if(EBPM[idname]["dev"] == "") {
      print "No eFBPM device found."

   } else {
      efbpm_main(idname, options)
   }
}'

def efbpm_setdefault(idname) '{
   if (EBPM[0] <= 0 && idname == "") {
#      print "No eFBPM devices configured. Use first \`ebpmsetup\'."
      return(0)
   }
   if (idname != "") {
      EBPM["default"] = idname
      if (!list_check(EBPM, idname)) {
         print "\`" idname "\' is not a valid eFBPM device."
      }
   } 
   if (!list_check(EBPM, EBPM["default"])) {
      EBPM["default"] = EBPM[1]
      print "Setting \`" EBPM["default"] "\' as default eFBPM device."
   }
   return(1)
}'

def efbpm_main(idname, options) '{
   local updateT line
   local line time0
   local minT maxT

   if (minT <= 0) minT = EBPM[idname]["updateT"]
   if (maxT <= 0) maxT = EBPM[idname]["updateT"]
   updateT = maxT
   update_flag = 0

   EBPM["ncomm"]++

   efbpm_update(idname)
   efbpm___process(idname, ".")

   while(1){
      time0 = time()
      line = ""
      printf("\n")
      efbpm___prompt
      while(1) {
         sleep(0.05)
         c = input(-1)
         if (c == "\n") {
            printf("\n")
            tty_cntl("cd")
            break
         } else if ((c == "\b" || c == "\177") && line) {
            line = substr(line, 0, length(line)-1)
            printf("\b \b")
         } else if (asc(c) == 27) {
            while(input(-1));
         } else if (c >= " " && c <= "z") {
            line = line c
            printf(c) 
         }
         if ((time()-time0) > updateT) {
            efbpm_update(idname)
            if (efbpm_update(idname)){
               printf("\n")
               efbpm___prompt
               updateT = minT
            } else {
               updateT *= 2
               if (updateT > maxT)
                  updateT = maxT
            }
            time0 = time()
         }
      }
      if (efbpm___process(idname, line) == -1)
         return(0)
      EBPM["ncomm"]++
      efbpm_update(idname)
   }
}'

def efbpm_shcomm(comm, descr) '{printf("\t%-20s -  %s\n", comm, descr)}'

def efbpm___process(idname, line) '{
   local comm[] npar i 

   if ((npar = split(line, comm) - 1) >= 0){
      if (substr(comm[0], 1, 1) != ".")
         return(eval(line))

      if (comm[0] == "." || comm[0] == ".h" || comm[0] == ".help") {
         print
         print "\tSpecial commands:"
         print "\t-----------------"
         efbpm_shcomm("., .h, .help", "Display available commands")
         efbpm_shcomm(".i, .info",    "Display device information")
         efbpm_shcomm(".f, .filter",  "Set filter value")
         efbpm_shcomm(".m, .mode",    "Switch plot mode")
         efbpm_shcomm(".p, .plot",    "Switch plotted spectra")
         efbpm_shcomm(".r, .reset",   "Reset filter")
         efbpm_shcomm(".s, .save",    "Save in data file")
         efbpm_shcomm(".x, .xrange",  "Set X-axis range")
         efbpm_shcomm(".q, .quit",    "Quit interactive macro")

      } else if (comm[0] == ".info" || comm[0] == ".i") {
         print
         print "\teFBPM info"
         print "\t---------"
         print "\tName:   ", idname
         print "\tDevice: ", EBPM[idname]["dev"]
         print "\tSetup:  ", EBPM[idname]["setup"]

      } else if (comm[0] == ".quit" || comm[0] == ".q") {
         return(-1)

      } else if (comm[0] == ".mode" || comm[0] == ".m") {
         if (EBPM[idname]["mode"] == "freq")
            EBPM[idname]["mode"] = "time"
         else
            EBPM[idname]["mode"] = "freq"

         print "Switching plot mode to \`" EBPM[idname]["mode"] "\' "

      } else if (comm[0] == ".plot" || comm[0] == ".p") {
         if (npar)
            EBPM[idname]["allcases"] = !EBPM[idname]["allcases"]
         efbpm_pcols(idname)

      } else if (comm[0] == ".save" || comm[0] == ".s") {
         efbpm_save(idname)
         print "Saving eFBPM data as scan \#" SCAN_N " in \`" DATAFILE "\'"

      } else if (comm[0] == ".filter" || comm[0] == ".f") {
         if (npar == 0 || comm[1] < 1) {
            EBPM[idname]["plotfilter"] = !EBPM[idname]["plotfilter"]
            printf("Plotting %sfiltered values\n", EBPM[idname]["plotfilter"]?"":"non ")
         } else {
            EBPM[idname]["filter"] = int(comm[1])
            EBPM[idname]["plotfilter"] = 1
            print "Setting filter value to : ", EBPM[idname]["filter"]
         }
            
      } else if (comm[0] == ".xrange" || comm[0] == ".x") {
         if (!npar) {
            if (EBPM[idname]["mode"] == "freq")
               EBPM[idname]["Fmin"] = EBPM[idname]["Fmax"] = "auto"
            else
               EBPM[idname]["Tmin"] = EBPM[idname]["Tmax"] = "auto"
         } else if (npar == 1) {
            if (EBPM[idname]["mode"] == "freq")
               EBPM[idname]["Fmax"] = comm[1]
            else
               EBPM[idname]["Tmax"] = comm[1]
         } else {
            if (EBPM[idname]["mode"] == "freq") {
               EBPM[idname]["Fmin"] = comm[1]
               EBPM[idname]["Fmax"] = comm[2]
            } else {
               EBPM[idname]["Tmin"] = comm[1]
               EBPM[idname]["Tmax"] = comm[2]
            }
         }

            
      } else if (comm[0] == ".reset" || comm[0] == ".r") {
         efbpm_reset_filter
            
      } else {
         printf("Internal command [%s] not valid.\n", comm[0])
      }
   
   }
   return(0)
}'

def efbpm___prompt '
  printf("%d.eFBPM - %s > %s", EBPM["ncomm"], idname, line)
'

#%MACROS%

#%AUTHOR% P.Fajardo, (Original 10/04).
#  $Revision: 1.9 $ / $Date: 2019/10/10 08:04:53 $
#%TOC%