py4sci

Table Of Contents

Previous topic

Overview

Next topic

Scan Commands

This Page

Scan Client

This example shows how to connect to the scan server, submit a scan, and monitor its progress using the basic API, without using site-specific settings or abstractions like the table-based scan.

Example

import time
from scan import *
  
client = ScanClient('localhost')
print client

print client.serverInfo()

# Assemble commands for a scan
# Much more on that later...
cmds = [ Comment('Hello'), Set('motor_x', 10) ]

# Optionally, request a simulation that shows
# how 'Include' and 'Loop' commands get expanded.
simulation = client.simulate(cmds)
print simulation

# Submit scan for execution
id = client.submit(cmds, 'My First Scan')
print id

# Fetch information about scan
info = client.scanInfo(id)
print info

# Could poll scanInfo until info.isDone().
# Shortcut:
info = client.waitUntilDone(id)
print info

# A submitted scan can be paused..
id = client.submit(cmds, 'Not sure about this one')

client.pause(id)
print client.scanInfo(id)

client.resume(id)
print client.scanInfo(id)

# .. or even aborted  & deleted
client.abort(id)
print client.scanInfo(id)

print "Before deleting scan %d:" % id, [ str(info) for info in client.scanInfos() ]
client.delete(id)
print "After  deleting scan %d:" % id, [ str(info) for info in client.scanInfos() ]

# In extreme cases, it is possible to change a running scan
id = client.submit([ Delay(5), Set('motor_x', 10) ], 'Changing...')
client.pause(id)
# Want to set 'motor_x' to 5 instead of 10
client.patch(id, 1, 'value', 5)
client.resume(id)
client.abort(id)

try:
    client.waitUntilDone(id)
except Exception, e:
    print "Waiting for an aborted scan will result in an exception: ", e

try:
    # This scan will time out
    id = client.submit( [ Wait("motor_x", 60, timeout=1)], "Timeout Test")
    client.waitUntilDone(id)
except Exception, e:
    print "Waiting for a failed scan will result in an exception: ", e

# Log data during scan
cmds = [ Loop('motor_x', 1, 10, 1,
              [ 
                  Set('neutrons', 0),
                  Loop('motor_y', 1, 3, 1,
                       [
                           Delay(1),
                           Log('motor_y')
                       ]),
                  Log('motor_x', 'neutrons')
              ])
       ]
id = client.submit(cmds, 'Data Demo')
info = client.waitUntilDone(id)
print "Number of log calls: %d" % client.lastSerial(id)

# Fetch data
data = client.getData(id)
 
# Create table for motor_x and neutrons
table = createTable(data, 'motor_x', 'neutrons')
print "Positions: ", table[0]
print "Counts   : ", table[1]
for (pos, count) in zip(*table):
    print "Counts at motor position %g: %g" % (pos, count)
    
# Could plot this with numpy/scipy:  plot(table[0], table[1]) etc.

# TODO get commands back from server

# Remove information for all completed scans
client.clear()

API

class scan.client.scanclient.ScanClient(host='localhost', port=4810)

Client interface to the scan server

Parameters:
  • host – The IP address or name of scan server host.
  • port – The TCP port of the scan server.

Example:

>>> client = ScanClient('localhost')
abort(scanID=-1)

Abort a running or paused scan

Parameters:scanID – ID of scan or -1 to abort current scan

Using PUT {BaseURL}/scan/{id}/abort

Example:

>>> id = client.submit(commands)
>>> client.abort(id)
clear()

Remove all completed scans.

Using DELETE {BaseURL}/scans/completed

Usage:

>>> client.clear()
delete(scanID)

Remove a completed scan.

Using DELETE {BaseURL}/scan/{id}

Parameters:scanID – The id of scan you want to delete.

Example:

>>> id = client.submit(commands)
>>> client.abort(id)
>>> client.delete(id)
getData(scanID)

Fetch logged data of a scan

Parameters:scanID – ID of scan
Returns:Data dictionary
Example:
>>> data = client.getData(id)
>>> print data

Format of the data:

{ 'device1': {'id': [0, 1, 2, 3, 4 ],
              'value': [2.0, 3.0, 4.0, 2.0, 4.0],
              'time': [1427913270352, 1427913270470, 1427913270528, 1427913270596, 1427913270695]
             },
  'device2': {'id': [0, 3, 6, 9, 12],
              'value': [1.0, 2.0, 3.0, 4.0, 5.0],
              'time': [1427913270351, 1427913270595, 1427913270795, 1427913271076, 1427913271393]
             }
}

The data dictionary has one entry per logged device. Its value is again a dictionary with entries

id:
Sample IDs, starting from 0
value:
Sample values
time:
Times in Posix milliseconds
lastSerial(scanID)

Get the last log data serial.

Obtains the serial ID of the last logged sample of a scan. Allows clients which monitor the progress of a scan to poll for changes in the logged data without always having to pull the complete data log.

Parameters:scanID – The ID of scan for which to fetch information.
Returns:Id of last logged sample of the scan.

Example:

>>> last_log_fetched = -1
>>> while not client.scanInfo(id).isDone:
>>>     last_logged = client.lastSerial(id)
>>>     if last_log_fetched != last_logged:
>>>        # .. fetch logged data, because it has changed..
>>>        last_log_fetched = last_logged
>>>     time.sleep(10
patch(scanID, address, property, value)

Update scan on server.

This can be used to update parameters of an existing command in an existing scan on the server.

In case the command had already been executed, the change has no effect.

Using PUT {BaseURL}/scan/{id}/patch

Parameters:
  • scanID – The id of scan you want to update.
  • address – Address of the command to update. Counted within the scan starting at 0.
  • property – The property of the command to update.
  • value – The new value for that property.

Example:

>>> id = client.submit([ Delay(5), Set('motor_x', 10) ], 'Changing...')
>>> client.pause(id)
>>> # Want to set 'motor_x' to 5 instead of 10
>>> client.patch(id, 1, 'value', 5)
>>> client.resume(id)
pause(scanID=-1)

Pause a running scan

Parameters:scanID – ID of scan or -1 to pause current scan

Using PUT {BaseURL}/scan/{id}/pause

Example:

>>> id = client.submit(commands)
>>> client.pause(id)
resume(scanID=-1)

Resume a paused scan

Parameters:scanID – ID of scan or -1 to resume current scan

Using PUT {BaseURL}/scan/{id}/resume

Example:

>>> id = client.submit(commands)
>>> client.pause(id)
>>> client.resume(id)
scanCmds(scanID)

Get the commands of scan.

Reads scan commands from scan server. Only possible for scans that are still available on the server, not for older scans that only have logged data but no command detail.

:param scanID:: The ID of scan for which to fetch information.

Returns:Scan commands in XML format of a scan.

Example:

>>> client = ScanClient()
>>> scanid = client.submit(...someCMDs...)
>>> # Submit it again:
>>> client.submit(client.scanCmds(scanid))
scanDevices(scanID=-1)

Get list of devices used by scan.

Parameters:scanID – The ID of scan that is still held in scan server, -1 to fetch default devices.

Provides a list of devices used by a scan. For a running scan, this includes devices accessed in the pre- and post-scan. Also includes devices configured with alias names, but not necessarily used by the scan.

Returns:XML with info about devices.
scanInfo(scanID, timeout=10)

Get information for a scan

Using GET {BaseURL}/scan/{id}

Parameters:
  • scanID – The ID of scan for which to fetch information.
  • timeout – Throws exception when no reply within that time in seconds
Returns:

ScanInfo

Example:

>>> client = ScanClient()
>>> print client.scanInfo(42)
scanInfos(timeout=20)

Get information of all scans

Using GET {BaseURL}/scans

Parameters:timeout – Throws exception when no reply within that time in seconds
Returns:List of ScanInfo

Example:

>>> infos = client.scanInfos()
>>> print [ str(info) for info in infos ]
serverInfo()

Get scan server information

Provides version number, configuration, ... of current server

Using GET {BaseURL}/server/info

Returns:XML with server info

Usage:

>>> client = ScanClient()
>>> print client.serverInfo()
simulate(cmds)

Submit scan to scan server for simulation

Parameters:cmds – List of commands, CommandSequence or text with raw XML format.
Returns:Simulation result as dictionary { ‘simulation’: “Printable text”, ‘seconds’: 193.0 }

Example:

>>> result = client.simulate([ Set('x', 5), Delay(2) ])
>>> print result['simulation']
submit(cmds, name='UnNamed', queue=True, timeout=0, deadline=None, pre_post=True)

Submit scan to scan server for execution

Parameters:
  • cmds – List of commands, CommandSequence or text with raw XML format.
  • name – Name of scan
  • queue – Submit to scan server queue, or execute as soon as possible?
  • timeout – Timeout in seconds after which scan will self-abort
  • deadline – Execution deadline in “yyyy-MM-dd HH:mm:ss” format when scan will self-abort
  • pre_post – Execute pre- and post-scan commands (default: True)
Returns:

ID of submitted scan

By default, a submitted scan will be queued. One scan is then executed at a time, in order of submission. Each scan is allowed to run until all its commands complete.

The ‘queue’ parameter allows submitting scans for immediate execution, i.e. in parallel to the queued commands.

Either the ‘timeout’ or the ‘deadline’ might be used to limit the execution time.

Examples:

>>> cmds = [ Comment('Hello'), Set('x', 10) ]
>>> id = client.submit(cmds, "My First Scan")
>>> cmds = CommandSequence(Comment('Hello'))
>>> cmds.append(Set('x', 10))
>>> id = client.submit(cmds, "My Second Scan")
>>> cmds = CommandSequence(Delay(600))
>>> id = client.submit(cmds, "Timeout", timeout=10)
waitUntilDone(scanID)

Wait until scan finishes.

On return, the scan has finished successfully. Can also be used for an older scan that has logged data, whereupon this call will return immediately.

In case the scan failed or was aborted, an exception is raised.

If scan information is not available (timeout while requesting it), keep checking.

Parameters:scanID – ID of scan on which to wait
Returns:Scan info
Raises Exception:
 If scan was aborted or failed.
class scan.client.scaninfo.ScanInfo(xml)

Information about a scan

Parameters:xml – XML element for a scan info
createdDatetime()
Returns:datetime when scan was created
isDone()
Returns:True if scan has completed, successful or not
percentage()
Returns:Percent of work done, 0...100