Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c7c09d42b | |||
| 54c3c94d33 | |||
| 2b3a7d07d1 | |||
| 7681c5e1b1 | |||
| 343c978fbd | |||
| 1abd571460 | |||
| f35d5964f9 | |||
| 6c8351238c | |||
| b65ed70f32 | |||
| 434db75f6c | |||
| 1950ee5c85 | |||
| a11fe91998 | |||
|
c58b0c1d20
|
|||
| 1041e3a308 | |||
| 2912a306ab | |||
| 3c54d98ce5 | |||
| feaa340670 |
+1
-1
@@ -2,7 +2,7 @@
|
||||
# It is needed to track the repo template version, and editing may break things.
|
||||
# This file will be overwritten by copier on template updates.
|
||||
|
||||
_commit: v1.2.2
|
||||
_commit: v1.4.0
|
||||
_src_path: https://github.com/bec-project/plugin_copier_template.git
|
||||
make_commit: false
|
||||
project_name: pxii_bec
|
||||
|
||||
+14
-9
@@ -28,7 +28,7 @@ on:
|
||||
description: "Python version to use"
|
||||
required: false
|
||||
type: string
|
||||
default: "3.11"
|
||||
default: "3.12"
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
@@ -44,7 +44,19 @@ jobs:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "${{ inputs.PYTHON_VERSION || '3.11' }}"
|
||||
python-version: "${{ inputs.PYTHON_VERSION || '3.12' }}"
|
||||
|
||||
- name: Checkout BEC Plugin Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: bec/pxii_bec
|
||||
ref: "${{ inputs.BEC_PLUGIN_REPO_BRANCH || github.head_ref || github.sha }}"
|
||||
path: ./pxii_bec
|
||||
|
||||
- name: Lint for merge conflicts from template updates
|
||||
shell: bash
|
||||
# Find all Copier conflicts except this line
|
||||
run: '! grep -r "<<<<<<< before updating" | grep -v "grep -r \"<<<<<<< before updating"'
|
||||
|
||||
- name: Checkout BEC Core
|
||||
uses: actions/checkout@v4
|
||||
@@ -67,13 +79,6 @@ jobs:
|
||||
ref: "${{ inputs.BEC_WIDGETS_BRANCH || 'main' }}"
|
||||
path: ./bec_widgets
|
||||
|
||||
- name: Checkout BEC Plugin Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: bec/pxii_bec
|
||||
ref: "${{ inputs.BEC_PLUGIN_REPO_BRANCH || github.head_ref || github.sha }}"
|
||||
path: ./pxii_bec
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
name: Create template upgrade PR for pxii_bec
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
create_update_branch_and_pr:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create virtualenv
|
||||
run: |
|
||||
python -m virtualenv .venv
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
pip install copier PySide6 bec_lib
|
||||
|
||||
- name: Perform update
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
git config --global user.email "bec_ci_staging@psi.ch"
|
||||
git config --global user.name "BEC automated CI"
|
||||
|
||||
branch="chore/update-template-$(python -m uuid)"
|
||||
echo "switching to branch $branch"
|
||||
git checkout -b $branch
|
||||
|
||||
echo "Running copier update..."
|
||||
copier update --trust --defaults --conflict inline 2>&1 | tee copier.log
|
||||
status=${PIPESTATUS[0]}
|
||||
output="$(cat copier.log)"
|
||||
echo $output
|
||||
msg="$(printf '%s\n' "$output" | head -n 1)"
|
||||
|
||||
if ! grep -q "make_commit: true" .copier-answers.yml ; then
|
||||
echo "Autocommit not made, committing..."
|
||||
git add -A
|
||||
git commit -a -m "$msg"
|
||||
fi
|
||||
|
||||
if diff-index --quiet HEAD ; then
|
||||
echo "No changes detected"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git push -u origin $branch
|
||||
curl -X POST "https://gitea.psi.ch/api/v1/repos/${{ gitea.repository }}/pulls" \
|
||||
-H "Authorization: token ${{ secrets.CI_REPO_WRITE }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"title\": \"Template: $(echo $msg)\",
|
||||
\"body\": \"This PR was created by Gitea Actions\",
|
||||
\"head\": \"$(echo $branch)\",
|
||||
\"base\": \"main\"
|
||||
}"
|
||||
@@ -1,7 +0,0 @@
|
||||
include:
|
||||
- file: /templates/plugin-repo-template.yml
|
||||
inputs:
|
||||
name: pxii_bec
|
||||
target: pxii_bec
|
||||
branch: $CHILD_PIPELINE_BRANCH
|
||||
project: bec/awi_utils
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
|
||||
from bec_widgets.cli.rpc.rpc_base import RPCBase, rpc_call
|
||||
from bec_widgets.cli.rpc.rpc_base import RPCBase, rpc_call, rpc_timeout
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -18,6 +18,8 @@ _Widgets = {
|
||||
|
||||
|
||||
class ScanHistory(RPCBase):
|
||||
_IMPORT_MODULE = "pxii_bec.bec_widgets.widgets.scan_history.scan_history"
|
||||
|
||||
@rpc_call
|
||||
def select_scan_from_history(self, value: "int") -> "None":
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file was automatically generated by generate_cli.py
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
# pylint: skip-file
|
||||
|
||||
designer_plugins = {
|
||||
"ScanHistory": ("pxii_bec.bec_widgets.widgets.scan_history.scan_history", "ScanHistory"),
|
||||
}
|
||||
|
||||
widget_icons = {
|
||||
"ScanHistory": "widgets",
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
states:
|
||||
robot_sample_exchange:
|
||||
allow_modifiers: true
|
||||
bl_pos: in
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: out
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: out
|
||||
fl_bright: 'off'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
sample_alignment:
|
||||
allow_modifiers: true
|
||||
bl_pos: in
|
||||
bl_bright: 'on'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: out
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: out
|
||||
fl_bright: 'on'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
data_collection:
|
||||
allow_modifiers: true
|
||||
bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: in
|
||||
cryo_pos: in
|
||||
det_cov: 'open'
|
||||
diag_y: out
|
||||
fl_bright: 'on'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
DC_XRF:
|
||||
allow_modifiers: true
|
||||
# bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: in
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: out
|
||||
fl_bright: 'on'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: in
|
||||
|
||||
manual_sample_exchange:
|
||||
allow_modifiers: true
|
||||
bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: out
|
||||
bs_z: safe
|
||||
coll_y: park
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: park
|
||||
fl_bright: 'off'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
beam_visualisation:
|
||||
bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: out
|
||||
cryo_pos: out
|
||||
det_cov: 'close'
|
||||
diag_y: scint
|
||||
fl_bright: 'off'
|
||||
gon_x: out
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
flux_measurement:
|
||||
bl_pos: in
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: out
|
||||
cryo_pos: out
|
||||
det_cov: 'close'
|
||||
diag_y: i1
|
||||
fl_bright: 'off'
|
||||
gon_x: out
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
beamstop_alignment:
|
||||
bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: in
|
||||
bs_z: samp
|
||||
coll_y: out
|
||||
cryo_pos: out
|
||||
det_cov: 'close'
|
||||
diag_y: out
|
||||
fl_bright: 'on'
|
||||
gon_x: out
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
maintenance:
|
||||
allow_modifiers: true
|
||||
bl_pos: out
|
||||
bl_bright: 'off'
|
||||
bs_pos: out
|
||||
bs_z: safe
|
||||
coll_y: park
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: park
|
||||
fl_bright: 'off'
|
||||
gon_x: out
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
xtal_snapshot:
|
||||
allow_modifiers: true
|
||||
bl_pos: in
|
||||
bl_bright: 'on'
|
||||
bs_pos: in
|
||||
bs_z: safe
|
||||
coll_y: intermediate
|
||||
cryo_pos: in
|
||||
det_cov: 'close'
|
||||
diag_y: out
|
||||
fl_bright: 'on'
|
||||
gon_x: in
|
||||
# smargon: not implemented
|
||||
xrf_pos: out
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ bsf_sl_xr:
|
||||
|
||||
bsf_sl_yt:
|
||||
description: BSF slit top
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceClass: ophyd_devices.EpicsMotorEC
|
||||
deviceConfig: {prefix: 'X10SA-OP-BSFSLV:TRYT'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
@@ -742,18 +742,6 @@ ss_f4_x:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
ss_sl_xw:
|
||||
description: SS slit wall
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-SSSLH:TRXW'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- ss
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
ss_sl_xr:
|
||||
description: SS slit ring
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
@@ -1415,18 +1403,18 @@ bcu_sl_ysize:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
xrf_pos:
|
||||
description: XRF det in/out
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-XRF:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type":positioner}
|
||||
# xrf_pos:
|
||||
# description: XRF det in/out
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-XRF:POS-SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type":positioner}
|
||||
|
||||
samcam_x:
|
||||
description: sample cam X
|
||||
@@ -1524,17 +1512,17 @@ scam_zoom:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
fl_bright:
|
||||
description: Frontlight brightness
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-FL:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
# fl_bright:
|
||||
# description: Frontlight brightness
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-FL:SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
|
||||
coll_x:
|
||||
description: Collimator X
|
||||
@@ -1548,31 +1536,31 @@ coll_x:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
coll_y:
|
||||
description: Collimator Y
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-COL:TRY'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type": multi-position, "in": 41.5, "out": 20.0, "park": 0,"tol":0.05}
|
||||
# coll_y:
|
||||
# description: Collimator Y
|
||||
# deviceClass: ophyd.EpicsMotor
|
||||
# deviceConfig: {prefix: 'X10SA-ES-COL:TRY'}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type": multi-position, "in": 41.5, "out": 20.0, "park": 0,"tol":0.05}
|
||||
|
||||
diag_y:
|
||||
description: Scintillator/diode Y
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-SCL:TRY'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type": multi-position, "scint": 38.62, "i1": 44.0, "out": 20.0,"park": 0,"tol":0.3}
|
||||
# diag_y:
|
||||
# description: Scintillator/diode Y
|
||||
# deviceClass: ophyd.EpicsMotor
|
||||
# deviceConfig: {prefix: 'X10SA-ES-SCL:TRY'}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type": multi-position, "scint": 38.62, "i1": 44.0, "out": 20.0,"park": 0,"tol":0.3}
|
||||
|
||||
diag_z:
|
||||
description: Scintillator/diode Z
|
||||
@@ -1598,30 +1586,30 @@ i1:
|
||||
readOnly: True
|
||||
softwareTrigger: false
|
||||
|
||||
bl_pos:
|
||||
description: Backlight positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BL:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type":positioner}
|
||||
# bl_pos:
|
||||
# description: Backlight positioner
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-BL:POS-SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type":positioner}
|
||||
|
||||
bl_bright:
|
||||
description: Backlight brightness
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BL:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
# bl_bright:
|
||||
# description: Backlight brightness
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-BL:SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
|
||||
bs_x:
|
||||
description: Beamstop X
|
||||
@@ -1647,44 +1635,44 @@ bs_y:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
bs_z:
|
||||
description: Beamstop Z
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-BS:TRZ'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type": guarded, "min": 13, "samp": 15, "work_min": 20, "safe": 41, "max_blin": 42, "max_blout": 70}
|
||||
# bs_z:
|
||||
# description: Beamstop Z
|
||||
# deviceClass: ophyd.EpicsMotor
|
||||
# deviceConfig: {prefix: 'X10SA-ES-BS:TRZ'}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type": guarded, "min": 13, "samp": 15, "work_min": 20, "safe": 41, "max_blin": 42, "max_blout": 70}
|
||||
|
||||
bs_pos:
|
||||
description: Beamstop positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BS:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type":positioner}
|
||||
# bs_pos:
|
||||
# description: Beamstop positioner
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-BS:POS-SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type":positioner}
|
||||
|
||||
gon_x:
|
||||
description: Goniometer X
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-DF1:TRX1'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- det
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type": guarded, "in": 18.0, "out": -10.0, "safe": -100,"tol":0.5}
|
||||
# gon_x:
|
||||
# description: Goniometer X
|
||||
# deviceClass: ophyd.EpicsMotor
|
||||
# deviceConfig: {prefix: 'X10SA-ES-DF1:TRX1'}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - det
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type": guarded, "in": 18.0, "out": -10.0, "safe": -100,"tol":0.5}
|
||||
|
||||
gon_y:
|
||||
description: Goniometer Y
|
||||
@@ -1722,18 +1710,18 @@ omega:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
cryo_pos:
|
||||
description: Cryo positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-CS:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type":positioner}
|
||||
# cryo_pos:
|
||||
# description: Cryo positioner
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-CS:POS-SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - se
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type":positioner}
|
||||
|
||||
cryo_x:
|
||||
description: Cryojet X
|
||||
@@ -1879,18 +1867,18 @@ det_xicam_gain:
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
|
||||
det_cov:
|
||||
description: Detector cover
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-DETCOV:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- det
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter: {"type":positioner}
|
||||
# det_cov:
|
||||
# description: Detector cover
|
||||
# deviceClass: ophyd.EpicsSignal
|
||||
# deviceConfig: {read_pv: 'X10SA-ES-DETCOV:SET', auto_monitor: true}
|
||||
# onFailure: buffer
|
||||
# enabled: True
|
||||
# readoutPriority: baseline
|
||||
# deviceTags:
|
||||
# - det
|
||||
# readOnly: False
|
||||
# softwareTrigger: false
|
||||
# userParameter: {"type":positioner}
|
||||
|
||||
det_y:
|
||||
description: Detector Y
|
||||
|
||||
@@ -7,35 +7,35 @@ fe_bpm4,FE XBPM Signal 4,SignalRO,X10SA-FE-XBPM1:Current4:MeanValue_RBV,monitore
|
||||
fe_bpmsum,FE XBPM Summed,SignalRO,X10SA-FE-XBPM1:SumAll:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
fe_bpm_x,FE BPM X,Motor,X10SA-FE-XBPM1:TRX,baseline,fe,no,yes,,
|
||||
fe_bpm_y,FE BPM Y,Motor,X10SA-FE-XBPM1:TRY,baseline,fe,no,yes,,
|
||||
fe_sl_xr,FE Slit X Ring,Motor,X10SA-FE-SL1:TRXR,baseline,fe,no,yes,,
|
||||
fe_sl_yt,FE Slit Y top,Motor,X10SA-FE-SL1:TRYT,baseline,fe,no,yes,,
|
||||
fe_sl_xw,FE Slit X Wall,Motor,X10SA-FE-SL1:TRXW,baseline,fe,no,yes,,
|
||||
fe_sl_yb,FE SlitY Bottom,Motor,X10SA-FE-SL1:TRYB,baseline,fe,no,yes,,
|
||||
fe_sl_xcen,FE Slit X Centre,Motor,X10SA-FE-SL1:CENTERX,baseline,fe,no,yes,,
|
||||
fe_sl_xsize,FE Slit X Size,Motor,X10SA-FE-SL1:SIZEX,baseline,fe,no,yes,,
|
||||
fe_sl_ycen,FE Slit Y Centre,Motor,X10SA-FE-SL1:CENTERY,baseline,fe,no,yes,,
|
||||
fe_sl_ysize,FE Slit Y Size,Motor,X10SA-FE-SL1:SIZEY,baseline,fe,no,yes,,
|
||||
fe_sl_xr,FE Slit X Ring,MotorEC,X10SA-FE-SL1:TRXR,baseline,fe,no,yes,,
|
||||
fe_sl_yt,FE Slit Y top,MotorEC,X10SA-FE-SL1:TRYT,baseline,fe,no,yes,,
|
||||
fe_sl_xw,FE Slit X Wall,MotorEC,X10SA-FE-SL1:TRXW,baseline,fe,no,yes,,
|
||||
fe_sl_yb,FE SlitY Bottom,MotorEC,X10SA-FE-SL1:TRYB,baseline,fe,no,yes,,
|
||||
fe_sl_xcen,FE Slit X Centre,MotorEC,X10SA-FE-SL1:CENTERX,baseline,fe,no,yes,,
|
||||
fe_sl_xsize,FE Slit X Size,MotorEC,X10SA-FE-SL1:SIZEX,baseline,fe,no,yes,,
|
||||
fe_sl_ycen,FE Slit Y Centre,MotorEC,X10SA-FE-SL1:CENTERY,baseline,fe,no,yes,,
|
||||
fe_sl_ysize,FE Slit Y Size,MotorEC,X10SA-FE-SL1:SIZEY,baseline,fe,no,yes,,
|
||||
bsf_bpm1,BSF BPM Signal 1,SignalRO,X10SA-OP-BSFBPM:SIGNAL1,monitored,bpm,yes,no,,
|
||||
bsf_bpm2,BSF BPM Signal 2,SignalRO,X10SA-OP-BSFBPM:SIGNAL2,monitored,bpm,yes,no,,
|
||||
bsf_bpm3,BSF BPM Signal 3,SignalRO,X10SA-OP-BSFBPM:SIGNAL3,monitored,bpm,yes,no,,
|
||||
bsf_bpm4,BSF BPM Signal 4,SignalRO,X10SA-OP-BSFBPM:SIGNAL4,monitored,bpm,yes,no,,
|
||||
bsf_bpmsum,BSF BPM Summed,SignalRO,X10SA-OP-BSFBPM:SUM,monitored,bpm,yes,no,,
|
||||
bsf_sl_xw,BSF slit outboard,Motor,X10SA-OP-BSFSLH:TRXW,baseline,bsf,no,yes,,
|
||||
bsf_sl_xr,BSF slit inboard,Motor,X10SA-OP-BSFSLH:TRXR,baseline,bsf,no,yes,,
|
||||
bsf_sl_yt,BSF slit top,Motor,X10SA-OP-BSFSLV:TRYT,baseline,bsf,no,yes,,
|
||||
bsf_sl_yb,BSF slit bottom,Motor,X10SA-OP-BSFSLV:TRYB,baseline,bsf,no,yes,,
|
||||
bsf_sl_xcen,BSF X centre,Motor,X10SA-OP-BSFSLH:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_xsize,BSF X size,Motor,X10SA-OP-BSFSLH:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_sl_ycen,BSF Y centre,Motor,X10SA-OP-BSFSLV:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_ysize,BSF Y size,Motor,X10SA-OP-BSFSLV:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_f1_y,BSF Filter 1 Y,Motor,X10SA-OP-BSFFI1:TRY,baseline,bsf,no,yes,,
|
||||
bsf_f2_y,BSF Filter 2 Y,Motor,X10SA-OP-BSFFI2:TRY,baseline,bsf,no,yes,,
|
||||
dcm_bragg,DCM Bragg angle,Motor,X10SA-OP-DCM:ROTY,baseline,dcm,no,yes,,
|
||||
dcm_x,DCM lateral,Motor,X10SA-OP-DCM:TRX,baseline,dcm,no,yes,,
|
||||
dcm_perp,DCM Perp,Motor,X10SA-OP-DCM:TRX-CR2,baseline,dcm,no,yes,,
|
||||
dcm_pitch,DCM 2nd crystal pitch,Motor,X10SA-OP-DCM:ROTY-CR2-PITCH,baseline,dcm,no,yes,,
|
||||
dcm_fpitch,DCM 2nd crystal fine pitch,Motor,X10SA-OP-DCM:ROTY-CR2-FINEPITCH,baseline,dcm,no,yes,,
|
||||
dcm_froll,DCM 2nd crystal fine roll,Motor,X10SA-OP-DCM:ROTZ-CR2-FINEROLL,baseline,dcm,no,yes,,
|
||||
bsf_sl_xw,BSF slit outboard,MotorEC,X10SA-OP-BSFSLH:TRXW,baseline,bsf,no,yes,,
|
||||
bsf_sl_xr,BSF slit inboard,MotorEC,X10SA-OP-BSFSLH:TRXR,baseline,bsf,no,yes,,
|
||||
bsf_sl_yt,BSF slit top,MotorEC,X10SA-OP-BSFSLV:TRYT,baseline,bsf,no,yes,,
|
||||
bsf_sl_yb,BSF slit bottom,MotorEC,X10SA-OP-BSFSLV:TRYB,baseline,bsf,no,yes,,
|
||||
bsf_sl_xcen,BSF X centre,MotorEC,X10SA-OP-BSFSLH:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_xsize,BSF X size,MotorEC,X10SA-OP-BSFSLH:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_sl_ycen,BSF Y centre,MotorEC,X10SA-OP-BSFSLV:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_ysize,BSF Y size,MotorEC,X10SA-OP-BSFSLV:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_f1_y,BSF Filter 1 Y,MotorEC,X10SA-OP-BSFFI1:TRY,baseline,bsf,no,yes,,
|
||||
bsf_f2_y,BSF Filter 2 Y,MotorEC,X10SA-OP-BSFFI2:TRY,baseline,bsf,no,yes,,
|
||||
dcm_bragg,DCM Bragg angle,MotorEC,X10SA-OP-DCM:ROTY,baseline,dcm,no,yes,,
|
||||
dcm_x,DCM lateral,MotorEC,X10SA-OP-DCM:TRX,baseline,dcm,no,yes,,
|
||||
dcm_perp,DCM Perp,MotorEC,X10SA-OP-DCM:TRX-CR2,baseline,dcm,no,yes,,
|
||||
dcm_pitch,DCM 2nd crystal pitch,MotorEC,X10SA-OP-DCM:ROTY-CR2-PITCH,baseline,dcm,no,yes,,
|
||||
dcm_fpitch,DCM 2nd crystal fine pitch,MotorEC,X10SA-OP-DCM:ROTY-CR2-FINEPITCH,baseline,dcm,no,yes,,
|
||||
dcm_froll,DCM 2nd crystal fine roll,MotorEC,X10SA-OP-DCM:ROTZ-CR2-FINEROLL,baseline,dcm,no,yes,,
|
||||
lu_bpm1,LU BPM Signal 1,SignalRO,X10SA-OP-LUBPM:Current1:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
lu_bpm2,LU BPM Signal 2,SignalRO,X10SA-OP-LUBPM:Current2:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
lu_bpm3,LU BPM Signal 3,SignalRO,X10SA-OP-LUBPM:Current3:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
@@ -80,37 +80,37 @@ ss_sl_ycen,SS slit Y centre,Motor,X10SA-ES-SSSLV:CENTER,baseline,ss,no,yes,,
|
||||
ss_sl_ysize,SS slit Y size,Motor,X10SA-ES-SSSLV:SIZE,baseline,ss,no,yes,,
|
||||
ss_xi_x,SS X-ray eye X,Motor,X10SA-ES-SSXI:TRX,baseline,ss,no,yes,"{""type"": multi-position,""in"": 7.5, ""out"": -2.1}",
|
||||
ss_xi_y,SS X-ray eye Y,Motor,X10SA-ES-SSXI:TRY,baseline,ss,no,yes,,
|
||||
ss_xicam_x,ss cam X,SignalRO,X10SA-ES-SSXI:cam1:Stats5:CentroidX_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_y,ss cam Y,SignalRO,X10SA-ES-SSXI:cam1:Stats5:CentroidY_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_max,ss cam max value,SignalRO,X10SA-ES-SSXI:cam1:Stats5:MaxValue_RBV,monitored,ss,yes,yes,,
|
||||
ss_xicam_exp,ss camera exposure,Signal,X10SA-ES-SSXI:cam1:AcquireTime,baseline,ss,no,yes,,
|
||||
ss_xicam_gain,ss camera gain,Signal,X10SA-ES-SSXI:cam1:cam1:Gain,baseline,ss,no,yes,,
|
||||
ss_xicam_xsig,ss camera x sigma,Signal,X10SA-ES-SSXI:cam1:Stats5:SigmaX_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_ysig,ss camera y sigma,Signal,X10SA-ES-SSXI:cam1:Stats5:SigmaY_RBV,baseline,ss,yes,yes,,
|
||||
vfm_xu,VFM Upstream X,Motor,X10SA-ES-KBV:TRXU,baseline,vfm,no,no,,
|
||||
vfm_xd,VFM Downstream X,Motor,X10SA-ES-KBV:TRXD,baseline,vfm,no,no,,
|
||||
vfm_yur,VFM Upstream Ring Y,Motor,X10SA-ES-KBV:TRYUR,baseline,vfm,no,no,,
|
||||
vfm_yw,VFM Wall Y,Motor,X10SA-ES-KBV:TRYW,baseline,vfm,no,no,,
|
||||
vfm_ydr,VFM Downstream Ring Y,Motor,X10SA-ES-KBV:TRYDR,baseline,vfm,no,no,,
|
||||
vfm_bu,VFM Upstream Bender,Motor,X10SA-ES-KBV:BNDU,baseline,vfm,no,no,,
|
||||
vfm_bd,VFM Downstream Bender,Motor,X10SA-ES-KBV:BNDD,baseline,vfm,no,no,,
|
||||
vfm_yaw,VFM Virtual Yaw,Motor,X10SA-ES-KBV:YAW,baseline,vfm,no,no,,
|
||||
vfm_roll,VFM Virtual Roll,Motor,X10SA-ES-KBV:ROLL,baseline,vfm,no,no,,
|
||||
vfm_pitch,VFM Virtual Pitch,Motor,X10SA-ES-KBV:PITCH,baseline,vfm,no,no,,
|
||||
vfm_x,VFM Virtual X,Motor,X10SA-ES-KBV:TRX,baseline,vfm,no,no,,
|
||||
vfm_y,VFM Virtual Y ,Motor,X10SA-ES-KBV:TRY,baseline,vfm,no,no,,
|
||||
hfm_xu,HFM Upstream X,Motor,X10SA-ES-KBH:TRXU,baseline,hfm,no,no,,
|
||||
hfm_xd,HFM Downstream X,Motor,X10SA-ES-KBH:TRXD,baseline,hfm,no,no,,
|
||||
hfm_yuw,HFM Upstream Wall Y,Motor,X10SA-ES-KBH:TRYUW,baseline,hfm,no,no,,
|
||||
hfm_yr,HFM Ring Y,Motor,X10SA-ES-KBH:TRYR,baseline,hfm,no,no,,
|
||||
hfm_ydw,HFM Downstream Wall Y,Motor,X10SA-ES-KBH:TRYDW,baseline,hfm,no,no,,
|
||||
hfm_bu,HFM Upstream Bender,Motor,X10SA-ES-KBH:BNDU,baseline,hfm,no,no,,
|
||||
hfm_bd,HFM Downstream Bender,Motor,X10SA-ES-KBH:BNDD,baseline,hfm,no,no,,
|
||||
hfm_yaw,HFM Virtual Yaw,Motor,X10SA-ES-KBH:YAW,baseline,hfm,no,no,,
|
||||
hfm_roll,HFM Virtual Roll,Motor,X10SA-ES-KBH:ROLL,baseline,hfm,no,no,,
|
||||
hfm_pitch,HFM Virtual Pitch,Motor,X10SA-ES-KBH:PITCH,baseline,hfm,no,no,,
|
||||
hfm_x,HFM Virtual X,Motor,X10SA-ES-KBH:TRX,baseline,hfm,no,no,,
|
||||
hfm_y,HFM Virtual Y ,Motor,X10SA-ES-KBH:TRY,baseline,hfm,no,no,,
|
||||
ss_xicam_x,ss cam X,SignalRO,X10SA-ES-SSXI:cam1:Stats5:CentroidX_RBV,baseline,ss,yes,no,,
|
||||
ss_xicam_y,ss cam Y,SignalRO,X10SA-ES-SSXI:cam1:Stats5:CentroidY_RBV,baseline,ss,yes,no,,
|
||||
ss_xicam_max,ss cam max value,SignalRO,X10SA-ES-SSXI:cam1:Stats5:MaxValue_RBV,monitored,ss,yes,no,,
|
||||
ss_xicam_exp,ss camera exposure,Signal,X10SA-ES-SSXI:cam1:AcquireTime,baseline,ss,no,no,,
|
||||
ss_xicam_gain,ss camera gain,Signal,X10SA-ES-SSXI:cam1:cam1:Gain,baseline,ss,no,no,,
|
||||
ss_xicam_xsig,ss camera x sigma,Signal,X10SA-ES-SSXI:cam1:Stats5:SigmaX_RBV,baseline,ss,yes,no,,
|
||||
ss_xicam_ysig,ss camera y sigma,Signal,X10SA-ES-SSXI:cam1:Stats5:SigmaY_RBV,baseline,ss,yes,no,,
|
||||
vfm_xu,VFM Upstream X,MotorEC,X10SA-ES-KBV:TRXU,baseline,vfm,no,no,,
|
||||
vfm_xd,VFM Downstream X,MotorEC,X10SA-ES-KBV:TRXD,baseline,vfm,no,no,,
|
||||
vfm_yur,VFM Upstream Ring Y,MotorEC,X10SA-ES-KBV:TRYUR,baseline,vfm,no,no,,
|
||||
vfm_yw,VFM Wall Y,MotorEC,X10SA-ES-KBV:TRYW,baseline,vfm,no,no,,
|
||||
vfm_ydr,VFM Downstream Ring Y,MotorEC,X10SA-ES-KBV:TRYDR,baseline,vfm,no,no,,
|
||||
vfm_bu,VFM Upstream Bender,MotorEC,X10SA-ES-KBV:BNDU,baseline,vfm,no,no,,
|
||||
vfm_bd,VFM Downstream Bender,MotorEC,X10SA-ES-KBV:BNDD,baseline,vfm,no,no,,
|
||||
vfm_yaw,VFM Virtual Yaw,MotorEC,X10SA-ES-KBV:YAW,baseline,vfm,no,no,,
|
||||
vfm_roll,VFM Virtual Roll,MotorEC,X10SA-ES-KBV:ROLL,baseline,vfm,no,no,,
|
||||
vfm_pitch,VFM Virtual Pitch,MotorEC,X10SA-ES-KBV:PITCH,baseline,vfm,no,no,,
|
||||
vfm_x,VFM Virtual X,MotorEC,X10SA-ES-KBV:TRX,baseline,vfm,no,no,,
|
||||
vfm_y,VFM Virtual Y ,MotorEC,X10SA-ES-KBV:TRY,baseline,vfm,no,no,,
|
||||
hfm_xu,HFM Upstream X,MotorEC,X10SA-ES-KBH:TRXU,baseline,hfm,no,no,,
|
||||
hfm_xd,HFM Downstream X,MotorEC,X10SA-ES-KBH:TRXD,baseline,hfm,no,no,,
|
||||
hfm_yuw,HFM Upstream Wall Y,MotorEC,X10SA-ES-KBH:TRYUW,baseline,hfm,no,no,,
|
||||
hfm_yr,HFM Ring Y,MotorEC,X10SA-ES-KBH:TRYR,baseline,hfm,no,no,,
|
||||
hfm_ydw,HFM Downstream Wall Y,MotorEC,X10SA-ES-KBH:TRYDW,baseline,hfm,no,no,,
|
||||
hfm_bu,HFM Upstream Bender,MotorEC,X10SA-ES-KBH:BNDU,baseline,hfm,no,no,,
|
||||
hfm_bd,HFM Downstream Bender,MotorEC,X10SA-ES-KBH:BNDD,baseline,hfm,no,no,,
|
||||
hfm_yaw,HFM Virtual Yaw,MotorEC,X10SA-ES-KBH:YAW,baseline,hfm,no,no,,
|
||||
hfm_roll,HFM Virtual Roll,MotorEC,X10SA-ES-KBH:ROLL,baseline,hfm,no,no,,
|
||||
hfm_pitch,HFM Virtual Pitch,MotorEC,X10SA-ES-KBH:PITCH,baseline,hfm,no,no,,
|
||||
hfm_x,HFM Virtual X,MotorEC,X10SA-ES-KBH:TRX,baseline,hfm,no,no,,
|
||||
hfm_y,HFM Virtual Y ,MotorEC,X10SA-ES-KBH:TRY,baseline,hfm,no,no,,
|
||||
bcu_bpm1,BCU BPM Signal 1 ,SignalRO,X10SA-ES-BCBPM:Current1:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
bcu_bpm2,BCU BPM Signal 2,SignalRO,X10SA-ES-BCBPM:Current2:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
bcu_bpm3,BCU BPM Signal 3,SignalRO,X10SA-ES-BCBPM:Current3:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
@@ -126,7 +126,7 @@ bcu_sl_yt,BCU slit top,Motor,X10SA-ES-BCSLV:TRYT,baseline,bcu,no,no,,
|
||||
bcu_sl_yb,BCU slit bottom,Motor,X10SA-ES-BCSLV:TRYB,baseline,bcu,no,no,,
|
||||
bcu_sl_ycen,BCU slit Y centre,Motor,X10SA-ES-BCSLV:CENTER,baseline,bcu,no,no,,
|
||||
bcu_sl_ysize,BCU slit Y size,Motor,X10SA-ES-BCSLV:SIZE,baseline,bcu,no,no,,
|
||||
xrf_pos,XRF det in/out,Signal,X10SA-ES-XRF:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
xrf_pos,XRF det in/out,Signal,X10SA-ES-XRF:POS-SET,baseline,se,no,no,"{""type"":positioner}",
|
||||
samcam_x,sample cam X ,SignalRO,X10SA-ES-MS:Stats5:CentroidX_RBV,baseline,scam,yes,yes,,
|
||||
samcam_xsig,sample cam X sigma,SignalRO,X10SA-ES-MS:Stats5:SigmaX_RBV,monitored,scam,yes,yes,,
|
||||
samcam_y,sample cam Y ,SignalRO,X10SA-ES-MS:Stats5:CentroidY_RBV,baseline,scam,yes,yes,,
|
||||
@@ -135,23 +135,23 @@ samcam_max,sample cam max value,SignalRO,X10SA-ES-MS:Stats5:MaxValue_RBV,monitor
|
||||
samcam_exp,sample cam exp time,Signal,X10SA-ES-MS:cam1:AcquireTime,baseline,scam,no,yes,,
|
||||
samcam_gain,sample cam gain,Signal,X10SA-ES-MS:cam1:Gain,baseline,scam,no,yes,,
|
||||
scam_zoom,Sample cam zoom,Motor,X10SA-ES-MS:ZOOM,baseline,scam,no,yes,,
|
||||
fl_bright,Frontlight brightness,Signal,X10SA-ES-FL:SET,baseline,se,no,yes,,
|
||||
fl_bright,Frontlight brightness,Signal,X10SA-ES-FL:SET,baseline,se,no,no,,
|
||||
coll_x,Collimator X,Motor,X10SA-ES-COL:TRX,baseline,se,no,yes,,
|
||||
coll_y,Collimator Y,Motor,X10SA-ES-COL:TRY,baseline,se,no,yes,"{""type"": multi-position, ""in"": 41.5, ""out"": 20.0, ""park"": 0,""tol"":0.05}",
|
||||
diag_y,Scintillator/diode Y,Motor,X10SA-ES-SCL:TRY,baseline,se,no,yes,"{""type"": multi-position, ""scint"": 38.62, ""i1"": 44.0, ""out"": 20.0,""park"": 0,""tol"":0.3}",
|
||||
coll_y,Collimator Y,Motor,X10SA-ES-COL:TRY,baseline,se,no,no,"{""type"": multi-position, ""in"": 41.5, ""out"": 20.0, ""park"": 0,""tol"":0.05}",
|
||||
diag_y,Scintillator/diode Y,Motor,X10SA-ES-SCL:TRY,baseline,se,no,no,"{""type"": multi-position, ""scint"": 38.62, ""i1"": 44.0, ""out"": 20.0,""park"": 0,""tol"":0.3}",
|
||||
diag_z,Scintillator/diode Z,Motor,X10SA-ES-SCL:TRZ,baseline,se,no,yes,,
|
||||
i1,i1 diode reading,SignalRO,X10SA-ES-SCLDI:READOUT,monitored,bpm,yes,yes,,
|
||||
bl_pos,Backlight positioner,Signal,X10SA-ES-BL:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
bl_bright,Backlight brightness,Signal,X10SA-ES-BL:SET,baseline,se,no,yes,,
|
||||
bl_pos,Backlight positioner,Signal,X10SA-ES-BL:POS-SET,baseline,se,no,no,"{""type"":positioner}",
|
||||
bl_bright,Backlight brightness,Signal,X10SA-ES-BL:SET,baseline,se,no,no,,
|
||||
bs_x,Beamstop X,Motor,X10SA-ES-BS:TRX,baseline,se,no,yes,,
|
||||
bs_y,Beamstop Y,Motor,X10SA-ES-BS:TRY,baseline,se,no,yes,,
|
||||
bs_z,Beamstop Z,Motor,X10SA-ES-BS:TRZ,baseline,se,no,yes,"{""type"": guarded, ""min"": 13, ""samp"": 15, ""work_min"": 20, ""safe"": 41, ""max_blin"": 42, ""max_blout"": 70}",
|
||||
bs_pos,Beamstop positioner,Signal,X10SA-ES-BS:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
gon_x,Goniometer X,Motor,X10SA-ES-DF1:TRX1,baseline,det,no,yes,"{""type"": guarded, ""in"": 18.0, ""out"": -10.0, ""safe"": -100,""tol"":0.5}",
|
||||
bs_z,Beamstop Z,Motor,X10SA-ES-BS:TRZ,baseline,se,no,no,"{""type"": guarded, ""min"": 13, ""samp"": 15, ""work_min"": 20, ""safe"": 41, ""max_blin"": 42, ""max_blout"": 70}",
|
||||
bs_pos,Beamstop positioner,Signal,X10SA-ES-BS:POS-SET,baseline,se,no,no,"{""type"":positioner}",
|
||||
gon_x,Goniometer X,Motor,X10SA-ES-DF1:TRX1,baseline,det,no,no,"{""type"": guarded, ""in"": 18.0, ""out"": -10.0, ""safe"": -100,""tol"":0.5}",
|
||||
gon_y,Goniometer Y,Motor,X10SA-ES-DF1:TRY1,baseline,det,no,yes,,
|
||||
gon_z,Goniometer X,Motor,X10SA-ES-DF1:TRZ1,baseline,det,no,yes,,
|
||||
omega,Omega,Motor,X10SA-ES-DF1:ROTU,baseline,det,no,yes,,
|
||||
cryo_pos,Cryo positioner,Signal,X10SA-ES-CS:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
cryo_pos,Cryo positioner,Signal,X10SA-ES-CS:POS-SET,baseline,se,no,no,"{""type"":positioner}",
|
||||
cryo_x,Cryojet X ,Motor,X10SA-ES-CS:TRX,baseline,se,no,yes,,
|
||||
det_xi_focus,X-ray eye 2 Focus,Motor,X10SA-ES-XEYE:FOCUS,baseline,det,no,yes,,
|
||||
det_xi_zoom,X-ray eye 2 Zoom,Motor,X10SA-ES-XEYE:ZOOM,baseline,det,no,yes,,
|
||||
@@ -164,6 +164,6 @@ det_xicam_ysig,sample cam Y sigma,SignalRO,X10SA-ES-XEYE:cam1:Stats5:SigmaY_RBV,
|
||||
det_xicam_max,sample cam max value,SignalRO,X10SA-ES-XEYE:cam1:Stats5:MaxValue_RBV,monitored,scam,yes,no,,
|
||||
det_xicam_exp,sample cam exp time,Signal,X10SA-ES-XEYE:cam1:cam1:AcquireTime,baseline,scam,no,no,,
|
||||
det_xicam_gain,sample cam gain,Signal,X10SA-ES-XEYE:cam1:cam1:Gain,baseline,scam,no,no,,
|
||||
det_cov,Detector cover,Signal,X10SA-ES-DETCOV:SET,baseline,det,no,yes,"{""type"":positioner}",
|
||||
det_cov,Detector cover,Signal,X10SA-ES-DETCOV:SET,baseline,det,no,no,"{""type"":positioner}",
|
||||
det_y,Detector Y,Motor,X10SA-ES-DET:TRY,baseline,det,no,yes,,
|
||||
det_z,Detector Z,Motor,X10SA-ES-DET:TRZ,baseline,det,no,yes,,
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,146 @@
|
||||
name,description,deviceClass,PV,readoutPriority,tag,readOnly,include,userParameter,
|
||||
sls_current,SLS current,SignalRO,ARS07-DPCT-0100:CURR,monitored,SLS,yes,yes,,
|
||||
fe_sl_xr,FE Slit X Ring,Motor,X06DA-FE-SLDI:TRXR,baseline,fe,no,yes,,
|
||||
fe_sl_yt,FE Slit Y top,Motor,X06DA-FE-SLDI:TRYT,baseline,fe,no,yes,,
|
||||
fe_sl_xw,FE Slit X Wall,Motor,X06DA-FE-SLDI:TRXW,baseline,fe,no,yes,,
|
||||
fe_sl_yb,FE SlitY Bottom,Motor,X06DA-FE-SLDI:TRYB,baseline,fe,no,yes,,
|
||||
fe_sl_xcen,FE Slit X Centre,Motor,X06DA-FE-SLDI:CENTERX,baseline,fe,no,yes,,
|
||||
fe_sl_xsize,FE Slit X Size,Motor,X06DA-FE-SLDI:SIZEX,baseline,fe,no,yes,,
|
||||
fe_sl_ycen,FE Slit Y Centre,Motor,X06DA-FE-SLDI:CENTERY,baseline,fe,no,yes,,
|
||||
fe_sl_ysize,FE Slit Y Size,Motor,X06DA-FE-SLDI:SIZEY,baseline,fe,no,yes,,
|
||||
fe_cm_xu,FE Coll Mirror Upstream X,Motor,X06DA-ES-MI1:TRXU,baseline,fe_cm,no,yes,,
|
||||
fe_cm_xd,FE Coll Mirror Downstream X,Motor,X06DA-ES-MI1:TRXD,baseline,fe_cm,no,yes,,
|
||||
fe_cm_yur,FE Coll Mirror Upstream Ring Y,Motor,X06DA-ES-MI1:TRYUR,baseline,fe_cm,no,yes,,
|
||||
fe_cm_yw,FE Coll Mirror Wall Y,Motor,X06DA-ES-MI1:TRYW,baseline,fe_cm,no,yes,,
|
||||
fe_cm_ydr,FE Coll Mirror Downstream Ring Y,Motor,X06DA-ES-MI1:TRYDR,baseline,fe_cm,no,yes,,
|
||||
fe_cm_b1,FE Coll Mirror Bender,Motor,X06DA-ES-MI1:BND1,baseline,fe_cm,no,yes,,
|
||||
fe_cm_yaw,FE Coll Mirror Yaw,Motor,X06DA-ES-MI1:YAW,baseline,fe_cm,no,yes,,
|
||||
fe_cm_roll,FE Coll Mirror Roll,Motor,X06DA-ES-MI1:ROLL,baseline,fe_cm,no,yes,,
|
||||
fe_cm_pitch,FE Coll Mirror Pitch,Motor,X06DA-ES-MI1:PITCH,baseline,fe_cm,no,yes,,
|
||||
fe_cm_x,FE Coll Mirror X,Motor,X06DA-ES-MI1:TRX,baseline,fe_cm,no,yes,,
|
||||
fe_cm_y,FE Coll Mirror Y ,Motor,X06DA-ES-MI1:TRY,baseline,fe_cm,no,yes,,
|
||||
bsf_bpm1,BSF BPM Signal 1,SignalRO,X06DA-OP-BSFBPM:SIGNAL1,monitored,bpm,yes,no,,
|
||||
bsf_bpm2,BSF BPM Signal 2,SignalRO,X06DA-OP-BSFBPM:SIGNAL2,monitored,bpm,yes,no,,
|
||||
bsf_bpm3,BSF BPM Signal 3,SignalRO,X06DA-OP-BSFBPM:SIGNAL3,monitored,bpm,yes,no,,
|
||||
bsf_bpm4,BSF BPM Signal 4,SignalRO,X06DA-OP-BSFBPM:SIGNAL4,monitored,bpm,yes,no,,
|
||||
bsf_bpmsum,BSF BPM Summed,SignalRO,X06DA-OP-BSFBPM:SUM,monitored,bpm,yes,no,,
|
||||
bsf_sl_xw,BSF slit outboard,Motor,X06DA-OP-BSFSLH:TRXW,baseline,bsf,no,yes,,
|
||||
bsf_sl_xr,BSF slit inboard,Motor,X06DA-OP-BSFSLH:TRXR,baseline,bsf,no,yes,,
|
||||
bsf_sl_yt,BSF slit top,Motor,X06DA-OP-BSFSLV:TRYT,baseline,bsf,no,yes,,
|
||||
bsf_sl_yb,BSF slit bottom,Motor,X06DA-OP-BSFSLV:TRYB,baseline,bsf,no,yes,,
|
||||
bsf_sl_xcen,BSF X centre,Motor,X06DA-OP-BSFSLH:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_xsize,BSF X size,Motor,X06DA-OP-BSFSLH:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_sl_ycen,BSF Y centre,Motor,X06DA-OP-BSFSLV:CENTER,baseline,bsf,no,yes,,
|
||||
bsf_sl_ysize,BSF Y size,Motor,X06DA-OP-BSFSLV:SIZE,baseline,bsf,no,yes,,
|
||||
bsf_f1_y,BSF Filter 1 Y,Motor,X06DA-OP-BSFFI1:TRY,baseline,bsf,no,yes,,
|
||||
bsf_f2_y,BSF Filter 2 Y,Motor,X06DA-OP-BSFFI2:TRY,baseline,bsf,no,yes,,
|
||||
dccm_theta1,DCCM theta1,Motor,X06DA-OP-DCCM:ROTX-CR1,baseline,dccm,no,yes,,
|
||||
dccm_theta2,DCCM theta2,Motor,X06DA-OP-DCCM:ROTX-CR2,baseline,dccm,no,yes,,
|
||||
dccm_rotz,DCCM Crystal 2 rotz ,Motor,X06DA-OP-DCCM:ROTZ-CR2,baseline,dccm,no,yes,,
|
||||
dccm_energy,DCCM energy,Motor,X06DA-OP-DCCM:ENERGY,baseline,dccm,no,yes,,
|
||||
dccm_diode_t,Top diode between mono crystals,SignalRO,X06DA-OP-XPM1:TOP:READOUT,baseline,dccm,no,yes,,
|
||||
dccm_diode_b,Bottom diode between mono crystals,SignalRO,X06DA-OP-XPM1:BOT:READOUT,baseline,dccm,no,yes,,
|
||||
dccm_xbpm1,XBPM after mono ch1,SignalRO,X06DA-OP-XBPM1:Current1:MeanValue_RBV,baseline,dccm,no,yes,,
|
||||
dccm_xbpm2,XBPM after mono ch2,SignalRO,X06DA-OP-XBPM1:Current2:MeanValue_RBV,baseline,dccm,no,yes,,
|
||||
dccm_xbpm3,XBPM after mono ch3,SignalRO,X06DA-OP-XBPM1:Current3:MeanValue_RBV,baseline,dccm,no,yes,,
|
||||
dccm_xbpm4,XBPM after mono ch4,SignalRO,X06DA-OP-XBPM1:Current4:MeanValue_RBV,baseline,dccm,no,yes,,
|
||||
dccm_xbpmsum,XBPM after mono summed,SignalRO,X06DA-OP-XBPM1:SumAll:MeanValue_RBV,baseline,dccm,no,yes,,
|
||||
ss_bpm1,SS BPM Signal 1,SignalRO,X06DA-ES-SSBPM:Current1:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
ss_bpm2,SS BPM Signal 2,SignalRO,X06DA-ES-SSBPM:Current2:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
ss_bpm3,SS BPM Signal 3,SignalRO,X06DA-ES-SSBPM:Current3:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
ss_bpm4,SS BPM Signal 4,SignalRO,X06DA-ES-SSBPM:Current4:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
ss_bpmsum,SS BPM Summed,SignalRO,X06DA-ES-SSBPM:SumAll:MeanValue_RBV,monitored,bpm,yes,yes,,
|
||||
ss_bpm_x,SS BPM X,Motor,X06DA-ES-SSBPM:TRX,baseline,ss,no,yes,,
|
||||
ss_bpm_y,SS BPM Y,Motor,X06DA-ES-SSBPM:TRY,baseline,ss,no,yes,,
|
||||
ss_sl_xw,SS slit wall,Motor,X06DA-ES-SSSLH:TRXW,baseline,ss,no,yes,,
|
||||
ss_sl_xr,SS slit ring,Motor,X06DA-ES-SSSLH:TRXR,baseline,ss,no,yes,,
|
||||
ss_sl_xcen,SS slit X centre,Motor,X06DA-ES-SSSLH:CENTER,baseline,ss,no,yes,,
|
||||
ss_sl_xsize,SS slit X size,Motor,X06DA-ES-SSSLH:SIZE,baseline,ss,no,yes,,
|
||||
ss_sl_yt,SS slit top,Motor,X06DA-ES-SSSLV:TRYT,baseline,ss,no,yes,,
|
||||
ss_sl_yb,SS slit bottom,Motor,X06DA-ES-SSSLV:TRYB,baseline,ss,no,yes,,
|
||||
ss_sl_ycen,SS slit Y centre,Motor,X06DA-ES-SSSLV:CENTER,baseline,ss,no,yes,,
|
||||
ss_sl_ysize,SS slit Y size,Motor,X06DA-ES-SSSLV:SIZE,baseline,ss,no,yes,,
|
||||
ss_xi_x,SS X-ray eye X,Motor,X06DA-ES-SSXI:TRX,baseline,ss,no,yes,,
|
||||
ss_xi_y,SS X-ray eye Y,Motor,X06DA-ES-SSXI:TRY,baseline,ss,no,yes,,
|
||||
ss_xicam_x,ss cam X,SignalRO,X06DA-ES-SSXI:cam1:Stats5:CentroidX_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_y,ss cam Y,SignalRO,X06DA-ES-SSXI:cam1:Stats5:CentroidY_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_max,ss cam max value,SignalRO,X06DA-ES-SSXI:cam1:Stats5:MaxValue_RBV,monitored,ss,yes,yes,,
|
||||
ss_xicam_exp,ss camera exposure,Signal,X06DA-ES-SSXI:cam1:AcquireTime,baseline,ss,no,yes,,
|
||||
ss_xicam_gain,ss camera gain,Signal,X06DA-ES-SSXI:cam1:cam1:Gain,baseline,ss,no,yes,,
|
||||
ss_xicam_xsig,ss camera x sigma,Signal,X06DA-ES-SSXI:cam1:Stats5:SigmaX_RBV,baseline,ss,yes,yes,,
|
||||
ss_xicam_ysig,ss camera y sigma,Signal,X06DA-ES-SSXI:cam1:Stats5:SigmaY_RBV,baseline,ss,yes,yes,,
|
||||
vfm_xu,VFM Upstream X,Motor,X06DA-ES-KBV:TRXU,baseline,vfm,no,no,,
|
||||
vfm_xd,VFM Downstream X,Motor,X06DA-ES-KBV:TRXD,baseline,vfm,no,no,,
|
||||
vfm_yur,VFM Upstream Ring Y,Motor,X06DA-ES-KBV:TRYUR,baseline,vfm,no,no,,
|
||||
vfm_yw,VFM Wall Y,Motor,X06DA-ES-KBV:TRYW,baseline,vfm,no,no,,
|
||||
vfm_ydr,VFM Downstream Ring Y,Motor,X06DA-ES-KBV:TRYDR,baseline,vfm,no,no,,
|
||||
vfm_bu,VFM Upstream Bender,Motor,X06DA-ES-KBV:BNDU,baseline,vfm,no,no,,
|
||||
vfm_bd,VFM Downstream Bender,Motor,X06DA-ES-KBV:BNDD,baseline,vfm,no,no,,
|
||||
vfm_yaw,VFM Virtual Yaw,Motor,X06DA-ES-KBV:YAW,baseline,vfm,no,no,,
|
||||
vfm_roll,VFM Virtual Roll,Motor,X06DA-ES-KBV:ROLL,baseline,vfm,no,no,,
|
||||
vfm_pitch,VFM Virtual Pitch,Motor,X06DA-ES-KBV:PITCH,baseline,vfm,no,no,,
|
||||
vfm_x,VFM Virtual X,Motor,X06DA-ES-KBV:TRX,baseline,vfm,no,no,,
|
||||
vfm_y,VFM Virtual Y ,Motor,X06DA-ES-KBV:TRY,baseline,vfm,no,no,,
|
||||
hfm_xu,HFM Upstream X,Motor,X06DA-ES-KBH:TRXU,baseline,hfm,no,no,,
|
||||
hfm_xd,HFM Downstream X,Motor,X06DA-ES-KBH:TRXD,baseline,hfm,no,no,,
|
||||
hfm_yuw,HFM Upstream Wall Y,Motor,X06DA-ES-KBH:TRYUW,baseline,hfm,no,no,,
|
||||
hfm_yr,HFM Ring Y,Motor,X06DA-ES-KBH:TRYR,baseline,hfm,no,no,,
|
||||
hfm_ydw,HFM Downstream Wall Y,Motor,X06DA-ES-KBH:TRYDW,baseline,hfm,no,no,,
|
||||
hfm_bu,HFM Upstream Bender,Motor,X06DA-ES-KBH:BNDU,baseline,hfm,no,no,,
|
||||
hfm_bd,HFM Downstream Bender,Motor,X06DA-ES-KBH:BNDD,baseline,hfm,no,no,,
|
||||
hfm_yaw,HFM Virtual Yaw,Motor,X06DA-ES-KBH:YAW,baseline,hfm,no,no,,
|
||||
hfm_roll,HFM Virtual Roll,Motor,X06DA-ES-KBH:ROLL,baseline,hfm,no,no,,
|
||||
hfm_pitch,HFM Virtual Pitch,Motor,X06DA-ES-KBH:PITCH,baseline,hfm,no,no,,
|
||||
hfm_x,HFM Virtual X,Motor,X06DA-ES-KBH:TRX,baseline,hfm,no,no,,
|
||||
hfm_y,HFM Virtual Y ,Motor,X06DA-ES-KBH:TRY,baseline,hfm,no,no,,
|
||||
bcu_bpm1,BCU BPM Signal 1 ,SignalRO,X06DA-ES-BCBPM:Current1:MeanValue_RBV,monitored,bpm,yes,no,,
|
||||
bcu_bpm2,BCU BPM Signal 2,SignalRO,X06DA-ES-BCBPM:Current2:MeanValue_RBV,monitored,bpm,yes,no,,
|
||||
bcu_bpm3,BCU BPM Signal 3,SignalRO,X06DA-ES-BCBPM:Current3:MeanValue_RBV,monitored,bpm,yes,no,,
|
||||
bcu_bpm4,BCU BPM Signal 4,SignalRO,X06DA-ES-BCBPM:Current4:MeanValue_RBV,monitored,bpm,yes,no,,
|
||||
bcu_bpmsum,BCU BPM Summed,SignalRO,X06DA-ES-BCBPM:SumAll:MeanValue_RBV,monitored,bpm,yes,no,,
|
||||
bcu_bpm_x,BCU BPM X,Motor,X06DA-ES-BCBPM:TRX,baseline,bcu,no,no,,
|
||||
bcu_bpm_y,BCU BPM Y ,Motor,X06DA-ES-BCBPM:TRY,baseline,bcu,no,no,,
|
||||
bcu_sl_xw,BCU slit wall,Motor,X06DA-ES-BCSLH:TRXW,baseline,bcu,no,no,,
|
||||
bcu_sl_xr,BCU slit ring,Motor,X06DA-ES-BCSLH:TRXR,baseline,bcu,no,no,,
|
||||
bcu_sl_xcen,BCU slit X centre,Motor,X06DA-ES-BCSLH:CENTER,baseline,bcu,no,no,,
|
||||
bcu_sl_xsize,BCU slit X size,Motor,X06DA-ES-BCSLH:SIZEX,baseline,bcu,no,no,,
|
||||
bcu_sl_yt,BCU slit top,Motor,X06DA-ES-BCSLV:TRYT,baseline,bcu,no,no,,
|
||||
bcu_sl_yb,BCU slit bottom,Motor,X06DA-ES-BCSLV:TRYB,baseline,bcu,no,no,,
|
||||
bcu_sl_ycen,BCU slit Y centre,Motor,X06DA-ES-BCSLV:CENTER,baseline,bcu,no,no,,
|
||||
bcu_sl_ysize,BCU slit Y size,Motor,X06DA-ES-BCSLV:SIZE,baseline,bcu,no,no,,
|
||||
bcu_f1_x,BCU filter 1 X,Motor,X06DA-ES-BCFI1:TRX,baseline,bcu,no,no,,
|
||||
bcu_f2_x,BCU filter 2 X,Motor,X06DA-ES-BCFI2:TRX,baseline,bcu,no,no,,
|
||||
bcu_f3_x,BCU filter 3 X,Motor,X06DA-ES-BCFI3:TRX,baseline,bcu,no,no,,
|
||||
bcu_f4_x,BCU filter 4 X,Motor,X06DA-ES-BCFI4:TRX,baseline,bcu,no,no,,
|
||||
xrf_pos,XRF det in/out,Signal,X06DA-ES-XRF:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
samcam_x,sample cam X ,SignalRO,X06DA-ES-MS:Stats5:CentroidX_RBV,baseline,scam,yes,yes,,
|
||||
samcam_xsig,sample cam X sigma,SignalRO,X06DA-ES-MS:Stats5:SigmaX_RBV,monitored,scam,yes,yes,,
|
||||
samcam_y,sample cam Y ,SignalRO,X06DA-ES-MS:Stats5:CentroidY_RBV,baseline,scam,yes,yes,,
|
||||
samcam_ysig,sample cam Y sigma,SignalRO,X06DA-ES-MS:Stats5:SigmaY_RBV,monitored,scam,yes,yes,,
|
||||
samcam_max,sample cam max value,SignalRO,X06DA-ES-MS:Stats5:MaxValue_RBV,monitored,scam,yes,yes,,
|
||||
samcam_exp,sample cam exp time,Signal,X06DA-ES-MS:cam1:AcquireTime,baseline,scam,no,yes,,
|
||||
samcam_gain,sample cam gain,Signal,X06DA-ES-MS:cam1:Gain,baseline,scam,no,yes,,
|
||||
scam_zoom,Sample cam zoom,Motor,X06DA-ES-MS:ZOOM,baseline,scam,no,yes,,
|
||||
fl_bright,Frontlight brightness,Signal,X06DA-ES-FL:SET,baseline,se,no,yes,,
|
||||
coll_x,Collimator X,Motor,X06DA-ES-COL:TRX,baseline,se,no,yes,,
|
||||
coll_y,Collimator Y,Motor,X06DA-ES-COL:TRY,baseline,se,no,yes,"{""type"": multi-position, ""in"": 41.5, ""out"": 20.0, ""park"": 0,""tol"":0.05}",
|
||||
diag_y,Scintillator/diode Y,Motor,X06DA-ES-SCL:TRY,baseline,se,no,yes,"{""type"": multi-position, ""scint"": 38.62, ""i1"": 44.0, ""out"": 20.0,""park"": 0,""tol"":0.3}",
|
||||
diag_z,Scintillator/diode Z,Motor,X06DA-ES-SCL:TRZ,baseline,se,no,yes,,
|
||||
i1,i1 diode reading,SignalRO,X06DA-ES-SCLDI:READOUT,monitored,bpm,yes,yes,,
|
||||
bl_pos,Backlight positioner,Signal,X06DA-ES-BL:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
bl_bright,Backlight brightness,Signal,X06DA-ES-BL:SET,baseline,se,no,yes,,
|
||||
bs_x,Beamstop X,Motor,X06DA-ES-BS:TRX,baseline,se,no,yes,,
|
||||
bs_y,Beamstop Y,Motor,X06DA-ES-BS:TRY,baseline,se,no,yes,,
|
||||
bs_z,Beamstop Z,Motor,X06DA-ES-BS:TRZ,baseline,se,no,yes,"{""type"": guarded, ""min"": 13, ""samp"": 15, ""work_min"": 20, ""safe"": 41, ""max_blin"": 42, ""max_blout"": 70}",
|
||||
bs_pos,Beamstop positioner,Signal,X06DA-ES-BS:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
gon_x,Goniometer X,Motor,X06DA-ES-DF1:TRX1,baseline,det,no,yes,"{""type"": guarded, ""in"": 18.0, ""out"": -10.0, ""safe"": -100,""tol"":0.5}",
|
||||
gon_y,Goniometer Y,Motor,X06DA-ES-DF1:TRY1,baseline,det,no,yes,,
|
||||
gon_z,Goniometer X,Motor,X06DA-ES-DF1:TRZ1,baseline,det,no,yes,,
|
||||
omega,Omega,Motor,X06DA-ES-DF1:ROTU,baseline,det,no,yes,,
|
||||
cryo_pos,Cryo positioner,Signal,X06DA-ES-CS:POS-SET,baseline,se,no,yes,"{""type"":positioner}",
|
||||
cryo_x,Cryojet X ,Motor,X06DA-ES-CS:TRX,baseline,se,no,yes,,
|
||||
det_cov,Detector cover,Signal,X06DA-ES-DETCOV:SET,baseline,det,no,yes,"{""type"":positioner}",
|
||||
det_y,Detector Y,Motor,X06DA-ES-DET:TRY,baseline,det,no,yes,,
|
||||
det_z,Detector Z,Motor,X06DA-ES-DET:TRZ,baseline,det,no,yes,,
|
||||
gonpos,Sample sensor distance,SignalRO,X06DA-ES-DF1:CBOX-USER1,baseline,se,no,yes,,
|
||||
gonvalid,Sample in valid distance,SignalRO,X06DA-ES-DF1:CBOX-CMP1,baseline,se,no,yes,,
|
||||
|
@@ -0,0 +1,206 @@
|
||||
ss_sl_xw:
|
||||
description: SS slit wall
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-SSSLH:TRXW'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- ss
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
in: 1.0
|
||||
out: 2.0
|
||||
|
||||
bs_z:
|
||||
description: Beamstop Z
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-BS:TRZ'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
min: 13
|
||||
samp: 15
|
||||
work_min: 20
|
||||
safe: 41
|
||||
max_blin: 42
|
||||
max_blout: 70
|
||||
|
||||
gon_x:
|
||||
description: Goniometer X
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-DF1:TRX1'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- det
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
in: 0.0
|
||||
out: -10.0
|
||||
safe: -100
|
||||
tol: 0.5
|
||||
|
||||
diag_y:
|
||||
description: Scintillator/diode Y
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-SCL:TRY'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
scint: 38.62
|
||||
i1: 44.0
|
||||
out: 20.0
|
||||
park: 1
|
||||
tol: 0.3
|
||||
|
||||
coll_y:
|
||||
description: Collimator Y
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig: {prefix: 'X10SA-ES-COL:TRY'}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
in: 41.5
|
||||
intermediate: 32
|
||||
out: 20.0
|
||||
park: 1
|
||||
tol: 0.05
|
||||
|
||||
bs_pos:
|
||||
description: Beamstop positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BS:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: discrete
|
||||
in: 1.0
|
||||
out: 0.0
|
||||
|
||||
xrf_pos:
|
||||
description: XRF positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-XRF:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: discrete
|
||||
in: 1.0
|
||||
out: 0.0
|
||||
|
||||
cryo_pos:
|
||||
description: Cryo positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-CS:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: discrete
|
||||
in: 1.0
|
||||
out: 0.0
|
||||
|
||||
det_cov:
|
||||
description: Detector cover
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-DETCOV:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- det
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: discrete
|
||||
'open': 2.0
|
||||
'close': 1.0
|
||||
|
||||
bl_bright:
|
||||
description: Backlight brightness
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BL:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
'on': 1.3
|
||||
'off': 0.0
|
||||
'tol': 0.01
|
||||
|
||||
|
||||
bl_pos:
|
||||
description: Backlight positioner
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-BL:POS-SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: discrete
|
||||
in: 1.0
|
||||
out: 0.0
|
||||
|
||||
fl_bright:
|
||||
description: Frontlight brightness
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig: {read_pv: 'X10SA-ES-FL:SET', auto_monitor: true}
|
||||
onFailure: buffer
|
||||
enabled: True
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- se
|
||||
readOnly: False
|
||||
softwareTrigger: false
|
||||
userParameter:
|
||||
type: continuous
|
||||
'on': 3.0
|
||||
'off': 0.0
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
base_config:
|
||||
- !include ./pxii-autogenerated.yaml
|
||||
- !include ./pxii-devices-new.yaml
|
||||
sample_env:
|
||||
- !include ./se_devices.yaml
|
||||
id_gap:
|
||||
readoutPriority: baseline
|
||||
description: undulator gap
|
||||
@@ -22,4 +24,4 @@ smargon:
|
||||
- smargon
|
||||
- motors
|
||||
readOnly: false
|
||||
softwareTrigger: false
|
||||
softwareTrigger: false
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
from ophyd import Component as Cpt
|
||||
|
||||
from .http import TIMESTAMP_ID, HttpDeviceController, HttpDeviceSignal, HttpOphydDevice
|
||||
|
||||
|
||||
class AerotechController(HttpDeviceController):
|
||||
_readback_endpoint = "status"
|
||||
_target_endpoint = "position"
|
||||
|
||||
def __init__(self, *, prefix, **kwargs):
|
||||
self._readbacks: dict[str, dict[str, float | bool]] = {}
|
||||
super().__init__(prefix=prefix, **kwargs)
|
||||
|
||||
def put(self, axis: str, val: float):
|
||||
self._rest_post(body={axis: val})
|
||||
|
||||
def get_readback(self, axis_id: str) -> tuple[float, float] | None:
|
||||
with self._readback_lock:
|
||||
if axis_id not in self._readbacks or TIMESTAMP_ID not in self._readbacks:
|
||||
return None
|
||||
return self._readbacks.get(axis_id)["pos"], self._readbacks.get(TIMESTAMP_ID) # type: ignore
|
||||
|
||||
|
||||
class Aerotech(HttpOphydDevice):
|
||||
controller_class = AerotechController
|
||||
|
||||
x = Cpt(HttpDeviceSignal, axis_identifier="x", tolerance=0.01)
|
||||
y = Cpt(HttpDeviceSignal, axis_identifier="y", tolerance=0.01)
|
||||
z = Cpt(HttpDeviceSignal, axis_identifier="z", tolerance=0.01)
|
||||
u = Cpt(HttpDeviceSignal, axis_identifier="u", tolerance=0.01)
|
||||
vel_u_deg_s = Cpt(HttpDeviceSignal, axis_identifier="vel_u_deg_s", tolerance=0.01)
|
||||
|
||||
|
||||
def _test():
|
||||
a = Aerotech(name="aerotech", prefix="http://mx-x10sa-queue-01:5234")
|
||||
a.wait_for_connection()
|
||||
return a
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
aerotech = _test()
|
||||
print(aerotech.read())
|
||||
aerotech.stop()
|
||||
@@ -0,0 +1,178 @@
|
||||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
from threading import Event, RLock, Thread
|
||||
from typing import Any
|
||||
|
||||
from ophyd import OphydObject
|
||||
from ophyd_devices import PSIDeviceBase
|
||||
from ophyd_devices.utils.socket import SocketSignal
|
||||
from requests import Response, Session
|
||||
|
||||
TIMESTAMP_ID = "__timestamp"
|
||||
_POLL_INTERVAL_SLOW = 0.1
|
||||
|
||||
|
||||
class HttpRestError(Exception):
|
||||
"""Error for rest calls from a HttpRestSignal."""
|
||||
|
||||
def __init__(self, resp: Response, *args: object, value: Any | None = None) -> None:
|
||||
method, url = resp.request.method, resp.request.url
|
||||
data = f"{str(value)} to " if value is not None else ""
|
||||
super().__init__(
|
||||
f"Could not {method} {data}{url}. Code: {resp.status_code}. Reason: {resp.reason}.",
|
||||
*args,
|
||||
)
|
||||
|
||||
|
||||
class HttpDeviceController(OphydObject, ABC):
|
||||
"""Controller to consolidate polling loops and other REST calls for devices which communicate
|
||||
with HTTP REST interfaces"""
|
||||
|
||||
_readback_endpoint: str
|
||||
_target_endpoint: str
|
||||
|
||||
def __init__(self, *, prefix, **kwargs):
|
||||
self._readbacks: dict
|
||||
self._session = Session()
|
||||
self._prefix = prefix
|
||||
self._targets = {}
|
||||
self._signal_registry: set[str] = set()
|
||||
self._readback_poll_interval: float = _POLL_INTERVAL_SLOW
|
||||
|
||||
super().__init__(**kwargs)
|
||||
self._setup_readback()
|
||||
|
||||
def _setup_readback(self):
|
||||
self._stop_monitor_readback_event = Event()
|
||||
self._readback_lock = RLock()
|
||||
self._monitor_readback_thread = Thread(
|
||||
target=self._monitor,
|
||||
args=[
|
||||
self._readback_endpoint,
|
||||
self._stop_monitor_readback_event,
|
||||
self._readback_lock,
|
||||
self._readbacks,
|
||||
],
|
||||
)
|
||||
|
||||
def manual_update(self):
|
||||
self._update_reading(self._readback_endpoint, self._readback_lock, self._readbacks)
|
||||
|
||||
def _update_reading(self, endpoint: str, lock: RLock, buffer: dict):
|
||||
data = self._rest_get(endpoint)
|
||||
timestamp = time.monotonic()
|
||||
with lock:
|
||||
buffer.update(data)
|
||||
buffer["__timestamp"] = timestamp
|
||||
|
||||
def _monitor(self, endpoint: str, event: Event, lock: RLock, buffer: dict):
|
||||
while not event.is_set():
|
||||
self._update_reading(endpoint, lock, buffer)
|
||||
time.sleep(self._readback_poll_interval)
|
||||
|
||||
def _clean_monitor(self):
|
||||
if self._monitor_readback_thread.is_alive():
|
||||
self._stop_monitor_readback_event.set()
|
||||
self._monitor_readback_thread.join(timeout=2)
|
||||
if self._monitor_readback_thread.is_alive():
|
||||
raise RuntimeError("Failed to clean up Aerotech monitor thread.")
|
||||
|
||||
def register(self, axis_id: str):
|
||||
self._signal_registry.add(axis_id)
|
||||
|
||||
def _rest_get(self, endpoint):
|
||||
resp = self._session.get(self._prefix + endpoint)
|
||||
if not resp.ok:
|
||||
raise HttpRestError(resp)
|
||||
return resp.json()
|
||||
|
||||
def _rest_put(self, params: dict | None = None, body: dict | None = None):
|
||||
resp = self._session.put(self._prefix + self._target_endpoint, params=params, json=body)
|
||||
if not resp.ok:
|
||||
raise HttpRestError(resp, value=params)
|
||||
|
||||
def _rest_post(self, params: dict | None = None, body: dict | None = None):
|
||||
resp = self._session.post(self._prefix + self._target_endpoint, params=params, json=body)
|
||||
if not resp.ok:
|
||||
raise HttpRestError(resp, value=params)
|
||||
|
||||
def start_monitor(self):
|
||||
"""Start or restart the automonitor thread."""
|
||||
self._clean_monitor()
|
||||
self._setup_readback()
|
||||
self._monitor_readback_thread.start()
|
||||
|
||||
def monitor_stopped(self):
|
||||
return not self._monitor_readback_thread.is_alive()
|
||||
|
||||
def put(self, axis: str, val: float):
|
||||
self._rest_put({axis: val})
|
||||
|
||||
@abstractmethod
|
||||
def get_readback(self, axis_id: str) -> tuple[float, float] | None:
|
||||
"""Return a tuple (reading, timestamp) if the axis_id exists"""
|
||||
|
||||
def stop(self):
|
||||
# There doesn't appear to be a stop endpoint on the server
|
||||
# Best effort: set the target to the current position
|
||||
pass
|
||||
# TODO: self._rest_put(self._readbacks)
|
||||
|
||||
|
||||
class HttpDeviceSignal(SocketSignal):
|
||||
"""Ophyd signal which gets and puts to a REST API rather than EPICS PVs, mediated through the Aerotech
|
||||
Controller"""
|
||||
|
||||
def __init__(self, *args, axis_identifier: str, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
controller: HttpDeviceController | None = getattr(self.root, "controller", None)
|
||||
if controller is None:
|
||||
raise TypeError("HttpDeviceSignal must be used in a device with a HttpDeviceController")
|
||||
self._controller = controller
|
||||
self._axis_id = axis_identifier
|
||||
self._controller.register(self._axis_id)
|
||||
|
||||
def _socket_get(self): # type: ignore
|
||||
self._readback, self.metadata["timestamp"] = self._controller.get_readback(
|
||||
self._axis_id
|
||||
) or (0.0, 0.0)
|
||||
return self._readback
|
||||
|
||||
def _socket_set(self, val: float):
|
||||
self._controller.put(self._axis_id, val)
|
||||
|
||||
def get(self, **kwargs):
|
||||
if self._controller.monitor_stopped():
|
||||
self._controller.start_monitor()
|
||||
return super().get(**kwargs)
|
||||
|
||||
|
||||
class HttpOphydDevice(PSIDeviceBase):
|
||||
controller_class: type[HttpDeviceController]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
name: str,
|
||||
prefix: str = "",
|
||||
scan_info=None,
|
||||
device_manager=None,
|
||||
**kwargs,
|
||||
):
|
||||
self.controller = self.controller_class(prefix=prefix)
|
||||
super().__init__(
|
||||
name=name,
|
||||
prefix=prefix,
|
||||
scan_info=scan_info,
|
||||
device_manager=device_manager,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def wait_for_connection(self, **kwargs): # type: ignore
|
||||
self.controller.start_monitor()
|
||||
self.controller.manual_update()
|
||||
return super().wait_for_connection(**kwargs)
|
||||
|
||||
def stop(self, *, success: bool = False) -> None:
|
||||
self.controller.stop()
|
||||
return super().stop(success=success)
|
||||
@@ -1,122 +1,21 @@
|
||||
import time
|
||||
from threading import Event, RLock, Thread
|
||||
from typing import Any
|
||||
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import OphydObject
|
||||
from ophyd_devices import PSIDeviceBase
|
||||
from ophyd_devices.utils.socket import SocketSignal
|
||||
from requests import Response, get, put
|
||||
|
||||
from .http import HttpDeviceController, HttpDeviceSignal, HttpOphydDevice
|
||||
|
||||
_TIMESTAMP_ID = "__timestamp"
|
||||
_POLL_INTERVAL_SLOW = 0.1
|
||||
|
||||
|
||||
class HttpRestError(Exception):
|
||||
"""Error for rest calls from a HttpRestSignal."""
|
||||
|
||||
def __init__(self, resp: Response, *args: object, value: Any | None = None) -> None:
|
||||
method, url = resp.request.method, resp.request.url
|
||||
data = f"{str(value)} to " if value is not None else ""
|
||||
super().__init__(
|
||||
f"Could not {method} {data}{url}. Code: {resp.status_code}. Reason: {resp.reason}.",
|
||||
*args,
|
||||
)
|
||||
|
||||
|
||||
class SmargonSignal(SocketSignal):
|
||||
"""Ophyd signal which gets and puts to a REST API rather than EPICS PVs, mediated through the SmargonController"""
|
||||
|
||||
def __init__(self, *args, axis_identifier: str, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
controller: SmargonController | None = getattr(self.root, "controller", None)
|
||||
if controller is None:
|
||||
raise TypeError("SmargonSignal must be used in a device with a SmargonController")
|
||||
self._controller = controller
|
||||
self._axis_id = axis_identifier
|
||||
self._controller.register(self._axis_id)
|
||||
|
||||
def _socket_get(self): # type: ignore
|
||||
self._readback, self.metadata["timestamp"] = self._controller.get_readback(
|
||||
self._axis_id
|
||||
) or (0.0, 0.0)
|
||||
return self._readback
|
||||
|
||||
def _socket_set(self, val: float):
|
||||
self._controller.put(self._axis_id, val)
|
||||
|
||||
def get(self):
|
||||
if self._controller.monitor_stopped():
|
||||
self._controller.start_monitor()
|
||||
return super().get()
|
||||
|
||||
|
||||
class SmargonController(OphydObject):
|
||||
class SmargonController(HttpDeviceController):
|
||||
"""Controller to consolidate polling loops and other REST calls for the smargon"""
|
||||
|
||||
_readback_endpoint = "/readbackSCS"
|
||||
_target_endpoint = "/targetSCS"
|
||||
|
||||
def __init__(self, *, prefix, **kwargs):
|
||||
self._prefix = prefix
|
||||
self._readback_endpoint = "/readbackSCS"
|
||||
self._target_endpoint = "/targetSCS"
|
||||
self._targets = {}
|
||||
self._signal_registry: set[str] = set()
|
||||
self._readback_poll_interval: float = _POLL_INTERVAL_SLOW
|
||||
|
||||
super().__init__(**kwargs)
|
||||
self._setup_readback()
|
||||
|
||||
def _setup_readback(self):
|
||||
self._readbacks: dict[str, float] = {}
|
||||
self._stop_monitor_readback_event = Event()
|
||||
self._readback_lock = RLock()
|
||||
self._monitor_readback_thread = Thread(
|
||||
target=self._monitor,
|
||||
args=[
|
||||
self._readback_endpoint,
|
||||
self._stop_monitor_readback_event,
|
||||
self._readback_lock,
|
||||
self._readbacks,
|
||||
],
|
||||
)
|
||||
|
||||
def _monitor(self, endpoint: str, event: Event, lock: RLock, buffer: dict):
|
||||
while not event.is_set():
|
||||
data = self._rest_get(endpoint)
|
||||
timestamp = time.monotonic()
|
||||
with lock:
|
||||
buffer.update(data)
|
||||
buffer["__timestamp"] = timestamp
|
||||
time.sleep(self._readback_poll_interval)
|
||||
|
||||
def _clean_monitor(self):
|
||||
if self._monitor_readback_thread.is_alive():
|
||||
self._stop_monitor_readback_event.set()
|
||||
self._monitor_readback_thread.join(timeout=2)
|
||||
if self._monitor_readback_thread.is_alive():
|
||||
raise RuntimeError("Failed to clean up Smargon monitor thread.")
|
||||
|
||||
def register(self, axis_id: str):
|
||||
self._signal_registry.add(axis_id)
|
||||
|
||||
def _rest_get(self, endpoint):
|
||||
resp = get(self._prefix + endpoint)
|
||||
if not resp.ok:
|
||||
raise HttpRestError(resp)
|
||||
return resp.json()
|
||||
|
||||
def _rest_put(self, val: dict[str, float]):
|
||||
resp = put(self._prefix + self._target_endpoint, params=val)
|
||||
if not resp.ok:
|
||||
raise HttpRestError(resp, value=val)
|
||||
|
||||
def start_monitor(self):
|
||||
"""Start or restart the automonitor thread."""
|
||||
self._clean_monitor()
|
||||
self._setup_readback()
|
||||
self._monitor_readback_thread.start()
|
||||
|
||||
def monitor_stopped(self):
|
||||
return not self._monitor_readback_thread.is_alive()
|
||||
super().__init__(prefix=prefix, **kwargs)
|
||||
|
||||
def get_readback(self, axis_id: str) -> tuple[float, float] | None:
|
||||
with self._readback_lock:
|
||||
@@ -125,34 +24,19 @@ class SmargonController(OphydObject):
|
||||
return self._readbacks.get(axis_id), self._readbacks.get(_TIMESTAMP_ID) # type: ignore
|
||||
|
||||
def put(self, axis: str, val: float):
|
||||
self._rest_put({axis: val})
|
||||
self._rest_put(params={axis: val})
|
||||
|
||||
def stop(self):
|
||||
# There doesn't appear to be a stop endpoint on the server
|
||||
# Best effort: set the target to the current position
|
||||
self._rest_put(self._readbacks)
|
||||
self._rest_put(params=self._readbacks)
|
||||
|
||||
|
||||
class Smargon(PSIDeviceBase):
|
||||
class Smargon(HttpOphydDevice):
|
||||
controller_class = SmargonController
|
||||
|
||||
x = Cpt(SmargonSignal, axis_identifier="SHX", tolerance=0.01)
|
||||
y = Cpt(SmargonSignal, axis_identifier="SHY", tolerance=0.01)
|
||||
z = Cpt(SmargonSignal, axis_identifier="SHZ", tolerance=0.01)
|
||||
phi = Cpt(SmargonSignal, axis_identifier="PHI", tolerance=0.01)
|
||||
chi = Cpt(SmargonSignal, axis_identifier="CHI", tolerance=0.01)
|
||||
|
||||
def __init__(
|
||||
self, *, name: str, prefix: str = "", scan_info=None, device_manager=None, **kwargs
|
||||
):
|
||||
self.controller = SmargonController(prefix=prefix)
|
||||
super().__init__(
|
||||
name=name, prefix=prefix, scan_info=scan_info, device_manager=device_manager, **kwargs
|
||||
)
|
||||
|
||||
def wait_for_connection(self, **kwargs): # type: ignore
|
||||
self.controller.start_monitor()
|
||||
return super().wait_for_connection(**kwargs)
|
||||
|
||||
def stop(self, *, success: bool = False) -> None:
|
||||
self.controller.stop()
|
||||
return super().stop(success=success)
|
||||
x = Cpt(HttpDeviceSignal, axis_identifier="SHX", tolerance=0.01)
|
||||
y = Cpt(HttpDeviceSignal, axis_identifier="SHY", tolerance=0.01)
|
||||
z = Cpt(HttpDeviceSignal, axis_identifier="SHZ", tolerance=0.01)
|
||||
phi = Cpt(HttpDeviceSignal, axis_identifier="PHI", tolerance=0.01)
|
||||
chi = Cpt(HttpDeviceSignal, axis_identifier="CHI", tolerance=0.01)
|
||||
|
||||
@@ -528,7 +528,7 @@ def save_data(hindex: int, device_name: str, signal_name: str):
|
||||
|
||||
|
||||
#########################################
|
||||
### just retried the saved data from csv
|
||||
### just retrieve the saved data from csv
|
||||
########################################
|
||||
def read_data(filename: str):
|
||||
"""
|
||||
@@ -536,6 +536,7 @@ def read_data(filename: str):
|
||||
|
||||
Args:
|
||||
filename (str): the csv file, eg, of a Scan
|
||||
e.g., dat = read_data("/home/e18747/SLS2/Data/gaps/gaps10.txt")
|
||||
"""
|
||||
|
||||
# dirname = '/home/gac-x10sa/Data/'
|
||||
@@ -548,6 +549,8 @@ def read_data(filename: str):
|
||||
|
||||
print("No of Rows =", rows)
|
||||
print("No of Colums =", cols)
|
||||
ind1 = 0
|
||||
ind2 = 1
|
||||
if cols > 2:
|
||||
print(
|
||||
"only first 2 colums (data[:, 0] and data[:, 1]) are plotted, please consider the other columns as well!"
|
||||
@@ -646,7 +649,7 @@ def getdiodepos(diode="i1"):
|
||||
diode_in = 1
|
||||
dpos = dev.diag_y.user_parameter["i1"] # 44 # mm
|
||||
|
||||
measdev = dev.scin_y
|
||||
measdev = dev.diag_y
|
||||
diodepos_rb = measdev.user_readback.get()
|
||||
if abs(dpos - diodepos_rb) > 0.1:
|
||||
print("Diode not in, please move")
|
||||
@@ -656,7 +659,7 @@ def getdiodepos(diode="i1"):
|
||||
detpos_diode = 214.5
|
||||
detpos_rb = dev.det_z.user_readback.get()
|
||||
print("using Det diode requires det up and close and beamstop out")
|
||||
if abs(detpos - detpos_rb) > 0.5:
|
||||
if abs(detpos_diode - detpos_rb) > 0.5:
|
||||
print("Diode not in, please move Det up")
|
||||
diode_in = 0 # sys.exit(0)
|
||||
|
||||
@@ -1298,7 +1301,7 @@ def detxeye_out():
|
||||
|
||||
def measure_samcam(zoom=1000):
|
||||
scinti_inpos = 38.6 # mm
|
||||
sc_rb = dev.scin_y.user_readback.get()
|
||||
sc_rb = dev.diag_y.user_readback.get()
|
||||
if abs(scinti_inpos - sc_rb) > 0.3:
|
||||
print("Scinti not in, please move")
|
||||
sys.exit(0)
|
||||
@@ -1483,7 +1486,7 @@ def scan_eg(erange, nsteps=50, fit=True):
|
||||
### open window/doch for long gap scan
|
||||
################################################
|
||||
#
|
||||
|
||||
### Note: all deprecated !!!!
|
||||
def scan_window(wname="Scan", fit=True):
|
||||
dock_area = bec.gui.new()
|
||||
# Add a new dock with a Waveform to the BECDockArea
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
from bec_lib.device import Signal, Positioner
|
||||
|
||||
def check():
|
||||
check_devices(tolerance = 0.02)
|
||||
|
||||
|
||||
|
||||
def check_devices(tolerance):
|
||||
devices = list(dev.items())
|
||||
for name, obj in devices:
|
||||
|
||||
try:
|
||||
data = obj.read()
|
||||
# deal with smargon
|
||||
if "smargon" in name:
|
||||
continue
|
||||
|
||||
actual = data[name]["value"]
|
||||
|
||||
# If signal and a camera or bpm, check reading is not 0
|
||||
if isinstance(obj, Signal):
|
||||
if 'cam' in name or 'bpm' in name:
|
||||
if actual == 0.0:
|
||||
print(f"{name} is reading 0")
|
||||
|
||||
# if signal is a motor, check in position, error, moving
|
||||
if isinstance(obj, Positioner):
|
||||
# Check set position = real position
|
||||
|
||||
sp_key = f"{name}_user_setpoint"
|
||||
|
||||
if sp_key not in data:
|
||||
continue
|
||||
|
||||
setpoint = data[sp_key]["value"]
|
||||
|
||||
diff = abs(actual - setpoint)
|
||||
inpos = diff <= tolerance
|
||||
if not inpos:
|
||||
print(
|
||||
f"{name}: "
|
||||
# f"actual={actual:.4f}, "
|
||||
# f"setpoint={setpoint:.4f}, "
|
||||
# f"diff={diff:.4f}, "
|
||||
f"in position = {inpos}"
|
||||
)
|
||||
# check if motor is in error state
|
||||
error_status = obj.motor_status.get()
|
||||
|
||||
if error_status != 0:
|
||||
print(f"{name}: error_state = {error_status}")
|
||||
|
||||
# check if motor is moving
|
||||
move_status = obj.motor_is_moving.get()
|
||||
if move_status != 0:
|
||||
print(f"{name} is moving")
|
||||
|
||||
|
||||
except Exception as exc:
|
||||
|
||||
print(f"{name}: ERROR -> {exc}")
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
""" "Initialises the sample environment devices, guards,
|
||||
dependencies and planner"""
|
||||
|
||||
# import yaml
|
||||
# from devices import build_devices
|
||||
# from guards import attach_guards
|
||||
# from policies import attach_policies
|
||||
|
||||
|
||||
def init_se_devices():
|
||||
"""Initialises the sample environment devices"""
|
||||
directory = "/sls/x10sa/config/bec/production/pxii_bec/pxii_bec/device_configs/"
|
||||
# directory = "./"
|
||||
filename = "se_devices.yaml"
|
||||
file = directory + filename
|
||||
print(f"Loading devices from {file}")
|
||||
se_devices = build_devices(file)
|
||||
attach_guards(se_devices)
|
||||
attach_policies(se_devices)
|
||||
|
||||
return se_devices
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
"""Set up the positioned devices"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Callable, List, Dict, Optional, Union
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass
|
||||
class PositionDevice:
|
||||
"""Generic device that moves between named or numeric positions"""
|
||||
|
||||
bec_name: str
|
||||
positions: Dict[str, float] = field(default_factory=dict)
|
||||
tol: float = 0.1
|
||||
|
||||
guards: List[Callable[[], None]] = field(default_factory=list)
|
||||
policy: Optional[Callable[[float], None]] = None
|
||||
|
||||
# line below defines if the device is permitted to move to any arbitrary position or not
|
||||
allow_arbitrary: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
# Use this for BEC
|
||||
self.mot = getattr(dev, self.bec_name)
|
||||
|
||||
# Use this for testing
|
||||
# self.mot = self.MockMotor()
|
||||
|
||||
# Normalize position names
|
||||
self.positions = {k.lower(): v for k, v in self.positions.items()}
|
||||
|
||||
# -------------------------
|
||||
# internal helpers
|
||||
# -------------------------
|
||||
|
||||
def _check_guards(self):
|
||||
for g in self.guards:
|
||||
g()
|
||||
|
||||
def _resolve_target(self, target: Union[str, float]) -> float:
|
||||
"""Convert target into a motor position"""
|
||||
|
||||
if isinstance(target, str):
|
||||
name = target.lower()
|
||||
|
||||
if name not in self.positions:
|
||||
raise ValueError(f"Unknown position '{target}'")
|
||||
|
||||
return self.positions[name]
|
||||
|
||||
if isinstance(target, (float, int)):
|
||||
if not self.allow_arbitrary:
|
||||
raise ValueError(f"{self.bec_name} only accepts named positions")
|
||||
return float(target)
|
||||
|
||||
raise TypeError("Target must be str or float")
|
||||
|
||||
# -------------------------
|
||||
# motion
|
||||
# -------------------------
|
||||
|
||||
def move(self, target: Union[str, float]):
|
||||
"""Unified move interface"""
|
||||
|
||||
pos = self._resolve_target(target)
|
||||
|
||||
self._check_guards()
|
||||
|
||||
if self.policy:
|
||||
self.policy(pos)
|
||||
|
||||
# Use for testing
|
||||
# self.mot.move(pos)
|
||||
|
||||
# Use in BEC
|
||||
scans.umv(self.mot, pos, relative=False)
|
||||
# s = scans.mv(self.mot, pos, relative=False)
|
||||
# s.wait(timeout=5)
|
||||
|
||||
# def set_position(self, target: Union[str, float]):
|
||||
# """Only to be used for testing purposes"""
|
||||
# pos = self._resolve_target(target)
|
||||
# self.mot.move(pos)
|
||||
|
||||
# -------------------------
|
||||
# readback
|
||||
# -------------------------
|
||||
|
||||
@property
|
||||
def actual(self) -> float:
|
||||
"""Return the actual position of the device."""
|
||||
return self.mot.read()[self.bec_name]["value"]
|
||||
# return self.mot.position
|
||||
|
||||
@property
|
||||
def pos(self) -> str:
|
||||
"""Return the closest matching position"""
|
||||
|
||||
for name, pos in self.positions.items():
|
||||
if abs(self.actual - pos) <= self.tol:
|
||||
return name
|
||||
|
||||
return "unknown"
|
||||
|
||||
def is_at(self, position: str) -> bool:
|
||||
"""Return True if the device is at the given position."""
|
||||
position = position.lower()
|
||||
|
||||
if position not in self.positions:
|
||||
raise ValueError(f"Unknown position '{position}'")
|
||||
|
||||
return abs(self.actual - self.positions[position]) <= self.tol
|
||||
|
||||
# -------------------------
|
||||
# Mock Motor Implementation
|
||||
# -------------------------
|
||||
|
||||
class MockMotor:
|
||||
"""Mock implementation of MotorLike for testing and initialization."""
|
||||
|
||||
def __init__(self):
|
||||
self.position = 0.0
|
||||
|
||||
def move(self, value: float):
|
||||
"""Move the motor to the given position."""
|
||||
self.position = value
|
||||
|
||||
def read(self):
|
||||
"""Read the current position of the motor."""
|
||||
return {"value": self.position}
|
||||
|
||||
|
||||
def build_devices(yaml_file):
|
||||
"""Takes the defined positions from the device yaml file
|
||||
and adds them to the PositionDevice class.
|
||||
"""
|
||||
# discrete_devs = []
|
||||
# continuous_devs = []
|
||||
se_devices = {}
|
||||
|
||||
with open(yaml_file, encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
for bec_name, cfg in data.items():
|
||||
# Skip devices without userParameter
|
||||
user = cfg.get("userParameter")
|
||||
|
||||
if not user:
|
||||
continue
|
||||
|
||||
tol = user.get("tol", 0.1)
|
||||
|
||||
positions = {k: v for k, v in user.items() if k not in ("type", "tol")}
|
||||
|
||||
if user["type"] == "discrete":
|
||||
dev = PositionDevice(bec_name, positions, tol=tol, allow_arbitrary=False)
|
||||
# discrete_devs.append(bec_name)
|
||||
se_devices[bec_name] = dev
|
||||
elif user["type"] == "continuous":
|
||||
dev = PositionDevice(bec_name, positions, tol=tol, allow_arbitrary=True)
|
||||
# continuous_devs.append(bec_name)
|
||||
se_devices[bec_name] = dev
|
||||
|
||||
# print(f"Discrete devices: {discrete_devs}")
|
||||
# print(f"Continuous: {continuous_devs}")
|
||||
return se_devices
|
||||
@@ -0,0 +1,95 @@
|
||||
"""Setup guards for devices."""
|
||||
|
||||
|
||||
class GuardViolation(Exception):
|
||||
"""Raised when a guarded move is not allowed."""
|
||||
|
||||
|
||||
class AtPositionGuard:
|
||||
"""Guard that checks if a device is in a specific position."""
|
||||
|
||||
def __init__(self, device, position):
|
||||
self.device = device
|
||||
self.pos = position
|
||||
|
||||
def check(self):
|
||||
"""Check if the device is in the specified position."""
|
||||
if self.device.pos != self.pos:
|
||||
raise GuardViolation(
|
||||
f"{self.device.bec_name} must be in the '{self.pos}' position"
|
||||
)
|
||||
# print("move allowed")
|
||||
return True
|
||||
|
||||
def requirement(self):
|
||||
"""Return the requirement for the guard."""
|
||||
return (self.device.bec_name, self.pos)
|
||||
|
||||
|
||||
class MinMaxGuard:
|
||||
"""Guard that checks if a device is within a specific range."""
|
||||
|
||||
def __init__(self, device, limit_value, direction):
|
||||
self.device = device
|
||||
self.limit_value = limit_value
|
||||
self.direction = direction # direction: 'max' or 'min'
|
||||
|
||||
def check(self):
|
||||
"""Check if the device is within the specified range."""
|
||||
if self.direction == "less_than":
|
||||
if not (self.device.actual - self.device.tol) <= self.limit_value:
|
||||
raise GuardViolation(
|
||||
f"{self.device.bec_name} must be less than or equal to {self.limit_value} mm"
|
||||
)
|
||||
elif self.direction == "more_than":
|
||||
if not (self.device.actual + self.device.tol) >= self.limit_value:
|
||||
raise GuardViolation(
|
||||
f"{self.device.bec_name} must be greater than or equal to {self.limit_value} mm"
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Invalid direction '{self.direction}'. Use 'less_than' or 'more_than'."
|
||||
)
|
||||
|
||||
# print("move allowed")
|
||||
return True
|
||||
|
||||
def requirement(self):
|
||||
"""Return the requirement for the guard."""
|
||||
# planner cannot handle numeric constraints directly
|
||||
# return None -> planner ignores
|
||||
return None
|
||||
|
||||
|
||||
def guards_setup(d):
|
||||
"""Define guards for devices."""
|
||||
guards = {}
|
||||
guards["bs_safe"] = AtPositionGuard(d["bs_z"], position="safe")
|
||||
guards["bs_max_blin"] = MinMaxGuard(
|
||||
d["bs_z"], direction="less_than", limit_value=d["bs_z"].positions["max_blin"]
|
||||
)
|
||||
guards["bs_work_min"] = MinMaxGuard(
|
||||
d["bs_z"], direction="more_than", limit_value=d["bs_z"].positions["work_min"]
|
||||
)
|
||||
guards["bs_pos_in"] = AtPositionGuard(d["bs_pos"], position="in")
|
||||
guards["gonx_out"] = MinMaxGuard(
|
||||
d["gon_x"], direction="less_than", limit_value=d["gon_x"].positions["out"]
|
||||
)
|
||||
guards["gonx_safe"] = AtPositionGuard(d["gon_x"], position="safe")
|
||||
guards["diag_y_out"] = MinMaxGuard(
|
||||
d["diag_y"], direction="less_than", limit_value=d["diag_y"].positions["out"]
|
||||
)
|
||||
guards["coll_y_out"] = MinMaxGuard(
|
||||
d["coll_y"], direction="less_than", limit_value=d["coll_y"].positions["out"]
|
||||
)
|
||||
return guards
|
||||
|
||||
|
||||
def attach_guards(d):
|
||||
"""Attach guards to devices."""
|
||||
g = guards_setup(d)
|
||||
d["diag_y"].guards.append(g["bs_work_min"].check)
|
||||
d["bl_pos"].guards.append(g["bs_max_blin"].check)
|
||||
d["bs_pos"].guards.append(g["bs_safe"].check)
|
||||
d["bs_z"].guards.append(g["bs_pos_in"].check)
|
||||
d["coll_y"].guards.append(g["bs_work_min"].check)
|
||||
@@ -172,13 +172,12 @@ def select_bec_window(dock_area_name="Fitting"):
|
||||
open_docks = bec.gui.windows
|
||||
if open_docks.get(dock_area_name) is None:
|
||||
dock_area = bec.gui.new(dock_area_name)
|
||||
wf = dock_area.new("Plot").new(bec.gui.available_widgets.Waveform)
|
||||
text_box = dock_area.new("Results", position="bottom").new(
|
||||
widget=bec.gui.available_widgets.TextBox
|
||||
)
|
||||
# wf = dock_area.new("Plot").new(bec.gui.available_widgets.Waveform)
|
||||
wf = dock_area.new(widget='Waveform', object_name='Plot')
|
||||
text_box = dock_area.new(widget='TextBox', object_name="Results", where="bottom")
|
||||
else:
|
||||
wf = bec.gui.Fitting.Plot.Waveform
|
||||
text_box = bec.gui.Fitting.Results.TextBox
|
||||
wf = bec.gui.Fitting.Plot
|
||||
text_box = bec.gui.Fitting.Results
|
||||
return wf, text_box
|
||||
|
||||
|
||||
@@ -208,7 +207,7 @@ def plot_live_data_bec(
|
||||
wf.title = "Scan: Live scan"
|
||||
wf.x_label = motor_name
|
||||
wf.y_label = signal_name
|
||||
wf.plot(x_name=motor_name, y_name=signal_name)
|
||||
wf.plot(device_x=motor_name, device_y=signal_name)
|
||||
|
||||
|
||||
def plot_fitted_data_bec(
|
||||
@@ -248,6 +247,6 @@ def plot_fitted_data_bec(
|
||||
wf.y_label = data["signal_name"]
|
||||
wf.plot(x=data["x_data"], y=data["y_to_fit"], label="Data")
|
||||
wf.plot(x=fit_result["fit_xdata"], y=fit_result["fit_ydata"], label="Fit")
|
||||
wf.Fit.set(symbol_size = 0)
|
||||
|
||||
# wf.Fit.set(symbol_size = 0)
|
||||
wf.get_curve('Fit').set(symbol_size=0)
|
||||
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
"""Planner to move between beamline states"""
|
||||
from enum import Enum
|
||||
import yaml
|
||||
from collections import defaultdict, deque
|
||||
|
||||
|
||||
class BeamlineState(str, Enum):
|
||||
ROBOT_SAMPLE_EXCHANGE = "robot_sample_exchange"
|
||||
SAMPLE_ALIGNMENT = "sample_alignment"
|
||||
DATA_COLLECTION = "data_collection"
|
||||
DC_XRF = "DC_XRF"
|
||||
MANUAL_SAMPLE_EXCHANGE = "manual_sample_exchange"
|
||||
BEAM_VISUALISATION = "beam_visualisation"
|
||||
FLUX_MEASUREMENT = "flux_measurement"
|
||||
BEAMSTOP_ALIGNMENT = "beamstop_alignment"
|
||||
MAINTENANCE = "maintenance"
|
||||
XTAL_SNAPSHOT = "xtal_snapshot"
|
||||
|
||||
class TemperatureMode(str, Enum):
|
||||
CRYO = "cryo"
|
||||
ROOM_TEMP = "room_temp"
|
||||
|
||||
def get_states():
|
||||
"""Returns the states defined in beamline_states.yaml"""
|
||||
directory = "/sls/x10sa/config/bec/production/pxii_bec/pxii_bec/device_configs/"
|
||||
# directory = "./"
|
||||
filename = "beamline_states.yaml"
|
||||
file = directory + filename
|
||||
with open(file, "r", encoding="utf-8") as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
states = {}
|
||||
allow_modifiers = {}
|
||||
|
||||
for name, config in cfg["states"].items():
|
||||
state = BeamlineState(name)
|
||||
|
||||
allow_modifiers[state] = config.pop("allow_modifiers", False)
|
||||
|
||||
states[state] = config
|
||||
|
||||
return states, allow_modifiers
|
||||
|
||||
# cfg = yaml.safe_load(f)
|
||||
# return {
|
||||
# BeamlineState(name): config
|
||||
# for name, config in cfg["states"].items()
|
||||
# }
|
||||
|
||||
|
||||
class StateManager:
|
||||
"""Moves devices to the correct positions to achieve a given state"""
|
||||
|
||||
def __init__(self,
|
||||
devices,
|
||||
states: dict[BeamlineState, dict[str, str]],
|
||||
allow_modifiers=None,
|
||||
deps=None,
|
||||
debug=False,
|
||||
):
|
||||
self.devices = devices
|
||||
self.states = states
|
||||
self.allow_modifiers = allow_modifiers or {}
|
||||
self.deps = deps
|
||||
self.debug = debug
|
||||
|
||||
self.modifiers = {
|
||||
TemperatureMode.CRYO: {"cryo_pos": "in"},
|
||||
TemperatureMode.ROOM_TEMP: {"cryo_pos": "out"},
|
||||
}
|
||||
|
||||
def _merged_state(self, state, modifier):
|
||||
target = dict(self.states[state])
|
||||
|
||||
if modifier:
|
||||
if isinstance(modifier, str):
|
||||
modifier = TemperatureMode(modifier)
|
||||
|
||||
if self.allow_modifiers.get(state, False):
|
||||
target.update(self.modifiers[modifier])
|
||||
return target
|
||||
|
||||
def move_to(self, state_name, modifier=None):
|
||||
"""Move devices to the correct positions to achieve a given state"""
|
||||
if isinstance(state_name, str):
|
||||
state_name = BeamlineState(state_name)
|
||||
target = self._merged_state(state_name, modifier)
|
||||
|
||||
plan = self._plan(target)
|
||||
|
||||
print("PLAN:")
|
||||
for i, stage in enumerate(plan):
|
||||
print(f"Stage {i + 1}: {stage}")
|
||||
|
||||
for stage in plan:
|
||||
for dev, pos in stage:
|
||||
d = self.devices[dev]
|
||||
if not d.is_at(pos):
|
||||
|
||||
if self.debug:
|
||||
print(f"→ Moving {dev} -> {pos}")
|
||||
# print(" Before:", self.get_states())
|
||||
|
||||
try:
|
||||
d.move(pos)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Exception occurred: {e}")
|
||||
print(f"\nFAILED MOVE: {dev} -> {pos}")
|
||||
print("States at failure:", self.get_positions())
|
||||
raise
|
||||
|
||||
# if self.debug:
|
||||
# print(" After :", self.get_states())
|
||||
# if not d.is_at(pos):
|
||||
# d.move(pos)
|
||||
|
||||
# def reset(self, state):
|
||||
# """Reset all devices to the given state"""
|
||||
# if isinstance(state, str):
|
||||
# state = BeamlineState(state)
|
||||
# for dev, pos in self.states[state].items():
|
||||
# self.devices[dev].set_pos(pos)
|
||||
|
||||
def available_states(self):
|
||||
"""Return a list of available states"""
|
||||
return list(self.states.keys())
|
||||
|
||||
def get_positions(self):
|
||||
"""Return current positions of all SE devices"""
|
||||
return {name: dev.pos for name, dev in self.devices.items()}
|
||||
|
||||
def print_positions(self):
|
||||
"""Return current state of all devices"""
|
||||
for name, device in self.devices.items():
|
||||
print(f"{name:10s} : {device.pos}")
|
||||
|
||||
def diff_states(self, before):
|
||||
"""Return a dict of {device: (before, after)} pairs for devices that changed state"""
|
||||
after = self.get_positions()
|
||||
return {k: (before[k], after[k]) for k in before if before[k] != after[k]}
|
||||
|
||||
def current_state(self):
|
||||
"""Return all current matching BeamlineState and TemperatureMode combinations,
|
||||
prioritizing non-None modifiers first."""
|
||||
matches = [] # Store all matching (state, modifier) pairs
|
||||
ignore_keys = {"bl_bright", "fl_bright"}
|
||||
|
||||
for state in self.states:
|
||||
# Start with prioritized modifiers: Non-None first, then None.
|
||||
modifiers = list(self.modifiers.keys())
|
||||
modifiers.append(None) # Add `None` as a fallback after real modifiers.
|
||||
|
||||
for modifier in modifiers:
|
||||
# Combine state and modifier to get full configuration
|
||||
config = self._merged_state(state, modifier)
|
||||
|
||||
# Check if all devices match their expected positions
|
||||
if all(self.devices[d].is_at(p)
|
||||
for d, p in config.items()
|
||||
if d not in ignore_keys
|
||||
):
|
||||
# print(f"Current state: {state.name}, Modifier: {modifier.name if modifier else 'None'}")
|
||||
matches.append((state.name, modifier.name if modifier else 'None'))
|
||||
|
||||
return matches if matches else None
|
||||
|
||||
|
||||
|
||||
def is_state(self, state, modifier=None):
|
||||
"""Check if the current state matches the given state and modifier."""
|
||||
actual = self.current_state()
|
||||
if not actual:
|
||||
return False
|
||||
|
||||
if modifier is None:
|
||||
# match any modifier
|
||||
return any(s == state.name for s, _ in actual)
|
||||
|
||||
return (state.name, modifier.name) in actual
|
||||
|
||||
def _plan(self, target):
|
||||
|
||||
graph = defaultdict(set)
|
||||
indeg = defaultdict(int)
|
||||
nodes = set()
|
||||
|
||||
for dev, pos in target.items():
|
||||
node = (dev, pos)
|
||||
nodes.add(node)
|
||||
|
||||
for dep in self.deps.get(node, []):
|
||||
graph[dep].add(node)
|
||||
indeg[node] += 1
|
||||
nodes.add(dep)
|
||||
|
||||
q = deque(n for n in nodes if indeg[n] == 0)
|
||||
stages = []
|
||||
|
||||
while q:
|
||||
stage = list(q)
|
||||
stages.append(stage)
|
||||
q.clear()
|
||||
|
||||
for n in stage:
|
||||
for m in graph[n]:
|
||||
indeg[m] -= 1
|
||||
if indeg[m] == 0:
|
||||
q.append(m)
|
||||
|
||||
if sum(len(s) for s in stages) != len(nodes):
|
||||
raise RuntimeError("Circular dependency in state dependencies")
|
||||
return stages
|
||||
|
||||
|
||||
def planner_deps():
|
||||
"""Define the dependencies between beamline positions"""
|
||||
return {
|
||||
("bs_z", "samp"): [
|
||||
("gon_x", "out"),
|
||||
("diag_y", "out"),
|
||||
("coll_y", "out"),
|
||||
],
|
||||
("gon_x", "in"): [
|
||||
("diag_y", "out"),
|
||||
("bs_z", "safe"),
|
||||
],
|
||||
("diag_y", "scint"): [
|
||||
("gon_x", "out"),
|
||||
("cryo_pos", "out")
|
||||
],
|
||||
("diag_y", "i1"): [
|
||||
("gon_x", "out"),
|
||||
("cryo_pos", "out")],
|
||||
("bs_pos", "out"): [("bs_z", "safe")],
|
||||
("bs_pos", "in"): [("bs_z", "safe")],
|
||||
("diag_y", "out"): [("bs_z", "safe")],
|
||||
("diag_y", "park"): [("bs_z", "safe")],
|
||||
("coll_y", "out"): [("bs_z", "safe")],
|
||||
("coll_y", "park"): [("bs_z", "safe")],
|
||||
("coll_y", "in"): [("bs_z", "safe")],
|
||||
("coll_y", "intermediate"): [("bs_z", "safe")]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
'''Define guard policies for devices in the beamline.'''
|
||||
# from guards import GuardViolation, guards_setup
|
||||
|
||||
|
||||
def is_sample_area_clear_for_beamstop(d):
|
||||
'''Check if the sample area is clear of diag_y, coll_y, and gonx'''
|
||||
g = guards_setup(d)
|
||||
if g["diag_y_out"].check() and g["coll_y_out"].check() and g["gonx_out"].check():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_sample_area_clear_for_gonx(d):
|
||||
'''Check if the sample area is clear of diag_y and bs_z'''
|
||||
g = guards_setup(d)
|
||||
if g["diag_y_out"].check() and g["bs_work_min"].check():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def make_gon_x_policy(d):
|
||||
'''Create the policy for gon_x'''
|
||||
def gon_x_policy(target):
|
||||
cfg = d["gon_x"].positions
|
||||
if target >= cfg["out"] and not is_sample_area_clear_for_gonx(d):
|
||||
raise GuardViolation("Sample area is not clear")
|
||||
|
||||
return gon_x_policy
|
||||
|
||||
|
||||
def make_bs_z_policy(d):
|
||||
'''Create the policy for bs_z'''
|
||||
def bs_z_policy(target):
|
||||
"""Checks that the target position is within limits"""
|
||||
cfg = d["bs_z"].positions
|
||||
# Lower bound
|
||||
if target < cfg["work_min"] and not is_sample_area_clear_for_beamstop(d):
|
||||
raise GuardViolation("Sample area is not clear")
|
||||
if target < cfg["min"]:
|
||||
raise GuardViolation(
|
||||
f"Requested beamstop Z {target} is below recommended minimum {cfg['min']}"
|
||||
)
|
||||
# Upper bound
|
||||
if d["bl_pos"].pos == "in" and target > cfg["max_blin"]:
|
||||
raise GuardViolation(
|
||||
f"Beamstop Z cannot move beyond {cfg['max_blin']} when backlight is IN"
|
||||
)
|
||||
|
||||
return bs_z_policy
|
||||
|
||||
|
||||
def make_diag_y_policy(d):
|
||||
'''Create the policy for diag_y'''
|
||||
def diag_y_policy(target):
|
||||
cfg = d["diag_y"].positions
|
||||
# Don't move in if the goniometer is >= 'in'
|
||||
if d["gon_x"].actual >= d["gon_x"].positions["in"] and target > cfg['out']:
|
||||
raise GuardViolation(
|
||||
f"Diagnostic device cannot move beyond {cfg['out']} mm when goniometer is not OUT"
|
||||
)
|
||||
if d['cryo_pos'].pos == "in" and target > cfg["out"]:
|
||||
raise GuardViolation(
|
||||
f"Diagnostic device cannot move beyond {cfg['out']} mm when cryo is IN"
|
||||
)
|
||||
|
||||
return diag_y_policy
|
||||
|
||||
|
||||
def attach_policies(d):
|
||||
'''Attach the policies to the devices'''
|
||||
d["bs_z"].policy = make_bs_z_policy(d)
|
||||
d["gon_x"].policy = make_gon_x_policy(d)
|
||||
d["diag_y"].policy = make_diag_y_policy(d)
|
||||
@@ -1,280 +0,0 @@
|
||||
"""Guards for preventing clashing devices in
|
||||
the sample environment"""
|
||||
|
||||
# PD_guards2.py
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Callable, List, Dict
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Exceptions
|
||||
# ----------------------------
|
||||
|
||||
|
||||
class GuardViolation(RuntimeError):
|
||||
"""Raised when a guarded move is not allowed."""
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Guarded axis
|
||||
# ----------------------------
|
||||
|
||||
|
||||
class GuardedAxis:
|
||||
""" Motor axis protected by guard policy """
|
||||
def __init__(
|
||||
self,
|
||||
bec_name: str,
|
||||
policy: Callable[[float], None],
|
||||
config: Dict[str, float] = None
|
||||
):
|
||||
self.bec_name = bec_name
|
||||
self.policy = policy
|
||||
self.config = config or {}
|
||||
self.mot = getattr(dev, self.bec_name)
|
||||
|
||||
@property
|
||||
def actual(self) -> float:
|
||||
"""Returns the current motor position"""
|
||||
return self.mot.read()[self.bec_name]["value"]
|
||||
|
||||
def move(self, target: float):
|
||||
"""Used to move a guarded axis to a target value"""
|
||||
self.policy(target) # must raise if disallowed
|
||||
scans.umv(self.mot, target, relative=False)
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Positioned device (IN / OUT)
|
||||
# ----------------------------
|
||||
|
||||
|
||||
@dataclass
|
||||
class PositionedDevice:
|
||||
"""Applies to devices that only have IN and OUT positions
|
||||
Guards are defined by guard rules to ensure their safe operation"""
|
||||
|
||||
bec_name: str
|
||||
inpos: float
|
||||
outpos: float
|
||||
tol: float = 0.01
|
||||
guards: List[Callable[[], None]] = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
self.mot = getattr(dev, self.bec_name)
|
||||
|
||||
def _check_guards(self):
|
||||
for g in self.guards:
|
||||
g()
|
||||
|
||||
def mvin(self):
|
||||
"""Move a positioned device to IN position"""
|
||||
self._check_guards()
|
||||
scans.umv(self.mot, self.inpos, relative=False)
|
||||
|
||||
def mvout(self):
|
||||
"""Move a positioned device to OUT position"""
|
||||
self._check_guards()
|
||||
scans.umv(self.mot, self.outpos, relative=False)
|
||||
|
||||
def is_in(self):
|
||||
"""Returns true if the device is IN"""
|
||||
return abs(self.mot.read()[self.bec_name]["value"] - self.inpos) <= self.tol
|
||||
|
||||
def is_out(self):
|
||||
"""Returns true if the device is OUT"""
|
||||
return abs(self.mot.read()[self.bec_name]["value"] - self.outpos) <= self.tol
|
||||
|
||||
|
||||
@dataclass
|
||||
class MultiPositionDevice:
|
||||
""" Devices that have multiple defined positions. Guards rules are defined to
|
||||
ensure their safe operation"""
|
||||
bec_name: str
|
||||
positions: Dict[str, float] # {"out": 0.0, "scint": 10.0, "i1": 20.0}
|
||||
tol: float = 0.01
|
||||
guards: List[Callable[[], None]] = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
self.mot = getattr(dev, self.bec_name)
|
||||
|
||||
def _check_guards(self):
|
||||
"""Check guard conditions"""
|
||||
for g in self.guards:
|
||||
g()
|
||||
|
||||
def move_to(self, state: str):
|
||||
"""Move to one of the states defined in self.positions"""
|
||||
if state not in self.positions:
|
||||
raise ValueError(f"Unknown state '{state}'")
|
||||
|
||||
self._check_guards()
|
||||
scans.umv(self.mot, self.positions[state], relative=False)
|
||||
|
||||
def is_at(self, state: str) -> bool:
|
||||
"""Check if device is at a given state"""
|
||||
if state not in self.positions:
|
||||
raise ValueError(f"Unknown state '{state}'")
|
||||
|
||||
return abs(self.mot.read()[self.bec_name]["value"] - self.positions[state]) <= self.tol
|
||||
|
||||
@property
|
||||
def actual(self) -> float:
|
||||
"""Returns current motor position"""
|
||||
return self.mot.read()[self.bec_name]["value"]
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Returns current state"""
|
||||
for name, pos in self.positions.items():
|
||||
if abs(self.mot.read()[self.bec_name]["value"] - pos) <= self.tol:
|
||||
return name
|
||||
return "unknown"
|
||||
|
||||
def is_clear(self):
|
||||
"""Returns true if device is at OUT or below e.g. PARK"""
|
||||
if "out" not in self.positions:
|
||||
raise ValueError("MultiPosition device requires 'out' state")
|
||||
return self.actual < (self.positions["out"] + self.tol)
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# PD namespace (filled at runtime)
|
||||
# ----------------------------
|
||||
|
||||
|
||||
class PD:
|
||||
"""Populated when the PD devices are initialised"""
|
||||
pass
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Guard rules for BS_Z
|
||||
# ----------------------------
|
||||
# BS positioner must be in for BS_Z to move
|
||||
def bs_z_requires_bs_pos_in():
|
||||
"""Cannot move bs_z unless the BS positioner is in"""
|
||||
if not PD.bs_pos.is_in():
|
||||
raise GuardViolation("BS_Z cannot move unless beamstop positioner is IN")
|
||||
|
||||
def bs_z_range_check(target):
|
||||
"""Checks that the target position is within limits"""
|
||||
cfg = PD.bs_z.config
|
||||
|
||||
# Lower bound
|
||||
if target < cfg["work_min"] and not is_sample_area_clear(beamstop=True):
|
||||
raise GuardViolation(
|
||||
f"Requested beamstop Z {target} is below working range minimum {cfg['work_min']}"
|
||||
)
|
||||
if target < cfg["min"]:
|
||||
raise GuardViolation(
|
||||
f"Requested beamstop Z {target} is below absolute minimum {cfg['min']}"
|
||||
)
|
||||
|
||||
# Maximum position depend on backlight position
|
||||
if PD.bl_pos.is_in():
|
||||
if target > cfg["max_blin"]:
|
||||
raise GuardViolation(
|
||||
f"Requested beamstop Z value of {target} mm exceeds maximum allowed"
|
||||
f"value of {cfg['max_blin']} while backlight is IN"
|
||||
)
|
||||
else:
|
||||
if target > cfg["max_blout"]:
|
||||
raise GuardViolation(
|
||||
f"Requested beamstop Z value of {target} mm exceeds maximum allowed "
|
||||
f"value of {cfg['max_blout']} mm"
|
||||
)
|
||||
|
||||
|
||||
def is_sample_area_clear(beamstop=True):
|
||||
"""Check if the sample area is clear, raising GuardViolation if constraints are not met."""
|
||||
if beamstop:
|
||||
# Check collimator, and diagnostic device positions
|
||||
if not PD.coll_y.is_clear():
|
||||
raise GuardViolation("Sample area is not clear: Collimator is IN")
|
||||
if not PD.diag_y.is_clear():
|
||||
raise GuardViolation("Sample area is not clear: Diagnostic device is IN")
|
||||
|
||||
# Validate goniometer position
|
||||
if not abs(PD.gon_x.actual - PD.gon_x.config["out"]) < PD.gon_x.config["tol"]:
|
||||
raise GuardViolation("Sample area is not clear: Goniometer is IN")
|
||||
else:
|
||||
# Check that diagnostic (scintillator/i1) device is out
|
||||
if not PD.diag_y.is_clear():
|
||||
raise GuardViolation("Sample are is not clear: Diagnostic device is IN")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def bs_z_policy(target):
|
||||
"""Defines the policy for bs_z operation"""
|
||||
# Beamstop z can only move when the positioner is in
|
||||
bs_z_requires_bs_pos_in()
|
||||
|
||||
# Check the allowed range for bs_z
|
||||
bs_z_range_check(target)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def gon_x_policy(target):
|
||||
"""Defines the policy for gon_x operation"""
|
||||
is_sample_area_clear(beamstop=False)
|
||||
bs_z_above_work_min()
|
||||
return True
|
||||
|
||||
|
||||
def bs_pos_requires_bs_z_safe():
|
||||
"""bs_pos can only move when bs_z is at the safe position"""
|
||||
safe = PD.bs_z.config["safe"]
|
||||
actual = PD.bs_z.actual
|
||||
tol = 0.1
|
||||
|
||||
if abs(actual - safe) > tol:
|
||||
raise GuardViolation(f"Beamstop positioner can only move when BS_Z is at {safe} mm")
|
||||
|
||||
|
||||
def bs_z_above_work_min():
|
||||
"""work_min specifies the minimum bs_z value that is
|
||||
outside of the sample area i.e. no clashes with diagnostic
|
||||
device or collimator"""
|
||||
work_min = PD.bs_z.config["work_min"]
|
||||
if PD.bs_z.actual < work_min:
|
||||
raise GuardViolation(f"BS_Z must be greater than {work_min} mm")
|
||||
|
||||
|
||||
def bs_z_below_max_blin():
|
||||
"""Maximum bs_z vale when the backlight is in"""
|
||||
max_blin = PD.bs_z.config["max_blin"]
|
||||
if PD.bs_z.actual > max_blin:
|
||||
raise GuardViolation(f"BS_Z must be less than {max_blin} mm")
|
||||
|
||||
|
||||
def gonio_is_out():
|
||||
"""Maximum bs_z value when the backlight is out"""
|
||||
if not abs(PD.gon_x.actual - PD.gon_x.config["out"]) < PD.gon_x.config["tol"]:
|
||||
raise GuardViolation(f"Goniometer must be OUT ({PD.gon_x.config['out']} mm)")
|
||||
|
||||
|
||||
def get_policy_for_axis(bec_name):
|
||||
"""Specify the policy for guarded axis"""
|
||||
policy_registry = {"bs_z": bs_z_policy, "gon_x": gon_x_policy}
|
||||
return policy_registry.get(bec_name, lambda target: True)
|
||||
|
||||
|
||||
def init_collision_guards():
|
||||
"""Add the guard rules for positioned devices"""
|
||||
PD.bs_pos.guards.append(bs_pos_requires_bs_z_safe)
|
||||
PD.bl_pos.guards.append(bs_z_below_max_blin)
|
||||
PD.coll_y.guards.append(bs_z_above_work_min)
|
||||
PD.diag_y.guards.append(bs_z_above_work_min)
|
||||
PD.diag_y.guards.append(gonio_is_out)
|
||||
PD.diag_y.guards.append(bs_z_requires_bs_pos_in)
|
||||
|
||||
|
||||
def init_positioned_devices():
|
||||
"""Initialises the positioned devices"""
|
||||
file = "/sls/x10sa/config/bec/production/pxii_bec/pxii_bec/device_configs/pxii-autogenerated.yaml"
|
||||
build_pd(file)
|
||||
init_collision_guards()
|
||||
print(f"Defined positions for devices have been updated from {file}")
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
"""File to store beamline parameters and defaults"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Callable
|
||||
import numpy as np
|
||||
import yaml
|
||||
|
||||
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EnergyDefaults:
|
||||
"""Parameters for PXII energy changes"""
|
||||
|
||||
min_energy_change = 1
|
||||
min_energy_ev = 4800
|
||||
max_energy_ev = 30002
|
||||
beam_offset = 6
|
||||
signals = {"sig1": dev.lu_bpmsum, "sig2": dev.bsc_bpmsum, "sig3": dev.bcu_bpmsum}
|
||||
energy = dev.dcm_bragg
|
||||
mono_pitch = dev.dcm_pitch
|
||||
mono_perp = dev.dcm_perp
|
||||
mono_roll = dev.dcm_froll
|
||||
mono_roll_value = 4.65
|
||||
LUT_table = "luts/energy_lut.csv"
|
||||
stripe_thresholds = {"silicon": 9000, "rhodium": 20000, "platinum": 40000}
|
||||
pitch_scan = {"halfwidth": 0.075, "steps": 20}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Calibration:
|
||||
"""Calibration parameters for PXII optics"""
|
||||
|
||||
pitch = np.array([4.61823701e-14, -1.97330772e-09, 2.89694543e-05, -5.34468669e00])
|
||||
roll = np.array([2.28291039e-03, -2.41928101e01])
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Gap:
|
||||
"""Fit parameters to calculate gap from harmonics"""
|
||||
|
||||
harmonics = {
|
||||
"H3": np.array([9.15e-04, 4.49e-01]),
|
||||
"H5": np.array([5.19e-04, 7.149e-01]),
|
||||
"H7": np.array([3.57694643e-04, 8.73775476e-01]),
|
||||
"H9": np.array([2.76335714e-04, 8.98471905e-01]),
|
||||
"H11": np.array([2.2225e-04, 9.582e-01]),
|
||||
"H13": np.array([1.9e-4, 9.262e-01]),
|
||||
"H15": np.array([1.67e-4, 8.83e-01]),
|
||||
}
|
||||
# Define harmonic ranges as a constant
|
||||
harmonic_ranges = {
|
||||
"H3": (4900, 7000),
|
||||
"H5": (7000, 10000),
|
||||
"H7": (10000, 13000),
|
||||
"H9": (13000, 16000),
|
||||
"H11": (16000, 19000),
|
||||
"H13": (19000, 22000),
|
||||
"H15": (22000, float("inf")),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_harmonic_by_energy(energy_ev: float):
|
||||
"""
|
||||
Determines the harmonic key based on the provided energy.
|
||||
|
||||
Args:
|
||||
energy_ev (float): The energy value (eV).
|
||||
|
||||
Returns:
|
||||
Optional[str]: The harmonic name (e.g., 'H3', 'H7')
|
||||
if the range matches, None otherwise.
|
||||
"""
|
||||
for harmonic, (low, high) in Gap.harmonic_ranges.items():
|
||||
if low < energy_ev <= high:
|
||||
return harmonic
|
||||
return None
|
||||
|
||||
def get_harmonic_values(self, energy_ev: float):
|
||||
"""
|
||||
Retrieves the harmonic array based on the energy value.
|
||||
|
||||
Args:
|
||||
energy_ev (float): The energy value (eV).
|
||||
|
||||
Returns:
|
||||
Optional[np.array]: The corresponding array of harmonic values
|
||||
if the range matches, None otherwise.
|
||||
"""
|
||||
harmonic = self.get_harmonic_by_energy(energy_ev)
|
||||
return self.harmonics.get(harmonic) if harmonic else None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Harmonics:
|
||||
"""Anuschka's harmonics data for PXII U19 Undulator"""
|
||||
|
||||
min_gap_value = 4.5
|
||||
map = {
|
||||
3: np.array([1.07141725, -0.52834258]),
|
||||
4: np.array([0.007111, -0.13678409, 1.52295567, -1.06882785]),
|
||||
5: np.array([0.00315051, -0.0766359, 1.13107469, -0.86442062]),
|
||||
6: np.array([0.00162862, -0.04452336, 0.82948259, -0.37329674]),
|
||||
7: np.array([0.00080764, -0.02418882, 0.59212947, 0.15702886]),
|
||||
8: np.array([1.16699242e-03, -4.68207543e-02, 9.43972396e-01, -1.94201019e00]),
|
||||
9: np.array([0.00048419, -0.02010648, 0.55514114, -0.38180067]),
|
||||
10: np.array([2.11583333e-04, -8.03503571e-03, 3.43141595e-01, 6.02318000e-01]),
|
||||
11: np.array([0.00334392, -0.18405336, 3.58338994, -19.3640241]),
|
||||
12: np.array([3.20520798e-05, 2.39253145e-03, 8.09198503e-02, 2.22897377e00]),
|
||||
13: np.array([0.00278744, 0.07979874, 2.05143916]),
|
||||
}
|
||||
energy_ranges = {3: (0, 7), 5: (7, 10), 7: (10, 13), 9: (13, 16), 11: (16, 19), 13: (19, 22)}
|
||||
high_energy = [(15, (23, 25)), (17, (25, 29)), (19, (29, float("inf")))]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CamConversion:
|
||||
"""Convert pixels to microns for sam cam"""
|
||||
|
||||
a = 0.5208
|
||||
b = 0.002586
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BPMScans:
|
||||
"""Define the names of the motors and bpm channels"""
|
||||
|
||||
fe = {
|
||||
"x_name": dev.fe_bpm_x.name,
|
||||
"y_name": dev.fe_bpm_y.name,
|
||||
"z1_name": dev.fe_bpm1.name,
|
||||
"z2_name": dev.fe_bpm2.name,
|
||||
"z3_name": dev.fe_bpm3.name,
|
||||
"z4_name": dev.fe_bpm3.name,
|
||||
"z5_name": dev.fe_bpmsum.name,
|
||||
"x_device": dev.fe_bpm_x,
|
||||
"y_device": dev.fe_bpm_y,
|
||||
}
|
||||
lu = {
|
||||
"x_name": dev.lu_bpm_x.name,
|
||||
"y_name": dev.lu_bpm_y.name,
|
||||
"z1_name": dev.lu_bpm1.name,
|
||||
"z2_name": dev.lu_bpm2.name,
|
||||
"z3_name": dev.lu_bpm3.name,
|
||||
"z4_name": dev.lu_bpm4.name,
|
||||
"z5_name": dev.lu_bpmsum.name,
|
||||
"x_device": dev.lu_bpm_x,
|
||||
"y_device": dev.lu_bpm_y,
|
||||
}
|
||||
bsc = {
|
||||
"x_name": dev.bsc_bpm_x.name,
|
||||
"y_name": dev.bsc_bpm_y.name,
|
||||
"z1_name": dev.bsc_bpm1.name,
|
||||
"z2_name": dev.bsc_bpm2.name,
|
||||
"z3_name": dev.bsc_bpm3.name,
|
||||
"z4_name": dev.bsc_bpm4.name,
|
||||
"z5_name": dev.bsc_bpmsum.name,
|
||||
"x_device": dev.bsc_bpm_x,
|
||||
"y_device": dev.bsc_bpm_y,
|
||||
}
|
||||
bcu = {
|
||||
"x_name": dev.bcu_bpm_x.name,
|
||||
"y_name": dev.bcu_bpm_y.name,
|
||||
"z1_name": dev.bcu_bpm1.name,
|
||||
"z2_name": dev.bcu_bpm2.name,
|
||||
"z3_name": dev.bcu_bpm3.name,
|
||||
"z4_name": dev.bcu_bpm4.name,
|
||||
"z5_name": dev.bcu_bpmsum.name,
|
||||
"x_device": dev.bcu_bpm_x,
|
||||
"y_device": dev.bcu_bpm_y,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MirrorConfig:
|
||||
"""Define the names of the mirror channels"""
|
||||
|
||||
hfm = {
|
||||
"bu_name": dev.hfm_bu.name,
|
||||
"bd_name": dev.hfm_bd.name,
|
||||
"z_name": dev.samcam_xsig.name,
|
||||
"x_device": dev.hfm_bu,
|
||||
"y_device": dev.hfm_bd,
|
||||
}
|
||||
vfm = {
|
||||
"bu_name": dev.vfm_bu.name,
|
||||
"bd_name": dev.vfm_bd.name,
|
||||
"z_name": dev.samcam_ysig.name,
|
||||
"x_device": dev.vfm_bu,
|
||||
"y_device": dev.vfm_bd,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class PositionedDevice:
|
||||
"""Class for devices with defined in and out positions"""
|
||||
|
||||
device_name: str
|
||||
type: str
|
||||
name: str
|
||||
inpos: float
|
||||
outpos: float
|
||||
tol: float
|
||||
mot: str
|
||||
reader: Callable[[], float]
|
||||
|
||||
@property
|
||||
def actual(self):
|
||||
"""Returns current motor position"""
|
||||
return self.reader()
|
||||
|
||||
def checkin(self):
|
||||
"""Returns True if motor in in the 'in' position"""
|
||||
return abs(self.actual - self.inpos) <= self.tol
|
||||
|
||||
def mvin(self):
|
||||
"""Moves motor to the 'in' position"""
|
||||
scans.umv(self.mot, self.inpos, relative=False)
|
||||
|
||||
def mvout(self):
|
||||
"""Moves motor to the 'out' position"""
|
||||
scans.umv(self.mot, self.outpos, relative=False)
|
||||
|
||||
def status(self):
|
||||
""" Check if device is in or out or moving"""
|
||||
positions = ("in", "out", "moving", "undefined")
|
||||
target_in = self.inpos
|
||||
target_out = self.outpos
|
||||
actual = self.actual
|
||||
delta_in = actual - target_in
|
||||
delta_out = actual - target_out
|
||||
# Check if motor is moving
|
||||
if "Signal" in self.type:
|
||||
moving = 0
|
||||
elif "Motor" in self.type:
|
||||
d = getattr(dev, self.device_name)
|
||||
moving = d.motor_is_moving.get()
|
||||
if moving:
|
||||
pos = positions[2]
|
||||
return {"position": pos.upper(),
|
||||
"name": self.name,
|
||||
"moving": moving}
|
||||
|
||||
if abs(delta_in) > self.tol and abs(delta_out) > self.tol:
|
||||
pos = positions[3]
|
||||
return {"position": pos.upper(),
|
||||
"name": self.name,
|
||||
"actual": actual,
|
||||
"moving": moving}
|
||||
|
||||
elif abs(delta_in) <= self.tol:
|
||||
target = self.inpos
|
||||
pos = positions[0]
|
||||
delta = delta_in
|
||||
elif abs(delta_out) <= self.tol:
|
||||
target = self.outpos
|
||||
pos = positions[1]
|
||||
delta = delta_out
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"position": pos.upper(),
|
||||
"target": target,
|
||||
"actual": actual,
|
||||
"delta": delta,
|
||||
"tol": self.tol,
|
||||
"moving": moving,
|
||||
}
|
||||
|
||||
def report(self):
|
||||
""" Print status of motor """
|
||||
s = self.status()
|
||||
|
||||
if s['position'] == "UNDEFINED":
|
||||
return (f"{s['name']:15s}: "
|
||||
f"{s['position']} "
|
||||
f"position {s['actual']:.3f}")
|
||||
elif s['position'] == "MOVING":
|
||||
return (f"{s['name']:15s}: "
|
||||
f"{s['position']} ")
|
||||
else:
|
||||
return (
|
||||
f"{s['name']:15s}: "
|
||||
f"[{s['position']}] "
|
||||
f"actual = {s['actual']:.3f} "
|
||||
f"target = {s['target']:.3f} "
|
||||
f"delta = {s['delta']:.3f}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PD:
|
||||
"""Class for positioned device positions"""
|
||||
|
||||
|
||||
def build_pd(yaml_file):
|
||||
"""Takes the in and out values from the yaml file
|
||||
and adds them to the PD class
|
||||
"""
|
||||
with open(yaml_file, encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
for device_name, cfg in data.items():
|
||||
# Skip devices without userParameter
|
||||
user = cfg.get("userParameter")
|
||||
if not user:
|
||||
continue
|
||||
# Set tolerance
|
||||
if "tol" not in user:
|
||||
user["tol"] = 0.01
|
||||
|
||||
try:
|
||||
dev_obj = getattr(dev, device_name)
|
||||
except:
|
||||
raise KeyError(f"Device {device_name} not found in device list")
|
||||
desc = cfg.get("description")
|
||||
type = cfg.get("deviceClass")
|
||||
target = PositionedDevice(
|
||||
device_name=device_name,
|
||||
type = type,
|
||||
name=desc,
|
||||
inpos=user["in"],
|
||||
outpos=user["out"],
|
||||
tol=user["tol"],
|
||||
mot=dev_obj,
|
||||
reader=lambda d=dev_obj, n=device_name: d.read()[n]["value"],
|
||||
)
|
||||
|
||||
setattr(PD, device_name, target)
|
||||
|
||||
|
||||
def init_positioned_devices():
|
||||
"""Initialises the positioned devices"""
|
||||
file = (
|
||||
"/sls/x10sa/config/bec/production/pxii_bec/pxii_bec/device_configs/pxii-autogenerated.yaml"
|
||||
)
|
||||
build_pd(file)
|
||||
print("Defined positions for devices have been updated from pxii-autogenerated.yaml")
|
||||
@@ -0,0 +1,38 @@
|
||||
import random
|
||||
import time
|
||||
|
||||
def test_mv():
|
||||
tol = 0.1
|
||||
if abs(dev.coll_y.position) < tol:
|
||||
value = 40
|
||||
else:
|
||||
value = 0
|
||||
print(f"Moving coll_y to {value}")
|
||||
s = scans.mv(dev.coll_y, value, relative=False)
|
||||
s.wait(timeout = 3)
|
||||
|
||||
def test_states():
|
||||
d = init_se_devices()
|
||||
states, allow_modifiers = get_states()
|
||||
deps = planner_deps()
|
||||
planner = StateManager(d, states, allow_modifiers, deps)
|
||||
states_to_test = [
|
||||
BeamlineState.ROBOT_SAMPLE_EXCHANGE,
|
||||
BeamlineState.DATA_COLLECTION,
|
||||
BeamlineState.MANUAL_SAMPLE_EXCHANGE,
|
||||
BeamlineState.XTAL_SNAPSHOT,
|
||||
|
||||
]
|
||||
previous = None
|
||||
tested_states = []
|
||||
for i in range(10):
|
||||
choices = [ s for s in states_to_test if s != previous]
|
||||
current = random.choice(choices)
|
||||
print(f"Moving to state {current}")
|
||||
planner.move_to(current)
|
||||
tested_states.append(current)
|
||||
time.sleep(5)
|
||||
previous = current
|
||||
print(f"Tested states: {tested_states}")
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
print("Hello World")
|
||||
try:
|
||||
print(PD.coll_y.state)
|
||||
print("success")
|
||||
except Exception as e:
|
||||
print(f"Error {e}")
|
||||
@@ -1,59 +0,0 @@
|
||||
"""
|
||||
update_PD_from_yaml.py
|
||||
|
||||
Creates PositionedDevice, MultiPositionDevice and GuardedAxis
|
||||
instances from YAML configuration.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def build_pd(yaml_file):
|
||||
"""Takes the defined positions from the device yaml file
|
||||
and adds them to the PD class
|
||||
"""
|
||||
pos_devs = []
|
||||
mp_devs = []
|
||||
ga_devs = []
|
||||
|
||||
|
||||
with open(yaml_file, encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
for bec_name, cfg in data.items():
|
||||
# Skip devices without userParameter
|
||||
user = cfg.get("userParameter")
|
||||
|
||||
if not user:
|
||||
continue
|
||||
# ------------------------------------------------------------------
|
||||
# Positioned device
|
||||
# ------------------------------------------------------------------
|
||||
if user["type"] == "positioner":
|
||||
pos_devs.append(bec_name)
|
||||
posdev = PositionedDevice(bec_name=bec_name, inpos=1.0, outpos=0.0)
|
||||
setattr(PD, bec_name, posdev)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Multi-position device
|
||||
# ------------------------------------------------------------------
|
||||
elif user["type"] == "multi-position":
|
||||
mp_devs.append(bec_name)
|
||||
positions = {k: v for k, v in user.items() if k != "type"}
|
||||
mpdev = MultiPositionDevice(bec_name=bec_name, positions=positions)
|
||||
setattr(PD, bec_name, mpdev)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Guarded device
|
||||
# ------------------------------------------------------------------
|
||||
elif user["type"] == "guarded":
|
||||
ga_devs.append(bec_name)
|
||||
config = {k: v for k, v in user.items() if k != "type"}
|
||||
gadev = GuardedAxis(
|
||||
bec_name=bec_name, policy=get_policy_for_axis(bec_name), config=config
|
||||
)
|
||||
setattr(PD, bec_name, gadev)
|
||||
|
||||
print(f"Positioned devices: {pos_devs}")
|
||||
print(f"Guarded axes: {ga_devs}")
|
||||
print(f"Multi position devices: {mp_devs}")
|
||||
@@ -0,0 +1,12 @@
|
||||
"""
|
||||
Scan components for pxii_bec.
|
||||
|
||||
The scan components module allows you to define custom components that can be used in your scans.
|
||||
These components can be used to encapsulate reusable logic, interact with devices, or perform specific actions during the scan lifecycle.
|
||||
"""
|
||||
|
||||
from bec_server.scan_server.scans.scan_components import ScanComponents
|
||||
|
||||
|
||||
class PxiiBecScanComponents(ScanComponents):
|
||||
"""Scan components for pxii_bec."""
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
Scan modifier plugin for pxii_bec.
|
||||
|
||||
The scan modifier allows you to modify the scan lifecycle and run custom actions before or after the scan hook or replace the scan hook entirely.
|
||||
Note that the scan_modifier module must be registered as a plugin in the pyproject.toml file for it to be recognized by the BEC framework and that
|
||||
there can only be one scan_modifier plugin registered at a time. If you need to run multiple scan modifiers, you can create a single scan
|
||||
modifier plugin that runs multiple actions in sequence with conditional logic to determine which actions to run based on the scan context.
|
||||
"""
|
||||
|
||||
from bec_server.scan_server.scans.scan_modifier import ScanModifier, scan_hook_impl
|
||||
|
||||
|
||||
class PxiiBecScanModifier(ScanModifier):
|
||||
"""
|
||||
Scan modifier for pxii_bec.
|
||||
|
||||
By inheriting from the ScanModifier base class, you get access to currently running scan (self.scan), the devices (self.dev), the scan info (self.scan_info),
|
||||
the scan components (self.components) and the scan actions (self.actions).
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize the scan modifier."""
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# Example of running code before the scan stage for a specific scan
|
||||
# @scan_hook_impl("stage", "before")
|
||||
# def before_stage(self):
|
||||
# """Run before the stage hook."""
|
||||
# self.actions.send_client_info("Custom stage logic executed by ScanModifier.")
|
||||
# if self.scan_info.scan_name == "example_scan":
|
||||
# self.dev.samx.set(20)
|
||||
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
||||
name = "pxii_bec"
|
||||
version = "0.0.0"
|
||||
description = "A plugin repository for BEC"
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Programming Language :: Python :: 3",
|
||||
@@ -25,6 +25,7 @@ dev = [
|
||||
"pytest-random-order",
|
||||
"ophyd_devices",
|
||||
"bec_server",
|
||||
"requests-mock",
|
||||
]
|
||||
|
||||
[project.entry-points."bec"]
|
||||
@@ -39,6 +40,9 @@ plugin_file_writer = "pxii_bec.file_writer"
|
||||
[project.entry-points."bec.scans"]
|
||||
plugin_scans = "pxii_bec.scans"
|
||||
|
||||
[project.entry-points."bec.scans.scan_modifier"]
|
||||
plugin_scan_modifier = "pxii_bec.scans.scan_customization.scan_modifier"
|
||||
|
||||
[project.entry-points."bec.scans.metadata_schema"]
|
||||
plugin_metadata_schema = "pxii_bec.scans.metadata_schema"
|
||||
|
||||
@@ -76,3 +80,6 @@ good-names-rgxs = [
|
||||
".*_2D.*",
|
||||
".*_1D.*",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"""A mock smargopolo REST interface with mock motoers, for testing devices against"""
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
import time
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
from copy import copy
|
||||
from threading import RLock
|
||||
from unittest.mock import ANY
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class MockServer:
|
||||
def __init__(self) -> None:
|
||||
self.lock = RLock()
|
||||
self.mock_data = {
|
||||
"x": {"pos": 1.0},
|
||||
"y": {"pos": 1.0},
|
||||
"z": {"pos": 1.0},
|
||||
"u": {"pos": 1.0},
|
||||
"vel_u_deg_s": {"pos": 1.0},
|
||||
}
|
||||
|
||||
def get(self, endpoint):
|
||||
with self.lock:
|
||||
return copy(self.mock_data)
|
||||
|
||||
def put(self, params: dict | None = None, body: dict | None = None):
|
||||
with self.lock:
|
||||
assert body is not None
|
||||
for k, v in body.items():
|
||||
self.mock_data[k]["pos"] = v
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aerotech():
|
||||
mock_server = MockServer()
|
||||
from pxii_bec.devices.aerotech import Aerotech
|
||||
|
||||
s = Aerotech(name="aerotech", prefix="http://test-aerotech.psi.ch")
|
||||
s.controller._rest_get = mock_server.get
|
||||
s.controller._rest_post = mock_server.put
|
||||
yield s
|
||||
s.controller._stop_monitor_readback_event.set()
|
||||
|
||||
|
||||
class TestAerotech:
|
||||
def test_aerotech_read(self, aerotech):
|
||||
aerotech.wait_for_connection()
|
||||
reading = aerotech.read()
|
||||
assert dict(reading) == {
|
||||
"aerotech_x": {"value": 1.0, "timestamp": ANY},
|
||||
"aerotech_y": {"value": 1.0, "timestamp": ANY},
|
||||
"aerotech_z": {"value": 1.0, "timestamp": ANY},
|
||||
"aerotech_u": {"value": 1.0, "timestamp": ANY},
|
||||
"aerotech_vel_u_deg_s": {"value": 1.0, "timestamp": ANY},
|
||||
}
|
||||
|
||||
def test_aerotech_set_with_status(self, aerotech):
|
||||
aerotech.wait_for_connection()
|
||||
st = aerotech.x.set(5.0)
|
||||
st.wait(timeout=1)
|
||||
assert aerotech.x.get() == 5.0
|
||||
@@ -0,0 +1,51 @@
|
||||
from copy import copy
|
||||
from threading import RLock
|
||||
from unittest.mock import ANY
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class MockServer:
|
||||
def __init__(self) -> None:
|
||||
self.lock = RLock()
|
||||
self.mock_data = {"SHX": 1.0, "SHY": 1.0, "SHZ": 1.0, "PHI": 1.0, "CHI": 1.0}
|
||||
|
||||
def get(self, endpoint):
|
||||
with self.lock:
|
||||
return copy(self.mock_data)
|
||||
|
||||
def put(self, params: dict | None = None, body: dict | None = None):
|
||||
with self.lock:
|
||||
assert params is not None
|
||||
self.mock_data.update(params)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def smargon():
|
||||
mock_server = MockServer()
|
||||
from pxii_bec.devices.smargopolo_smargon import Smargon
|
||||
|
||||
s = Smargon(name="smargon", prefix="http://test-smargopolo.psi.ch")
|
||||
s.controller._rest_get = mock_server.get
|
||||
s.controller._rest_put = mock_server.put
|
||||
yield s
|
||||
s.controller._stop_monitor_readback_event.set()
|
||||
|
||||
|
||||
class TestSmargon:
|
||||
def test_smargon_read(self, smargon):
|
||||
smargon.wait_for_connection()
|
||||
reading = smargon.read()
|
||||
assert dict(reading) == {
|
||||
"smargon_x": {"value": 1.0, "timestamp": ANY},
|
||||
"smargon_y": {"value": 1.0, "timestamp": ANY},
|
||||
"smargon_z": {"value": 1.0, "timestamp": ANY},
|
||||
"smargon_phi": {"value": 1.0, "timestamp": ANY},
|
||||
"smargon_chi": {"value": 1.0, "timestamp": ANY},
|
||||
}
|
||||
|
||||
def test_smargon_set_with_status(self, smargon):
|
||||
smargon.wait_for_connection()
|
||||
st = smargon.x.set(5.0)
|
||||
st.wait(timeout=1)
|
||||
assert smargon.x.get() == 5.0
|
||||
Reference in New Issue
Block a user