presented by Matias Guijarro
Beamline Control Unit, Software Group
ESRF, Grenoble, France
Diamond Light Source
2 February 2018
BeamLine Instrumentation Support Software
Limitations
Workarounds
Maintenance cost
Python library + tools
Technical choices
Beacon: services for BLISS
Hardware control
Scanning & data acquisition
Data management
Sequences as genuine Python functions
Embed into any Python program
>>> from bliss.common.axis import Axis
>>> from bliss.controllers.motors import IcePAP
>>> iceid2322 = IcePAP.IcePAP("iceid2322",
{"host": "iceid2322"},
[("mbv4mot", Axis, { "address": 1,
"steps_per_unit": 80,
"velocity": 125,
"acceleration": 500
}
)], [])
>>> iceid2322.initialize()
>>> m = iceid2322.get_axis("mbv4mot")
>>> m.velocity()
125.0
>>> m.acceleration()
500.0
>>> m.position()
252.23750000000001
>>>
Command Line Interface based on ptpython
matias@kashyyyk:~ % bliss -s test_session
test_session: Executing setup...
Initializing 'heater`
...
Initializing 's1hg`
Done.
>>> ascan(m1, 0, 10, 30, 0.1, diode, save=False)
Total 30 points, 3.0 seconds
Scan 4 Mon Sep 11 11:58:03 2017 <no file> test_session user = guijarro
ascan m1 0 10 30 0.1
# timestamp m1 diode
0 1.50512e+09 0 499.112
1 1.50512e+09 0.345 500.799
...
28 1.50512e+09 9.655 505.622
29 1.50512e+09 10 499.883
Configuration web application
Graphical interface for users: interactive web shell
All I/O based on gevent
cooperative multi-tasking
Direct hardware control
Distributed control ownership & shared state
Persistent settings
cache
Transient data store
Scan acquisition chain, represented as a tree
online data analysis
data visualisation
data archiving
Web interface for configuration editing
Beacon server
.yml
Devices & sequences configuration in YAML format
Sessions to group
objects
Python setup file
User scripts
Can replace TANGO DB
Conversion script provided
sybil:~/local/beamline_configuration % tree
.
├── beacon.rdb
├── eh
│ ├── diode.yml
│ ├── __init__.yml
│ └── motors
│ ├── bv.yml
│ ├── DtoX.yml
│ ├── __init__.yml
│ ├── md2.yml
│ ├── mirror1.yml
│ ├── slits.yml
│ └── table.yml
├── oh
│ ├── bpm.yml
│ ├── __init__.yml
│ ├── motors
│ │ ├── bv.yml
│ │ ├── __init__.yml
│ │ ├── mono.yml
│ │ ├── slits.yml
│ │ └── transfocators.yml
│ └── wagos.yml
└── sessions
├── id232_setup.py
├── id232.yml
└── __init__.yml
- controller:
class: IcePAP
host: iceid2322
axes:
- name: mbv4mot
address: 1
steps_per_unit: 817
velocity: 0.3
acceleration: 3
bv.yml:
motor object
Beacon server,
services built on top of
Transient data store
Persistent settings cache
Message broker
acquire lock
ok !
acquire lock
ok !
move
acquire lock
move
psy1 locked to A
state channels update
5
10
m0 position
m0 speed
detector frame triggering
sybil:~ % bliss
>>> from bliss.scanning.chain import AcquisitionChain
>>> from bliss.scanning.acquisition.motor import SoftwarePositionTriggerMaster
>>> from bliss.scanning.acquisition.lima import LimaAcquisitionDevice
>>> from PyTango.gevent import DeviceProxy
>>> m0 = config.get("m0")
>>> lima_dev = DeviceProxy("id30a3/limaccd/simulation")
>>> chain = AcquisitionChain()
>>> chain.add(SoftwarePositionTriggerMaster(m0, start=5, end=10,
npoints=10, time=5),
LimaAcquisitionDevice(lima_dev, acq_nb_frames=5, acq_expo_time=0.03,
acq_trigger_mode="INTERNAL_TRIGGER_MULTI"))
>>> SCAN_SAVING.template = '/data/id23eh2/inhouse/{date}/{sample}'
>>> SCAN_SAVING.sample = 'HAK1234'
>>> SCAN_SAVING.get_path()
"/data/id23eh2/inhouse/20170324/HAK1234"
>>> from bliss.scanning.scan import Scan
>>> my_continuous_scan = Scan(chain)
>>> my_continuous_scan.start()
Mirroring of the Acquisition Chain tree
each device in the chain has a name
each device define 1 or more 'AcquisitionChannel' objects
Acquisition channels
must have a name, a type and a shape
Metadata
scan_info dictionary ({ key: value, ... }) associated with scans
While a scan is running, data is published to the redis database provided by Beacon
scalar values are stored directly
bigger data (images, spectra) is just referenced
configurable time to live (TTL)
from bliss import * # imports generic scans, cleanup functions, etc
from bliss.setup_globals import * # imports objects from session (setup)
import numpy # I know you dreamt of it
import gevent
def set_detector_cover(in):
wcidxx.set('detcover', in)
# 5 seconds timeout waiting for detector cover to move
with gevent.Timeout(5):
while wcidxx.get('detcover_in') == in:
time.sleep(0.1)
def my_super_experiment(name):
safety_shutter.open()
old_att = attenuators.get()
def restore_beamline():
set_detcover_open(False)
attenuators.set(old_att)
with cleanup(safety_shutter.close): # cleanup is always called at the end
with error_cleanup(restore_beamline): # this will only be called in case of error
attenuators.set(50)
set_detcover_open(True)
SCAN_SAVING.name = name
MEASUREMENT_GROUP.enable('diode')
data_node = dscan(m0, -5, 5, 10, 0.1)
for data in data_node.walk_data():
# do something useful with data...
from bliss import * # imports generic scans, cleanup functions, etc
from bliss.setup_globals import * # imports objects from session (setup)
import numpy # I know you dreamt of it
import gevent
def set_detector_cover(in):
wcidxx.set('detcover', in)
# 5 seconds timeout waiting for detector cover to move
with gevent.Timeout(5):
while wcidxx.get('detcover_in') == in:
time.sleep(0.1)
def my_super_experiment(name):
safety_shutter.open()
old_att = attenuators.get()
def restore_beamline():
set_detcover_open(False)
attenuators.set(old_att)
with cleanup(safety_shutter.close):
with error_cleanup(restore_beamline):
attenuators.set(50)
set_detcover_open(True)
SCAN_SAVING.name = name
MEASUREMENT_GROUP.enable('diode')
data_node = dscan(m0, -5, 5, 10, 0.1)
for data in data_node.walk_data():
# do something useful with data...
with cleanup(safety_shutter.close): # cleanup is always called at the end
with error_cleanup(restore_beamline): # only called in case of error
...
Use of Python context managers for cleanup
Normal Python functions
Easy timeouts with gevent.Timeout
# 5 seconds timeout waiting for detector cover to move
with gevent.Timeout(5):
while wcidxx.get('detcover_in') == in:
time.sleep(0.1)
BLISS core development team
+ ESRF BCU contributing members: A. Beteva, M.C.Dominguez, M. Perez, J. Meyer
ESRF Software Group: A. Goetz
A. Homs
E. Papillon
J. Bodera
C. Guilloud
J. Bodera
M. Guijarro
T. Coutinho
S. Petitdemange
V. Michel