Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e428140e8 |
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
# It is needed to track the repo template version, and editing may break things.
|
# It is needed to track the repo template version, and editing may break things.
|
||||||
# This file will be overwritten by copier on template updates.
|
# This file will be overwritten by copier on template updates.
|
||||||
|
|
||||||
_commit: v1.4.0
|
_commit: v1.2.2
|
||||||
_src_path: https://github.com/bec-project/plugin_copier_template.git
|
_src_path: https://github.com/bec-project/plugin_copier_template.git
|
||||||
make_commit: false
|
make_commit: false
|
||||||
project_name: pxiii_bec
|
project_name: pxiii_bec
|
||||||
|
|||||||
+9
-14
@@ -28,7 +28,7 @@ on:
|
|||||||
description: "Python version to use"
|
description: "Python version to use"
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: "3.12"
|
default: "3.11"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -44,19 +44,7 @@ jobs:
|
|||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "${{ inputs.PYTHON_VERSION || '3.12' }}"
|
python-version: "${{ inputs.PYTHON_VERSION || '3.11' }}"
|
||||||
|
|
||||||
- name: Checkout BEC Plugin Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: bec/pxiii_bec
|
|
||||||
ref: "${{ inputs.BEC_PLUGIN_REPO_BRANCH || github.head_ref || github.sha }}"
|
|
||||||
path: ./pxiii_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
|
- name: Checkout BEC Core
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -79,6 +67,13 @@ jobs:
|
|||||||
ref: "${{ inputs.BEC_WIDGETS_BRANCH || 'main' }}"
|
ref: "${{ inputs.BEC_WIDGETS_BRANCH || 'main' }}"
|
||||||
path: ./bec_widgets
|
path: ./bec_widgets
|
||||||
|
|
||||||
|
- name: Checkout BEC Plugin Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: bec/pxiii_bec
|
||||||
|
ref: "${{ inputs.BEC_PLUGIN_REPO_BRANCH || github.head_ref || github.sha }}"
|
||||||
|
path: ./pxiii_bec
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
name: Create template upgrade PR for pxiii_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\"
|
|
||||||
}"
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
include:
|
||||||
|
- file: /templates/plugin-repo-template.yml
|
||||||
|
inputs:
|
||||||
|
name: pxiii_bec
|
||||||
|
target: pxiii_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_lib.logger import bec_logger
|
||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_base import RPCBase, rpc_call, rpc_timeout
|
from bec_widgets.cli.rpc.rpc_base import RPCBase, rpc_call
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
@@ -18,8 +18,6 @@ _Widgets = {
|
|||||||
|
|
||||||
|
|
||||||
class ScanHistory(RPCBase):
|
class ScanHistory(RPCBase):
|
||||||
_IMPORT_MODULE = "pxiii_bec.bec_widgets.widgets.scan_history.scan_history"
|
|
||||||
|
|
||||||
@rpc_call
|
@rpc_call
|
||||||
def select_scan_from_history(self, value: "int") -> "None":
|
def select_scan_from_history(self, value: "int") -> "None":
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# This file was automatically generated by generate_cli.py
|
|
||||||
# type: ignore
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
# pylint: skip-file
|
|
||||||
|
|
||||||
designer_plugins = {
|
|
||||||
"ScanHistory": ("pxiii_bec.bec_widgets.widgets.scan_history.scan_history", "ScanHistory"),
|
|
||||||
}
|
|
||||||
|
|
||||||
widget_icons = {
|
|
||||||
"ScanHistory": "widgets",
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import csv
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def str_to_bool(val):
|
|
||||||
return str(val).strip().lower() in ["yes", "true", "1"]
|
|
||||||
|
|
||||||
def create(INPUT_CSV, OUTPUT_YAML):
|
|
||||||
with open(INPUT_CSV, newline="") as csvfile:
|
|
||||||
reader = csv.DictReader(csvfile)
|
|
||||||
|
|
||||||
with open(OUTPUT_YAML, "w") as yamlfile:
|
|
||||||
for row in reader:
|
|
||||||
include = row["include"]
|
|
||||||
name = row["name"]
|
|
||||||
desc = row["description"]
|
|
||||||
device_class = row["deviceClass"]
|
|
||||||
pv = row["PV"]
|
|
||||||
readout_priority = row["readoutPriority"]
|
|
||||||
tag = row["tag"]
|
|
||||||
read_only = str_to_bool(row["readOnly"])
|
|
||||||
user_param = row.get("userParameter", "").strip()
|
|
||||||
|
|
||||||
if str(include).strip().lower() != "yes":
|
|
||||||
continue
|
|
||||||
|
|
||||||
yamlfile.write(f"{name}:\n")
|
|
||||||
yamlfile.write(f" description: {desc}\n")
|
|
||||||
|
|
||||||
if device_class == "Motor" or device_class == "MotorEC":
|
|
||||||
yamlfile.write(f" deviceClass: ophyd_devices.Epics{device_class}\n")
|
|
||||||
yamlfile.write(f" deviceConfig: {{prefix: '{pv}'}}\n")
|
|
||||||
else:
|
|
||||||
yamlfile.write(f" deviceClass: ophyd.Epics{device_class}\n")
|
|
||||||
yamlfile.write(
|
|
||||||
f" deviceConfig: {{read_pv: '{pv}', auto_monitor: true}}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
yamlfile.write(" onFailure: buffer\n")
|
|
||||||
yamlfile.write(" enabled: True\n")
|
|
||||||
yamlfile.write(f" readoutPriority: {readout_priority}\n")
|
|
||||||
yamlfile.write(" deviceTags:\n")
|
|
||||||
yamlfile.write(f" - {tag}\n")
|
|
||||||
yamlfile.write(f" readOnly: {read_only}\n")
|
|
||||||
yamlfile.write(" softwareTrigger: false\n")
|
|
||||||
|
|
||||||
# Only add userParameter for Motors if present
|
|
||||||
# if device_class == "Motor" and user_param:
|
|
||||||
if user_param:
|
|
||||||
try:
|
|
||||||
parsed = json.loads(user_param)
|
|
||||||
yamlfile.write(" userParameter:\n")
|
|
||||||
for k, v in parsed.items():
|
|
||||||
yamlfile.write(f" {k}: {v}\n")
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
yamlfile.write(f" userParameter: {user_param}\n")
|
|
||||||
|
|
||||||
yamlfile.write("\n")
|
|
||||||
|
|
||||||
print(f"YAML written to {OUTPUT_YAML}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
devices = "pxiii-standard-devices"
|
|
||||||
states = "pxiii-state-devices"
|
|
||||||
|
|
||||||
device_files = [
|
|
||||||
f"{devices}.csv",
|
|
||||||
f"{devices}.yaml"
|
|
||||||
]
|
|
||||||
state_files = [
|
|
||||||
f"{states}.csv",
|
|
||||||
f"{states}.yaml"
|
|
||||||
]
|
|
||||||
|
|
||||||
create(device_files[0],device_files[1])
|
|
||||||
create(state_files[0],state_files[1])
|
|
||||||
|
|
||||||
main()
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
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,MotorEC,X06DA-FE-SLDI:TRXR,baseline,fe,no,yes,,
|
|
||||||
fe_sl_yt,FE Slit Y Top,MotorEC,X06DA-FE-SLDI:TRYT,baseline,fe,no,yes,,
|
|
||||||
fe_sl_xw,FE Slit X Wall,MotorEC,X06DA-FE-SLDI:TRXW,baseline,fe,no,yes,,
|
|
||||||
fe_sl_yb,FE Slit Y Bottom,MotorEC,X06DA-FE-SLDI:TRYB,baseline,fe,no,yes,,
|
|
||||||
fe_sl_xcen,FE Slit X Centre,MotorEC,X06DA-FE-SLDI:CENTERX,baseline,fe,no,yes,,
|
|
||||||
fe_sl_xsize,FE Slit X Size,MotorEC,X06DA-FE-SLDI:SIZEX,baseline,fe,no,yes,,
|
|
||||||
fe_sl_ycen,FE Slit Y Centre,MotorEC,X06DA-FE-SLDI:CENTERY,baseline,fe,no,yes,,
|
|
||||||
fe_sl_ysize,FE Slit Y Size,MotorEC,X06DA-FE-SLDI:SIZEY,baseline,fe,no,yes,,
|
|
||||||
tm_xu,TorM Upstream X,MotorEC,X06DA-FE-MI1:TRXU,baseline,tm,no,yes,,
|
|
||||||
tm_xd,TorM Downstream X,MotorEC,X06DA-FE-MI1:TRXD,baseline,tm,no,yes,,
|
|
||||||
tm_yur,TorM Upstream Ring Y,MotorEC,X06DA-FE-MI1:TRYUR,baseline,tm,no,yes,,
|
|
||||||
tm_yw,TorM Wall Y,MotorEC,X06DA-FE-MI1:TRYUW,baseline,tm,no,yes,,
|
|
||||||
tm_yd,TorM Downstream Y,MotorEC,X06DA-FE-MI1:TRYD,baseline,tm,no,yes,,
|
|
||||||
tm_b1,TorM Bender,MotorEC,X06DA-FE-MI1:BEND1,baseline,tm,no,yes,,
|
|
||||||
tm_yaw,TorM Virtual Yaw,MotorEC,X06DA-FE-MI1:YAW,baseline,tm,no,yes,,
|
|
||||||
tm_roll,TorM Virtual Roll,MotorEC,X06DA-FE-MI1:ROLL,baseline,tm,no,yes,,
|
|
||||||
tm_pitch,TorM Virtual Pitch,MotorEC,X06DA-FE-MI1:PITCH,baseline,tm,no,yes,,
|
|
||||||
tm_x,TorM Virtual X,MotorEC,X06DA-FE-MI1:TRX,baseline,tm,no,yes,,
|
|
||||||
tm_y,TorM Virtual Y ,MotorEC,X06DA-FE-MI1:TRY,baseline,tm,no,yes,,
|
|
||||||
bsf_bpm1,BSF BPM Channel 1,SignalRO,X06DA-OP-BSFBPM:SIGNAL1,monitored,bpm,yes,no,,
|
|
||||||
bsf_bpm2,BSF BPM Channel 2,SignalRO,X06DA-OP-BSFBPM:SIGNAL2,monitored,bpm,yes,no,,
|
|
||||||
bsf_bpm3,BSF BPM Channel 3,SignalRO,X06DA-OP-BSFBPM:SIGNAL3,monitored,bpm,yes,no,,
|
|
||||||
bsf_bpm4,BSF BPM Channel 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,MotorEC,X06DA-OP-BSFSLH:TRXW,baseline,bsf,no,yes,,
|
|
||||||
bsf_sl_xr,BSF Slit inboard,MotorEC,X06DA-OP-BSFSLH:TRXR,baseline,bsf,no,yes,,
|
|
||||||
bsf_sl_xcen,BSF X Centre,MotorEC,X06DA-OP-BSFSLH:CENTER,baseline,bsf,no,yes,,
|
|
||||||
bsf_sl_xsize,BSF X Size,MotorEC,X06DA-OP-BSFSLH:SIZE,baseline,bsf,no,yes,,
|
|
||||||
bsf_f1_y,BSF Filter 1 Y,MotorEC,X06DA-OP-BSFFI1:TRY,baseline,bsf,no,yes,,
|
|
||||||
dccm_theta1,DCCM Theta Xtal1,MotorEC,X06DA-OP-DCCM:ROTX-CR1,baseline,dccm,no,yes,,
|
|
||||||
dccm_theta2,DCCM Theta Xtal2,MotorEC,X06DA-OP-DCCM:ROTX-CR2,baseline,dccm,no,yes,,
|
|
||||||
dccm_rotz,DCCM RotZ Xtal 2,MotorEC,X06DA-OP-DCCM:ROTZ-CR2,baseline,dccm,no,yes,,
|
|
||||||
dccm_xbpm1_y,DCCM BPM1 Y,MotorEC,X06DA-OP-DCCMXBPM1:TRY,baseline,dccm,no,yes,,
|
|
||||||
dccm_xbpm2_y,DCCM BPM2 Y,MotorEC,X06DA-OP-DCCMXBPM2:TRY,baseline,dccm,no,yes,,
|
|
||||||
dccm_energy,DCCM Energy,Motor,X06DA-OP-DCCM:ENERGY,baseline,dccm,no,yes,,
|
|
||||||
dccm_di_top,DCCM Diode Top,SignalRO,X06DA-OP-DCCMXBPM1T:READOUT,monitored,dccm,no,yes,,
|
|
||||||
dccm_di_bot,DCCM Diode Bottom,SignalRO,X06DA-OP-DCCMXBPM1B:READOUT,monitored,dccm,no,yes,,
|
|
||||||
dccm_bpm1,DCCM BPM Channel 1,SignalRO,X06DA-OP-DCCMXBPM2:Current1:MeanValue_RBV,monitored,dccm,no,yes,,
|
|
||||||
dccm_bpm2,DCCM BPM Channel 2,SignalRO,X06DA-OP-DCCMXBPM2:Current2:MeanValue_RBV,monitored,dccm,no,yes,,
|
|
||||||
dccm_bpm3,DCCM BPM Channel 3,SignalRO,X06DA-OP-DCCMXBPM2:Current3:MeanValue_RBV,monitored,dccm,no,yes,,
|
|
||||||
dccm_bpm4,DCCM BPM Channel 4,SignalRO,X06DA-OP-DCCMXBPM2:Current4:MeanValue_RBV,monitored,dccm,no,yes,,
|
|
||||||
dccm_bpmsum,DCCM BPM Summed,SignalRO,X06DA-OP-DCCMXBPM2:SumAll:MeanValue_RBV,monitored,dccm,no,yes,,
|
|
||||||
ss_bpm1,SS BPM Channel 1,SignalRO,X06DA-ES-SSBPM:Current1:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
ss_bpm2,SS BPM Channel 2,SignalRO,X06DA-ES-SSBPM:Current2:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
ss_bpm3,SS BPM Channel 3,SignalRO,X06DA-ES-SSBPM:Current3:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
ss_bpm4,SS BPM Channel 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,"{""type"": multi-position,""in"": 7.5, ""out"": -2.1}",
|
|
||||||
ss_xi_y,SS X-ray Eye Y,Motor,X06DA-ES-SSXI:TRY,baseline,ss,no,yes,,
|
|
||||||
ss_xicam_x,SS Camera X,SignalRO,X06DA-ES-SSCAM:Stats5:CentroidX_RBV,baseline,ss,yes,yes,,
|
|
||||||
ss_xicam_y,SS Camera Y,SignalRO,X06DA-ES-SSCAM:Stats5:CentroidY_RBV,baseline,ss,yes,yes,,
|
|
||||||
ss_xicam_max,SS Cam Max,SignalRO,X06DA-ES-SSCAM:Stats5:MaxValue_RBV,monitored,ss,yes,yes,,
|
|
||||||
ss_xicam_exp,SS Camera Exposure,Signal,X06DA-ES-SSCAM:cam1:AcquireTime,baseline,ss,no,yes,,
|
|
||||||
ss_xicam_gain,SS Camera Gain,Signal,X06DA-ES-SSCAM:cam1:Gain,baseline,ss,no,yes,,
|
|
||||||
ss_xicam_xsig,SS Camera X Sigma,Signal,X06DA-ES-SSCAM:Stats5:SigmaX_RBV,baseline,ss,yes,yes,,
|
|
||||||
ss_xicam_ysig,SS Camera Y Sigma,Signal,X06DA-ES-SSCAM:Stats5:SigmaY_RBV,baseline,ss,yes,yes,,
|
|
||||||
vfm_xu,VFM Upstream X,MotorEC,X06DA-ES-VFM:TRXU,baseline,vfm,no,yes,,
|
|
||||||
vfm_xd,VFM Downstream X,MotorEC,X06DA-ES-VFM:TRXD,baseline,vfm,no,yes,,
|
|
||||||
vfm_yur,VFM Upstream Ring Y,MotorEC,X06DA-ES-VFM:TRYUR,baseline,vfm,no,yes,,
|
|
||||||
vfm_yw,VFM Wall Y,MotorEC,X06DA-ES-VFM:TRYW,baseline,vfm,no,yes,,
|
|
||||||
vfm_ydr,VFM Downstream Ring Y,MotorEC,X06DA-ES-VFM:TRYDR,baseline,vfm,no,yes,,
|
|
||||||
vfm_bu,VFM Upstream Bender,MotorEC,X06DA-ES-VFM:BNDU,baseline,vfm,no,yes,,
|
|
||||||
vfm_bd,VFM Downstream Bender,MotorEC,X06DA-ES-VFM:BNDD,baseline,vfm,no,yes,,
|
|
||||||
vfm_yaw,VFM Virtual Yaw,MotorEC,X06DA-ES-VFM:YAW,baseline,vfm,no,yes,,
|
|
||||||
vfm_roll,VFM Virtual Roll,MotorEC,X06DA-ES-VFM:ROLL,baseline,vfm,no,yes,,
|
|
||||||
vfm_pitch,VFM Virtual Pitch,MotorEC,X06DA-ES-VFM:PITCH,baseline,vfm,no,yes,,
|
|
||||||
vfm_x,VFM Virtual X,MotorEC,X06DA-ES-VFM:TRX,baseline,vfm,no,yes,,
|
|
||||||
vfm_y,VFM Virtual Y ,MotorEC,X06DA-ES-VFM:TRY,baseline,vfm,no,yes,,
|
|
||||||
hfm_xu,HFM Upstream X,MotorEC,X06DA-ES-HFM:TRXU,baseline,hfm,no,yes,,
|
|
||||||
hfm_xd,HFM Downstream X,MotorEC,X06DA-ES-HFM:TRXD,baseline,hfm,no,yes,,
|
|
||||||
hfm_yuw,HFM Upstream Wall Y,MotorEC,X06DA-ES-HFM:TRYUW,baseline,hfm,no,yes,,
|
|
||||||
hfm_yr,HFM Ring Y,MotorEC,X06DA-ES-HFM:TRYR,baseline,hfm,no,yes,,
|
|
||||||
hfm_ydw,HFM Downstream Wall Y,MotorEC,X06DA-ES-HFM:TRYDW,baseline,hfm,no,yes,,
|
|
||||||
hfm_bu,HFM Upstream Bender,MotorEC,X06DA-ES-HFM:BNDU,baseline,hfm,no,yes,,
|
|
||||||
hfm_bd,HFM Downstream Bender,MotorEC,X06DA-ES-HFM:BNDD,baseline,hfm,no,yes,,
|
|
||||||
hfm_yaw,HFM Virtual Yaw,MotorEC,X06DA-ES-HFM:YAW,baseline,hfm,no,yes,,
|
|
||||||
hfm_roll,HFM Virtual Roll,MotorEC,X06DA-ES-HFM:ROLL,baseline,hfm,no,yes,,
|
|
||||||
hfm_pitch,HFM Virtual Pitch,MotorEC,X06DA-ES-HFM:PITCH,baseline,hfm,no,yes,,
|
|
||||||
hfm_x,HFM Virtual X,MotorEC,X06DA-ES-HFM:TRX,baseline,hfm,no,yes,,
|
|
||||||
hfm_y,HFM Virtual Y ,MotorEC,X06DA-ES-HFM:TRY,baseline,hfm,no,yes,,
|
|
||||||
bcu_bpm1,BCU BPM Channel 1 ,SignalRO,X06DA-ES-BCBPM:Current1:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
bcu_bpm2,BCU BPM Channel 2,SignalRO,X06DA-ES-BCBPM:Current2:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
bcu_bpm3,BCU BPM Channel 3,SignalRO,X06DA-ES-BCBPM:Current3:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
bcu_bpm4,BCU BPM Channel 4,SignalRO,X06DA-ES-BCBPM:Current4:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
bcu_bpmsum,BCU BPM Summed,SignalRO,X06DA-ES-BCBPM:SumAll:MeanValue_RBV,monitored,bpm,yes,yes,,
|
|
||||||
bcu_bpm_x,BCU BPM X,Motor,X06DA-ES-BCBPM:TRX,baseline,bcu,no,yes,,
|
|
||||||
bcu_bpm_y,BCU BPM Y ,Motor,X06DA-ES-BCBPM:TRY,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_xw,BCU Slit Wall,Motor,X06DA-ES-BCSLH:TRXW,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_xr,BCU Slit Ring,Motor,X06DA-ES-BCSLH:TRXR,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_xcen,BCU Slit X Centre,Motor,X06DA-ES-BCSLH:CENTER,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_xsize,BCU Slit X Size,Motor,X06DA-ES-BCSLH:SIZE,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_yt,BCU Slit top,Motor,X06DA-ES-BCSLV:TRYT,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_yb,BCU Slit Bottom,Motor,X06DA-ES-BCSLV:TRYB,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_ycen,BCU Slit Y Centre,Motor,X06DA-ES-BCSLV:CENTER,baseline,bcu,no,yes,,
|
|
||||||
bcu_sl_ysize,BCU Slit Y Size,Motor,X06DA-ES-BCSLV:SIZE,baseline,bcu,no,yes,,
|
|
||||||
samcam_x,Sample Camera X ,SignalRO,X06DA-ES-MS:Stats5:CentroidX_RBV,baseline,scam,yes,no,,
|
|
||||||
samcam_xsig,Sample Camera X Sigma,SignalRO,X06DA-ES-MS:Stats5:SigmaX_RBV,monitored,scam,yes,no,,
|
|
||||||
samcam_y,Sample Camera Y ,SignalRO,X06DA-ES-MS:Stats5:CentroidY_RBV,baseline,scam,yes,no,,
|
|
||||||
samcam_ysig,Sample Camera Y Sigma,SignalRO,X06DA-ES-MS:Stats5:SigmaY_RBV,monitored,scam,yes,no,,
|
|
||||||
samcam_max,Sample Camera Max,SignalRO,X06DA-ES-MS:Stats5:MaxValue_RBV,monitored,scam,yes,no,,
|
|
||||||
samcam_exp,Sample Camera Exposure,Signal,X06DA-ES-MS:cam1:AcquireTime,baseline,scam,no,no,,
|
|
||||||
samcam_gain,Sample Camera Gain,Signal,X06DA-ES-MS:cam1:Gain,baseline,scam,no,no,,
|
|
||||||
scam_zoom,Sample Camera Zoom,Motor,X06DA-ES-MS:ZOOM,baseline,scam,no,yes,,
|
|
||||||
coll_x,Collimator X,Motor,X06DA-ES-COL:TRX,baseline,se,no,no,,
|
|
||||||
diag_z,Scintillator/diode Z,Motor,X06DA-ES-SCL:TRZ,baseline,se,no,no,,
|
|
||||||
i1,I1 diode,SignalRO,X06DA-ES-SCLDI:READOUT,monitored,bpm,yes,no,,
|
|
||||||
bs_x,Beamstop X,Motor,X06DA-ES-BS:TRX,baseline,se,no,no,,
|
|
||||||
bs_y,Beamstop Y,Motor,X06DA-ES-BS:TRY,baseline,se,no,no,,
|
|
||||||
gon_y,Goniometer Y,Motor,X06DA-ES-DF1:TRY1,baseline,det,no,no,,
|
|
||||||
gon_z,Goniometer X,Motor,X06DA-ES-DF1:TRZ1,baseline,det,no,no,,
|
|
||||||
omega,Omega,Motor,X06DA-ES-DF1:ROTU,baseline,det,no,no,,
|
|
||||||
cryo_x,Cryo X ,Motor,X06DA-ES-CS:TRX,baseline,se,no,no,,
|
|
||||||
cryo_temp,Cryo Temperature,SignalRO,X06DA-ES-CS:TEMP_RBV,baseline,se,no,no,,
|
|
||||||
det_y,Detector Y,MotorEC,X06DA-ES-DET:TRY,baseline,det,no,no,,
|
|
||||||
det_z,Detector Z,MotorEC,X06DA-ES-DET:TRZ,baseline,det,no,no,,
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
|||||||
name,description,deviceClass,PV,readoutPriority,tag,readOnly,include,userParameter
|
|
||||||
bl_bright,Backlight Brightness,Signal,X06DA-ES-BL:SET,baseline,state,no,yes,
|
|
||||||
bl_pos,Backlight Positioner,Signal,X06DA-ES-BL:POS-SET,baseline,state,no,no,"{""type"":positioner}"
|
|
||||||
bs_pos,Beamstop Positioner,Signal,X06DA-ES-BS:POS-SET,baseline,state,no,no,"{""type"":positioner}"
|
|
||||||
bs_z,Beamstop Z,Motor,X06DA-ES-BS:TRZ,baseline,state,no,yes,"{""type"": guarded, ""min"": 13, ""samp"": 15, ""work_min"": 20, ""safe"": 41, ""max_blin"": 42, ""max_blout"": 70}"
|
|
||||||
coll_y,Collimator Y,Motor,X06DA-ES-COL:TRY,baseline,state,no,yes,"{""type"": multi-position, ""in"": 40, ""out"": 20.0, ""park"": 0,""tol"":0.05}"
|
|
||||||
cryo_pos,Cryo positioner,Signal,X06DA-ES-CS:POS-SET,baseline,state,no,no,"{""type"":positioner}"
|
|
||||||
det_cov,Detector cover,Signal,X06DA-ES-DETCOV:SET,baseline,state,no,no,"{""type"":positioner}"
|
|
||||||
diag_y,Scintillator/diode Y,Motor,X06DA-ES-SCL:TRY,baseline,state,no,yes,"{""type"": multi-position, ""scint"": 39, ""i1"": 44.0, ""out"": 20.0,""park"": 0,""tol"":0.3}"
|
|
||||||
fl_bright,Frontlight Brightness,Signal,X06DA-ES-FL:SET,baseline,state,no,yes,
|
|
||||||
xrf_pos,XRF Positioner,Signal,X06DA-ES-XRF:POS-SET,baseline,state,no,no,"{""type"":positioner}"
|
|
||||||
|
@@ -1,63 +0,0 @@
|
|||||||
bl_bright:
|
|
||||||
description: Backlight Brightness
|
|
||||||
deviceClass: ophyd.EpicsSignal
|
|
||||||
deviceConfig: {read_pv: 'X06DA-ES-BL:SET', auto_monitor: true}
|
|
||||||
onFailure: buffer
|
|
||||||
enabled: True
|
|
||||||
readoutPriority: baseline
|
|
||||||
deviceTags:
|
|
||||||
- state
|
|
||||||
readOnly: False
|
|
||||||
softwareTrigger: false
|
|
||||||
|
|
||||||
bs_z:
|
|
||||||
description: Beamstop Z
|
|
||||||
deviceClass: ophyd_devices.EpicsMotor
|
|
||||||
deviceConfig: {prefix: 'X06DA-ES-BS:TRZ'}
|
|
||||||
onFailure: buffer
|
|
||||||
enabled: True
|
|
||||||
readoutPriority: baseline
|
|
||||||
deviceTags:
|
|
||||||
- state
|
|
||||||
readOnly: False
|
|
||||||
softwareTrigger: false
|
|
||||||
userParameter: {"type": guarded, "min": 13, "samp": 15, "work_min": 20, "safe": 41, "max_blin": 42, "max_blout": 70}
|
|
||||||
|
|
||||||
coll_y:
|
|
||||||
description: Collimator Y
|
|
||||||
deviceClass: ophyd_devices.EpicsMotor
|
|
||||||
deviceConfig: {prefix: 'X06DA-ES-COL:TRY'}
|
|
||||||
onFailure: buffer
|
|
||||||
enabled: True
|
|
||||||
readoutPriority: baseline
|
|
||||||
deviceTags:
|
|
||||||
- state
|
|
||||||
readOnly: False
|
|
||||||
softwareTrigger: false
|
|
||||||
userParameter: {"type": multi-position, "in": 40, "out": 20.0, "park": 0,"tol":0.05}
|
|
||||||
|
|
||||||
diag_y:
|
|
||||||
description: Scintillator/diode Y
|
|
||||||
deviceClass: ophyd_devices.EpicsMotor
|
|
||||||
deviceConfig: {prefix: 'X06DA-ES-SCL:TRY'}
|
|
||||||
onFailure: buffer
|
|
||||||
enabled: True
|
|
||||||
readoutPriority: baseline
|
|
||||||
deviceTags:
|
|
||||||
- state
|
|
||||||
readOnly: False
|
|
||||||
softwareTrigger: false
|
|
||||||
userParameter: {"type": multi-position, "scint": 39, "i1": 44.0, "out": 20.0,"park": 0,"tol":0.3}
|
|
||||||
|
|
||||||
fl_bright:
|
|
||||||
description: Frontlight Brightness
|
|
||||||
deviceClass: ophyd.EpicsSignal
|
|
||||||
deviceConfig: {read_pv: 'X06DA-ES-FL:SET', auto_monitor: true}
|
|
||||||
onFailure: buffer
|
|
||||||
enabled: True
|
|
||||||
readoutPriority: baseline
|
|
||||||
deviceTags:
|
|
||||||
- state
|
|
||||||
readOnly: False
|
|
||||||
softwareTrigger: false
|
|
||||||
|
|
||||||
@@ -1,4 +1,757 @@
|
|||||||
base_config:
|
sls_current:
|
||||||
- !include ./pxiii-standard-devices.yaml
|
description: sls current
|
||||||
states_config:
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
- !include ./pxiii-state-devices.yaml
|
deviceConfig: {read_pv: 'ARS07-DPCT-0100:CURR', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
vg0_press:
|
||||||
|
description: VG0 pressure
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-FE-VMCC-0000:PRESSURE', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
abs_press:
|
||||||
|
description: Absorber pressure
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-FE-ABS1-VMCC-1010:PRESSURE', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
|
||||||
|
sldi_cenx:
|
||||||
|
description: FE slit-diaphragm horizontal center
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-SLDI:CENTERX'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
sldi_sizex:
|
||||||
|
description: FE slit-diaphragm horizontal size
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-SLDI:SIZEX'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
sldi_ceny:
|
||||||
|
description: FE slit-diaphragm vertical center
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-SLDI:CENTERY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
sldi_sizey:
|
||||||
|
description: FE slit-diaphragm vertical size
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-SLDI:SIZEY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
fecmi_try:
|
||||||
|
description: FE collimating mirror try
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-MI1:TRY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
fecmi_pitch:
|
||||||
|
description: FE collimating mirror pitch
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-MI1:PITCH'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
fecmi_bend:
|
||||||
|
description: FE collimating mirror bend
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-FE-MI1:BEND1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
deviceTags:
|
||||||
|
- fe
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
slh_press:
|
||||||
|
description: OP slit pressure
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-OP-SLH-VMFR-1010:PRESSURE', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
slh_trxr:
|
||||||
|
description: OP slit inner blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-SLH:TRXR'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
slh_trxw:
|
||||||
|
description: OP slit outer blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-SLH:TRXW'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
fi1_try:
|
||||||
|
description: Beam attenuator motion before mono
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-FI1:TRY1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_theta1:
|
||||||
|
description: Monochromator pitch 1
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-DCCM:THETA1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_diode_top:
|
||||||
|
description: Top diode between mono crystals
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-OP-XPM1:TOP:READOUT', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_diode_bottom:
|
||||||
|
description: Bottom diode between mono crystals
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-OP-XPM1:BOT:READOUT', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_theta2:
|
||||||
|
description: Monochromator pitch 2
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-DCCM:THETA2'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_xbpm:
|
||||||
|
description: XBPM total intensity after monochromator
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-OP-XBPM1:SumAll:MeanValue_RBV', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_energy:
|
||||||
|
description: Monochromator energy
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-DCCM:ENERGY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
dccm_eoffset:
|
||||||
|
description: Monochromator energy offset
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-OP-DCCM:EOFFSET'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssxbpm_trx:
|
||||||
|
description: XBPM motion before secondary source
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSBPM1:TRX1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssxbpm_try:
|
||||||
|
description: XBPM motion before secondary source
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSBPM1:TRY1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssxbpm:
|
||||||
|
description: XBPM before secondary source
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-SSBPM1:SumAll:MeanValue_RBV'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
ssslit_trxr:
|
||||||
|
description: Secondary source blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSSH1:TRXR'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssslit_trxw:
|
||||||
|
description: Secondary source blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSSH1:TRXW'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssslit_tryt:
|
||||||
|
description: Secondary source blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSSV1:TRYT'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssslit_tryb:
|
||||||
|
description: Secondary source blade motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSSV1:TRYB'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssxi1_trx:
|
||||||
|
description: Secondary source diagnostic screen motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSXI1:TRX1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
ssxi1_try:
|
||||||
|
description: Secondary source diagnostic screen motion
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SSXI1:TRY1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_trxu:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:TRXU'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_trxd:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:TRXD'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
# vfm_tryuw:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-VFM:TRYUW'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
# vfm_tryr:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-VFM:TRYR'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
# vfm_trydw:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-VFM:TRYDW'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
vfm_pitch:
|
||||||
|
description: KB mirror vertical steering
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:PITCH'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_yaw:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:YAW'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_roll:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:ROLL'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_trx:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:TRX'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
vfm_try:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-VFM:TRY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_trxu:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:TRXU'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_trxd:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:TRXD'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
# hfm_tryur:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-HFM:TRYUR'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
# hfm_tryw:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-HFM:TRYW'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
# hfm_trydr:
|
||||||
|
# deviceClass: ophyd.EpicsMotor
|
||||||
|
# deviceConfig: {prefix: 'X06DA-ES-HFM:TRYDR'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
hfm_pitch:
|
||||||
|
description: KB mirror horizontal steering
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:PITCH'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_yaw:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:YAW'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_roll:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:ROLL'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_trx:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:TRX'}
|
||||||
|
enabled: false
|
||||||
|
onFailure: buffer
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
hfm_try:
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-HFM:TRY'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
# xbox_xbpm:
|
||||||
|
# description: Exposure box XBPM
|
||||||
|
# deviceClass: ophyd.EpicsSignalRO
|
||||||
|
# deviceConfig: {read_pv: 'X06DA-ES-XBBPM1:SumAll:MeanValue_RBV'}
|
||||||
|
# onFailure: buffer
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: monitored
|
||||||
|
# readOnly: true
|
||||||
|
# softwareTrigger: false
|
||||||
|
xbox_fil1:
|
||||||
|
description: Exposure box filter wheel 1
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-FI1:ROZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
xbox_fil2:
|
||||||
|
description: Exposure box filter wheel 2
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-FI2:ROZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
xbox_fil3:
|
||||||
|
description: Exposure box filter wheel 3
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-FI3:ROZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
xbox_fil4:
|
||||||
|
description: Exposure box filter wheel 4
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-FI4:ROZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
xbox_diode:
|
||||||
|
description: Exposure box diode
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-DI1:READOUT'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
gonpos:
|
||||||
|
description: Sample sensor distance
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-DF1:CBOX-USER1', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
gonvalid:
|
||||||
|
description: Sample in valid distance
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-DF1:CBOX-CMP1', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
samzoom:
|
||||||
|
description: Sample microscope zoom
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-SAMCAM:ZOOM'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
samcam:
|
||||||
|
description: Sample camera aggregate device
|
||||||
|
deviceClass: pxiii_bec.devices.SamCamDetector
|
||||||
|
deviceConfig: {prefix: 'X06DA-SAMCAM:'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
samstream:
|
||||||
|
description: Sample camera ZMQ stream
|
||||||
|
deviceClass: pxiii_bec.devices.StdDaqPreviewDetector
|
||||||
|
deviceConfig:
|
||||||
|
url: 'tcp://129.129.110.12:9089'
|
||||||
|
deviceTags:
|
||||||
|
- detector
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: async
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
# samimg:
|
||||||
|
# description: Sample camera image from EPICS
|
||||||
|
# deviceClass: pxiii_bec.devices.NDArrayPreview
|
||||||
|
# deviceConfig:
|
||||||
|
# prefix: 'X06DA-SAMCAM:image1:'
|
||||||
|
# deviceTags:
|
||||||
|
# - detector
|
||||||
|
# enabled: true
|
||||||
|
# readoutPriority: async
|
||||||
|
# readOnly: false
|
||||||
|
# softwareTrigger: false
|
||||||
|
|
||||||
|
|
||||||
|
bstop_pneum:
|
||||||
|
description: Beamstop pneumatic in-out
|
||||||
|
deviceClass: ophyd.EpicsSignal
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-BS:GET-POS', write_pv: 'X06DA-ES-BS:SET-POS'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
bstop_x:
|
||||||
|
description: Beamstop translation
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-BS:TRX1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
bstop_y:
|
||||||
|
description: Beamstop translation
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-BS:TRY1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
bstop_z:
|
||||||
|
description: Beamstop translation
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-BS:TRZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
bstop_pneum:
|
||||||
|
description: Beamstop pneumatic
|
||||||
|
deviceClass: pxiii_bec.devices.PneumaticValve
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-BS:GET-POS', write_pv: 'X06DA-ES-BS:SET-POS', kind: 'config', auto_monitor: true, put_complete: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: baseline
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
bstop_diode:
|
||||||
|
description: Beamstop diode
|
||||||
|
deviceClass: ophyd.EpicsSignalRO
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-BS:READOUT', auto_monitor: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: true
|
||||||
|
softwareTrigger: false
|
||||||
|
frontlight:
|
||||||
|
description: Microscope frontlight
|
||||||
|
deviceClass: ophyd.EpicsSignal
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-FL:SET-BRGHT', kind: 'config', put_complete: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
backlight:
|
||||||
|
description: Backlight reflector
|
||||||
|
deviceClass: pxiii_bec.devices.PneumaticValve
|
||||||
|
deviceConfig: {read_pv: 'X06DA-ES-BL:GET-POS', write_pv: 'X06DA-ES-BL:SET-POS', kind: 'config', auto_monitor: true, put_complete: true}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: baseline
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gmx:
|
||||||
|
description: ABR horizontal stage
|
||||||
|
deviceClass: pxiii_bec.devices.A3200Axis
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DF1:GMX', base_pv: 'X06DA-ES'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
gmy:
|
||||||
|
description: ABR vertical stage
|
||||||
|
deviceClass: pxiii_bec.devices.A3200Axis
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DF1:GMY', base_pv: 'X06DA-ES'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
gmz:
|
||||||
|
description: ABR axial stage
|
||||||
|
deviceClass: pxiii_bec.devices.A3200Axis
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DF1:GMZ', base_pv: 'X06DA-ES'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
omega:
|
||||||
|
description: ABR rotation stage
|
||||||
|
deviceClass: pxiii_bec.devices.A3200Axis
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DF1:OMEGA', base_pv: 'X06DA-ES'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
abr:
|
||||||
|
description: Aerotech ABR motion system
|
||||||
|
deviceClass: pxiii_bec.devices.AerotechAbrStage
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
shx:
|
||||||
|
description: SmarGon X axis
|
||||||
|
deviceClass: pxiii_bec.devices.SmarGonAxisB
|
||||||
|
deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
shy:
|
||||||
|
description: SmarGon Y axis
|
||||||
|
deviceClass: pxiii_bec.devices.SmarGonAxisB
|
||||||
|
deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
shz:
|
||||||
|
description: SmarGon Z axis
|
||||||
|
deviceClass: pxiii_bec.devices.SmarGonAxisB
|
||||||
|
deviceConfig: {prefix: 'SCS', low_limit: 10, high_limit: 22, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
chi:
|
||||||
|
description: SmarGon CHI axis
|
||||||
|
deviceClass: pxiii_bec.devices.SmarGonAxisB
|
||||||
|
deviceConfig: {prefix: 'SCS', low_limit: 0, high_limit: 40, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
phi:
|
||||||
|
description: SmarGon PHI axis
|
||||||
|
deviceClass: pxiii_bec.devices.SmarGonAxisB
|
||||||
|
deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
det_y:
|
||||||
|
description: Pilatus height
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DET:TRY1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
det_z:
|
||||||
|
description: Pilatus translation
|
||||||
|
deviceClass: ophyd.EpicsMotor
|
||||||
|
deviceConfig: {prefix: 'X06DA-ES-DET:TRZ1'}
|
||||||
|
onFailure: buffer
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: monitored
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
@@ -11,42 +11,74 @@ Created on Thu Jan 30 2025
|
|||||||
|
|
||||||
@author: mohacsi_i
|
@author: mohacsi_i
|
||||||
"""
|
"""
|
||||||
from ophyd import ADComponent
|
from __future__ import annotations
|
||||||
from ophyd_devices.devices.areadetector.cam import GenICam
|
|
||||||
|
|
||||||
# from ophyd_devices.devices.areadetector.plugins import ImagePlugin_V35
|
from typing import TYPE_CHECKING
|
||||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
|
||||||
PSIDetectorBase,
|
|
||||||
CustomDetectorMixin,
|
|
||||||
)
|
|
||||||
|
|
||||||
from bec_lib import bec_logger
|
from bec_lib import bec_logger
|
||||||
|
from ophyd import ADComponent
|
||||||
|
from ophyd_devices.devices.areadetector.cam import GenICam
|
||||||
|
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ophyd import DeviceStatus, StatusBase
|
||||||
|
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|
||||||
class SamCamSetup(CustomDetectorMixin):
|
class SamCamDetector(PSIDeviceBase):
|
||||||
"""Simple camera mixin class, the SAMCAM is usually streaming"""
|
|
||||||
|
|
||||||
def on_stage(self):
|
|
||||||
"""Just make sure it's running continously"""
|
|
||||||
self.parent.cam.acquire.put(1, wait=True)
|
|
||||||
|
|
||||||
def on_unstage(self):
|
|
||||||
"""Should run continously"""
|
|
||||||
|
|
||||||
def on_stop(self):
|
|
||||||
"""Should run continously"""
|
|
||||||
|
|
||||||
|
|
||||||
class SamCamDetector(PSIDetectorBase):
|
|
||||||
"""Sample camera device
|
"""Sample camera device
|
||||||
|
|
||||||
The SAMCAM continously streams images to the GUI and sample alignment
|
The SAMCAM continously streams images to the GUI and sample alignment
|
||||||
scripts via ZMQ.
|
scripts via ZMQ.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
custom_prepare_cls = SamCamSetup
|
|
||||||
|
|
||||||
cam = ADComponent(GenICam, "cam1:")
|
cam = ADComponent(GenICam, "cam1:")
|
||||||
# image = ADComponent(ImagePlugin_V35, "image1:")
|
|
||||||
|
########################################
|
||||||
|
# Beamline Specific Implementations #
|
||||||
|
########################################
|
||||||
|
|
||||||
|
def on_init(self) -> None:
|
||||||
|
"""
|
||||||
|
Called when the device is initialized.
|
||||||
|
|
||||||
|
No signals are connected at this point. If you like to
|
||||||
|
set default values on signals, please use on_connected instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def on_connected(self) -> None:
|
||||||
|
"""
|
||||||
|
Called after the device is connected and its signals are connected.
|
||||||
|
Default values for signals should be set here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def on_stage(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""
|
||||||
|
Called while staging the device.
|
||||||
|
|
||||||
|
Information about the upcoming scan can be accessed from the scan_info (self.scan_info.msg) object.
|
||||||
|
"""
|
||||||
|
self.parent.cam.acquire.put(1, wait=True)
|
||||||
|
|
||||||
|
def on_unstage(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""Called while unstaging the device."""
|
||||||
|
|
||||||
|
def on_pre_scan(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""Called right before the scan starts on all devices automatically."""
|
||||||
|
|
||||||
|
def on_trigger(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""Called when the device is triggered."""
|
||||||
|
|
||||||
|
def on_complete(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""Called to inquire if a device has completed a scans."""
|
||||||
|
|
||||||
|
def on_kickoff(self) -> DeviceStatus | StatusBase | None:
|
||||||
|
"""Called to kickoff a device for a fly scan. Has to be called explicitly."""
|
||||||
|
|
||||||
|
def on_stop(self) -> None:
|
||||||
|
"""Called when the device is stopped."""
|
||||||
|
|
||||||
|
def on_destroy(self) -> None:
|
||||||
|
"""Called when the device is destroyed. Cleanup resources here."""
|
||||||
|
|||||||
@@ -1,357 +0,0 @@
|
|||||||
"""Utility functions for calculating energy, wavelength, and Bragg angle."""
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import numpy as np
|
|
||||||
# from pxii_parameters import (EnergyDefaults, CamConversion)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Constants:
|
|
||||||
"""Constants used in energy calculations"""
|
|
||||||
|
|
||||||
# # Physical Constants from https://physics.nist.gov/cuu/Constants/index.html
|
|
||||||
ANGSTROM_CONVERSION = 1e10 # Convert meters to angstrom
|
|
||||||
PLANCK_CONST_EV = 4.135667696e-15 # eV/Hz
|
|
||||||
SPEED_OF_LIGHT = 299792458 # m/s
|
|
||||||
|
|
||||||
# d-spacings
|
|
||||||
d_spacing = {120: 3.13481, 298: 3.13562}
|
|
||||||
|
|
||||||
|
|
||||||
def speed_of_light_ang():
|
|
||||||
"""
|
|
||||||
Calculate the speed of light in angstroms per second.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: The speed of light converted to angstroms per second.
|
|
||||||
"""
|
|
||||||
return Constants.SPEED_OF_LIGHT * Constants.ANGSTROM_CONVERSION
|
|
||||||
|
|
||||||
|
|
||||||
def en_wav_factor():
|
|
||||||
"""
|
|
||||||
Calculate the energy wavelength factor.
|
|
||||||
|
|
||||||
This function computes a constant factor used to calculate energy
|
|
||||||
values in relation to wavelength by combining Planck's constant,
|
|
||||||
in eV/Hz, and the speed of light in angstrom.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: The computed energy wavelength factor.
|
|
||||||
"""
|
|
||||||
return Constants.PLANCK_CONST_EV * speed_of_light_ang()
|
|
||||||
|
|
||||||
|
|
||||||
# Helper Functions
|
|
||||||
def convert_to_degrees(angle_mrad: float) -> float:
|
|
||||||
"""
|
|
||||||
Convert an angle from milliradians to degrees.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
angle_mrad: The angle value in milliradians.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The angle converted into degrees as a float.
|
|
||||||
"""
|
|
||||||
return np.rad2deg(angle_mrad / 1000)
|
|
||||||
|
|
||||||
|
|
||||||
def create_conversion_result(
|
|
||||||
energy_ev: float, wavelength: float, bragg_angle_mrad: float
|
|
||||||
) -> dict:
|
|
||||||
"""
|
|
||||||
Creates a dictionary containing converted values of energy and angles.
|
|
||||||
|
|
||||||
This function takes the energy in electron-volts, the wavelength,
|
|
||||||
and the Bragg angle in milliradians as input. It computes and
|
|
||||||
returns a dictionary containing the energy in both electron-volts
|
|
||||||
and kiloelectron-volts, the wavelength, the Bragg angle in milliradians,
|
|
||||||
and the Bragg angle converted to degrees.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev: Energy value in electron-volts.
|
|
||||||
wavelength: Wavelength value.
|
|
||||||
bragg_angle_mrad: Bragg angle in milliradians.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing the following keys:
|
|
||||||
- "energy_kev": Energy value in kiloelectron-volts.
|
|
||||||
- "energy_ev": Energy value in electron-volts.
|
|
||||||
- "wavelength": Wavelength value.
|
|
||||||
- "bragg_angle_mrad": Bragg angle in milliradians.
|
|
||||||
- "bragg_angle_deg": Bragg angle in degrees.
|
|
||||||
"""
|
|
||||||
return {
|
|
||||||
"energy_kev": energy_ev / 1000,
|
|
||||||
"energy_ev": energy_ev,
|
|
||||||
"wavelength": wavelength,
|
|
||||||
"bragg_angle_mrad": float(bragg_angle_mrad),
|
|
||||||
"bragg_angle_deg": float(convert_to_degrees(bragg_angle_mrad)),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def print_conversion_result(result: dict) -> None:
|
|
||||||
"""
|
|
||||||
Prints the energy-related conversion results to the console.
|
|
||||||
"""
|
|
||||||
|
|
||||||
line = (
|
|
||||||
f"energy: {result['energy_ev']:.6g} eV, energy: {result['energy_kev']:.6g} keV, "
|
|
||||||
f"wavelength: {result['wavelength']:.4g} Å, "
|
|
||||||
f"bragg angle: {result['bragg_angle_mrad']:.5g} mrad, {result['bragg_angle_deg']:.4g} deg"
|
|
||||||
)
|
|
||||||
print(line)
|
|
||||||
|
|
||||||
|
|
||||||
# Conversion Functions
|
|
||||||
def calculate_wavelength_from_angle(bragg_angle_mrad: float, temp=120) -> float:
|
|
||||||
"""
|
|
||||||
calculate_wavelength_from_angle(bragg_angle_mrad: float) -> float
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
bragg_angle_mrad: The Bragg angle in milliradians, used to compute the
|
|
||||||
sine value required for the wavelength calculation.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The calculated wavelength as a float value.
|
|
||||||
"""
|
|
||||||
d = Constants.d_spacing[temp]
|
|
||||||
return 2 * d * np.sin(bragg_angle_mrad / 1000)
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_energy_from_wavelength(wavelength: float) -> float:
|
|
||||||
"""
|
|
||||||
Calculates the energy of a photon based on its wavelength.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
wavelength: The wavelength of the photon in angstrom.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The energy of the photon in eV.
|
|
||||||
"""
|
|
||||||
return en_wav_factor() / wavelength
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_wavelength_from_energy(energy_ev: float) -> float:
|
|
||||||
"""
|
|
||||||
Calculates the wavelength of a photon from its energy.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
energy_ev: float
|
|
||||||
The energy of the photon in electronvolts (eV).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float
|
|
||||||
The calculated wavelength of the photon in angstrom.
|
|
||||||
"""
|
|
||||||
return en_wav_factor() / energy_ev
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_bragg_angle_from_wavelength(wavelength: float, temp=120) -> float:
|
|
||||||
"""
|
|
||||||
Calculate the Bragg angle in milliradians for a given wavelength.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
wavelength: The wavelength in angstrom.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The Bragg angle in milliradians as a float.
|
|
||||||
"""
|
|
||||||
d = Constants.d_spacing[temp]
|
|
||||||
angle_rad = np.arcsin(wavelength / (2 * d))
|
|
||||||
return angle_rad * 1000
|
|
||||||
|
|
||||||
|
|
||||||
def convert_input_angle_to_mrad(bragg_angle: float) -> float:
|
|
||||||
"""
|
|
||||||
Convert input angle into milliradians (mrad).
|
|
||||||
|
|
||||||
This function takes an angle as input and determines its likely unit,
|
|
||||||
converting it to milliradians (mrad) if necessary. If the input value
|
|
||||||
is less than 1, it is assumed to be in radians and is converted to
|
|
||||||
mrad. If the input value falls between predefined minimum and
|
|
||||||
maximum values for mrad, it is assumed to be in degrees and thus
|
|
||||||
converted to mrad using the degrees-to-radians conversion factor.
|
|
||||||
|
|
||||||
For input values that don't match these scenarios, it assumes
|
|
||||||
that the input is already in mrad and returns it unchanged.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
bragg_angle (float): The input Bragg angle, which can be in
|
|
||||||
radians, degrees, or milliradians.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: The Bragg angle converted into milliradians (mrad).
|
|
||||||
"""
|
|
||||||
if bragg_angle < 1: # Likely the input angle is in radians
|
|
||||||
return bragg_angle * 1000
|
|
||||||
if 3 < bragg_angle < 25: # Likely input angle is in degrees
|
|
||||||
return np.deg2rad(bragg_angle) * 1000
|
|
||||||
return bragg_angle # Already in mrad
|
|
||||||
|
|
||||||
|
|
||||||
# Core Functions
|
|
||||||
def validate_energy(energy_ev):
|
|
||||||
"""
|
|
||||||
Validates the energy value to ensure it falls within the acceptable range. The function
|
|
||||||
converts the provided energy from keV to eV if the input value is less than 1/1000 of the
|
|
||||||
maximum energy value. It then checks whether the energy is within the defined bounds.
|
|
||||||
If the energy value is outside the acceptable range, the function raises a ValueError.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev (float): The energy value in eV or keV to be validated. If this value is
|
|
||||||
smaller than 1/1000 of the maximum allowed energy (in eV), it will be multiplied
|
|
||||||
by 1000 to convert it from keV to eV.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: The validated energy value in eV that falls within the acceptable range.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If the energy value is outside the defined range of
|
|
||||||
[MIN_ENERGY_EV, MAX_ENERGY_EV].
|
|
||||||
"""
|
|
||||||
if energy_ev < EnergyDefaults.max_energy_ev / 1000: # Assuming the input is in keV.
|
|
||||||
energy_ev *= 1000
|
|
||||||
if not EnergyDefaults.min_energy_ev <= energy_ev <= EnergyDefaults.max_energy_ev:
|
|
||||||
raise ValueError(
|
|
||||||
f"Energy of {energy_ev} eV is outside the valid range "
|
|
||||||
f"({EnergyDefaults.min_energy_ev} eV to {EnergyDefaults.max_energy_ev} eV)"
|
|
||||||
)
|
|
||||||
return energy_ev
|
|
||||||
|
|
||||||
|
|
||||||
def convert_from_bragg(
|
|
||||||
bragg_angle_mrad: float, temp=120, print_result: bool = False
|
|
||||||
) -> dict:
|
|
||||||
"""
|
|
||||||
Convert the Bragg angle to wavelength and energy, returning the result as a dictionary.
|
|
||||||
|
|
||||||
This function converts a given Bragg angle (in milliradians) into the corresponding
|
|
||||||
wavelength and energy values, and returns them in a dictionary format. The function
|
|
||||||
also supports optional printing of the calculated results.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bragg_angle_mrad (float): The Bragg angle in milliradians to be converted.
|
|
||||||
print_result (bool): Whether to print the conversion result. Defaults to False.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing the following keys:
|
|
||||||
- 'energy_ev': Energy in electronvolts.
|
|
||||||
- 'wavelength': Wavelength corresponding to the input angle.
|
|
||||||
- 'bragg_angle_mrad': Input Bragg angle in milliradians.
|
|
||||||
"""
|
|
||||||
bragg_angle_mrad = convert_input_angle_to_mrad(bragg_angle_mrad)
|
|
||||||
wavelength = float(calculate_wavelength_from_angle(bragg_angle_mrad, temp=temp))
|
|
||||||
energy_ev = float(calculate_energy_from_wavelength(wavelength))
|
|
||||||
result = create_conversion_result(energy_ev, wavelength, bragg_angle_mrad)
|
|
||||||
if print_result:
|
|
||||||
print_conversion_result(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def convert_from_energy(energy_ev: float, temp=120, print_result: bool = False) -> dict:
|
|
||||||
"""
|
|
||||||
Convert energy in electron volts (eV) to wavelength and Bragg angle in milliradians
|
|
||||||
(mrad). This method validates the given energy, calculates corresponding properties,
|
|
||||||
and optionally prints the result.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev: Energy value in electron volts (float) to be converted.
|
|
||||||
print_result: Flag indicating whether to print the resulting
|
|
||||||
conversion details (bool). Defaults to False.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dictionary containing the following key-value pairs:
|
|
||||||
- "energy_ev" (float): Validated energy in eV.
|
|
||||||
- "wavelength" (float): Calculated wavelength in meters.
|
|
||||||
- "bragg_angle_mrad" (float): Calculated Bragg angle in mrad.
|
|
||||||
"""
|
|
||||||
energy_ev = validate_energy(energy_ev)
|
|
||||||
wavelength = calculate_wavelength_from_energy(energy_ev)
|
|
||||||
bragg_angle_mrad = float(
|
|
||||||
calculate_bragg_angle_from_wavelength(wavelength, temp=temp)
|
|
||||||
)
|
|
||||||
result = create_conversion_result(energy_ev, wavelength, bragg_angle_mrad)
|
|
||||||
if print_result:
|
|
||||||
print_conversion_result(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def convert_from_wavelength(
|
|
||||||
wavelength: float,
|
|
||||||
temp: float = 120,
|
|
||||||
print_result: bool = False,
|
|
||||||
) -> dict:
|
|
||||||
"""
|
|
||||||
Convert a given wavelength value into corresponding energy, Bragg angle, and
|
|
||||||
generate a result dictionary.
|
|
||||||
|
|
||||||
The function processes a wavelength value, checks its validity against a
|
|
||||||
permitted range, calculates corresponding energy and Bragg angle, and
|
|
||||||
formats the results into a dictionary. Optionally, the function can print
|
|
||||||
the result.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
wavelength: float
|
|
||||||
The input wavelength value in Angstroms to be converted. Should
|
|
||||||
fall within the permitted wavelength range.
|
|
||||||
print_result: bool
|
|
||||||
Optional flag indicating whether to print the conversion result.
|
|
||||||
Default is False.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict
|
|
||||||
A dictionary containing the energy (electron-volts), wavelength
|
|
||||||
(Angstroms), and Bragg angle (milliradians). If the wavelength is
|
|
||||||
outside of the permitted range, returns None.
|
|
||||||
"""
|
|
||||||
energy_ev = calculate_energy_from_wavelength(wavelength)
|
|
||||||
bragg_angle_mrad = float(
|
|
||||||
calculate_bragg_angle_from_wavelength(wavelength, temp=temp)
|
|
||||||
)
|
|
||||||
result = create_conversion_result(energy_ev, wavelength, bragg_angle_mrad)
|
|
||||||
if print_result:
|
|
||||||
print_conversion_result(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def calc_perp_position(
|
|
||||||
energy_ev: float,
|
|
||||||
print_result: bool = False,
|
|
||||||
) -> float:
|
|
||||||
"""
|
|
||||||
Calculate the perpendicular motor position based on provided energy in electron-volts (eV).
|
|
||||||
|
|
||||||
This function computes the perpendicular motor position using the given energy value in
|
|
||||||
electron-volts. The calculation is based on the Bragg angle derived from the energy. An optional
|
|
||||||
parameter allows printing the result during execution.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
energy_ev (float): The energy value in electron-volts used for the calculation.
|
|
||||||
print_result (bool): Flag to determine whether to print the computed perpendicular offset.
|
|
||||||
Default is False.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: The computed perpendicular position.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
result = convert_from_energy(energy_ev, print_result=False)
|
|
||||||
bragg_angle_rad = result["bragg_angle_mrad"] / 1000
|
|
||||||
perp_offset = float(EnergyDefaults.beam_offset / (2 * np.cos(bragg_angle_rad))) - 3
|
|
||||||
if print_result:
|
|
||||||
print(f"Perp = {perp_offset: .4f}")
|
|
||||||
return perp_offset
|
|
||||||
|
|
||||||
def calc_scam_microns(pixels, zoom = 1000):
|
|
||||||
return pixels/(0.5208 * np.exp(0.002586 * zoom))
|
|
||||||
|
|
||||||
def calc_scam_microns(pixels, zoom=1000):
|
|
||||||
"""Convert pixels to microns for the sample camera"""
|
|
||||||
return float(pixels / (CamConversion.a * np.exp(CamConversion.b * zoom)))
|
|
||||||
|
|
||||||
def calc_bsccam_microns(pixels):
|
|
||||||
"""Convert pixels to microns for the BSC camera"""
|
|
||||||
return pixels*20
|
|
||||||
|
|
||||||
@@ -1,495 +0,0 @@
|
|||||||
from dataclasses import dataclass, field
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Any, Callable
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from bec_lib.device import Signal, Positioner
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Status Enum
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
|
||||||
OK = 0
|
|
||||||
WARNING = 1
|
|
||||||
ERROR = 2
|
|
||||||
UNKNOWN = 3
|
|
||||||
|
|
||||||
@property
|
|
||||||
def color(self):
|
|
||||||
return {
|
|
||||||
Status.OK: "green",
|
|
||||||
Status.WARNING: "yellow",
|
|
||||||
Status.ERROR: "red",
|
|
||||||
Status.UNKNOWN: "blue",
|
|
||||||
}[self]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def color_scilog(self):
|
|
||||||
return {
|
|
||||||
Status.OK: "green",
|
|
||||||
Status.WARNING: "",
|
|
||||||
Status.ERROR: "red",
|
|
||||||
Status.UNKNOWN: "",
|
|
||||||
}[self]
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Health Result Object
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class HealthCheckResult:
|
|
||||||
|
|
||||||
name: str
|
|
||||||
description: str
|
|
||||||
status: Status
|
|
||||||
|
|
||||||
value: Any = None
|
|
||||||
|
|
||||||
message: str = ""
|
|
||||||
|
|
||||||
category: str = "general"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
|
|
||||||
if self.status == Status.OK:
|
|
||||||
return f"[{self.status.name}] {self.description}"
|
|
||||||
|
|
||||||
return (
|
|
||||||
f"[{self.status.name}] "
|
|
||||||
f"{self.description}: {self.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def formatted_message(self):
|
|
||||||
if self.status == Status.OK:
|
|
||||||
return f"[{self.status.name}] {self.name}"
|
|
||||||
|
|
||||||
return (
|
|
||||||
f"[{self.status.name}] "
|
|
||||||
f"{self.description}: {self.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Send to SciLog
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
def send_to_scilog(results):
|
|
||||||
|
|
||||||
counts = {
|
|
||||||
Status.OK: 0,
|
|
||||||
Status.WARNING: 0,
|
|
||||||
Status.ERROR: 0,
|
|
||||||
Status.UNKNOWN: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
for result in results:
|
|
||||||
counts[result.status] += 1
|
|
||||||
timestamp = datetime.now().strftime("%Y/%m/%d %H:%M")
|
|
||||||
|
|
||||||
msg = bec.messaging.scilog.new()
|
|
||||||
|
|
||||||
msg.add_text(
|
|
||||||
f"Beamline Health Summary {timestamp}",
|
|
||||||
bold = True
|
|
||||||
)
|
|
||||||
|
|
||||||
msg.add_text("\n")
|
|
||||||
for status, count in counts.items():
|
|
||||||
msg.add_text(
|
|
||||||
f"{status.name:<10}: {count}",
|
|
||||||
bold=True,
|
|
||||||
)
|
|
||||||
msg.add_text("\n")
|
|
||||||
|
|
||||||
for result in results:
|
|
||||||
msg.add_text(
|
|
||||||
result.formatted_message(),
|
|
||||||
# bold=result.status != Status.OK,
|
|
||||||
color = result.status.color_scilog
|
|
||||||
)
|
|
||||||
msg.add_text("\n")
|
|
||||||
msg.add_tags(["beamline health check"])
|
|
||||||
msg.send()
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Configuration
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class BeamlineHealthConfig:
|
|
||||||
|
|
||||||
signal_rules: dict[str, Callable] = field(
|
|
||||||
default_factory=lambda: {
|
|
||||||
"cam": lambda x: x != 0,
|
|
||||||
"bpm": lambda x: x != 0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
motor_tolerances: dict[str, float] = field(
|
|
||||||
default_factory=lambda: {
|
|
||||||
# examples
|
|
||||||
# "mono_theta": 0.001,
|
|
||||||
# "detector_z": 0.1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
default_motor_tolerance: float = 0.02
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Device Collection
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def get_devices():
|
|
||||||
return list(dev.items())
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Signal Checks
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def check_signals(devices, config: BeamlineHealthConfig):
|
|
||||||
|
|
||||||
results = []
|
|
||||||
|
|
||||||
signal_devices = [
|
|
||||||
(name, obj)
|
|
||||||
for name, obj in devices
|
|
||||||
if isinstance(obj, Signal)
|
|
||||||
]
|
|
||||||
|
|
||||||
for name, obj in signal_devices:
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = obj.read()
|
|
||||||
actual = data[name]["value"]
|
|
||||||
description = obj.description
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=name,
|
|
||||||
status=Status.UNKNOWN,
|
|
||||||
message=f"Failed to read signal: {e}",
|
|
||||||
category="signals",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
matched = False
|
|
||||||
|
|
||||||
for keyword, rule in config.signal_rules.items():
|
|
||||||
|
|
||||||
if keyword in name:
|
|
||||||
|
|
||||||
matched = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
passed = rule(actual)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=name,
|
|
||||||
status=Status.UNKNOWN,
|
|
||||||
value=actual,
|
|
||||||
message=f"Rule evaluation failed: {e}",
|
|
||||||
category="signals",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
if passed:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.OK,
|
|
||||||
value=actual,
|
|
||||||
category="signals",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.ERROR,
|
|
||||||
value=actual,
|
|
||||||
message=f"Signal value {actual} failed validation",
|
|
||||||
category="signals",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
if not matched:
|
|
||||||
continue
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Motor Checks
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def check_motors(devices, config: BeamlineHealthConfig):
|
|
||||||
|
|
||||||
results = []
|
|
||||||
|
|
||||||
motor_devices = [
|
|
||||||
(name, obj)
|
|
||||||
for name, obj in devices
|
|
||||||
if isinstance(obj, Positioner)
|
|
||||||
]
|
|
||||||
|
|
||||||
for name, obj in motor_devices:
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
data = obj.read()
|
|
||||||
|
|
||||||
description = obj.description
|
|
||||||
|
|
||||||
actual = data[name]["value"]
|
|
||||||
|
|
||||||
error_code = obj.motor_status.get()
|
|
||||||
|
|
||||||
move_state = obj.motor_is_moving.get()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=name,
|
|
||||||
status=Status.UNKNOWN,
|
|
||||||
message=f"Failed to read motor: {e}",
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
# Error state
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
|
|
||||||
if error_code != 0:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.ERROR,
|
|
||||||
value=error_code,
|
|
||||||
message=f"motor error code: {error_code}",
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
# Moving state
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
|
|
||||||
if move_state != 0:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.WARNING,
|
|
||||||
value=move_state,
|
|
||||||
message="motor is currently moving",
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
# Setpoint comparison
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
|
|
||||||
sp_key = f"{name}_user_setpoint"
|
|
||||||
|
|
||||||
if sp_key in data:
|
|
||||||
|
|
||||||
setpoint = data[sp_key]["value"]
|
|
||||||
|
|
||||||
diff = abs(actual - setpoint)
|
|
||||||
|
|
||||||
tolerance = config.motor_tolerances.get(
|
|
||||||
name,
|
|
||||||
config.default_motor_tolerance,
|
|
||||||
)
|
|
||||||
|
|
||||||
if diff > tolerance:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.WARNING,
|
|
||||||
value=diff,
|
|
||||||
message=(
|
|
||||||
f"Setpoint {setpoint:.5g} differs "
|
|
||||||
f"from readback {actual:.5g} "
|
|
||||||
f"by {diff:.4g}"
|
|
||||||
),
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.OK,
|
|
||||||
value=actual,
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
HealthCheckResult(
|
|
||||||
name=name,
|
|
||||||
description=description,
|
|
||||||
status=Status.UNKNOWN,
|
|
||||||
message="No setpoint available",
|
|
||||||
category="motors",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Main Check Entry Point
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def check2(config: BeamlineHealthConfig | None = None):
|
|
||||||
if config is None:
|
|
||||||
config = BeamlineHealthConfig()
|
|
||||||
|
|
||||||
devices = get_devices()
|
|
||||||
|
|
||||||
results = []
|
|
||||||
|
|
||||||
results.extend(check_signals(devices, config))
|
|
||||||
|
|
||||||
results.extend(check_motors(devices, config))
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# Sort by severity
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
|
|
||||||
results.sort(
|
|
||||||
key=lambda r: r.status.value,
|
|
||||||
)
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Summary Printer
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def summary_text(results):
|
|
||||||
|
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
||||||
|
|
||||||
|
|
||||||
n_ok = sum(r.status == Status.OK for r in results)
|
|
||||||
|
|
||||||
n_warn = sum(r.status == Status.WARNING for r in results)
|
|
||||||
|
|
||||||
n_err = sum(r.status == Status.ERROR for r in results)
|
|
||||||
|
|
||||||
n_unknown = sum(r.status == Status.UNKNOWN for r in results)
|
|
||||||
|
|
||||||
return (
|
|
||||||
f"==========================================\n"
|
|
||||||
f"Beamline Health Check at {timestamp}\n"
|
|
||||||
f"==========================================\n"
|
|
||||||
f"OK : {n_ok}\n"
|
|
||||||
f"WARNING : {n_warn}\n"
|
|
||||||
f"ERROR : {n_err}\n"
|
|
||||||
f"UNKNOWN : {n_unknown}\n"
|
|
||||||
"==========================================\n"
|
|
||||||
)
|
|
||||||
# return "\n".join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# Filter results
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
def filter_results(results, statuses = None):
|
|
||||||
if statuses is None:
|
|
||||||
return results
|
|
||||||
|
|
||||||
return [
|
|
||||||
r for r in results
|
|
||||||
if r.status in statuses
|
|
||||||
]
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# CLI Entry Point
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def run_check(show_all= False):
|
|
||||||
|
|
||||||
results = check2()
|
|
||||||
|
|
||||||
print(summary_text(results))
|
|
||||||
|
|
||||||
problem_results = filter_results(
|
|
||||||
results,
|
|
||||||
statuses={
|
|
||||||
Status.WARNING,
|
|
||||||
Status.ERROR,
|
|
||||||
Status.UNKNOWN,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
send_to_scilog(results)
|
|
||||||
|
|
||||||
if not show_all:
|
|
||||||
results = filter_results(
|
|
||||||
results,
|
|
||||||
statuses={
|
|
||||||
Status.WARNING,
|
|
||||||
Status.ERROR,
|
|
||||||
Status.UNKNOWN
|
|
||||||
}
|
|
||||||
)
|
|
||||||
for result in results:
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
"""Get data from an h5 file or BEC history and perform fitting."""
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from lmfit.models import (
|
|
||||||
GaussianModel,
|
|
||||||
LorentzianModel,
|
|
||||||
VoigtModel,
|
|
||||||
ConstantModel,
|
|
||||||
LinearModel,
|
|
||||||
)
|
|
||||||
from scipy.ndimage import gaussian_filter1d
|
|
||||||
import h5py
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
|
|
||||||
def create_fit_parameters(
|
|
||||||
deriv: bool = False,
|
|
||||||
model: str = "Voigt",
|
|
||||||
baseline: str = "Linear",
|
|
||||||
smoothing: None = None,
|
|
||||||
):
|
|
||||||
"""Store the fit parameters in a dictionary."""
|
|
||||||
# map input model to lmfit model name
|
|
||||||
model_mappings = {
|
|
||||||
"Gaussian": GaussianModel,
|
|
||||||
"Lorentzian": LorentzianModel,
|
|
||||||
"Voigt": VoigtModel,
|
|
||||||
"Constant": ConstantModel,
|
|
||||||
"Linear": LinearModel,
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
"deriv": deriv,
|
|
||||||
"model": model_mappings[model],
|
|
||||||
"baseline": model_mappings[baseline],
|
|
||||||
"smoothing": smoothing,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_data_from_h5(signal_name: str = "lu_bpmsum"):
|
|
||||||
"""Get data from an h5 file."""
|
|
||||||
with h5py.File("scan_676.h5", "r") as f:
|
|
||||||
entry = f["entry"]["collection"]
|
|
||||||
y_data = entry["devices"][signal_name][signal_name]["value"][:]
|
|
||||||
motor_data = entry["metadata"]["bec"]
|
|
||||||
motor_name = motor_data["scan_motors"][0].decode()
|
|
||||||
scan_number = motor_data["scan_number"][()]
|
|
||||||
x_data = entry["devices"][motor_name][motor_name]["value"][:]
|
|
||||||
return {
|
|
||||||
"x_data": x_data,
|
|
||||||
"y_data": y_data,
|
|
||||||
"signal_name": signal_name,
|
|
||||||
"motor_name": motor_name,
|
|
||||||
"scan_number": str(scan_number),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_data_from_history(
|
|
||||||
history_index: int,
|
|
||||||
signal_name: str = "lu_bpmsum",
|
|
||||||
):
|
|
||||||
"""Read data from the BEC history and return the X and Y data as arrays."""
|
|
||||||
scan = bec.history[history_index]
|
|
||||||
md = scan.metadata["bec"]
|
|
||||||
motor_name = md["scan_motors"][0].decode()
|
|
||||||
scan_number = md["scan_number"]
|
|
||||||
x_data = scan.devices[motor_name][motor_name].read()["value"]
|
|
||||||
y_data = scan.devices[signal_name][signal_name].read()["value"]
|
|
||||||
return {
|
|
||||||
"signal_name": signal_name,
|
|
||||||
"x_data": x_data,
|
|
||||||
"y_data": y_data,
|
|
||||||
"motor_name": motor_name,
|
|
||||||
"scan_number": scan_number,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def process_data(data, fit_params):
|
|
||||||
"""
|
|
||||||
Process the signal data for fitting based on derivative or smoothing.
|
|
||||||
"""
|
|
||||||
smoothing, deriv = fit_params["smoothing"], fit_params["deriv"]
|
|
||||||
signal_name = data["signal_name"]
|
|
||||||
y_data = data["y_data"]
|
|
||||||
|
|
||||||
if deriv:
|
|
||||||
if smoothing:
|
|
||||||
y_smooth = gaussian_filter1d(y_data, smoothing)
|
|
||||||
fitting_data = np.gradient(y_smooth)
|
|
||||||
signal_name = f"Derivative of smoothed {signal_name}"
|
|
||||||
else:
|
|
||||||
fitting_data = np.gradient(y_data)
|
|
||||||
signal_name = f"Derivative of {signal_name}"
|
|
||||||
elif smoothing and smoothing > 0.01:
|
|
||||||
fitting_data = gaussian_filter1d(y_data, smoothing)
|
|
||||||
signal_name = f"Smoothed {signal_name}"
|
|
||||||
else:
|
|
||||||
fitting_data = y_data
|
|
||||||
|
|
||||||
updated_data = {
|
|
||||||
"y_to_fit": fitting_data,
|
|
||||||
"signal_name": signal_name,
|
|
||||||
}
|
|
||||||
data.update(updated_data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def fit(data, fit_params):
|
|
||||||
"""Fit a signal to a model and return the fitting results."""
|
|
||||||
# Create the model
|
|
||||||
peak_model = fit_params["model"](prefix="peak_")
|
|
||||||
baseline_model = fit_params["baseline"](prefix="base_")
|
|
||||||
full_model = peak_model + baseline_model
|
|
||||||
|
|
||||||
# Prepare data
|
|
||||||
processed_data = process_data(data, fit_params)
|
|
||||||
params = full_model.make_params()
|
|
||||||
y_min = np.min(processed_data["y_to_fit"])
|
|
||||||
|
|
||||||
# Configure baseline parameters
|
|
||||||
if fit_params["baseline"] == ConstantModel:
|
|
||||||
params["base_c"].set(value=y_min)
|
|
||||||
elif fit_params["baseline"] == LinearModel:
|
|
||||||
params["base_intercept"].set(value=y_min)
|
|
||||||
params["base_slope"].set(value=0)
|
|
||||||
|
|
||||||
# Add peak-specific parameters
|
|
||||||
params.update(
|
|
||||||
peak_model.guess(processed_data["y_to_fit"], x=processed_data["x_data"])
|
|
||||||
)
|
|
||||||
|
|
||||||
# Perform the fitting
|
|
||||||
lmfit_result = full_model.fit(
|
|
||||||
processed_data["y_to_fit"], params, x=processed_data["x_data"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Find the X that gives the max Y
|
|
||||||
max_index = np.argmax(processed_data["y_to_fit"])
|
|
||||||
x_max = processed_data["x_data"][max_index]
|
|
||||||
|
|
||||||
# Generate data for a smoothed fit curve
|
|
||||||
fit_xdata = np.linspace(np.min(data["x_data"]), np.max(data["x_data"]), 500)
|
|
||||||
fit_ydata = lmfit_result.eval(x=fit_xdata, params=lmfit_result.params)
|
|
||||||
|
|
||||||
# Collect results
|
|
||||||
return {
|
|
||||||
"model": fit_params["model"].__name__,
|
|
||||||
"fwhm": lmfit_result.params["peak_fwhm"].value,
|
|
||||||
"centre": lmfit_result.best_values["peak_center"],
|
|
||||||
"height": lmfit_result.params["peak_height"].value,
|
|
||||||
"chi_sq": lmfit_result.chisqr,
|
|
||||||
"lmfit_result": lmfit_result,
|
|
||||||
"x_max": x_max,
|
|
||||||
"fit_xdata": fit_xdata,
|
|
||||||
"fit_ydata": fit_ydata,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def plot_fitted_data(data, fit_result):
|
|
||||||
"""Plot the original data and the fitted model."""
|
|
||||||
plt.plot(data["x_data"], data["y_to_fit"], label="Data")
|
|
||||||
plt.plot(fit_result['fit_xdata'], fit_result['fit_ydata'], label="Fit")
|
|
||||||
plt.xlabel(data["motor_name"])
|
|
||||||
plt.ylabel(data["signal_name"])
|
|
||||||
plt.title(f"Scan {data['scan_number']}, fitted with {fit_result['model']}")
|
|
||||||
plt.grid(True)
|
|
||||||
plt.legend()
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
|
|
||||||
def select_bec_window(dock_area_name="Fitting"):
|
|
||||||
"""Check to see if the fitting results dock is already open and re-create it if not"""
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
text_box = bec.gui.Fitting.Results
|
|
||||||
return wf, text_box
|
|
||||||
|
|
||||||
|
|
||||||
def plot_live_data_bec(
|
|
||||||
motor_name,
|
|
||||||
signal_name,
|
|
||||||
window_name="Fitting"
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Plotting live data for motor and signal using BEC.
|
|
||||||
|
|
||||||
This function plots live data from a specified motor and signal.
|
|
||||||
It clears the current plot window, sets its title, labels the axes
|
|
||||||
with the provided motor and signal names, and initializes live plotting
|
|
||||||
on the given signal against the motor.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
motor_name (str): The name of the motor to be used as the x-axis.
|
|
||||||
signal_name (str): The name of the signal to be used as the y-axis.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
wf, text_box = select_bec_window(window_name)
|
|
||||||
text_box.set_plain_text("Plotting live data")
|
|
||||||
wf.clear_all()
|
|
||||||
wf.title = "Scan: Live scan"
|
|
||||||
wf.x_label = motor_name
|
|
||||||
wf.y_label = signal_name
|
|
||||||
wf.plot(device_x=motor_name, device_y=signal_name)
|
|
||||||
|
|
||||||
|
|
||||||
def plot_fitted_data_bec(
|
|
||||||
data,
|
|
||||||
fit_result,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Plot fitted data and display fitting parameters in the specified window.
|
|
||||||
|
|
||||||
This function selects a BEC window and plots the original data along with the
|
|
||||||
fitted function. Additionally, it displays the fitting results in a text
|
|
||||||
box within the same window for better visualization of the fit results.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
data : dict
|
|
||||||
Dictionary containing the original dataset, where 'x_data' and 'y_to_fit'
|
|
||||||
hold the independent variable and the dependent variable, respectively,
|
|
||||||
'scan_number' represents the scan number, 'motor_name' and 'signal_name'
|
|
||||||
provide axis labels.
|
|
||||||
fit_result : dict
|
|
||||||
Dictionary containing the results of the fit, including parameters such
|
|
||||||
as 'centre', 'fwhm', 'height', and the fitted model stored under
|
|
||||||
'lmfit_result', with its 'best_fit' attribute representing the fitted data.
|
|
||||||
"""
|
|
||||||
wf, text_box = select_bec_window()
|
|
||||||
fit_text = (
|
|
||||||
f"Fit parameters: Centre = {fit_result['centre']:.4f}, "
|
|
||||||
f"FWHM = {fit_result['fwhm']:.3f}, "
|
|
||||||
f"Height = {fit_result['height']:.4f}\n"
|
|
||||||
f"Model = {fit_result['model']}\n"
|
|
||||||
f"Chi sq = {fit_result['chi_sq']:.3g}"
|
|
||||||
)
|
|
||||||
text_box.set_plain_text(fit_text)
|
|
||||||
wf.clear_all()
|
|
||||||
wf.title = f"Scan: {data['scan_number']}"
|
|
||||||
wf.x_label = data["motor_name"]
|
|
||||||
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.get_curve('Fit').set(symbol_size=0)
|
|
||||||
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
"""Use the methods in mx_basics to perform:
|
|
||||||
1) a go_to_peak scan, that scans a motor, finds the peak position and moves to peak
|
|
||||||
2) fits data from a bec history file
|
|
||||||
"""
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# from pxiii_parameters import FitDefaults, BPMScans, MirrorConfig
|
|
||||||
|
|
||||||
# from mx_basics import (
|
|
||||||
# create_fit_parameters,
|
|
||||||
# get_data_from_history,
|
|
||||||
# fit,
|
|
||||||
# plot_fitted_data_bec,
|
|
||||||
# plot_live_data_bec,
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
# Method functions
|
|
||||||
def calculate_step_size(start: float, stop: float, steps: int) -> float:
|
|
||||||
"""
|
|
||||||
Provides the function to calculate the step size for dividing a specified range
|
|
||||||
into a given number of steps.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
start: The starting value of the range.
|
|
||||||
stop: The stopping value of the range.
|
|
||||||
steps: The number of steps to divide the range into. Must be at least 1.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If the steps value is less than 1.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The calculated step size as a float, rounded to three decimal places.
|
|
||||||
"""
|
|
||||||
if steps < 1:
|
|
||||||
raise ValueError("Number of steps must be at least 1.")
|
|
||||||
return round((stop - start) / steps, 3)
|
|
||||||
|
|
||||||
|
|
||||||
def move_to_position(motor_device, motor_name: str, position: float, data: dict):
|
|
||||||
"""
|
|
||||||
Function to move a specified motor device to a given position.
|
|
||||||
|
|
||||||
The function verifies if the requested position is within the scan range of the
|
|
||||||
motor device provided. If the position is outside the range, the motor is
|
|
||||||
moved to the center of its scan range, an error message is raised, and the
|
|
||||||
operation is halted. If the position is valid, the motor is moved to the
|
|
||||||
specified position.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
motor_device: The motor device to be moved.
|
|
||||||
motor_name: str
|
|
||||||
The name of the motor as a string
|
|
||||||
position: float
|
|
||||||
The desired position to move the motor to. Position should be within
|
|
||||||
the scan range of the motor determined by the provided data.
|
|
||||||
data: dict
|
|
||||||
A dictionary containing "x_data", which is used to determine the
|
|
||||||
scan range of the motor.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: Raised if the specified position is outside the valid scan
|
|
||||||
range determined by "x_data" in the data dictionary. The motor will
|
|
||||||
return to the center of its scan range in this case.
|
|
||||||
"""
|
|
||||||
|
|
||||||
motor_min = np.min(data["x_data"])
|
|
||||||
motor_max = np.max(data["x_data"])
|
|
||||||
motor_centre = (motor_max + motor_min) / 2
|
|
||||||
|
|
||||||
if not motor_min <= position <= motor_max:
|
|
||||||
scans.umv(motor_device, motor_centre, relative=False)
|
|
||||||
msg = (
|
|
||||||
f"Position {position: .2f} is outside the scan range of "
|
|
||||||
f"{motor_min: .2f} to {motor_max: .2f}. "
|
|
||||||
f"Returning to centre of scan range {motor_centre: .3f}."
|
|
||||||
)
|
|
||||||
raise ValueError(msg)
|
|
||||||
motor_position = round(position, 4)
|
|
||||||
scans.umv(motor_device, motor_position, relative=False)
|
|
||||||
print(f"\n Moving {motor_name} to position {motor_position: .3f}")
|
|
||||||
|
|
||||||
|
|
||||||
# @dataclass(frozen=True)
|
|
||||||
# class FitDefaults:
|
|
||||||
# """Default values for fitting routines"""
|
|
||||||
|
|
||||||
# # Constants for default models, baselines, and parameters
|
|
||||||
# MODEL = "Voigt"
|
|
||||||
# BASELINE = "Linear"
|
|
||||||
# SETTLE_TIME = 0.1
|
|
||||||
# RELATIVE_MODE = True
|
|
||||||
|
|
||||||
|
|
||||||
def go_to_peak(
|
|
||||||
motor_device,
|
|
||||||
signal_device,
|
|
||||||
start: float,
|
|
||||||
stop: float,
|
|
||||||
steps: int,
|
|
||||||
relative: bool = FitDefaults.RELATIVE_MODE,
|
|
||||||
plot: bool = True,
|
|
||||||
settle: float = FitDefaults.SETTLE_TIME,
|
|
||||||
confirm: bool = True,
|
|
||||||
gomax: bool = False,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Go to the peak of a signal by scanning a motor within a specified range and
|
|
||||||
identifying the optimal position based on signal peak data.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
motor_device: The motor device to be scanned.
|
|
||||||
signal_device: The signal device to monitor during the scan.
|
|
||||||
start (float): The starting position of the scan. Ignored if `relative` is True.
|
|
||||||
stop (float): The ending position of the scan. Ignored if `relative` is True.
|
|
||||||
steps (int): The number of steps to divide the scan range into.
|
|
||||||
relative (bool, optional): If True, interpret `start` and `stop` as relative to
|
|
||||||
the current motor position. Defaults to RELATIVE_MODE constant.
|
|
||||||
plot (bool, optional): If True, plot the scan data and the fitted results.
|
|
||||||
Defaults to True.
|
|
||||||
settle (float, optional): The time in seconds to wait after each step for the
|
|
||||||
signal to stabilize. Defaults to DEFAULT_SETTLE_TIME constant.
|
|
||||||
confirm (bool, optional): If True, ask for user confirmation before starting
|
|
||||||
the scan. Defaults to True.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
Exception: Raises exceptions potentially raised by dependent functions or
|
|
||||||
operations such as plotting, fitting, or motor movement.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
motor_name = motor_device.name
|
|
||||||
signal_name = signal_device.name
|
|
||||||
# wf.plot(x_name=motor_name, y_name=signal_name)
|
|
||||||
if plot:
|
|
||||||
plot_live_data_bec(motor_name, signal_name)
|
|
||||||
|
|
||||||
# Validate and calculate step size
|
|
||||||
step_size = calculate_step_size(start, stop, steps)
|
|
||||||
|
|
||||||
# Confirm the scan range
|
|
||||||
# current_motor_position = motor_device.user_readback.get()
|
|
||||||
current_motor_position = motor_device.read()[motor_name]["value"]
|
|
||||||
if confirm:
|
|
||||||
if relative:
|
|
||||||
scan_start = current_motor_position + start
|
|
||||||
scan_end = current_motor_position + stop
|
|
||||||
print(
|
|
||||||
f"\nScanning from {scan_start: .6g} to {scan_end: .6g} in "
|
|
||||||
f"{steps} steps of size {step_size}"
|
|
||||||
)
|
|
||||||
print(f"Relative mode = {relative}")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"\nScanning from {start: .5g} to {stop: .5g} in {steps} steps of size {step_size}"
|
|
||||||
)
|
|
||||||
print(f"Relative mode = {relative}")
|
|
||||||
input("Press Enter to continue...")
|
|
||||||
# Perform the scan
|
|
||||||
scan_result = scans.line_scan(
|
|
||||||
motor_device, start, stop, steps=steps, relative=relative, settling_time=settle
|
|
||||||
)
|
|
||||||
motor_data = scan_result.scan.live_data[motor_name][motor_name].val
|
|
||||||
signal_data = scan_result.scan.live_data[signal_name][signal_name].val
|
|
||||||
scan_number = "Current"
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"x_data": np.array(motor_data),
|
|
||||||
"y_data": np.array(signal_data),
|
|
||||||
"motor_name": motor_name,
|
|
||||||
"signal_name": signal_name,
|
|
||||||
"motor_device": motor_device,
|
|
||||||
"scan_number": scan_number,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Define and fit model to scan data
|
|
||||||
fit_params = create_fit_parameters(False, FitDefaults.MODEL, FitDefaults.BASELINE)
|
|
||||||
fit_result = fit(data, fit_params)
|
|
||||||
|
|
||||||
# Plot the fitted data if plot = True
|
|
||||||
if plot:
|
|
||||||
plot_fitted_data_bec(data, fit_result)
|
|
||||||
|
|
||||||
# If gomax is set then move to the maximum value, rather than the fit centre
|
|
||||||
if gomax:
|
|
||||||
value = fit_result["x_max"]
|
|
||||||
print(f"Max position is at {value}")
|
|
||||||
move_to_position(data["motor_device"], data["motor_name"], fit_result["x_max"], data)
|
|
||||||
else:
|
|
||||||
# Safely move the motor to the peak position
|
|
||||||
move_to_position(data["motor_device"], data["motor_name"], fit_result["centre"], data)
|
|
||||||
|
|
||||||
|
|
||||||
def fit_history(
|
|
||||||
history_index: int,
|
|
||||||
signal_name: str,
|
|
||||||
deriv: bool = False,
|
|
||||||
model: str = FitDefaults.MODEL,
|
|
||||||
move_to_peak: bool = False,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Retrieve and analyze historical data by fitting a model, optionally moving to
|
|
||||||
a peak position.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
history_index (int): Index of the historical data set to retrieve.
|
|
||||||
signal_name (str): Name of the signal to fit.
|
|
||||||
deriv (bool, optional): Whether to include the derivative in the fitting
|
|
||||||
procedure. Defaults to False.
|
|
||||||
model (str, optional): Name of the model to use for fitting. Defaults to
|
|
||||||
DEFAULT_MODEL.
|
|
||||||
move_to_peak (bool, optional): Whether to move the motor to the peak position
|
|
||||||
after fitting. Defaults to False.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
KeyError: If required keys are not found in the retrieved data dictionary.
|
|
||||||
ValueError: If the fitting process fails or produces invalid results.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
# Retrieve historical data
|
|
||||||
data = get_data_from_history(history_index, signal_name)
|
|
||||||
|
|
||||||
# Define fitting parameters
|
|
||||||
fit_params = create_fit_parameters(deriv, model, FitDefaults.BASELINE)
|
|
||||||
|
|
||||||
# Perform fit and plot the data
|
|
||||||
fit_result = fit(data, fit_params)
|
|
||||||
plot_fitted_data_bec(data, fit_result)
|
|
||||||
|
|
||||||
# Optionally move the motor to the peak position
|
|
||||||
if move_to_peak:
|
|
||||||
move_to_position(data["motor_device"], data["motor_name"], fit_result["centre"], data)
|
|
||||||
|
|
||||||
|
|
||||||
def scan_bpm(bpmname):
|
|
||||||
"""
|
|
||||||
Runs a grid scan of a BPM in x and y, and plots each channel
|
|
||||||
as a heatmap.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
bpmname: the name of the bpm to be scanned e.g. "fe"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Open a dock area and set up the heatmaps
|
|
||||||
dock_area = bec.gui.new("XBPM_Scan")
|
|
||||||
wf5 = dock_area.new("Sum").new(bec.gui.available_widgets.Heatmap)
|
|
||||||
wf1 = dock_area.new("Ch1", relative_to="Sum", position="bottom").new(
|
|
||||||
bec.gui.available_widgets.Heatmap
|
|
||||||
)
|
|
||||||
wf3 = dock_area.new("Ch3", relative_to="Ch1", position="right").new(
|
|
||||||
bec.gui.available_widgets.Heatmap
|
|
||||||
)
|
|
||||||
wf4 = dock_area.new("Ch4", relative_to="Ch3", position="bottom").new(
|
|
||||||
bec.gui.available_widgets.Heatmap
|
|
||||||
)
|
|
||||||
wf2 = dock_area.new("Ch2", relative_to="Ch1", position="bottom").new(
|
|
||||||
bec.gui.available_widgets.Heatmap
|
|
||||||
)
|
|
||||||
wfscan = dock_area.new("ScanControl").new(bec.gui.available_widgets.ScanControl)
|
|
||||||
|
|
||||||
cfg = getattr(BPMScans, bpmname)
|
|
||||||
|
|
||||||
wf1.x_label = cfg["x_name"]
|
|
||||||
wf1.y_label = cfg["y_name"]
|
|
||||||
wf1.plot(x_name=cfg["x_name"], y_name=cfg["y_name"], z_name=cfg["z1_name"], color_map="plasma")
|
|
||||||
|
|
||||||
wf2.x_label = cfg["x_name"]
|
|
||||||
wf2.y_label = cfg["y_name"]
|
|
||||||
wf2.plot(x_name=cfg["x_name"], y_name=cfg["y_name"], z_name=cfg["z2_name"], color_map="plasma")
|
|
||||||
|
|
||||||
wf3.x_label = cfg["x_name"]
|
|
||||||
wf3.y_label = cfg["y_name"]
|
|
||||||
wf3.plot(x_name=cfg["x_name"], y_name=cfg["y_name"], z_name=cfg["z3_name"], color_map="plasma")
|
|
||||||
|
|
||||||
wf4.x_label = cfg["x_name"]
|
|
||||||
wf4.y_label = cfg["y_name"]
|
|
||||||
wf4.plot(x_name=cfg["x_name"], y_name=cfg["y_name"], z_name=cfg["z4_name"], color_map="plasma")
|
|
||||||
|
|
||||||
wf5.x_label = cfg["x_name"]
|
|
||||||
wf5.y_label = cfg["y_name"]
|
|
||||||
wf5.plot(x_name=cfg["x_name"], y_name=cfg["y_name"], z_name=cfg["z5_name"], color_map="plasma")
|
|
||||||
# Run the scan
|
|
||||||
x_mot = cfg["x_device"]
|
|
||||||
y_mot = cfg["y_device"]
|
|
||||||
# scans.grid_scan(x_mot, -0.5, 0.5, 20, y_mot, -0.5, 0.5, 20,
|
|
||||||
# exp_time=0.5, relative=False, snaked=True)
|
|
||||||
|
|
||||||
|
|
||||||
def optimise_kb(mirror):
|
|
||||||
"""
|
|
||||||
Runs a grid scan of a the upstream and downstream benders,
|
|
||||||
and plots a heatmap of the sample camera x or y sigma.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
mirror: either "hfm" or :vfm"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Open a dock area and set up the heatmaps
|
|
||||||
dock_area = bec.gui.new(mirror)
|
|
||||||
wf1 = dock_area.new("Heatmap").new(bec.gui.available_widgets.Heatmap)
|
|
||||||
|
|
||||||
wfscan = dock_area.new("ScanControl").new(bec.gui.available_widgets.ScanControl)
|
|
||||||
|
|
||||||
cfg = getattr(MirrorConfig, mirror)
|
|
||||||
|
|
||||||
wf1.x_label = cfg["bu_name"]
|
|
||||||
wf1.y_label = cfg["bd_name"]
|
|
||||||
wf1.plot(x_name=cfg["bu_name"], y_name=cfg["bd_name"], z_name=cfg["z_name"], color_map="plasma")
|
|
||||||
|
|
||||||
# Run the scan
|
|
||||||
x_mot = cfg["x_device"]
|
|
||||||
y_mot = cfg["y_device"]
|
|
||||||
# scans.grid_scan(x_mot, -0.02, 0.02, 11, y_mot, -0.02, 0.02, 11,
|
|
||||||
# exp_time=0.5, relative=True, snaked=True)
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
"""Script to change energy at PXIII by setting DCCM motors and mirror stripe
|
|
||||||
|
|
||||||
Moving DCCM motors - implemented for dccm_theta1 and dccm_theta2
|
|
||||||
Mirrors - change of mirror stripe is not yet implemented
|
|
||||||
Plotting optional
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
# from mx_methods import go_to_peak
|
|
||||||
# from pxiii_parameters import EnergyDefaults
|
|
||||||
|
|
||||||
# from calculator import (
|
|
||||||
# validate_energy,
|
|
||||||
# convert_from_bragg,
|
|
||||||
# convert_from_energy,
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
def get_current_energy():
|
|
||||||
"""
|
|
||||||
Returns the energy in eV from the current bragg angle.
|
|
||||||
"""
|
|
||||||
# current_bragg_angle = dev.dccm_theta1.user_readback.get()
|
|
||||||
current_bragg_angle = -EnergyDefaults.energy.user_readback.get()
|
|
||||||
current_energy = convert_from_bragg(current_bragg_angle, print_result=False)[
|
|
||||||
"energy_ev"
|
|
||||||
]
|
|
||||||
return current_energy
|
|
||||||
|
|
||||||
|
|
||||||
# Functions below are common to all beamlines
|
|
||||||
def calculate_energy_difference(current_energy, target_energy):
|
|
||||||
"""
|
|
||||||
Calculate the absolute difference in energy between the current energy level
|
|
||||||
and the target energy level.
|
|
||||||
"""
|
|
||||||
return abs(target_energy - current_energy)
|
|
||||||
|
|
||||||
|
|
||||||
def interpolate_column(energy_ev, x_values, y_values):
|
|
||||||
"""
|
|
||||||
Perform interpolation for a specific column of data.
|
|
||||||
|
|
||||||
This function uses numpy's interpolation method to perform linear
|
|
||||||
interpolation. It calculates the interpolated y-values corresponding
|
|
||||||
to the given energy in electron-volts (energy_ev), based on specified
|
|
||||||
x-values and y-values.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
energy_ev (array-like): Array of energy values in electron-volts
|
|
||||||
at which interpolation is needed.
|
|
||||||
x_values (array-like): Array of x-values corresponding to known
|
|
||||||
data points.
|
|
||||||
y_values (array-like): Array of y-values corresponding to known
|
|
||||||
data points.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
numpy.ndarray: Interpolated y-values computed for the energy_ev
|
|
||||||
input.
|
|
||||||
"""
|
|
||||||
return np.interp(energy_ev, x_values, y_values)
|
|
||||||
|
|
||||||
|
|
||||||
def get_value_from_lut(energy_ev):
|
|
||||||
"""
|
|
||||||
Retrieve interpolated values from a Lookup Table (LUT) based on the provided energy
|
|
||||||
in electron volts (eV).
|
|
||||||
|
|
||||||
This function reads a CSV file containing energy lookup data and processes the LUT
|
|
||||||
to return interpolated values for specified relevant columns. The interpolation is
|
|
||||||
performed for the provided energy value using the LUT's energy and data values.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev (float): The energy value in electron volts for which the interpolated data is
|
|
||||||
required.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary where the keys are the relevant column names from the LUT, and the values
|
|
||||||
are the interpolated values as floats.
|
|
||||||
"""
|
|
||||||
|
|
||||||
energy_lookup_data = pd.read_csv(EnergyDefaults.LUT_table)
|
|
||||||
column_names = energy_lookup_data.columns.tolist()
|
|
||||||
lut_values = energy_lookup_data.values.astype(float).T
|
|
||||||
|
|
||||||
# Filter relevant columns for interpolation
|
|
||||||
relevant_columns = {"dccm_pitch"}
|
|
||||||
int_values = {}
|
|
||||||
|
|
||||||
for i, col_name in enumerate(column_names):
|
|
||||||
if col_name in relevant_columns:
|
|
||||||
int_values[col_name] = float(
|
|
||||||
interpolate_column(energy_ev, lut_values[0], lut_values[i])
|
|
||||||
)
|
|
||||||
return int_values
|
|
||||||
|
|
||||||
|
|
||||||
def get_mirror_stripe(energy_ev):
|
|
||||||
"""
|
|
||||||
Determines the mirror stripe material based on the energy level provided.
|
|
||||||
|
|
||||||
This function evaluates the given energy level in electron volts (eV) and
|
|
||||||
identifies the material type that corresponds to the specified thresholds
|
|
||||||
for silicon, rhodium, and, if applicable, platinum.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev (float): Energy level in electron volts, used to determine
|
|
||||||
the corresponding material type.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: A string indicating the material type corresponding to the provided
|
|
||||||
energy level. Possible values are "silicon", "rhodium", or "platinum".
|
|
||||||
"""
|
|
||||||
if energy_ev <= EnergyDefaults.stripe_thresholds["silicon"]:
|
|
||||||
return "silicon"
|
|
||||||
if (
|
|
||||||
EnergyDefaults.stripe_thresholds["silicon"]
|
|
||||||
< energy_ev
|
|
||||||
<= EnergyDefaults.stripe_thresholds["rhodium"]
|
|
||||||
):
|
|
||||||
return "rhodium"
|
|
||||||
return "platinum"
|
|
||||||
|
|
||||||
|
|
||||||
def set_mirror_stripe(energy_ev):
|
|
||||||
"""
|
|
||||||
Selects and sets the appropriate mirror stripe based on the given energy value
|
|
||||||
in electron volts (eV). Prints the selected mirror stripe.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev (float): The energy value in electron volts used to determine
|
|
||||||
the appropriate mirror stripe.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
selected_stripe = get_mirror_stripe(energy_ev)
|
|
||||||
print(f"Selected mirror stripe: {selected_stripe}")
|
|
||||||
|
|
||||||
|
|
||||||
def mono_pitch_scan(plot=True):
|
|
||||||
"""Scan the monochromator pitch and move to the peak."""
|
|
||||||
|
|
||||||
if plot:
|
|
||||||
print("Scanning monochromator pitch and moving to peak, with plotting.")
|
|
||||||
go_to_peak(
|
|
||||||
EnergyDefaults.mono_pitch,
|
|
||||||
EnergyDefaults.signals["sig1"],
|
|
||||||
-EnergyDefaults.pitch_scan["halfwidth"],
|
|
||||||
EnergyDefaults.pitch_scan["halfwidth"],
|
|
||||||
steps=EnergyDefaults.pitch_scan["steps"],
|
|
||||||
relative=True,
|
|
||||||
settle=0.01,
|
|
||||||
plot=True,
|
|
||||||
confirm=False,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print("Scanning monochromator pitch and moving to peak, without plotting.")
|
|
||||||
go_to_peak(
|
|
||||||
EnergyDefaults.mono_pitch,
|
|
||||||
EnergyDefaults.signals["sig1"],
|
|
||||||
-EnergyDefaults.pitch_scan["halfwidth"],
|
|
||||||
EnergyDefaults.pitch_scan["halfwidth"],
|
|
||||||
steps=EnergyDefaults.pitch_scan["steps"],
|
|
||||||
relative=True,
|
|
||||||
settle=0.01,
|
|
||||||
plot=False,
|
|
||||||
confirm=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_dccm_motors_positions(energy_ev):
|
|
||||||
"""
|
|
||||||
Retrieve the positions of DCCM motors based on given energy value.
|
|
||||||
The function returns a dictionary containing all
|
|
||||||
calculated motor positions.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
energy_ev (float): The energy value in electron volts for which the
|
|
||||||
DCCM motor positions are to be calculated.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing the calculated DCCM motor positions
|
|
||||||
including values retrieved from the lookup table, if applicable.
|
|
||||||
"""
|
|
||||||
# dccm_motor_values = get_value_from_lut(energy_ev)
|
|
||||||
th1_angle = -convert_from_energy(energy_ev, print_result=False)["bragg_angle_deg"]
|
|
||||||
th2_angle = convert_from_energy(energy_ev, temp=298, print_result=False)["bragg_angle_deg"]
|
|
||||||
# dccm_motor_values.update({"theta1_angle": th1_angle, "theta2_angle": th2_angle})
|
|
||||||
dccm_motor_values = {"theta1_angle": th1_angle, "theta2_angle": th2_angle}
|
|
||||||
return dccm_motor_values
|
|
||||||
|
|
||||||
|
|
||||||
def move_dccm_motors(energy_ev):
|
|
||||||
"""
|
|
||||||
Move the DCCM theta1 and theta2 motors to the required positions
|
|
||||||
for the given energy in eV.
|
|
||||||
|
|
||||||
"""
|
|
||||||
dccm_pos = get_dccm_motors_positions(energy_ev)
|
|
||||||
print(
|
|
||||||
f"Moving DCCM theta1: {dccm_pos['theta1_angle']: .5g} deg, theta2: {dccm_pos['theta2_angle']: .5g} deg, "
|
|
||||||
# f"DCM pitch: {dcm_pos['dcm_pitch']: .5g} mrad, "
|
|
||||||
)
|
|
||||||
umv(EnergyDefaults.energy, dccm_pos["theta1_angle"],
|
|
||||||
EnergyDefaults.mono_pitch, dccm_pos["theta2_angle"])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def bl_energy(energy_ev, plot=True):
|
|
||||||
"""
|
|
||||||
Adjusts the beamline's energy to the specified energy in electron volts (eV).
|
|
||||||
The function validates the target energy, checks the current energy, and makes
|
|
||||||
adjustments only if the energy difference is significant enough. It performs
|
|
||||||
necessary operations including changing DCCM motors, updating
|
|
||||||
the mirror stripe, and scanning to find the optimal DCCM pitch of 2nd crystal..
|
|
||||||
|
|
||||||
Args:
|
|
||||||
energy_ev: Target energy in electron volts to which the beamline should be adjusted.
|
|
||||||
plot: Boolean flag indicating whether to plot the DCCM pitch scan for finding the peak.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
energy_ev = validate_energy(energy_ev) # Ensure energy is valid.
|
|
||||||
|
|
||||||
# Check current energy to avoid unnecessary adjustments.
|
|
||||||
|
|
||||||
current_energy = get_current_energy()
|
|
||||||
energy_diff = calculate_energy_difference(current_energy, energy_ev)
|
|
||||||
|
|
||||||
if energy_diff <= EnergyDefaults.min_energy_change:
|
|
||||||
print(
|
|
||||||
f"Energy change of {energy_diff:.2f} eV is too small, not changing energy."
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Step 1: Move and set the DCCM motors.
|
|
||||||
move_dccm_motors(energy_ev)
|
|
||||||
|
|
||||||
# Step 2: Update the mirror stripe.
|
|
||||||
set_mirror_stripe(energy_ev)
|
|
||||||
|
|
||||||
# Step 3: Perform DCCM pitch scan and move to peak.
|
|
||||||
if plot:
|
|
||||||
mono_pitch_scan(plot=True)
|
|
||||||
else:
|
|
||||||
mono_pitch_scan(plot=False)
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
"""File to store beamline parameters and defaults"""
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class FitDefaults:
|
|
||||||
"""Default values for fitting routines"""
|
|
||||||
|
|
||||||
# Constants for default models, baselines, and parameters
|
|
||||||
MODEL = "Voigt"
|
|
||||||
BASELINE = "Linear"
|
|
||||||
SETTLE_TIME = 0.1
|
|
||||||
RELATIVE_MODE = True
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class EnergyDefaults:
|
|
||||||
"""Parameters for PXIII energy changes"""
|
|
||||||
|
|
||||||
min_energy_change = 1
|
|
||||||
min_energy_ev = 4500
|
|
||||||
max_energy_ev = 15000
|
|
||||||
signals = {
|
|
||||||
"sig1": dev.dccm_di_top,
|
|
||||||
"sig2": dev.dccm_bpmsum,
|
|
||||||
"sig3": dev.ss_bpmsum,
|
|
||||||
# "sig4": dev.xbox_xbpm,
|
|
||||||
}
|
|
||||||
energy = dev.dccm_theta1
|
|
||||||
mono_pitch = dev.dccm_theta2
|
|
||||||
# LUT_table = "luts/energy_lut.csv"
|
|
||||||
stripe_thresholds = {"silicon": 9000, "rhodium": 40000}
|
|
||||||
pitch_scan = {"halfwidth": 0.15, "steps": 30}
|
|
||||||
|
|
||||||
|
|
||||||
@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"""
|
|
||||||
|
|
||||||
ss = {
|
|
||||||
"x_name": dev.ss_bpm_x.name,
|
|
||||||
"y_name": dev.ss_bpm_y.name,
|
|
||||||
"z1_name": dev.ss_bpm1.name,
|
|
||||||
"z2_name": dev.ss_bpm2.name,
|
|
||||||
"z3_name": dev.ss_bpm3.name,
|
|
||||||
"z4_name": dev.ss_bpm3.name,
|
|
||||||
"z5_name": dev.ss_bpmsum.name,
|
|
||||||
"x_device": dev.ss_bpm_x,
|
|
||||||
"y_device": dev.ss_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,
|
|
||||||
# }
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
"""
|
|
||||||
Scan components for pxiii_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 PxiiiBecScanComponents(ScanComponents):
|
|
||||||
"""Scan components for pxiii_bec."""
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
"""
|
|
||||||
Scan modifier plugin for pxiii_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 PxiiiBecScanModifier(ScanModifier):
|
|
||||||
"""
|
|
||||||
Scan modifier for pxiii_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)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -16,8 +16,7 @@ def alignment_fit_and_plot(
|
|||||||
Args:
|
Args:
|
||||||
history_index (int): scan to fetch, e.g. -1 for the most recent scan
|
history_index (int): scan to fetch, e.g. -1 for the most recent scan
|
||||||
device_name (str): the device for which to get the monitoring data
|
device_name (str): the device for which to get the monitoring data
|
||||||
signal_name (str | None): the signal to plot, if different from the device name.
|
|
||||||
smoothing_sigma (float): the sigma for the Gaussian smoothing filter
|
|
||||||
"""
|
"""
|
||||||
# Fetch scan data from the history
|
# Fetch scan data from the history
|
||||||
# by default, signal = device name, unless otherwise specified
|
# by default, signal = device name, unless otherwise specified
|
||||||
@@ -30,9 +29,9 @@ def alignment_fit_and_plot(
|
|||||||
|
|
||||||
# Create a plot and a text box to display results
|
# Create a plot and a text box to display results
|
||||||
dock_area = bec.gui.new()
|
dock_area = bec.gui.new()
|
||||||
wf = dock_area.new(bec.gui.available_widgets.Waveform)
|
wf = dock_area.new().new(bec.gui.available_widgets.Waveform)
|
||||||
wf.title = f"Scan {md['scan_number']}: {md['scan_name']} of {motor_name}"
|
wf.title = f"Scan {md['scan_number']}: {md['scan_name']} of {motor_name}"
|
||||||
text = dock_area.new(bec.gui.available_widgets.TextBox, where="right")
|
text = dock_area.new(position="right").new(widget=bec.gui.available_widgets.TextBox)
|
||||||
|
|
||||||
# Calculate some processed data and add everything to the plot
|
# Calculate some processed data and add everything to the plot
|
||||||
wf.plot(data, label="Raw data")
|
wf.plot(data, label="Raw data")
|
||||||
|
|||||||
@@ -5,18 +5,6 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def _device_name(device):
|
|
||||||
return device.name if hasattr(device, "name") else str(device)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_or_create_scan_window(name="CurrentScan"):
|
|
||||||
window = bec.gui.windows.get(name)
|
|
||||||
if window is None:
|
|
||||||
return bec.gui.new(name)
|
|
||||||
window.delete_all()
|
|
||||||
return window
|
|
||||||
|
|
||||||
|
|
||||||
def rock(steps, exp_time, scan_start=None, scan_end=None, datasource=None, visual=True, **kwargs):
|
def rock(steps, exp_time, scan_start=None, scan_end=None, datasource=None, visual=True, **kwargs):
|
||||||
"""Demo step scan with plotting
|
"""Demo step scan with plotting
|
||||||
|
|
||||||
@@ -38,18 +26,22 @@ def rock(steps, exp_time, scan_start=None, scan_end=None, datasource=None, visua
|
|||||||
scan_end = 0.05 / dev.dccm_energy.user_readback.get()
|
scan_end = 0.05 / dev.dccm_energy.user_readback.get()
|
||||||
|
|
||||||
if visual:
|
if visual:
|
||||||
# Get or create scan specific window.
|
# Get or create scan specific window
|
||||||
window = _get_or_create_scan_window("CurrentScan")
|
window = None
|
||||||
motor_name = _device_name(motor)
|
for _, val in bec.gui.windows.items():
|
||||||
datasource_name = _device_name(datasource)
|
if val.title == "CurrentScan":
|
||||||
|
window = val.widget
|
||||||
|
window.clear_all()
|
||||||
|
if window is None:
|
||||||
|
window = bec.gui.new("CurrentScan")
|
||||||
|
|
||||||
# Draw a waveform plot in the window.
|
# Draw a simploe plot in the window
|
||||||
plt1 = window.new(
|
dock = window.add_dock(f"ScanDisplay {motor}")
|
||||||
bec.gui.available_widgets.Waveform, object_name=f"ScanDisplay_{motor_name}"
|
plt1 = dock.add_widget("BECWaveformWidget")
|
||||||
)
|
plt1.plot(x_name=motor, y_name=datasource)
|
||||||
plt1.plot(device_x=motor_name, device_y=datasource_name, dap="LinearModel")
|
plt1.set_x_label(motor)
|
||||||
plt1.x_label = motor_name
|
plt1.set_y_label(datasource)
|
||||||
plt1.y_label = datasource_name
|
plt1.add_dap(motor, datasource, dap="LinearModel")
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
print("Handing over to 'scans.line_scan'")
|
print("Handing over to 'scans.line_scan'")
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ def scan_theta2(scan_start, scan_end, stepno, exp):
|
|||||||
|
|
||||||
# # Create a plot to display the results
|
# # Create a plot to display the results
|
||||||
dock_area = bec.gui.new()
|
dock_area = bec.gui.new()
|
||||||
wf = dock_area.new(bec.gui.available_widgets.Waveform)
|
wf = dock_area.new().new(bec.gui.available_widgets.Waveform)
|
||||||
wf.title = f"Scan of DCCM_theta2"
|
wf.title = f"Scan of DCCM_theta2"
|
||||||
wf.plot(device_x="dccm_theta2", device_y="dccm_xbpm", label="dccm_xbpm-dccm_xbpm")
|
wf.plot(x_name='dccm_theta2', y_name='dccm_xbpm')
|
||||||
dap_xbpm = wf.add_dap_curve(device_label="dccm_xbpm-dccm_xbpm", dap_name="GaussianModel")
|
wf.add_dap_curve(device_label='dccm_xbpm-dccm_xbpm', dap_name='GaussianModel')
|
||||||
print(dap_xbpm.dap_params)
|
print(dap_xbpm.dap_params)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,6 @@ def bl_check_beam():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _device_name(device):
|
|
||||||
return device.name if hasattr(device, "name") else str(device)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_or_create_scan_window(name="CurrentScan"):
|
|
||||||
window = bec.gui.windows.get(name)
|
|
||||||
if window is None:
|
|
||||||
return bec.gui.new(name)
|
|
||||||
window.delete_all()
|
|
||||||
return window
|
|
||||||
|
|
||||||
|
|
||||||
def ascan(
|
def ascan(
|
||||||
motor, scan_start, scan_end, steps, exp_time, plot=None, visual=True, relative=False, **kwargs
|
motor, scan_start, scan_end, steps, exp_time, plot=None, visual=True, relative=False, **kwargs
|
||||||
):
|
):
|
||||||
@@ -35,18 +23,22 @@ def ascan(
|
|||||||
raise RuntimeError("Beamline is not in ready state")
|
raise RuntimeError("Beamline is not in ready state")
|
||||||
|
|
||||||
if visual:
|
if visual:
|
||||||
# Get or create scan specific window.
|
# Get or create scan specific window
|
||||||
window = _get_or_create_scan_window("CurrentScan")
|
window = None
|
||||||
motor_name = _device_name(motor)
|
for _, val in bec.gui.windows.items():
|
||||||
plot_name = _device_name(plot)
|
if val.title == "CurrentScan":
|
||||||
|
window = val.widget
|
||||||
|
window.clear_all()
|
||||||
|
if window is None:
|
||||||
|
window = bec.gui.new("CurrentScan")
|
||||||
|
|
||||||
# Draw a waveform plot in the window.
|
# Draw a simploe plot in the window
|
||||||
plt1 = window.new(
|
dock = window.add_dock(f"ScanDisplay {motor}")
|
||||||
bec.gui.available_widgets.Waveform, object_name=f"ScanDisplay_{motor_name}"
|
plt1 = dock.add_widget("BECWaveformWidget")
|
||||||
)
|
plt1.plot(x_name=motor, y_name=plot)
|
||||||
plt1.plot(device_x=motor_name, device_y=plot_name, dap="LinearModel")
|
plt1.set_x_label(motor)
|
||||||
plt1.x_label = motor_name
|
plt1.set_y_label(plot)
|
||||||
plt1.y_label = plot_name
|
plt1.add_dap(motor, plot, dap="LinearModel")
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
print("Handing over to 'scans.line_scan'")
|
print("Handing over to 'scans.line_scan'")
|
||||||
|
|||||||
+1
-4
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|||||||
name = "pxiii_bec"
|
name = "pxiii_bec"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
description = "A plugin repository for BEC"
|
description = "A plugin repository for BEC"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.10"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Alpha",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
@@ -51,9 +51,6 @@ plugin_file_writer = "pxiii_bec.file_writer"
|
|||||||
[project.entry-points."bec.scans"]
|
[project.entry-points."bec.scans"]
|
||||||
plugin_scans = "pxiii_bec.scans"
|
plugin_scans = "pxiii_bec.scans"
|
||||||
|
|
||||||
[project.entry-points."bec.scans.scan_modifier"]
|
|
||||||
plugin_scan_modifier = "pxiii_bec.scans.scan_customization.scan_modifier"
|
|
||||||
|
|
||||||
[project.entry-points."bec.scans.metadata_schema"]
|
[project.entry-points."bec.scans.metadata_schema"]
|
||||||
plugin_metadata_schema = "pxiii_bec.scans.metadata_schema"
|
plugin_metadata_schema = "pxiii_bec.scans.metadata_schema"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user