esrf

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

#%TITLE% HELICAL_OSCIL.MAC
#%NAME%
# Macros to do helical type datacollection
#%DESCRIPTION%
# Move the crystal while doing the oscilation from a start to finalposition.
# The positions are chosen before the start of the datacollection .
#%END%
 
global HELICAL_OSCIL
#%IU% ()
#%MDESC% Setup the motors to move durinfg the datacollection. Prepare the
# oscilation for the helical type.
def helical_motors() '{
local mne motnum flag
global HELICAL_PARS HELICAL_OSCIL
global HELICAL_MNE HELICAL_MOT
global HELICAL_OSCIL_POS HELICAL_POS

  flag = 0

  HELICAL_MNE["phiy"] = "phiy"
  HELICAL_MNE["phiz"] = "phiz"
  HELICAL_MNE["sampx"] = "sampx"
  HELICAL_MNE["sampy"] = "sampy"

  for (mne in HELICAL_MNE) {
    motnum = motor_num(mne)
    if (motnum == -1) {
      eprintf ("Motor %s not configured, exiting\n", mne)
      exit
    }
    HELICAL_MOT[mne] = motnum
  }

  HELICAL_PARS["nb_pos"] = 2

  HELICAL_PARS["udiff"] = 0
  if (motor_par(HELICAL_MNE["phiy"],"device_id") == "udiff_mot") {
    HELICAL_PARS["udiff"] = 1
    if (MXBCM_PARS["detector"]["type"] == "pilatus")
      flag = 1
  }

  if (flag == 0)
    cdef("osc_prepare", "helical_follow_phi(\$1);",HELICAL_MNE["phiy"],0x11)
}'

#%IU% ()
#%MDESC% Calculate the displacement of the motors as function of the previously
#defined the start and end positions. The function is called by the macro where
#the local actions to prepare a scan or data collection are defined.
def helical_calc() '{
global HELICAL_POS
local i j mne phi_start phi_stop phi_range msg
local phiy_tst phiy_range

  if (HELICAL_PARS["nb_pos"] < 2) {
    msg = sprintf ("Helical: At least two positions should be specified, exiting")
    eprintf ("%s\n", msg)
    egui_fatal(msg)
    exit
  }

  j = 1
  while (j <= HELICAL_PARS["nb_pos"]) {
    phiy_tst = HELICAL_OSCIL_POS[j]["phiy"]
    for (i = 1 ; i<=HELICAL_PARS["nb_pos"]; i++) {
      if (i != j) {
        if (fabs(phiy_tst - HELICAL_OSCIL_POS[i]["phiy"]) < 0.002) {
          msg = sprintf ("Helical: %s position identical to %s position.", \
		HELICAL_POS[i]["label"], HELICAL_POS[j]["label"])
          msg = sprintf ("%s Please change and restart.", msg)
          eprintf ("%s\n", msg)
          egui_fatal(msg)
          HELICAL_OSCIL = 0
          #return(-1)
          exit
        }
      }
    }
    j++
  }

  phiy_range = HELICAL_OSCIL_POS[1]["phiy"] - HELICAL_OSCIL_POS[2]["phiy"]

  HELICAL_POS[1]["sampx"] = \
	(HELICAL_OSCIL_POS[1]["sampx"] - HELICAL_OSCIL_POS[2]["sampx"]) / \
	phiy_range
  HELICAL_POS[1]["sampy"] = \
	(HELICAL_OSCIL_POS[1]["sampy"] - HELICAL_OSCIL_POS[2]["sampy"]) / \
	phiy_range
  HELICAL_POS[1]["phiz"] = \
	(HELICAL_OSCIL_POS[1]["phiz"] - HELICAL_OSCIL_POS[2]["phiz"]) / \
	phiy_range
  HELICAL_POS[2]["sampx"] = \
	((HELICAL_OSCIL_POS[1]["phiy"] * HELICAL_OSCIL_POS[2]["sampx"]) - \
	(HELICAL_OSCIL_POS[2]["phiy"] * HELICAL_OSCIL_POS[1]["sampx"])) / \
	phiy_range
  HELICAL_POS[2]["sampy"] = \
	((HELICAL_OSCIL_POS[1]["phiy"] * HELICAL_OSCIL_POS[2]["sampy"]) - \
	(HELICAL_OSCIL_POS[2]["phiy"] * HELICAL_OSCIL_POS[1]["sampy"])) / \
	phiy_range
  HELICAL_POS[2]["phiz"] = \
	((HELICAL_OSCIL_POS[1]["phiy"] * HELICAL_OSCIL_POS[2]["phiz"]) - \
	(HELICAL_OSCIL_POS[2]["phiy"] * HELICAL_OSCIL_POS[1]["phiz"])) / \
	phiy_range

  phi_start = COLLECT_SEQ["start"]
  phi_stop = (COLLECT_SEQ["range"]-COLLECT_SEQ["overlap"])* \
	(COLLECT_SEQ["number_of_images"]-1) + COLLECT_SEQ["start"]
  phi_range = phi_start - phi_stop

  if (fabs(phi_range) < 0.001)
    return(-1)
  HELICAL_POS[1]["phiy"] = phiy_range / phi_range
  HELICAL_POS[2]["phiy"] = \
	((phi_start * HELICAL_OSCIL_POS[2]["phiy"]) - \
	(phi_stop * HELICAL_OSCIL_POS[1]["phiy"])) / phi_range
  printf ("start: %g, stop: %g, range: %g\n", phi_start, phi_stop, phi_range)
  print HELICAL_POS
  HELICAL_PARS["phiy_pos"] = 0
}'

#%IU% (phi_pos)
#%MDESC% Move the crystal while moving phi.The movement is a function of the
#%B%phi_pos%B% and the previously calculated displacement.
def helical_follow_phi(phi_pos) '{
local pos[]
local msg i
global HELICAL_SCAN4D

  if (HELICAL_PARS["debug"])
    printf ("helical_follow_phi %d\n",HELICAL_OSCIL)

  if (HELICAL_SCAN4D == 1)
    HELICAL_OSCIL = 0

  if (HELICAL_OSCIL == 0)
    return(0)

  for (i=1; i<=HELICAL_PARS["nb_pos"]; i++) {
    if (HELICAL_OSCIL_POS[i]["phiy"] == 0) {
      msg = sprintf ("Helical: %s position not saved, stopping the datacollection", HELICAL_POS[i]["label"])
      eprintf ("%s\n", msg)
      egui_fatal(msg)
      #return(-1)
      exit
    }
  }

  printf ("Helical oscilation with phi= %g\n", phi_pos)
  pos["phiy"] = HELICAL_POS[1]["phiy"] * phi_pos + HELICAL_POS[2]["phiy"]
  pos["phiz"] = HELICAL_POS[1]["phiz"] * pos["phiy"] + HELICAL_POS[2]["phiz"]
  pos["sampx"]= HELICAL_POS[1]["sampx"] * pos["phiy"] + HELICAL_POS[2]["sampx"]
  pos["sampy"]= HELICAL_POS[1]["sampy"] * pos["phiy"] + HELICAL_POS[2]["sampy"]

  if (fabs(pos["phiy"] - HELICAL_PARS["phiy_pos"]) > 0.001) {
    msg = "Moving Centring motors..."
    tty_cntl("md");printf ("%s\n", msg);tty_cntl("me")
    egui_logmsg(msg)

    if (HELICAL_PARS["udiff"] == 1) {
      for (mne in HELICAL_MOT) {
        A[HELICAL_MOT[mne]] = pos[mne]
        move_em; move_poll
      }
    } else {
      for (mne in HELICAL_MOT)
        A[HELICAL_MOT[mne]] = pos[mne]
      move_em; wait(0x20)
    }
    sleep(0.10)
    HELICAL_PARS["phiy_pos"] = pos["phiy"]
  }
}'

#%UU% ()
#%MDESC% Reset the helical oscillation parameters to forbid new collection.
def helical_resetpos() '{
global HELICAL_SCAN4D
  if (HELICAL_PARS["debug"])
    printf ("helical_resetpos()\n")
  HELICAL_OSCIL = 0
  HELICAL_SCAN4D = 0
  for (i=1; i<=2; i++) {
    if (HELICAL_OSCIL_POS[i]["phiy"])
      delete HELICAL_OSCIL_POS[i]["phiy"]
  }
  #HELICAL_PARS["nb_pos"] = 0  
}'

#### OBSOLETE MACROS - to be removed with the new mxcube ####
#%IU% position_number
#%MDESC% Get the motors position for position %B%number%B%. The start's
#number 1, the end is number 2. Input %B%11%B% moves the motors to the start
#and %B%22%B% to the final position.
def helical_getpos '{
global HELICAL_OSCIL_POS HELICAL_POS
local msg sampy_tst

  if ($1 <= 0) {
    eprintf ("Please specify position number, aborting...\n")
    exit
  }

  if ($1 == 99) {
    helical_resetpos()
    return
  }

  msg = ""

  if ($1 > 10) {
     for (mne in HELICAL_MOT) {
       if ($1 == 11) {
         A[HELICAL_MOT[mne]] = HELICAL_OSCIL_POS[1][mne]
       } else if ($1 == 22) {
         A[HELICAL_MOT[mne]] = HELICAL_OSCIL_POS[2][mne]
       }
    }
    move_em; waitmove
  } else {
    if ($1 == 1) {
      HELICAL_POS[1]["label"] = "Start"
    }
    if ($1 == 2) {
      HELICAL_POS[2]["label"] = "Final"
    }
    sampy_tst = HELICAL_OSCIL_POS[$1]["sampy"]
    sync; get_angles
    for (mne in HELICAL_MOT) {
      HELICAL_OSCIL_POS[$1][mne] = A[HELICAL_MOT[mne]]
      msg = sprintf ("%s=%2.4f %s", mne, A[HELICAL_MOT[mne]], msg)
    }
    if (fabs(sampy_tst - HELICAL_OSCIL_POS[$1]["sampy"]) > 0.001)
      HELICAL_PARS["nb_pos"] += 1
    if (HELICAL_PARS["nb_pos"] > 2)
      HELICAL_PARS["nb_pos"] = 2
    msg = sprintf ("Helical %s Position: %s\n", HELICAL_POS[$1]["label"], msg)
    printf ("%s\n", msg)
    egui_logmsg(msg)
  }
}'

#%IU% ()
#%MDESC% Check different positions. Return -1 if error, 0 otherwise. Set the
#message global to be used by other macros.
def helical_check() '{
local msg i j
  msg = ""

  if (HELICAL_PARS["nb_pos"] < 2) {
    if (HELICAL_SCAN4D == 1)
      msg = sprintf ("Scan 4D")
    else
      msg = sprintf ("Helical")
    msg = sprintf ("%s: At least two positions should be specified, exiting",\
		 msg)
    eprintf("%s\n", msg)
    egui_fatal(msg)
    HELICAL_PARS["msg"] = msg
    return(-1)
  }
  j = 1
  while (j <= HELICAL_PARS["nb_pos"]) {
    sampy_tst = HELICAL_OSCIL_POS[j]["sampy"]
    for (i = 1 ; i<=HELICAL_PARS["nb_pos"]; i++) {
      if (i != j) {
        if (fabs(sampy_tst - HELICAL_OSCIL_POS[i]["sampy"]) < 0.002) {
          msg = sprintf ("Helical: %s position identical to %s position.", \
		HELICAL_POS[i]["label"], HELICAL_POS[j]["label"])
          msg = sprintf ("%s Please change and restart.", msg)
          eprintf ("%s\n", msg)
          egui_fatal(msg)
          HELICAL_OSCIL = 0
          HELICAL_PARS["msg"] = msg
          return(-1)
        }
      }
    }
    j++
  }

  for (i=1; i<=HELICAL_PARS["nb_pos"]; i++) {
    if (HELICAL_OSCIL_POS[i]["sampy"] == 0) {
      msg = sprintf ("Helical: %s position not saved,exiting", HELICAL_POS[i]["label"])
      eprintf ("%s\n", msg)
      egui_fatal(msg)
      HELICAL_PARS["msg"] = msg
      return(-1)
    }
  }
  return(0)
}'

#%UU% 
#%MDESC% Activate the helical datacollection.
def helical_oscil_on '{
global HELICAL_OSCIL HELICAL_SCAN4D

  if (HELICAL_PARS["debug"])
    printf ("helical_oscil_on\n")

  if (HELICAL_SCAN4D == 0)
    HELICAL_OSCIL = 1
  else
    HELICAL_OSCIL = 0
}'

#%UU% 
#%MDESC% Deactivate the helical datacollection.
def helical_oscil_off '{
  if (HELICAL_PARS["debug"])
    printf ("helical_oscil_off\n")
  HELICAL_OSCIL = 0
}'

#%UU% 
#%MDESC% Activate the helical 4D scan datacollection.
def helical_scan4d_on '{
global HELICAL_OSCIL HELICAL_SCAN4D HELICAL_SCAN4D_MANUAL

  if (HELICAL_PARS["debug"])
    printf ("helical_scan4d_on\n")
  HELICAL_SCAN4D = 1
  HELICAL_SCAN4D_MANUAL = 1
  HELICAL_OSCIL = 0 
}'

#%UU% 
#%MDESC% Deactivate the helical 4D scan datacollection.
def helical_scan4d_off '{
global HELICAL_OSCIL HELICAL_SCAN4D

  if (HELICAL_PARS["debug"])
    printf ("helical_scan4d_off\n")
  HELICAL_SCAN4D = 0
  HELICAL_SCAN4D_MANUAL = 0
}'

#%UU% ()
#%MDESC% Prepare the helical datacollection when not using mxCuBE.
def helical_prepare() '{

  cdef("cleanup_once","helical_oscil_off;","helical_oscil")
  helical_oscil_on
  printf ("Please centre your crystal at the final position\n")
  if (yesno("Should I continue?", 0) == 0)
    exit
  helical_getpos 2
  printf ("Please centre your crystal at the initial position\n")
  if (yesno("Should I continue?", 0) == 0)
    exit
  helical_getpos 1
  tty_cntl("md")
  printf ("Now do the data collection.")
  printf ("Do not forget to run helical_oscil_off when finished\n")
  tty_cntl("me")
}'

def helical_queue() '{
global HELICAL_SCAN4D HELICAL_SCAN4D_MANUAL

  printf ("executing  helical_queue %d\n", HELICAL_PARS["nb_pos"])
  if ((COLLECT_SEQ["scan4d"]) && (HELICAL_SCAN4D_MANUAL == 0)) {
    HELICAL_PARS["nb_pos"] = 0
    HELICAL_SCAN4D = COLLECT_SEQ["scan4d"]
    unglobal HELICAL_OSCIL_POS
    global HELICAL_OSCIL_POS
    if (COLLECT_SEQ["phiy_s"]) {
      HELICAL_OSCIL_POS[1]["phiy"] = COLLECT_SEQ["phiy_s"]
      HELICAL_OSCIL_POS[1]["phiz"] = COLLECT_SEQ["phiz_s"]
      HELICAL_OSCIL_POS[1]["sampx"] = COLLECT_SEQ["sampx_s"]
      HELICAL_OSCIL_POS[1]["sampy"] = COLLECT_SEQ["sampy_s"]
      HELICAL_OSCIL_POS[2]["phiy"] = COLLECT_SEQ["phiy_e"]
      HELICAL_OSCIL_POS[2]["phiz"] = COLLECT_SEQ["phiz_e"]
      HELICAL_OSCIL_POS[2]["sampx"] = COLLECT_SEQ["sampx_e"]
      HELICAL_OSCIL_POS[2]["sampy"] = COLLECT_SEQ["sampy_e"]
      HELICAL_PARS["nb_pos"] = 2
    }
    if (helical_check() == -1)
      exit
  }
}'

#### END OBSOLETE MACROS ####

#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% D.Flot/A.Beteva%BR%
#$Revision: 2.0 $$Date: 2014/01/22 09:55:22 $%BR%
#%END%
#%LOG%
#$Log: helical_oscil.mac,v $
#Revision 2.0  2014/01/22 09:55:22  beteva
#Changes to cope with mxcube2. Remove obsolete variables and functions.
#
#Revision 1.9  2012/07/18 08:32:50  beteva
#added check for deleting the HELICAL_OSCIL_POS to avoid the
#Can't delete from non-associative array "HELICAL_OSCIL_POS error message.
#
#Revision 1.8  2012/06/20 08:56:53  beteva
#added test for nb of positions, corrected a typo on error message print
#
#Revision 1.7  2011/11/08 16:26:12  beteva
#removed the overlap test
#
#Revision 1.6  2011/11/08 15:55:19  guijarro
#fixed overlap ug
#
#Revision 1.5  2011/10/26 12:57:27  beteva
#added HELICAL_PARS["nb_acq"], calculated as function of the beam size
#added 4D scan handling
#
#Revision 1.4  2010/07/26 07:19:09  guijarro
#'pos' variable passed from global to lcoal
#
#Revision 1.3  2010/07/06 16:44:08  beteva
#added reset positions option; added test for microdiff; bug fixed in helical_getpos
#
#Revision 1.2  2010/06/29 16:33:07  beteva
#added reset position, check helical positions, test for overlap
#
#Revision 1.1  2010/05/19 12:57:33  beteva
#Initial revision