esrf

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

#%TITLE% CHKBEAM.MAC 
#%NAME%
#  Macros for checking beam presence during scans.
#
#%CATEGORY% X-ray beam, scans
#
#%OVERVIEW%
#  These macros implement beam checking during scans. When activated
#  (by %B%onbeamchk%B%) all standard scans are affected. 
#  After each scan step the counting rate of the monitor is calculated.
#  If it drops below a certain high threshold (the default is 80% of the
#  monitor value during the
#  previous counting interval) it is assumed that the beam was lost and
#  the program goes into a loop in which counting is repeated and the
#  monitor rate is periodically checked. The loop is exited and the scan
#  is resumed when the monitor rate becomes stable and greater than a low
#  threshold (defaulted to 10% of the value before the beam lost).
#  The thresholds can be changed by setting global variables (see below).%BR%
#  In order to avoid perturbances due to fast monitor fluctuations the
#  monitor rate is filtered by an algorithm that adds an extra waiting time
#  defaulted to 5 minutes.%BR%
#  This checking procedure requires a beam monitor that measures the actual
#  intensity of the beam. The variable %B%MON%B% must be set to the 
#  scaler used as a monitor, as selected by the %B%counters%B% macro.
#  If possible an integrating monitor, as a counting detector or an analog
#  detector followed by a F/V converter, should be used.%BR%
#  With the current version it is possible to use analog signals loaded into
#  pseudocounters like signals acquired by means of ADC's without integration.
#  When it is possible, the macros try to detect whether the monitor is
#  an integrating device or not. In the case of the %B%waitforbeam%B% macro,
#  the user must add an extra parameter to signal that the monitor is
#  analog.%BR%
#  The global variables %B%BEAMCHK_ON%B% and %B%BEAMCHK_FLAG%B% give extra
#  information when these macros are used inside other macros or command
#  files.%BR%
#  %B%BEAMCHK_ON%B% is set whenever the beam checking mode is active.%BR%
#  %B%BEAMCHK_FLAG%B% is set to 1 to indicate a `beam lost
#  condition'. Non standard scan macros can use this variable to detect beam
#  losses but it is their responsability to set it to zero before counting.%BR%
#  The global variable BEAMCHK_TAU contains the waiting time in seconds
#  (300 seconds by default).%BR%
#  The high and low thresholds can be set to values different from the defaults
#  (80% and 10% respectively) by assigning new values to the global variables
#  BEAMCHK_HI and BEAMCHK_LO. Positive numbers represent absolute thresholds
#  while negative numbers represent values relative to the monitor rate. 
#  For instance: BEAMCHK_HI=1000 represent a high theshold of 1000 monitor
#  counts while BEAMCHK_HI=-0.5 represent a threshold of 50% of the current
#  monitor rate.
#
#%EXAMPLE%
#  %DL%
#  %DT%onbeamchk
#  %DD%Activates beam checking.
#  %DT%offbeamchk
#  %DD%Cancels beam checking.
#  %DT%waitforbeam 5 1e6
#  %DD%Waits until the monitor counts accumulated in 5 seconds stabilize 
#  around one million (200000 c/s).
#  %DT%waitforbeam 1 1e6 analog
#  %DD%Loops counting for 1 second until the monitor value stabilizes
#  around one million (analog value).
#  %XDL%
#
#%END%

#%UU% [<counting_interval> [<monitor_counts> ["analog"]]
#%MDESC%
#  Activates the beam checking feature.%BR%
#  If <monitor_counts> is not especified, the macro estimates the current
#  monitor rate and the type of monitor device (analog or integrating).%BR%
#  If both <counting_interval> and <monitor_counts> are given, the monitor
#  rate is evaluated from these values. In such a case the monitor is
#  supposed to be by default an integrating device. This can overriden by
#  setting as third parameter the literal "analog".%BR%
#  
def onbeamchk '{
   global MON_ANALOG FILT_MON_RATE
   local t m

   t = ($1)
   m = ($2)

   if (m <= 0){
      count_em (t?t:COUNT)/2
      waitcount
      get_counts
      MON_RATE = (MON >= 0 && S[sec]!=0)? S[MON]/S[sec] : 0
      count_em (t?t:COUNT)
      waitcount
      get_counts
      MON_ANALOG = (MON >= 0 && S[MON] != 0 && S[sec] != 0 &&  \
                    MON_RATE/(S[MON]/S[sec]) > 1.5)
   } else {
      S[sec] = t
      if (MON >= 0)
         S[MON] = m
      MON_ANALOG = ("$3" == "analog")
   }

   if (MON<0 || S[sec]==0 || (MON_RATE=MON_ANALOG?S[MON]:S[MON]/S[sec])<=0 || \
       MON == sec) {
      # rdef chk_beam "break"
      cdef("_chk_beamc","","beam","delete")
      FILT_MON_RATE = 0
      print "ERROR: Beam check not activated. " 
      print "The beam is down or the timer and the monitor are not properly set up." 
      exit
   }
   printf("Beam check is ON. ")
   _onbeamchk
}'

#%IU% 
#%MDESC%
#  Activates the beam checking feature. This macro is called
#  from %B%onbeamchk%B% and %B%waitforbeam%B%.
#
def _onbeamchk '
   global BEAMCHK_FLAG BEAMCHK_ON
   global BEAMCHK_THRESH_HI BEAMCHK_THRESH_LO
   global BEAMCHK_LO BEAMCHK_HI BEAMCHK_TAU

   if (!BEAMCHK_LO) BEAMCHK_LO=-0.1
   if (!BEAMCHK_HI) BEAMCHK_HI=-0.8
   if (!BEAMCHK_TAU) BEAMCHK_TAU = 300


   FILT_MON_RATE = MON_RATE

   BEAMCHK_THRESH_HI = BEAMCHK_HI < 0 ? -BEAMCHK_HI*FILT_MON_RATE : BEAMCHK_HI
   BEAMCHK_THRESH_LO = BEAMCHK_LO < 0 ? -BEAMCHK_LO*FILT_MON_RATE : BEAMCHK_LO
   S[MON]=0
   if (MON_ANALOG) {
      printf("Analog monitor \`%s\' (%s), threshold value: %g\n",  \
              cnt_name(MON), cnt_mne(MON), BEAMCHK_THRESH_HI)
   } else {
      printf("Integrating monitor \`%s\' (%s), threshold rate: %g/s\n", \
              cnt_name(MON), cnt_mne(MON), BEAMCHK_THRESH_HI)
   }
   
   BEAMCHK_ON = 1
   #def chk_beam "local flag delay wtunit wtunitl; if (__chk_beam()) break;;"
   cdef("_chk_beamc","_chk_chkbeam\n","beam")
'

def _chk_chkbeam '{
   local flag delay wtuni wtunitl
   ret = __chk_beam()
   if (!ret) return(0)
}'

#%IU% 
#%MDESC%
#  This is the macro function that does the job. It returns "True" if the
#  counting was ok and "False" if it has to be repeated.
#
def __chk_beam () '{
   local nfilt wtime relmonrate bmess

   if (!BEAMCHK_ON)
      return(1)

   if (!S[sec]){
      nfilt = 1
      MON_RATE = 0
   } else {
      nfilt = (BEAMCHK_TAU/S[sec]) > 1? BEAMCHK_TAU/S[sec]:1
      MON_RATE = MON_ANALOG? S[MON] : S[MON]/S[sec]
   }
#   FILT_MON_RATE = (FILT_MON_RATE*(nfilt-1) + MON_RATE)/nfilt
   FILT_MON_RATE += MON_RATE/nfilt

   relmonrate = MON_RATE? FILT_MON_RATE/MON_RATE : 0

   if (relmonrate > 1) {
      FILT_MON_RATE=MON_RATE
      relmonrate = 1
   }
   if (!flag) {
      if (set_sim(-1) || MON_RATE >= BEAMCHK_THRESH_HI)  {
         if (BEAMCHK_HI < 0) 
            BEAMCHK_THRESH_HI = -BEAMCHK_HI * FILT_MON_RATE
         if (BEAMCHK_LO < 0) 
            BEAMCHK_THRESH_LO = -BEAMCHK_LO * FILT_MON_RATE
         return(1)
      } else {
         printf("Beam down on %s\n", date())
         printf("Waiting for beam ...\n")
         BEAMCHK_FLAG = flag = 1
         delay=time()
         FILT_MON_RATE = 0
      }
   } else {
      if (FILT_MON_RATE > BEAMCHK_THRESH_LO && relmonrate >= 1) {
         tty_move(-1500, 1001)
         tty_cntl("ce")
         comment "Waited %d %s for beam." (time()-delay)/wtunit,wtunitl 
         flag = 0
         user_chkbeam

      } else {
         wtime = time()-delay
         if (wtime > 3600) {
            wtunit = 3600; wtunitl = "hours"
         } else if (wtime > 60) {
            wtunit = 60; wtunitl = "minutes"
         } else {
            wtunit = 1; wtunitl = "seconds"
         } 
         bmess = FILT_MON_RATE/BEAMCHK_THRESH_LO > 1 ? \
                 sprintf("beam back: %8.2f%%",100*relmonrate):"beam down"
                 
         tty_move(-1500, 1001)
         printf("Been waiting %.2g %s for beam ... (%s)", \
            wtime/wtunit,wtunitl, bmess)
         tty_cntl("ce")
         print
         user_beambck
      }
   }
   return(0)
}'

if (!(whatis("user_chkbeam") & 2)) rdef user_chkbeam ""
if (!(whatis("user_beambck") & 2)) rdef user_beambck ""

#%UU% 
#%MDESC%
#  Cancels the beam checking feature.%BR%
#
def offbeamchk '
   BEAMCHK_ON = 0
   cdef("_chk_beamc","","beam","delete")
   print "Beam check is OFF."
'

#%UU% [<counting_interval> [<monitor_counts> ["analog"]]]
#%MDESC%
#  Waits until the beam is back.
#  This macro loops counting for <counting_interval> until the monitor
#  counts stabilize near <monitor_counts> (the threshold is actually 10%% of
#  this value).
#
def waitforbeam '{
   global MON_ANALOG FILT_MON_RATE 

   local t m
   if ($# > 3){
      print "Usage:  waitforbeam [counting_interval [monitor_counts [\"analog\"]]"
      exit
   }
   t = ($# < 1)? getval("Counting time in seconds", COUNT): $1
   m = ($# < 2)? getval(sprintf("Monitor counts in %g sec", t), \
               0.1*FILT_MON_RATE): $2
   MON_ANALOG = ($# < 3)? !yesno("Integrating monitor", !MON_ANALOG):("$3"=="analog")
   print

   if (MON < 0 || t == 0 || (MON_RATE=MON_ANALOG?m:m/t) <=0 || MON == sec) {
      # rdef chk_beam "break" # not sure of changing this with cdef
      cdef("_chk_beamc","","beam","delete")
      FILT_MON_RATE = 0
      print "ERROR: Beam check not activated. " 
      if (MON < 0 || MON == sec)
         print "The monitor is not properly set up." 
      else
         print "Input parameters are not valid."
      exit
   }
   _onbeamchk
   count t
}'

#%MACROS%
#%AUTHOR% P. Fajardo, (Original 6/94).
#  $Revision: 4.2 $ / $Date: 2008/02/27 13:27:42 $
#%TOC%