#!/usr/bin/env python
#
## script for BT Conrad S. - sweep scan using phyton
##
## usage:
##
## 1) adjust motors / devices acording to current device onnections
## see line 128 (at moment) - proxy connects to tango devices
##
## 2) copy this script into "online" foler and make it
## executable for P03user (i.e. as p03user do)
## a) cp cs_sweep.py /gpfs/current/raw/online/
## b) cd /gpfs/current/raw/online/
## chmod u+x cs_sweep.py
##
## 4) script can now be excecuted from within online folder by
## [from fresh terminal window: cd /gpfs/current/raw/online/ and then]
## ./cs_sweep.py [opt_args]
##
## !!! Do NOT stop reading here !!!
##
## The script writes its oputput into the directory from where it was called
## with a filename having the extension ".dat"
##
## When called without arguments, it takes the defaults defined in here,
## e.g. for filename and motor movement ranges
##
## The script can be called with optional args allowing to change the defaults
## Note: You can pass one or multiple args.
## If an argument is missing, the default is taken
## Order of arguments doesn't matter
##
## Opt args are:
##
## -p (or aquivalent --prefix): the filename prefix for the output file
## a 5 digit counter will be added automatically
## -sx (or aquivalent --startX): the start position of 1st motor
## -ex (or aquivalent --stopX): the stop position of 1st motor
## -sy (or aquivalent --startY): the start position of 2nd motor
## -ey (or aquivalent --stopY): the stop position of 2nd motor
## -l (or aquivalent --loopMax): the maximum number of loops (before script
## ends by itself)
## -d (or aquivalent --debug): NOT needed - just some additional screen
## output I used when writing the stuff
##
##
## Hence, script calls can be e.g. like this
##
## ./cs_sweep.py -p=dummy
##
## (output file should be named dummy, i.e. dummy_<5 digit counter>.dat,
## and defaults for all other actions implied)
##
## or
##
## ./cs_sweep.py -p=dummy -l=3 -sx=2
## (output file should be named dummy, number of loops should be 3 and
## 1st motor starting position to use is 2. defaults for all other actions implied)
##
## or
##
## ./cs_sweep.py -p=dummy -l=2 -sx=2 -ex=4 -sy=3 -ey=6
##
## (output file should be named dummy, number of loops should be 2,
## 1st motor should move from 2 to 4 and 2nd motor should move from 3 to 6.)
##
## The script runs until the max. number of loops defined is reached or
## can be stopped with the 'space bar'
##
##
## history
##
## ver 0.0 - the first - script for test environment
## * T.K. + W.O. + A.R., Oct 14, 2016
##
## ver 0.1 - modifications according to P03 BL and enhancements, Oct 14, 2016 by A.R./FSEC
## * argument parsing added
## * shutter control added
## * comments added
##
import time, sys
import PyTango
import HasyUtils
import argparse
class breakLoop( Exception): pass
## here we define the optional arguments and their defaults
## the --<name> defines the name of the variable used laten in the script
## e.g. --prefix results that a variable args.prefix exists
## (args.prefix because of the args = parser.... call lateron)
parser = argparse.ArgumentParser(description='CS sweep scan')
parser.add_argument('-p','--prefix', type=str, default="cs_sweep_p03",
help='the filename prefix for the output file (counter will be added)')
parser.add_argument('-l','--loopMax', type=int, default=10,
help='the maximum number of loops (defaults to 10)')
parser.add_argument('-sx','--startX', type=int, default=0,
help='the start position of 1st motor (exp_mot<NN>) (defaults to 0)')
parser.add_argument('-ex','--stopX', type=int, default=1,
help='the stop position of 1st motor (defaults to 1)')
parser.add_argument('-sy','--startY', type=int, default=0,
help='the start position of 2nd motor (exp_mot<NN>) (defaults to 0)')
parser.add_argument('-ey','--stopY', type=int, default=-1,
help='the stop position of 2nd motor (defaults to 0)')
parser.add_argument('-d','--debug', type=int, default=0,
help='a debug flag (defaults to 0)')
args = parser.parse_args()
out = None
# print something to the screen if set
if args.debug == 1:
print( "prefix: %s, startX: %g, stopX: %g, startY: %g, stopY: %g, loopMax: %g\n" % ( args.prefix,
args.startX, args.stopX, args.startY,
args.stopY, args.loopMax))
## establish proxy connects to devices involved
## use motor 26 as X (still defined as diode_x in online as of Oct. 14)
## use motor 25 as Y (still defined as diode_y in online as of Oct. 14)
## assign ADCs 1 and 2 (for the 0-10V signals Conrad will provide)
## use P03 vfcadc01 (the diode on primary BS)
## use output register 1 'oreg1 in online', i.e. connected to fast shutter at momentt
## W.O. to adjust
##
try:
diode_x = PyTango.DeviceProxy( "p03/motor/expmi.26")
diode_y = PyTango.DeviceProxy( "p03/motor/expmi.25")
adc_kraft = PyTango.DeviceProxy( "p03/adc/exp.01")
adc_weg = PyTango.DeviceProxy( "p03/adc/exp.02")
i0 = PyTango.DeviceProxy( "p03/vfc/exp.01")
fshttr = PyTango.DeviceProxy( "p03/register/exp.out01")
except:
print( "failed to create the proxies")
sys.exit( 255)
## definition to put single line to screen and into file
def recordData():
print( "%g %g %g %g %g" % ( diode_x.position,
diode_y.position,
adc_kraft.value,
adc_weg.value,
i0.value))
out.write( "%g %g %g %g %g %f\n" % ( diode_x.position,
diode_y.position,
adc_kraft.value,
adc_weg.value,
i0.value, time.time()))
if HasyUtils.inkey() == 32:
return False
return True
## definition for call (moving into starting position)
##
def moveToStart():
if( diode_x.state() != PyTango.DevState.ON or
diode_y.state() != PyTango.DevState.ON):
print( "state != ON")
return False
diode_x.position = args.startX
diode_y.position = args.startY
while( diode_x.state() == PyTango.DevState.MOVING or
diode_y.state() == PyTango.DevState.MOVING):
time.sleep(0.5)
print( "moving to start %g %g" % (diode_x.position, diode_y.position))
if HasyUtils.inkey() == 32:
print( "terminated by space-bar")
return False
return True
## make use of hasyutils and create a decent filename from the prefix given
## this also adds the 5 digit counter
##
fName = HasyUtils.createScanName( args.prefix)
if args.debug == 1:
print( "fName: %s\n" % ( fName))
## move to strating position or die
##
ret = moveToStart()
if not ret:
sys.exit( 255)
## create the output file (in the current directory)
##
out = open( fName + ".dat", "w")
out.write("!\n")
out.write("! Started at %s %f\n" % (HasyUtils.getDateTime(), time.time()))
out.write("! recording %s %s %s %s %s time\n" % (diode_x.name(),diode_y.name(),adc_kraft.name(),adc_weg.name(),i0.name()))
out.write("!\n")
## open the fast shutter (i.e. set register to low)
##
fshttr.value=0
## now loop until max num of loops is reached or space bar is pressed to abort
## data logging time reolution is currently 0.2s (I wouldn't go too low,
## maybe down to 0.05 (?) you may try ....)
## W.O. to adjust
##
try:
for i in range( args.loopMax):
out.write( "! sweep %d\n" % i)
print( "! sweep %d/%d \n" % (i, args.loopMax))
diode_x.position = args.stopX
diode_y.position = args.stopY
while( diode_x.state() == PyTango.DevState.MOVING or
diode_y.state() == PyTango.DevState.MOVING):
time.sleep(0.2)
if not recordData():
raise breakLoop
diode_x.position = args.startX
diode_y.position = args.startY
while( diode_x.state() == PyTango.DevState.MOVING or
diode_y.state() == PyTango.DevState.MOVING):
time.sleep(0.2)
if not recordData():
raise breakLoop
except breakLoop:
## close fast shutter
fshttr.value=1
print( "The eagle has landed!")
## close file
##
out.close()
## close fast shutter (in case of normal termination and to be save at all)
##
fshttr.value=1