Moving towards beamline startup

This commit is contained in:
Unknown MX Person
2024-11-13 14:30:57 +01:00
parent b0703552f2
commit 78c75b1769
7 changed files with 281 additions and 390 deletions

View File

@@ -1,55 +0,0 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 31 10:27:18 2022
Database migration from a sensible format to the BEC YAML file format
@author: mohacsi_i
"""
import yaml
import yaml.representer
def MigrateYamlFile(filein, fileout):
""" Migrates an absolutely minimal YAML config file to the format
required by the BEC (i.e. adding default fields).
"""
fp = open(filein, "r")
lut = yaml.load(fp, Loader=yaml.Loader)
# Allocate empty database
db = dict()
for k,v in lut.items():
new = v
# Adding defaults
if 'onFailure' not in new:
new['onFailure'] = "buffer"
if 'enabled' not in new:
new['enabled'] = True
if 'readoutPriority' not in new:
new['readoutPriority'] = "monitored"
if 'readOnly' not in new:
new['readOnly'] = bool(new['deviceClass'] in ('ophyd.EpicsSignalRO'))
if 'softwareTrigger' not in new:
new['softwareTrigger'] = False
if new['deviceClass'] == "ophyd.EpicsSignalRO":
if "read_pv" not in new['deviceConfig']:
new["deviceConfig"]["read_pv"] = new["deviceConfig"]["prefix"]
del new["deviceConfig"]["prefix"]
db[k] = new
with open(fileout, 'w') as stream:
yaml.dump(db, stream, default_flow_style=None, sort_keys=False)
# Automatically start simulation if directly invoked
if __name__ == "__main__":
MigrateYamlFile("./x06da_compact.lmay", "x06da_device_config.yaml")

View File

@@ -1,206 +0,0 @@
# OP before mono
slh_trxr:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-SLH:TRXR'
slh_trxw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-SLH:TRXW'
fi1_try:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-FI1:TRY'
# DCCM crystal 1
dccm_pitch1:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:PITCH1'
dccm_energy1:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:ENERGY1'
dccm_diode:
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
prefix: 'X06DA-OP-XPM1:BOT:READOUT'
# DCCM crystal 2
dccm_pitch2:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:PITCH2'
dccm_energy2:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:ENERGY2'
dccm_xbpm:
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
prefix: 'X06DA-OP-XBPM1:SumAll:MeanValue_RBV'
# DCCM common
dccm_energy:
description: Monochromator energy using ECMC virtual motors
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:_ENERGY'
dccm_eoffset:
description: Monochromator energy offset for ECMC virtual motors
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-OP-DCCM:_EOFFSET'
# Secondary source XBPM
ssxbpm_trx:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSBPM1:TRX'
ssxbpm_try:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSBPM1:TRY'
ssslit_trxr:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSSLH1:TRXR'
ssslit_trxw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSSLH1:TRXW'
ssslit_tryt:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSSLV1:TRYT'
ssslit_tryb:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSSLV1:TRYB'
ssxi1_trx:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSXI1:TRX'
ssxi1_try:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES-SSXI1:TRY'
# Vertical focusing mirror
vfm_trxu:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRXU'
enabled: false
vfm_trxd:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRXD'
enabled: false
vfm_tryuw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRYUW'
vfm_tryr:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRYR'
vfm_trydw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRYDW'
vfm_pitch:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:PITCH'
vfm_yaw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:YAW'
enabled: false
vfm_roll:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:ROLL'
enabled: false
vfm_trx:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRX'
enabled: false
vfm_try:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-VFM:TRY'
# Horizontal focusing mirror
hfm_trxu:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRXU'
enabled: false
hfm_trxd:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRXD'
enabled: false
hfm_tryur:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRYUR'
hfm_tryw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRYW'
hfm_trydr:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRYDR'
hfm_pitch:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:PITCH'
enabled: false
hfm_yaw:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:YAW'
enabled: false
hfm_roll:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:ROLL'
enabled: false
hfm_trx:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRX'
enabled: false
hfm_try:
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X06DA-ES1-HFM:TRY'
# Exposure box signals
xbox_diode:
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
prefix: 'X06DA-ES-DI1:READOUT'
bstop_diode:
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
prefix: 'X06DA-ES-BS:READOUT'
# End station
omega:
deviceClass: pxiii_bec.devices.A3200Axis
deviceConfig:
prefix: 'X06DA-ES-DF1:OMEGA'
abr:
deviceClass: pxiii_bec.devices.AerotechAbrStage
deviceConfig:
prefix: 'X06DA-ES'

View File

@@ -1,4 +1,5 @@
slh_trxr:
description: OP slit inner blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-SLH:TRXR'}
onFailure: buffer
@@ -7,6 +8,7 @@ slh_trxr:
readOnly: false
softwareTrigger: false
slh_trxw:
description: OP slit outer blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-SLH:TRXW'}
onFailure: buffer
@@ -15,15 +17,16 @@ slh_trxw:
readOnly: false
softwareTrigger: false
fi1_try:
description: Beam attenuator in OP
description: Beam attenuator motion before mono
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-FI1:TRY'}
deviceConfig: {prefix: 'X06DA-OP-FI1:TRY1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
dccm_pitch1:
description: Monochromator pitch 1
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:PITCH1'}
onFailure: buffer
@@ -32,6 +35,7 @@ dccm_pitch1:
readOnly: false
softwareTrigger: false
dccm_energy1:
description: Monochromator energy 1
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:ENERGY1'}
onFailure: buffer
@@ -40,6 +44,7 @@ dccm_energy1:
readOnly: false
softwareTrigger: false
dccm_diode:
description: Diode between mono crystals
deviceClass: ophyd.EpicsSignalRO
deviceConfig: {read_pv: 'X06DA-OP-XPM1:BOT:READOUT'}
onFailure: buffer
@@ -48,6 +53,7 @@ dccm_diode:
readOnly: true
softwareTrigger: false
dccm_pitch2:
description: Monochromator pitch 2
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:PITCH2'}
onFailure: buffer
@@ -56,6 +62,7 @@ dccm_pitch2:
readOnly: false
softwareTrigger: false
dccm_energy2:
description: Monochromator energy 2
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:ENERGY2'}
onFailure: buffer
@@ -64,6 +71,7 @@ dccm_energy2:
readOnly: false
softwareTrigger: false
dccm_xbpm:
description: XBPM total intensity after monochromator
deviceClass: ophyd.EpicsSignalRO
deviceConfig: {read_pv: 'X06DA-OP-XBPM1:SumAll:MeanValue_RBV'}
onFailure: buffer
@@ -71,25 +79,26 @@ dccm_xbpm:
readoutPriority: monitored
readOnly: true
softwareTrigger: false
dccm_energy:
description: Monochromator energy using ECMC virtual motors
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:_ENERGY'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
dccm_eoffset:
description: Monochromator energy offset for ECMC virtual motors
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-OP-DCCM:_EOFFSET'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
# dccm_energy:
# description: Monochromator energy using ECMC virtual motors
# deviceClass: ophyd.EpicsMotor
# deviceConfig: {prefix: 'X06DA-OP-DCCM:_ENERGY'}
# onFailure: buffer
# enabled: true
# readoutPriority: monitored
# readOnly: false
# softwareTrigger: false
# dccm_eoffset:
# description: Monochromator energy offset for ECMC virtual motors
# deviceClass: ophyd.EpicsMotor
# deviceConfig: {prefix: 'X06DA-OP-DCCM:_EOFFSET'}
# onFailure: buffer
# enabled: true
# readoutPriority: monitored
# readOnly: false
# softwareTrigger: false
ssxbpm_trx:
description: XBPM motion before secondary source
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSBPM1:TRX'}
onFailure: buffer
@@ -98,6 +107,7 @@ ssxbpm_trx:
readOnly: false
softwareTrigger: false
ssxbpm_try:
description: XBPM motion before secondary source
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSBPM1:TRY'}
onFailure: buffer
@@ -105,7 +115,17 @@ ssxbpm_try:
readoutPriority: monitored
readOnly: false
softwareTrigger: false
# ssxbpm:
# description: XBPM before secondary source
# deviceClass: ophyd.EpicsSignalRO
# deviceConfig: {read_pv: 'X06DA-ES-SSBPM1:SumAll:MeanValue_RBV'}
# onFailure: buffer
# enabled: true
# readoutPriority: monitored
# readOnly: true
# softwareTrigger: false
ssslit_trxr:
description: Secondary source blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSSLH1:TRXR'}
onFailure: buffer
@@ -114,6 +134,7 @@ ssslit_trxr:
readOnly: false
softwareTrigger: false
ssslit_trxw:
description: Secondary source blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSSLH1:TRXW'}
onFailure: buffer
@@ -122,6 +143,7 @@ ssslit_trxw:
readOnly: false
softwareTrigger: false
ssslit_tryt:
description: Secondary source blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSSLV1:TRYT'}
onFailure: buffer
@@ -130,6 +152,7 @@ ssslit_tryt:
readOnly: false
softwareTrigger: false
ssslit_tryb:
description: Secondary source blade motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSSLV1:TRYB'}
onFailure: buffer
@@ -138,6 +161,7 @@ ssslit_tryb:
readOnly: false
softwareTrigger: false
ssxi1_trx:
description: Secondary source diagnostic screen motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSXI1:TRX'}
onFailure: buffer
@@ -146,6 +170,7 @@ ssxi1_trx:
readOnly: false
softwareTrigger: false
ssxi1_try:
description: Secondary source diagnostic screen motion
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-SSXI1:TRY'}
onFailure: buffer
@@ -155,7 +180,7 @@ ssxi1_try:
softwareTrigger: false
vfm_trxu:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-VFM:TRXU'}
deviceConfig: {prefix: 'X06DA-ES-VFM:TRXU'}
enabled: false
onFailure: buffer
readoutPriority: monitored
@@ -163,7 +188,7 @@ vfm_trxu:
softwareTrigger: false
vfm_trxd:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-VFM:TRXD'}
deviceConfig: {prefix: 'X06DA-ES-VFM:TRXD'}
enabled: false
onFailure: buffer
readoutPriority: monitored
@@ -171,7 +196,7 @@ vfm_trxd:
softwareTrigger: false
vfm_tryuw:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-VFM:TRYUW'}
deviceConfig: {prefix: 'X06DA-ES-VFM:TRYUW'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -179,7 +204,7 @@ vfm_tryuw:
softwareTrigger: false
vfm_tryr:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-VFM:TRYR'}
deviceConfig: {prefix: 'X06DA-ES-VFM:TRYR'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -187,7 +212,7 @@ vfm_tryr:
softwareTrigger: false
vfm_trydw:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-VFM:TRYDW'}
deviceConfig: {prefix: 'X06DA-ES-VFM:TRYDW'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -236,7 +261,7 @@ vfm_try:
softwareTrigger: false
hfm_trxu:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-HFM:TRXU'}
deviceConfig: {prefix: 'X06DA-ES-HFM:TRXU'}
enabled: false
onFailure: buffer
readoutPriority: monitored
@@ -244,7 +269,7 @@ hfm_trxu:
softwareTrigger: false
hfm_trxd:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-HFM:TRXD'}
deviceConfig: {prefix: 'X06DA-ES-HFM:TRXD'}
enabled: false
onFailure: buffer
readoutPriority: monitored
@@ -252,7 +277,7 @@ hfm_trxd:
softwareTrigger: false
hfm_tryur:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-HFM:TRYUR'}
deviceConfig: {prefix: 'X06DA-ES-HFM:TRYUR'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -260,7 +285,7 @@ hfm_tryur:
softwareTrigger: false
hfm_tryw:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-HFM:TRYW'}
deviceConfig: {prefix: 'X06DA-ES-HFM:TRYW'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -268,7 +293,7 @@ hfm_tryw:
softwareTrigger: false
hfm_trydr:
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES1-HFM:TRYDR'}
deviceConfig: {prefix: 'X06DA-ES-HFM:TRYDR'}
onFailure: buffer
enabled: true
readoutPriority: monitored
@@ -315,6 +340,51 @@ hfm_try:
readoutPriority: monitored
readOnly: false
softwareTrigger: false
# xbox_xbpm:
# description: Exposure box XBPM
# deviceClass: ophyd.EpicsSignalRO
# deviceConfig: {read_pv: 'X06DA-ES-XBBPM1:SumAll:MeanValue_RBV'}
# onFailure: buffer
# enabled: true
# readoutPriority: monitored
# readOnly: true
# softwareTrigger: false
xbox_fil1:
description: Exposure box filter wheel 1
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-FI1:ROZ1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
xbox_fil2:
description: Exposure box filter wheel 2
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-FI2:ROZ1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
xbox_fil3:
description: Exposure box filter wheel 3
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-FI3:ROZ1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
xbox_fil4:
description: Exposure box filter wheel 4
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-FI4:ROZ1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
xbox_diode:
description: Exposure box diode
deviceClass: ophyd.EpicsSignalRO
@@ -324,6 +394,71 @@ xbox_diode:
readoutPriority: monitored
readOnly: true
softwareTrigger: false
ms_focus:
description: Sample microscope focus
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-MS:FOCUS'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
ms_zoom:
description: Sample microscope zoom
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-MS:ZOOM'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
ms_try:
description: Sample microscope translation
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-MS:TRY1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
bstop_pneum:
description: Beamstop pneumatic in-out
deviceClass: ophyd.EpicsSignal
deviceConfig: {read_pv: 'X06DA-ES-BS:GET-POS', write_pv: 'X06DA-ES-BS:SET-POS'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
bstop_x:
description: Beamstop translation
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-BS:TRX1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
bstop_y:
description: Beamstop translation
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-BS:TRY1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
bstop_z:
description: Beamstop translation
deviceClass: ophyd.EpicsMotor
deviceConfig: {prefix: 'X06DA-ES-BS:TRZ1'}
onFailure: buffer
enabled: true
readoutPriority: monitored
readOnly: false
softwareTrigger: false
bstop_diode:
description: Beamstop diode
deviceClass: ophyd.EpicsSignalRO

View File

@@ -79,12 +79,9 @@ Examples
"""
import time
import math
from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Kind, SignalRO
from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Kind
from ophyd.status import MoveStatus, SubscriptionStatus, DeviceStatus
from .A3200utils import A3200Axis, A3200RasterScanner, A3200Oscillator
@@ -147,13 +144,18 @@ class AerotechAbrStage(Device):
"""
USER_ACCESS = ['reset', 'kickoff', 'complete']
taskStop = Component(EpicsSignal, "-AERO:TSK-STOP", put_complete=True, kind=Kind.omitted)
status = Component(EpicsSignal, "-AERO:STAT", put_complete=True, kind=Kind.omitted)
taskStop = Component(
EpicsSignal, "-AERO:TSK-STOP", put_complete=True, kind=Kind.omitted)
status = Component(
EpicsSignal, "-AERO:STAT", put_complete=True, kind=Kind.omitted)
# Enable/disable motor movement via the IOC (i.e. make it task-only)
axisModeLocked = Component(EpicsSignal, "-DF1:LOCK", put_complete=True, kind=Kind.omitted)
axisModeDirect = Component(EpicsSignal, "-DF1:MODE-DIRECT", put_complete=True, kind=Kind.omitted)
axisAxesMode = Component(EpicsSignal, "-DF1:AXES-MODE", put_complete=True, kind=Kind.omitted)
axisModeLocked = Component(
EpicsSignal, "-DF1:LOCK", put_complete=True, kind=Kind.omitted)
axisModeDirect = Component(
EpicsSignal, "-DF1:MODE-DIRECT", put_complete=True, kind=Kind.omitted)
axisAxesMode = Component(
EpicsSignal, "-DF1:AXES-MODE", put_complete=True, kind=Kind.omitted)
# Shutter box is missing readback so the -GET signal is installed on the VME
# _shutter = Component(
@@ -169,9 +171,12 @@ class AerotechAbrStage(Device):
gmy = Component(A3200Axis, "-DF1:GMY", kind=Kind.hinted)
gmz = Component(A3200Axis, "-DF1:GMZ", kind=Kind.hinted)
scan_command = Component(EpicsSignal, "-PSO:CMD", put_complete=True, kind=Kind.omitted)
start_command = Component(EpicsSignal, "-PSO:START-TEST.PROC", put_complete=True, kind=Kind.omitted)
stop_command = Component(EpicsSignal, "-PSO:STOP-TEST.PROC", put_complete=True, kind=Kind.omitted)
scan_command = Component(
EpicsSignal, "-PSO:CMD", put_complete=True, kind=Kind.omitted)
start_command = Component(
EpicsSignal, "-PSO:START-TEST.PROC", put_complete=True, kind=Kind.omitted)
stop_command = Component(
EpicsSignal, "-PSO:STOP-TEST.PROC", put_complete=True, kind=Kind.omitted)
# Global variables to controll AeroBasic scripts
_var_1 = Component(EpicsSignal, "-PSO:VAR-1", put_complete=True, kind=Kind.omitted)
@@ -186,7 +191,8 @@ class AerotechAbrStage(Device):
_var_10 = Component(EpicsSignal, "-PSO:VAR-10", put_complete=True, kind=Kind.omitted)
# Task status PVs (programs always run on task 1)
task1 = Component(EpicsSignalRO, "-AERO:TSK1-DONE", auto_monitor=True, kind=Kind.hinted)
task1 = Component(
EpicsSignalRO, "-AERO:TSK1-DONE", auto_monitor=True, kind=Kind.hinted)
task2 = Component(EpicsSignalRO, "-AERO:TSK2-DONE", auto_monitor=True)
task3 = Component(EpicsSignalRO, "-AERO:TSK3-DONE", auto_monitor=True)
task4 = Component(EpicsSignalRO, "-AERO:TSK4-DONE", auto_monitor=True)
@@ -196,6 +202,14 @@ class AerotechAbrStage(Device):
raster_num_rows = Component(EpicsSignal, "-GRD:ROW-DONE", kind=Kind.config)
def set_axis_mode(self, mode: str, settle_time=0.1) -> None:
""" Set acix mode to direct/measurement mode.
Measurement mode blocks axis commands from the IOC.
Parameters:
-----------
mode : str
Valid values are 'direct' and 'measuring'.
"""
if mode=="direct":
self.axisModeDirect.set(37, settle_time=settle_time).wait()
if mode=="measuring":
@@ -259,20 +273,20 @@ class AerotechAbrStage(Device):
def complete(self, timeout=None) -> DeviceStatus:
""" ToDo: WTF was this device doing here? Whatever...
"""
return self.raster.complete()
return self.raster.complete()
def complete(self, timeout=None) -> SubscriptionStatus:
""" Waits for task execution
NOTE: Original complete was raster scanner complete...
"""
# Define wait until the busy flag goes down (excluding initial update)
def isIdle(*args, old_value, value, timestamp, **kwargs):
return bool(value==1)
def is_idle(*args, old_value, value, timestamp, **kwargs):
return bool(value==1)
# Subscribe and wait for update
status = SubscriptionStatus(self.task1, isIdle, timeout=timeout, settle_time=0.5)
status = SubscriptionStatus(self.task1, is_idle, timeout=timeout, settle_time=0.5)
return status
def reset(self, settle_time=0.1):
@@ -442,13 +456,15 @@ class AerotechAbrStage(Device):
print("%s --- trying start again.", str(e))
self.osc.kickoff()
def move(self, position, wait=False, velocity=None, relative=None, direct=False, **kwargs) -> MoveStatus:
def move(self, position, wait=False, velocity=None, relative=None, direct=False,
**kwargs) -> MoveStatus:
""" Move the omega axis
"""
return self.omega.move(position, wait=wait, velocity=velocity, relative=relative, direct=direct, **kwargs)
return self.omega.move(position, wait=wait, velocity=velocity, relative=relative,
direct=direct, **kwargs)
if __name__ == "__main__":
abr = AerotechAbrStage(prefix="X06DA-ES", name="abr")
abr.wait_for_connection()
abr.wait_for_connection()

View File

@@ -5,7 +5,8 @@ Created on Tue Jun 11 11:28:38 2024
@author: mohacsi_i
"""
import types
from ophyd import Component, PVPositioner, Device, Signal, EpicsSignal, EpicsSignalRO, Kind, PositionerBase
from ophyd import (Component, PVPositioner, Device, Signal, EpicsSignal, EpicsSignalRO, Kind,
PositionerBase)
from ophyd.status import Status, MoveStatus, SubscriptionStatus, DeviceStatus
@@ -51,8 +52,10 @@ class A3200Axis(PVPositioner):
"""
USER_ACCESS = ['omove']
abr_mode_direct = Component(EpicsSignal, "-DF1:MODE-DIRECT", put_complete=True, kind=Kind.omitted)
abr_mode = Component(EpicsSignal, "-DF1:AXES-MODE", auto_monitor=True, put_complete=True, kind=Kind.omitted)
abr_mode_direct = Component(
EpicsSignal, "-DF1:MODE-DIRECT", put_complete=True, kind=Kind.omitted)
abr_mode = Component(
EpicsSignal, "-DF1:AXES-MODE", auto_monitor=True, put_complete=True, kind=Kind.omitted)
# Basic PV positioner interface
done = Component(EpicsSignalRO, "-DONE", auto_monitor=True, kind=Kind.config)
@@ -87,34 +90,41 @@ class A3200Axis(PVPositioner):
vmax = Component(Signal, kind=Kind.config)
offset = Component(EpicsSignal, "-OFF", put_complete=True, kind=Kind.config)
def __init__(self, prefix="", *, name, base_pv="", kind=None, read_attrs=None, configuration_attrs=None, parent=None, llm=0, hlm=0, vmin=0, vmax=0, **kwargs):
def __init__(self, prefix="", *, name, base_pv="", kind=None, read_attrs=None,
configuration_attrs=None, parent=None, llm=0, hlm=0, vmin=0, vmax=0, **kwargs):
""" __init__ MUST have a full argument list"""
""" Patching the parent's PVs into the axis class to check for direct/locked mode"""
# Patching the parent's PVs into the axis class to check for direct/locked mode
if parent is None:
def maybe_add_prefix(self, instance, kw, suffix):
""" Patched not to enforce parent prefix when no parent"""
# Patched not to enforce parent prefix when no parent
if kw in self.add_prefix:
return suffix
return suffix
self.__class__.__dict__["abr_mode"].maybe_add_prefix = types.MethodType(maybe_add_prefix, self.__class__.__dict__["abr_mode"])
self.__class__.__dict__["abr_mode_direct"].maybe_add_prefix = types.MethodType(maybe_add_prefix, self.__class__.__dict__["abr_mode_direct"])
self.__class__.__dict__["abr_mode"].maybe_add_prefix = types.MethodType(
maybe_add_prefix,
self.__class__.__dict__["abr_mode"])
self.__class__.__dict__["abr_mode_direct"].maybe_add_prefix = types.MethodType(
maybe_add_prefix,
self.__class__.__dict__["abr_mode_direct"])
logger.info(self.__class__.__dict__["abr_mode"].kwargs)
self.__class__.__dict__["abr_mode"].suffix = base_pv + "-DF1:AXES-MODE"
self.__class__.__dict__["abr_mode_direct"].suffix = base_pv + "-DF1:MODE-DIRECT"
super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs)
super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs,
configuration_attrs=configuration_attrs, parent=parent, **kwargs)
self.llm.set(llm).wait()
self.hlm.set(hlm).wait()
self.vmin.set(vmin).wait()
self.vmax.set(vmax).wait()
def move(self, position, velocity=None, wait=True, relative=False, direct=False, timeout=None, **kwargs) -> MoveStatus:
def move(self, position, velocity=None, wait=True, relative=False, direct=False, timeout=None,
**kwargs) -> MoveStatus:
""" Native absolute/relative movement on the A3200 """
# Check if we're in direct movement mode
if self.abr_mode.value not in (DIRECT_MODE, "DIRECT"):
if direct:
if direct:
self.abr_mode_direct.set(1).wait()
else:
raise RuntimeError(f"ABR axis not in direct mode: {self.abr_mode.value}")
@@ -150,11 +160,12 @@ class A3200Axis(PVPositioner):
status.wait()
except KeyboardInterrupt:
self.stop()
raise
raise
return status
def omove(self, position, velocity=None, wait=True, relative=False, direct=False, **kwargs) -> MoveStatus:
def omove(self, position, velocity=None, wait=True, relative=False, direct=False,
**kwargs) -> MoveStatus:
""" Exposes the ophyd move command through BEC abstraction"""
return self.move(position, velocity, wait, relative, direct, **kwargs)
@@ -210,8 +221,10 @@ class A3200RasterScanner(Device):
# Also needs the command interface
_zcmd = Component(EpicsSignal, "-PSO:CMD", put_complete=True, kind=Kind.omitted)
_start_command = Component(EpicsSignal, "-PSO:START-TEST.PROC", put_complete=True, kind=Kind.omitted)
_stop_command = Component(EpicsSignal, "-PSO:STOP-TEST.PROC", put_complete=True, kind=Kind.omitted)
_start_command = Component(
EpicsSignal, "-PSO:START-TEST.PROC", put_complete=True, kind=Kind.omitted)
_stop_command = Component(
EpicsSignal, "-PSO:STOP-TEST.PROC", put_complete=True, kind=Kind.omitted)
def raster_setup(self, positions, columns, angle, etime):
@@ -276,8 +289,7 @@ class A3200RasterScanner(Device):
if r < self._raster_num_rows:
return (y, z)
else:
return (None, None)
return (None, None)
def next_row(self):
"""start rastering a new row"""
@@ -289,19 +301,19 @@ class A3200RasterScanner(Device):
"""
self.get_ready.set(1).wait()
for n in range(10):
for _ in range(10):
try:
# Define wait until the busy flag goes down (excluding initial update)
timestamp_ = 0
def isReady(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==ABR_READY)
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==ABR_READY)
print(f"Old {old_value}\tNew: {value}\tResult: {result}")
timestamp_ = timestamp
return result
# Subscribe and wait for update
status = SubscriptionStatus(self.grid_done, isReady, timeout=2, settle_time=0.5)
status = SubscriptionStatus(self.grid_done, isReady, timeout=2, settle_time=0.5)
status.wait()
except TimeoutError as e:
print(str(e), end=" ")
@@ -315,22 +327,21 @@ class A3200RasterScanner(Device):
else:
self.grid_next.set(1)
def is_scan_done(self):
return 1 == scan_done.get()
return 1 == self.scan_done.get()
def wait_scan_done(self, timeout=60.0) -> SubscriptionStatus:
# Define wait until the busy flag goes down (excluding initial update)
timestamp_ = 0
def isReady(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==1)
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==1)
print(f"Old {old_value}\tNew: {value}\tResult: {result}")
timestamp_ = timestamp
return result
# Subscribe and wait for update
status = SubscriptionStatus(self.scan_done, isReady, timeout=timeout, settle_time=0.5)
status = SubscriptionStatus(self.scan_done, isReady, timeout=timeout, settle_time=0.5)
status.wait()
return status
@@ -341,32 +352,36 @@ class A3200RasterScanner(Device):
def raster_wait_for_row(self, timeout=60) -> SubscriptionStatus:
# Define wait subscription
timestamp_ = 0
def isReady(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==1)
def is_ready(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==1)
print(f"Old {old_value}\tNew: {value}\tResult: {result}")
timestamp_ = timestamp
return result
# Subscribe and wait for update
status = SubscriptionStatus(self.row_done, isReady, timeout=timeout, settle_time=0.5)
status = SubscriptionStatus(self.row_done, is_ready, timeout=timeout, settle_time=0.5)
status.wait()
return status
def complete(self, timeout=None) -> DeviceStatus:
""" Wait for the grid scanner to finish
TODO: Probably redundant with task status wait?
"""
if timeout is not None:
# Define wait until the busy flag goes down (excluding initial update)
timestamp_ = 0
def isReady(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==GRID_SCAN_DONE)
nonlocal timestamp_
result = False if (timestamp_== 0) else bool(value==GRID_SCAN_DONE)
print(f"Old {old_value}\tNew: {value}\tResult: {result}")
timestamp_ = timestamp
return result
# Subscribe and wait for update
status = SubscriptionStatus(self.scan_done, isReady, timeout=timeout, settle_time=0.5)
status = SubscriptionStatus(self.scan_done, isReady, timeout=timeout, settle_time=0.5)
return status
status = DeviceStatus(self, settle_time=0.5)
status.set_finished()
@@ -374,14 +389,9 @@ class A3200RasterScanner(Device):
class A3200Oscillator(Device):
"""No clue what this does, seems to be redundant with the task based grid scanners...
"""
ostart_pos = Component(EpicsSignal, "-OSC:START-POS", put_complete=True, kind=Kind.config)
orange = Component(EpicsSignal, "-OSC:RANGE", put_complete=True, kind=Kind.config)
etime = Component(EpicsSignal, "-OSC:ETIME", put_complete=True, kind=Kind.config)
@@ -415,27 +425,16 @@ class A3200Oscillator(Device):
"""
# Define wait until the busy flag goes down (excluding initial update)
def inStatus(*args, old_value, value, timestamp, **kwargs):
result = bool(value==target)
result = bool(value==target)
print(f"Old {old_value}\tNew: {value}\tResult: {result}")
return result
# Subscribe and wait for update
status = SubscriptionStatus(self.phase, inStatus, timeout=timeout, settle_time=0.5)
status = SubscriptionStatus(self.phase, inStatus, timeout=timeout, settle_time=0.5)
return status
# Automatically start an axis if directly invoked
if __name__ == "__main__":
omega = A3200Axis(prefix="X06DA-ES-DF1:OMEGA", name="omega")

View File

@@ -1 +1,3 @@
from .mx_measurements import MeasureFastOmega, MeasureStandardWedge, MeasureVerticalLine, MeasureScanSlits, MeasureRasterSimple, MeasureScreening, MeasureRepeatedOscillation, MeasureMSOX, MeasureGrid
from .mx_measurements import (MeasureFastOmega, MeasureStandardWedge, MeasureVerticalLine,
MeasureScanSlits, MeasureRasterSimple, MeasureScreening, MeasureRepeatedOscillation,
MeasureMSOX, MeasureGrid)

View File

@@ -1,4 +1,8 @@
import time
""" MX measurements module
Scan primitives for standard BEC scans at the PX beamlines at SLS.
Theese scans define the event model and can be called from higher levels.
"""
import numpy as np
from bec_lib import bec_logger
@@ -10,13 +14,9 @@ logger = bec_logger.logger
FULL_PERIOD = 0
HALF_PERIOD = 1
class SasttSnakeMode:
SNAKE_SINGLE = 0
UNIDIRECTIONAL = 1
SNAKE_DOUBLE_PSO = 2
class AbrCmd:
""" Valid Aerotech ABR scan commands from the AeroBasic files"""
NONE = 0
RASTER_SCAN_SIMPLE = 1
MEASURE_STANDARD = 2
@@ -69,12 +69,13 @@ class AerotechFlyscanBase(AsyncFlyScanBase):
abr_raster_reset =False
abr_complete = False
abr_timeout = None
pointID = 0
num_pos = 0
def __init__(self, *args, parameter: dict = None, **kwargs):
""" Just set num_pos=0 to avoid hanging and override defaults if explicitly set from
parameters.
"""
self.num_pos = 0
super().__init__(parameter=parameter, **kwargs)
# Override if explicitly passed as parameter
@@ -104,7 +105,7 @@ class AerotechFlyscanBase(AsyncFlyScanBase):
# Reset the raster scan engine
if self.abr_raster_reset:
yield from self.stubs.command("abr", "raster_scan_done.set", 0)
yield from self.stubs.send_rpc_and_wait("abr", "raster_scan_done.set", 0)
# Configure the global variables
d = {"scan_command" : self.abr_command}
@@ -116,14 +117,13 @@ class AerotechFlyscanBase(AsyncFlyScanBase):
# Call super
yield from super().pre_scan()
def stage(self):
""" ToDo: Sot sure if we should call super() here as it'd stage the whole beamline"""
return super().stage()
# def stage(self):
# """ ToDo: Sot sure if we should call super() here as it'd stage the whole beamline"""
# return super().stage()
def scan_core(self):
""" The actual scan logic comes here.
"""
self.pointID = 0
# Kick off the run
yield from self.stubs.send_rpc_and_wait("abr", "start_command.set", 1)
logger.info("Measurement launched on the ABR stage...")
@@ -836,7 +836,7 @@ class MeasureGrid(AerotechFlyscanBase):
if len(self.scan_positions)==1:
raise RuntimeWarning("Raster scan with one cell makes no sense")
# Call base class
super().__init__(parameter=parameter, **kwargs)
@@ -893,7 +893,8 @@ class MeasureGridStill(AerotechFlyscanBase):
Example
-------
>>> scans.measure_raster(positions=[[11, 2, 3.4], [11, 2, 3.5], ...], steps_x=20, steps_y=20, exp_time=0.1, delay=0.05)
>>> pts = [[11, 2, 3.4], [11, 2, 3.5], ...]
>>> scans.measure_raster(positions=pts, steps_x=20, steps_y=20, exp_time=0.1, delay=0.05)
Parameters
----------
@@ -1012,7 +1013,9 @@ class MeasureJungfrau(AerotechFlyscanBase):
self.scan_stepsize_y = self.scan_range_y / self.scan_stepnum_y
self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_sleep = parameter['kwargs'].get("sleep", 0.1)
self.abr_timeout = None if self.scan_sleep <= 0 else 5.0 + (self.scan_num_rows * self.scan_sleep) + (self.scan_num_cols * self.scan_num_rows * self.scan_exp_time)
sleep_time = 5.0 + (self.scan_stepnum_y * self.scan_sleep) + (
self.scan_stepnum_x * self.scan_stepnum_y * self.scan_exp_time)
self.abr_timeout = None if self.scan_sleep <= 0 else sleep_time
self.abr_command = AbrCmd.JUNGFRAU
self.abr_complete = True
self.abr_globals = {
@@ -1024,7 +1027,7 @@ class MeasureJungfrau(AerotechFlyscanBase):
"var_6" : self.scan_sleep,
"var_7" : 0,
"var_8" : 0,
}
}
# Call base class
super().__init__(parameter=parameter, **kwargs)
@@ -1035,7 +1038,4 @@ class MeasureJungfrau(AerotechFlyscanBase):
# Go back to direct mode
st = yield from self.stubs.send_rpc_and_wait("abr", "set_axis_mode", "direct")
st.wait()
st.wait()