esrf

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

#%TITLE% oscilPX.mac
#%NAME%
#   Macros handling the oscillation for MX beamlines
#%CATEGORY% MX
#%END%

global OSCIL_CALCACC OSCIL_CALCVELOCITY OSCIL_CALCSLOPE
global OSCIL_DEFACC OSCIL_DEFVELOCITY     # default values from config
global OSCIL_MOTOR_NUM OSCIL_MOTOR_NAME
global OSCIL_PREDELAY OSCIL_POSTDELAY
global OSCIL_STEP_MARGIN
global OSCIL_PREDELAY_STEPS OSCIL_POSTDELAY_STEPS
global OSCIL_START_ANGLE OSCIL_FINAL_ANGLE
global MUSST_MARGIN MUSST_INTEGRATION_FACTOR MUSST_SAMPLING MUSST_INTEGRATED_COUNTS
global DIAGFILE
global DIAG_N
global OLDPREF MCCD_OLDDIR

MUSST_MARGIN      = 10
MUSST_INTEGRATION_FACTOR = 1
MUSST_SAMPLING    = 300
MUSST_INTEGRATED_COUNTS = 0

# array to contain diagnostic information from MUSST
float array musstdiag[100000][7]	


#%UU%
#%MDESC%
#
#   Oscillation setup macro
#
#   It has to be called once to setup values for axis control 
#   and synchronization
#
def oscilsetup '{
   local lerr_msg
   spec_par("modify_step_size",1)

   if ($#) {
       OSCIL_MOTOR_NAME  = "$1"
       OSCIL_PREDELAY    =  $2
       OSCIL_POSTDELAY   =  $3
       OSCIL_STEP_MARGIN =  $4
   } else {
      OSCIL_MOTOR_NAME  = sprintf("%s",getval("Axis mnemonics", OSCIL_MOTOR_NAME))
      OSCIL_PREDELAY    = getval ("Shutter pre-delay [ms]",     OSCIL_PREDELAY)
      OSCIL_POSTDELAY   = getval ("Shutter posr-delay [ms]",    OSCIL_POSTDELAY)
      OSCIL_STEP_MARGIN = getval ("Delay before shutter open/after shutter close positions [steps])", OSCIL_STEP_MARGIN)
   }

   OSCIL_MOTOR_NUM = motor_num(OSCIL_MOTOR_NAME)
   if (OSCIL_MOTOR_NUM < 0) {
       lerr_msg = sprintf("Error: Motor %s doesn\'t exist", OSCIL_MOTOR_NAME)
       fatal( lerr_msg )
   }

  #
  # Store the  default velocity and acceleration of the axis
  #
  cdef("cleanup_always","phi_cleanup;","scan",0x10)
}'


def oscil_on '{
  cdef("osc_scan",     "oscillation \$*",        "_pxoscil",0x20)
  cdef("osc_prepare",  "oscillation_prepare \$*","_pxoscil",0x20)
}'

def oscil_off '{
  cdef("","","_pxoscil","delete")
}'


def oscillation_prepare '{
  _oscillation_prepare( $1, $2, $3, $4 )
}'


def _oscillation_prepare(start_ang, stop_ang, exp_time, nb_pass) '{
   local abs_ang osctime

   cdef("cleanup_once","oscil_cleanup;","scan",0x10)
  
   abs_ang   = fabs(stop_ang - start_ang)
   osctime   = exp_time / nb_pass

   velocity  = abs_ang / osctime
   step_size = fabs(motor_par( OSCIL_MOTOR_NUM, "step_size" ))

   OSCIL_CALCVELOCITY = velocity * step_size
   OSCIL_CALCACC      = osc_acceleration( osctime )

   step_time    = (1/(OSCIL_CALCVELOCITY)) * 1000
   OSCIL_PREDELAY_STEPS =  fabs(int(OSCIL_PREDELAY / step_time))
   OSCIL_POSTDELAY_STEPS = fabs(int(OSCIL_POSTDELAY / step_time))

   OSCIL_CALCSLOPE  = osc_slope(velocity, OSCIL_CALCACC, step_size)

   printf("converted to : predelay = %d steps, postdelay = %d steps.\n", OSCIL_PREDELAY_STEPS, OSCIL_POSTDELAY_STEPS)

   if ( start_ang < stop_ang ) {
      OSCIL_START_ANGLE   = start_ang - 1.5 * OSCIL_CALCSLOPE
      OSCIL_FINAL_ANGLE  = stop_ang  + 1.5 * OSCIL_CALCSLOPE
   } else {
      OSCIL_START_ANGLE = start_ang + 1.5 * OSCIL_CALCSLOPE
      OSCIL_FINAL_ANGLE = stop_ang  - 1.5 * OSCIL_CALCSLOPE
   }
   #set the integration factor as function of the current gain
   MUSST_INTEGRATION_FACTOR = W_GAINF["i1"][sprintf ("%d",wcreadgain("i1")-1)]
   # move as fast as possible to the init angle
   motor_par( OSCIL_MOTOR_NUM, "velocity", motor_par(OSCIL_MOTOR_NUM, "config_velocity"))
   osc_goto( OSCIL_START_ANGLE )

   # set velocity and acceleration for the oscillation
   motor_par(OSCIL_MOTOR_NUM,  "velocity",     OSCIL_CALCVELOCITY)
   motor_par(OSCIL_MOTOR_NUM,  "acceleration", OSCIL_CALCACC)
}'


def test_oscillation '{
  printf("Oscillation prepare, start angle=%f, stop angle=%f, exposure time=%f, nb_passes=%d\n", $1, $2, $3, $4) 
  bench oscillation_prepare $1 $2 $3 $4
  print "Oscillation"
  bench oscillation $1 $2 $3 $4
}'


def oscillation '{
   _oscillation( $1, $2, $3, $4 )
}'


def _oscillation(start_trigger_ang, stop_trigger_ang, exp_time, nb_pass) '{
    local i 

    cdef("cleanup_once", "musst_shutter_reset; phi_cleanup;", "oscillation")
    
    step_size = motor_par(OSCIL_MOTOR_NUM,  "step_size")
    start_trigger_steps = start_trigger_ang * step_size
    stop_trigger_steps  = stop_trigger_ang * step_size
    start_steps = OSCIL_START_ANGLE * step_size
    end_steps = OSCIL_FINAL_ANGLE * step_size

    waitmove; getangles

    musst_prepare(start_trigger_steps, stop_trigger_steps, start_steps, end_steps, OSCIL_PREDELAY_STEPS, OSCIL_POSTDELAY_STEPS)

    for ( i=1; i <= nb_pass; i++) {
        printf( "\n        ** pass number: %d **\n", i)
        even = i%2 

        if ( even ) {
          musst_prepare(start_trigger_steps, stop_trigger_steps, start_steps, end_steps, OSCIL_PREDELAY_STEPS, OSCIL_POSTDELAY_STEPS)
          osc_goto(OSCIL_FINAL_ANGLE)
	} else {
          musst_prepare(stop_trigger_steps, start_trigger_steps, end_steps, start_steps, OSCIL_PREDELAY_STEPS, OSCIL_POSTDELAY_STEPS)
          osc_goto(OSCIL_START_ANGLE)
	}

        waitmove; getangles

        musst_handle_data i
    }
    musst_shutter_reset
    phi_cleanup 
}' 


def osc_goto( target_angle ) '{
   waitmove; get_angles
   
   if ( fabs( A[OSCIL_MOTOR_NUM] - target_angle ) < 0.001 ) {
      return
   }

   if (motor_par(OSCIL_MOTOR_NUM,"disable")==0) {
   	UPDATE_DELAY=1
   	A[OSCIL_MOTOR_NUM] = target_angle
   	move_em
   	UPDATE_DELAY=0
   } else {
        fatal(sprintf("Cannot move DISABLED motor %s, exiting\n",motor_mne(OSCIL_MOTOR_NUM)))
   }
}'


def osc_acceleration( osctime ) '{
  return 100
}'


def osc_slope( velocity, acceleration, step_size ) '{
  slope = fabs( (velocity * (acceleration / 1000)) + (OSCIL_STEP_MARGIN/step_size) ) / 2.0
  return  slope
}'


#
#  Cleanup Macros
#
#  Cleanup during oscillation
def oscil_cleanup '{
    msclose
    phi_cleanup
    musst_cleanup
}'


#%IU%
#%MDESC%
#  Restore phi parameters  
def phi_cleanup '{
  local defvel defacc
  print "doing phi cleanup"
  defvel = motor_par(OSCIL_MOTOR_NUM,"config_velocity")
  defacc = motor_par(OSCIL_MOTOR_NUM,"config_acceleration")
  motor_par( OSCIL_MOTOR_NUM, "velocity",     defvel)
  motor_par( OSCIL_MOTOR_NUM, "acceleration", defacc)
}'

def musst_prepare(start_steps, stop_steps, init_steps, final_steps, predelay, postdelay) '{
   local step_size phi_steps 
   local msg musst_hexa

   printf("  - predelay = %d steps, postdelay = %d steps\n", predelay, postdelay)

   # load current encoder value in MUSST
   step_size = motor_par( OSCIL_MOTOR_NUM,  "step_size")
   phi_steps = A[OSCIL_MOTOR_NUM] * step_size

   musstPX_init(phi_steps)

   if ( start_steps < stop_steps ) {
       start_steps  -= predelay
       stop_steps   -= postdelay
       init_steps   += MUSST_MARGIN
   } else {
       start_steps += predelay
       stop_steps  += postdelay
       init_steps  -= MUSST_MARGIN
   }

   musstPX_oscill(init_steps, final_steps, start_steps, stop_steps, MUSST_SAMPLING)
}'


def musst_shutter_reset '{
    musstPX_shclose()
}'


def musst_handle_data '{
    local npts maxvel nopass

    nopass = $1

    musst_postoscil

    array_op("fill",musstdiag,0,0)
    npts = musstPX_read(OSCIL_MOTOR_NUM, musstdiag) 

    if ( npts != -1 ) musst_save(npts,nopass)
}'


def musst_postoscil '{
   local step_size phi_steps musst_steps
   local msg

   step_size   = motor_par( OSCIL_MOTOR_NUM,  "step_size")
   phi_steps   = A[OSCIL_MOTOR_NUM] * step_size

   musst_steps = musstPX_getphi()

   msg =  sprintf("- oscillation ends. \n")
   msg =  sprintf("%s    PHI is now at  %4.4f ( %d steps )\n", msg, A[phi],phi_steps)
   msg =  sprintf("%s    MUSST shows %d steps\n", msg, musst_steps)
   print msg 
}'


def musst_save(npts,passno) '{
   global MUSST_INTEGRATED_COUNTS CURRENT_IMAGE_INTENSITY
   local i imgname curdir curpref npasses bkgrd bkgd_pts bkgd_average averaged_counts_per_pass
   local bkgd2 sigma_bkgr nsigma bkgd_pt
   local integrated_counts_per_pass cal
   
   curdir  = COLLECT_SEQ["fileinfo"]["directory"]
   curpref  = sprintf("%s_%d", COLLECT_SEQ["fileinfo"]["prefix"], COLLECT_SEQ["fileinfo"]["run_number"]) 
   npasses = COLLECT_SEQ["number_of_passes"]
   
   averaged_counts_per_pass = 0

   if ( OLDPREF != curpref || OLDDIR != curdir) { 
     DIAG_N   = 0
     DIAGFILE = sprintf("%s/%s_diag.dat", curdir, curpref )
     OLDPREF  = curpref
     OLDDIR   = curdir
   }

   diagname = sprintf("%s pass %d", getMxCollectPars("current_filename"), passno)
   printf("   - Saving diagnostics for %s to file: \n\t\t%s\n", diagname, DIAGFILE)

   HEADING = diagname 
   savefileheader(DIAGFILE, 1)
   savestdheader(DIAGFILE, 4, DIAG_N)

   fprintf(DIAGFILE, "#N %d\n",array_op("cols", musstdiag))
   fprintf(DIAGFILE, "#L Time(ms)  Speed  Phi  I1  I0  Shut Cmd  IR sensor\n")

   on(DIAGFILE);offt
   array_dump( musstdiag[0:npts-1] )
   ont; off(DIAGFILE); close(DIAGFILE)

   bkgd=0; bkgd2=0; sigma_bkgr=0; bkgd_pts=0; signal_pts=0;
   for (i=0;i<npts;i++) {
     if (musstdiag[i][5] == 0) {
       bkgd_pt = (musstdiag[i][3])*COLLECT_SEQ["exposure_time"]/npasses
       bkgd  = bkgd  +  bkgd_pt
       bkgd2 = bkgd2 + (bkgd_pt*bkgd_pt)
			 bkgd_pts += 1
     } else {
       integrated_counts_per_pass += (musstdiag[i][3])*COLLECT_SEQ["exposure_time"]/npasses
       signal_pts += 1
     }
   }
   if (signal_pts < 1) signal_pts = 1
   if (bkgd_pts > 0) {
     bkgd_average = bkgd/bkgd_pts
     sigma_bkgd= (bkgd2/bkgd_pts) - (bkgd_average*bkgd_average)
     if (sigma_bkgd < 0.001) sigma_bkgd = 0.001
     sigma_bkgd= sqrt(sigma_bkgd)
     printf("sigma background (%6.3f) is sqrt ((sum of bkgd_squared (%6.2g)/bkgd pts (%6.2f) - (bkgd_average (%6.2g) _squared) )\n", sigma_bkgd,bkgd2,bkgd_pts,bkgd_average)
   } else {
     bkgd_average = 0
   }
   bkgd = bkgd_average * signal_pts
   integrated_counts_per_pass = integrated_counts_per_pass - bkgd
   averaged_counts_per_pass = integrated_counts_per_pass / signal_pts
   nsigma = (averaged_counts_per_pass - bkgd_average) / sigma_bkgd
   printf("Nsigma (%6.3f) (should be bigger than 2) will be (averaged_counts_per_pass (%6.3f) - bkgd_average (%6.3f)) / sigma_background (%6.2f)\nsignal_avg %f and total points %d\n", nsigma,averaged_counts_per_pass,bkgd_average, sigma_bkgd,integrated_counts_per_pass/signal_pts,npts)
   if (fabs(nsigma) < 2) {
     printf("    - background and X-rays indistinguishable. Check i1 (ct in spec)\n") 
     egui_logmsg(sprintf("Measured values for background and X-ray intensity not very distinguishable. \n"))
     #MUSST_INTEGRATED_COUNTS += 0.0
     MUSST_INTEGRATED_COUNTS += fabs(averaged_counts_per_pass)
   } else {
     MUSST_INTEGRATED_COUNTS += fabs(averaged_counts_per_pass)
     printf("    - integrated counts for pass %d = %g (background = %g)\n", passno, MUSST_INTEGRATED_COUNTS, bkgd)
   }

   if (passno == npasses) {
     cal = flux_get_calibration()
     corrected_counts = \
	cal[1] * MUSST_INTEGRATED_COUNTS * MUSST_INTEGRATION_FACTOR
     printf("Musst integrated counts: %f\n",MUSST_INTEGRATED_COUNTS)
     CURRENT_IMAGE_INTENSITY=corrected_counts
     HDBCURR_INT=corrected_counts
     CURRENT_IMAGE_INTENSITY=corrected_counts
     # last pass
      printf("    - saving integrated counts to diag. file\n")      
      egui_logmsg(sprintf("Integrated counts for image : %.6g\n", corrected_counts))

      fprintf(DIAGFILE, "\n#S %d\n#N 1\n", DIAG_N+1)
      fprintf(DIAGFILE, "#L Integrated counts\n")
      fprintf(DIAGFILE, "%g\n", corrected_counts)

      MUSST_INTEGRATED_COUNTS=0
      corrected_counts=0
   } 

   close(DIAGFILE)

   DIAG_N++
}'


def musst_cleanup '{
   musst_comm("ABORT")

   musstPX_shclose()
}'


def fatal( msg ) '{
   tty_cntl("md")
   printf ("<OSCIL> -abort- %s\n", msg)	
   egui_logmsg(sprintf("<OSCIL>abort_from_spec %s", msg))
   tty_cntl("me")
   exit 
}'

#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% BLISS%BR%
#$Revision: 1.24 $$Date: 2012/05/10 14:46:42 $
#%END%
#%LOG%
#$Log: oscilPX.mac,v $
#Revision 1.24  2012/05/10 14:46:42  guijarro
#added phi cleanup
#
#Revision 1.23  2010/11/02 12:47:42  beteva
#set MUSST_INTEGRATION_FACTOR as function of the current Novelec gain.
#apply it for the integrated flux calculation
#