Move to the position calculated from the scan data

This file is a example how to move a motor after performing one scan to the position determined by the counts of a given counter.

The scan has to be performed from a macro which is calling the ascan macro, in other case the scan data are not available for the further analysis. Other possibility would be to read the id of the scan and get the scan data from a nexus file, but for the Petra experiments we are not using the nexus implementation in Sardana.

The commands to use in spock would be:

p09/door/haso111tb [70]: %make_scan exp_mot01 39 40 5 1
Operation will be saved in /home/tnunez/test.txt (Spec)
Scan #136 started at Fri Apr 26 15:11:11 2013. It will take at least 0:00:06
Moving to start positions...
 #Pt No      dt     exp_mot01  exp_t01   exp_c01 
   0      1.69902       39        1         3    
   1      9.71302      39.2       1         4    
   2       17.71       39.4       1         5    
   3      25.7155      39.6       1         6    
   4       33.715      39.8       1         5    
   5       41.723       40        1         4    
Operation saved in /home/tnunez/test.txt (Spec)
Scan #136 ended at Fri Apr 26 15:11:57 2013, taking 0:00:45.615066. Dead time 86.8% (motion dead time 48.7%)
p09/door/haso111tb [71]: %ana_func exp_c01
Position to move
39.6

p09/door/haso111tb [72]:

The motor exp_mot01 is scaned and at the end of the scan it is moved to the position determined from the counts of the exp_c01 counter.

The code of the macros ist:

#!/usr/bin/env python

"""the demo for moving a motor after an scan"""

from __future__ import print_function

__all__ = ["analysis_scan"]

import PyTango
from sardana.macroserver.macro import *
from sardana.macroserver.macro import macro
import json

ascan = 0
gmotor = 0

class make_scan(Macro):
    """Perfoms an scan keeping the data for further analysis/moves"""

    param_def = [
       ['motor',      Type.Motor,   None, 'Motor to move'],
       ['start_pos',  Type.Float,   None, 'Scan start position'],
       ['final_pos',  Type.Float,   None, 'Scan final position'],
       ['nr_interv',  Type.Integer, None, 'Number of scan intervals'],
       ['integ_time', Type.Float,   None, 'Integration time']
    ]
    result_def = [ [ "result", Type.String, None, "the ascan object" ]]
    def run(self, motor, start_pos, final_pos, nr_interv, integ_time):
        global ascan
        global gmotor
        
        gmotor = motor

        ascan, pars= self.createMacro("ascan",motor, start_pos, final_pos, nr_interv, integ_time)

        self.runMacro(ascan)
        result = " "
        for elm in ascan.data.records:
            result = result + str(elm.data)
        return result 

param_def = [
        ['channel',  Type.String,   None, 'Channel to analize']]

@macro()
def ana_data(self, channel):
    """Analysis function"""

    pools = []
    pools = self.getPools()
    pool = pools[0]
    self.output(pool)
    fullname = "Channel not found"
    for el in  pool.AcqChannelList:
        chan = json.loads( el)
        if channel == chan['name']:
            #
            # from: expchan/hasysis3820ctrl/1/value
            # to:   expchan/hasysis3820ctrl/1
            #
            arr = chan['full_name'].split("/")
            fullname = "/".join(arr[0:-1])

    global ascan
    global gmotor

    motor_name = gmotor.name

    arr_data = []
    arr_motpos = []
    for elm in ascan.data.records:
            self.output( elm.recordno)
            self.output( elm.data)
            self.output( elm.written)
            for dat in elm.data:
                if dat == fullname:
                    arr_data.append(elm.data[fullname])
                if dat == motor_name:
                    arr_motpos.append(elm.data[motor_name])

    # Compute maximum 
    dmax = 0
    for i in range(0, len(arr_data)):
        if arr_data[i] > dmax:
            dmax = arr_data[i]
            imax = i
    # Position to move arr_motpos[imax]

    self.output("Position to move")
    self.output(arr_motpos[imax])
    self.mv(gmotor,31)


class ana_func(Macro):
    
    """Analysis macro"""
    
    param_def = [
        ['channel',  Type.String,   None, 'Channel to analize']
        ]
    
    def prepare(self, channel):
        self.dmax = 0

        pools = []
        pools = self.getPools()
        pool = pools[0]
        self.fullname = "Channel not found"
        for el in  pool.AcqChannelList:
            chan = json.loads( el)
            if channel == chan['name']:
                #
                # from: expchan/hasysis3820ctrl/1/value
                # to:   expchan/hasysis3820ctrl/1
                #
                arr = chan['full_name'].split("/")
                self.fullname = "/".join(arr[0:-1])
        
    def run(self, channel):
     
        global ascan
        global gmotor
        
        motor_name = gmotor.name

        self.arr_data = []
        arr_motpos = []
        for elm in ascan.data.records:
            for dat in elm.data:
                if dat == self.fullname:
                    self.arr_data.append(elm.data[self.fullname])
                if dat == motor_name:
                    arr_motpos.append(elm.data[motor_name])

        self.peak()

        # Position to move arr_motpos[imax]

        self.output("Position to move")
        self.output(arr_motpos[self.imax])
        self.mv(gmotor,arr_motpos[self.imax])


    def peak(self):
        # Compute maximum 
        for i in range(0, len(self.arr_data)):
            if self.arr_data[i] > self.dmax:
                self.dmax = self.arr_data[i]
                self.imax = i

This code can be easily extended for moving to another calculated positions.