#!/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