Transfer macros from pxii to pxiii #32

Merged
mcauley_k merged 1 commits from x06da_production_20260522T162347 into main 2026-05-27 16:56:23 +02:00
13 changed files with 3418 additions and 757 deletions
@@ -0,0 +1,151 @@
states:
robot_sample_exchange:
allow_modifiers: true
bl_pos: in
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: out
cryo_pos: in
det_cov: 'close'
diag_y: out
fl_bright: 'off'
gon_x: in
# smargon: not implemented
xrf_pos: out
sample_alignment:
allow_modifiers: true
bl_pos: in
bl_bright: 'on'
bs_pos: in
bs_z: safe
coll_y: out
cryo_pos: in
det_cov: 'close'
diag_y: out
fl_bright: 'on'
gon_x: in
# smargon: not implemented
xrf_pos: out
data_collection:
allow_modifiers: true
bl_pos: out
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: in
cryo_pos: in
det_cov: 'open'
diag_y: out
fl_bright: 'on'
gon_x: in
# smargon: not implemented
xrf_pos: out
DC_XRF:
allow_modifiers: true
# bl_pos: out
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: in
cryo_pos: in
det_cov: 'close'
diag_y: out
fl_bright: 'on'
gon_x: in
# smargon: not implemented
xrf_pos: in
manual_sample_exchange:
allow_modifiers: true
bl_pos: out
bl_bright: 'off'
bs_pos: out
bs_z: safe
coll_y: park
cryo_pos: in
det_cov: 'close'
diag_y: park
fl_bright: 'off'
gon_x: in
# smargon: not implemented
xrf_pos: out
beam_visualisation:
bl_pos: out
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: out
cryo_pos: out
det_cov: 'close'
diag_y: scint
fl_bright: 'off'
gon_x: out
# smargon: not implemented
xrf_pos: out
flux_measurement:
bl_pos: in
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: out
cryo_pos: out
det_cov: 'close'
diag_y: i1
fl_bright: 'off'
gon_x: out
# smargon: not implemented
xrf_pos: out
beamstop_alignment:
bl_pos: out
bl_bright: 'off'
bs_pos: in
bs_z: samp
coll_y: out
cryo_pos: out
det_cov: 'close'
diag_y: out
fl_bright: 'on'
gon_x: out
# smargon: not implemented
xrf_pos: out
maintenance:
allow_modifiers: true
bl_pos: out
bl_bright: 'off'
bs_pos: out
bs_z: safe
coll_y: park
cryo_pos: in
det_cov: 'close'
diag_y: park
fl_bright: 'off'
gon_x: out
# smargon: not implemented
xrf_pos: out
xtal_snapshot:
allow_modifiers: true
bl_pos: in
bl_bright: 'on'
bs_pos: in
bs_z: safe
coll_y: intermediate
cryo_pos: in
det_cov: 'close'
diag_y: out
fl_bright: 'on'
gon_x: in
# smargon: not implemented
xrf_pos: out
+81
View File
@@ -0,0 +1,81 @@
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()
@@ -0,0 +1,127 @@
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,,
1 name description deviceClass PV readoutPriority tag readOnly include userParameter
2 sls_current SLS Current SignalRO ARS07-DPCT-0100:CURR monitored SLS yes yes
3 fe_sl_xr FE Slit X Ring MotorEC X06DA-FE-SLDI:TRXR baseline fe no yes
4 fe_sl_yt FE Slit Y Top MotorEC X06DA-FE-SLDI:TRYT baseline fe no yes
5 fe_sl_xw FE Slit X Wall MotorEC X06DA-FE-SLDI:TRXW baseline fe no yes
6 fe_sl_yb FE Slit Y Bottom MotorEC X06DA-FE-SLDI:TRYB baseline fe no yes
7 fe_sl_xcen FE Slit X Centre MotorEC X06DA-FE-SLDI:CENTERX baseline fe no yes
8 fe_sl_xsize FE Slit X Size MotorEC X06DA-FE-SLDI:SIZEX baseline fe no yes
9 fe_sl_ycen FE Slit Y Centre MotorEC X06DA-FE-SLDI:CENTERY baseline fe no yes
10 fe_sl_ysize FE Slit Y Size MotorEC X06DA-FE-SLDI:SIZEY baseline fe no yes
11 tm_xu TorM Upstream X MotorEC X06DA-FE-MI1:TRXU baseline tm no yes
12 tm_xd TorM Downstream X MotorEC X06DA-FE-MI1:TRXD baseline tm no yes
13 tm_yur TorM Upstream Ring Y MotorEC X06DA-FE-MI1:TRYUR baseline tm no yes
14 tm_yw TorM Wall Y MotorEC X06DA-FE-MI1:TRYUW baseline tm no yes
15 tm_yd TorM Downstream Y MotorEC X06DA-FE-MI1:TRYD baseline tm no yes
16 tm_b1 TorM Bender MotorEC X06DA-FE-MI1:BEND1 baseline tm no yes
17 tm_yaw TorM Virtual Yaw MotorEC X06DA-FE-MI1:YAW baseline tm no yes
18 tm_roll TorM Virtual Roll MotorEC X06DA-FE-MI1:ROLL baseline tm no yes
19 tm_pitch TorM Virtual Pitch MotorEC X06DA-FE-MI1:PITCH baseline tm no yes
20 tm_x TorM Virtual X MotorEC X06DA-FE-MI1:TRX baseline tm no yes
21 tm_y TorM Virtual Y MotorEC X06DA-FE-MI1:TRY baseline tm no yes
22 bsf_bpm1 BSF BPM Channel 1 SignalRO X06DA-OP-BSFBPM:SIGNAL1 monitored bpm yes no
23 bsf_bpm2 BSF BPM Channel 2 SignalRO X06DA-OP-BSFBPM:SIGNAL2 monitored bpm yes no
24 bsf_bpm3 BSF BPM Channel 3 SignalRO X06DA-OP-BSFBPM:SIGNAL3 monitored bpm yes no
25 bsf_bpm4 BSF BPM Channel 4 SignalRO X06DA-OP-BSFBPM:SIGNAL4 monitored bpm yes no
26 bsf_bpmsum BSF BPM Summed SignalRO X06DA-OP-BSFBPM:SUM monitored bpm yes no
27 bsf_sl_xw BSF Slit outboard MotorEC X06DA-OP-BSFSLH:TRXW baseline bsf no yes
28 bsf_sl_xr BSF Slit inboard MotorEC X06DA-OP-BSFSLH:TRXR baseline bsf no yes
29 bsf_sl_xcen BSF X Centre MotorEC X06DA-OP-BSFSLH:CENTER baseline bsf no yes
30 bsf_sl_xsize BSF X Size MotorEC X06DA-OP-BSFSLH:SIZE baseline bsf no yes
31 bsf_f1_y BSF Filter 1 Y MotorEC X06DA-OP-BSFFI1:TRY baseline bsf no yes
32 dccm_theta1 DCCM Theta Xtal1 MotorEC X06DA-OP-DCCM:ROTX-CR1 baseline dccm no yes
33 dccm_theta2 DCCM Theta Xtal2 MotorEC X06DA-OP-DCCM:ROTX-CR2 baseline dccm no yes
34 dccm_rotz DCCM RotZ Xtal 2 MotorEC X06DA-OP-DCCM:ROTZ-CR2 baseline dccm no yes
35 dccm_xbpm1_y DCCM BPM1 Y MotorEC X06DA-OP-DCCMXBPM1:TRY baseline dccm no yes
36 dccm_xbpm2_y DCCM BPM2 Y MotorEC X06DA-OP-DCCMXBPM2:TRY baseline dccm no yes
37 dccm_energy DCCM Energy Motor X06DA-OP-DCCM:ENERGY baseline dccm no yes
38 dccm_di_top DCCM Diode Top SignalRO X06DA-OP-DCCMXBPM1T:READOUT monitored dccm no yes
39 dccm_di_bot DCCM Diode Bottom SignalRO X06DA-OP-DCCMXBPM1B:READOUT monitored dccm no yes
40 dccm_bpm1 DCCM BPM Channel 1 SignalRO X06DA-OP-DCCMXBPM2:Current1:MeanValue_RBV monitored dccm no yes
41 dccm_bpm2 DCCM BPM Channel 2 SignalRO X06DA-OP-DCCMXBPM2:Current2:MeanValue_RBV monitored dccm no yes
42 dccm_bpm3 DCCM BPM Channel 3 SignalRO X06DA-OP-DCCMXBPM2:Current3:MeanValue_RBV monitored dccm no yes
43 dccm_bpm4 DCCM BPM Channel 4 SignalRO X06DA-OP-DCCMXBPM2:Current4:MeanValue_RBV monitored dccm no yes
44 dccm_bpmsum DCCM BPM Summed SignalRO X06DA-OP-DCCMXBPM2:SumAll:MeanValue_RBV monitored dccm no yes
45 ss_bpm1 SS BPM Channel 1 SignalRO X06DA-ES-SSBPM:Current1:MeanValue_RBV monitored bpm yes yes
46 ss_bpm2 SS BPM Channel 2 SignalRO X06DA-ES-SSBPM:Current2:MeanValue_RBV monitored bpm yes yes
47 ss_bpm3 SS BPM Channel 3 SignalRO X06DA-ES-SSBPM:Current3:MeanValue_RBV monitored bpm yes yes
48 ss_bpm4 SS BPM Channel 4 SignalRO X06DA-ES-SSBPM:Current4:MeanValue_RBV monitored bpm yes yes
49 ss_bpmsum SS BPM Summed SignalRO X06DA-ES-SSBPM:SumAll:MeanValue_RBV monitored bpm yes yes
50 ss_bpm_x SS BPM X Motor X06DA-ES-SSBPM:TRX baseline ss no yes
51 ss_bpm_y SS BPM Y Motor X06DA-ES-SSBPM:TRY baseline ss no yes
52 ss_sl_xw SS Slit Wall Motor X06DA-ES-SSSLH:TRXW baseline ss no yes
53 ss_sl_xr SS Slit Ring Motor X06DA-ES-SSSLH:TRXR baseline ss no yes
54 ss_sl_xcen SS Slit X Centre Motor X06DA-ES-SSSLH:CENTER baseline ss no yes
55 ss_sl_xsize SS Slit X Size Motor X06DA-ES-SSSLH:SIZE baseline ss no yes
56 ss_sl_yt SS Slit Top Motor X06DA-ES-SSSLV:TRYT baseline ss no yes
57 ss_sl_yb SS Slit Bottom Motor X06DA-ES-SSSLV:TRYB baseline ss no yes
58 ss_sl_ycen SS Slit Y Centre Motor X06DA-ES-SSSLV:CENTER baseline ss no yes
59 ss_sl_ysize SS Slit Y Size Motor X06DA-ES-SSSLV:SIZE baseline ss no yes
60 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}
61 ss_xi_y SS X-ray Eye Y Motor X06DA-ES-SSXI:TRY baseline ss no yes
62 ss_xicam_x SS Camera X SignalRO X06DA-ES-SSCAM:Stats5:CentroidX_RBV baseline ss yes yes
63 ss_xicam_y SS Camera Y SignalRO X06DA-ES-SSCAM:Stats5:CentroidY_RBV baseline ss yes yes
64 ss_xicam_max SS Cam Max SignalRO X06DA-ES-SSCAM:Stats5:MaxValue_RBV monitored ss yes yes
65 ss_xicam_exp SS Camera Exposure Signal X06DA-ES-SSCAM:cam1:AcquireTime baseline ss no yes
66 ss_xicam_gain SS Camera Gain Signal X06DA-ES-SSCAM:cam1:Gain baseline ss no yes
67 ss_xicam_xsig SS Camera X Sigma Signal X06DA-ES-SSCAM:Stats5:SigmaX_RBV baseline ss yes yes
68 ss_xicam_ysig SS Camera Y Sigma Signal X06DA-ES-SSCAM:Stats5:SigmaY_RBV baseline ss yes yes
69 vfm_xu VFM Upstream X MotorEC X06DA-ES-VFM:TRXU baseline vfm no yes
70 vfm_xd VFM Downstream X MotorEC X06DA-ES-VFM:TRXD baseline vfm no yes
71 vfm_yur VFM Upstream Ring Y MotorEC X06DA-ES-VFM:TRYUR baseline vfm no yes
72 vfm_yw VFM Wall Y MotorEC X06DA-ES-VFM:TRYW baseline vfm no yes
73 vfm_ydr VFM Downstream Ring Y MotorEC X06DA-ES-VFM:TRYDR baseline vfm no yes
74 vfm_bu VFM Upstream Bender MotorEC X06DA-ES-VFM:BNDU baseline vfm no yes
75 vfm_bd VFM Downstream Bender MotorEC X06DA-ES-VFM:BNDD baseline vfm no yes
76 vfm_yaw VFM Virtual Yaw MotorEC X06DA-ES-VFM:YAW baseline vfm no yes
77 vfm_roll VFM Virtual Roll MotorEC X06DA-ES-VFM:ROLL baseline vfm no yes
78 vfm_pitch VFM Virtual Pitch MotorEC X06DA-ES-VFM:PITCH baseline vfm no yes
79 vfm_x VFM Virtual X MotorEC X06DA-ES-VFM:TRX baseline vfm no yes
80 vfm_y VFM Virtual Y MotorEC X06DA-ES-VFM:TRY baseline vfm no yes
81 hfm_xu HFM Upstream X MotorEC X06DA-ES-HFM:TRXU baseline hfm no yes
82 hfm_xd HFM Downstream X MotorEC X06DA-ES-HFM:TRXD baseline hfm no yes
83 hfm_yuw HFM Upstream Wall Y MotorEC X06DA-ES-HFM:TRYUW baseline hfm no yes
84 hfm_yr HFM Ring Y MotorEC X06DA-ES-HFM:TRYR baseline hfm no yes
85 hfm_ydw HFM Downstream Wall Y MotorEC X06DA-ES-HFM:TRYDW baseline hfm no yes
86 hfm_bu HFM Upstream Bender MotorEC X06DA-ES-HFM:BNDU baseline hfm no yes
87 hfm_bd HFM Downstream Bender MotorEC X06DA-ES-HFM:BNDD baseline hfm no yes
88 hfm_yaw HFM Virtual Yaw MotorEC X06DA-ES-HFM:YAW baseline hfm no yes
89 hfm_roll HFM Virtual Roll MotorEC X06DA-ES-HFM:ROLL baseline hfm no yes
90 hfm_pitch HFM Virtual Pitch MotorEC X06DA-ES-HFM:PITCH baseline hfm no yes
91 hfm_x HFM Virtual X MotorEC X06DA-ES-HFM:TRX baseline hfm no yes
92 hfm_y HFM Virtual Y MotorEC X06DA-ES-HFM:TRY baseline hfm no yes
93 bcu_bpm1 BCU BPM Channel 1 SignalRO X06DA-ES-BCBPM:Current1:MeanValue_RBV monitored bpm yes yes
94 bcu_bpm2 BCU BPM Channel 2 SignalRO X06DA-ES-BCBPM:Current2:MeanValue_RBV monitored bpm yes yes
95 bcu_bpm3 BCU BPM Channel 3 SignalRO X06DA-ES-BCBPM:Current3:MeanValue_RBV monitored bpm yes yes
96 bcu_bpm4 BCU BPM Channel 4 SignalRO X06DA-ES-BCBPM:Current4:MeanValue_RBV monitored bpm yes yes
97 bcu_bpmsum BCU BPM Summed SignalRO X06DA-ES-BCBPM:SumAll:MeanValue_RBV monitored bpm yes yes
98 bcu_bpm_x BCU BPM X Motor X06DA-ES-BCBPM:TRX baseline bcu no yes
99 bcu_bpm_y BCU BPM Y Motor X06DA-ES-BCBPM:TRY baseline bcu no yes
100 bcu_sl_xw BCU Slit Wall Motor X06DA-ES-BCSLH:TRXW baseline bcu no yes
101 bcu_sl_xr BCU Slit Ring Motor X06DA-ES-BCSLH:TRXR baseline bcu no yes
102 bcu_sl_xcen BCU Slit X Centre Motor X06DA-ES-BCSLH:CENTER baseline bcu no yes
103 bcu_sl_xsize BCU Slit X Size Motor X06DA-ES-BCSLH:SIZE baseline bcu no yes
104 bcu_sl_yt BCU Slit top Motor X06DA-ES-BCSLV:TRYT baseline bcu no yes
105 bcu_sl_yb BCU Slit Bottom Motor X06DA-ES-BCSLV:TRYB baseline bcu no yes
106 bcu_sl_ycen BCU Slit Y Centre Motor X06DA-ES-BCSLV:CENTER baseline bcu no yes
107 bcu_sl_ysize BCU Slit Y Size Motor X06DA-ES-BCSLV:SIZE baseline bcu no yes
108 samcam_x Sample Camera X SignalRO X06DA-ES-MS:Stats5:CentroidX_RBV baseline scam yes no
109 samcam_xsig Sample Camera X Sigma SignalRO X06DA-ES-MS:Stats5:SigmaX_RBV monitored scam yes no
110 samcam_y Sample Camera Y SignalRO X06DA-ES-MS:Stats5:CentroidY_RBV baseline scam yes no
111 samcam_ysig Sample Camera Y Sigma SignalRO X06DA-ES-MS:Stats5:SigmaY_RBV monitored scam yes no
112 samcam_max Sample Camera Max SignalRO X06DA-ES-MS:Stats5:MaxValue_RBV monitored scam yes no
113 samcam_exp Sample Camera Exposure Signal X06DA-ES-MS:cam1:AcquireTime baseline scam no no
114 samcam_gain Sample Camera Gain Signal X06DA-ES-MS:cam1:Gain baseline scam no no
115 scam_zoom Sample Camera Zoom Motor X06DA-ES-MS:ZOOM baseline scam no yes
116 coll_x Collimator X Motor X06DA-ES-COL:TRX baseline se no no
117 diag_z Scintillator/diode Z Motor X06DA-ES-SCL:TRZ baseline se no no
118 i1 I1 diode SignalRO X06DA-ES-SCLDI:READOUT monitored bpm yes no
119 bs_x Beamstop X Motor X06DA-ES-BS:TRX baseline se no no
120 bs_y Beamstop Y Motor X06DA-ES-BS:TRY baseline se no no
121 gon_y Goniometer Y Motor X06DA-ES-DF1:TRY1 baseline det no no
122 gon_z Goniometer X Motor X06DA-ES-DF1:TRZ1 baseline det no no
123 omega Omega Motor X06DA-ES-DF1:ROTU baseline det no no
124 cryo_x Cryo X Motor X06DA-ES-CS:TRX baseline se no no
125 cryo_temp Cryo Temperature SignalRO X06DA-ES-CS:TEMP_RBV baseline se no no
126 det_y Detector Y MotorEC X06DA-ES-DET:TRY baseline det no no
127 det_z Detector Z MotorEC X06DA-ES-DET:TRZ baseline det no no
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
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 name description deviceClass PV readoutPriority tag readOnly include userParameter
2 bl_bright Backlight Brightness Signal X06DA-ES-BL:SET baseline state no yes
3 bl_pos Backlight Positioner Signal X06DA-ES-BL:POS-SET baseline state no no {"type":positioner}
4 bs_pos Beamstop Positioner Signal X06DA-ES-BS:POS-SET baseline state no no {"type":positioner}
5 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}
6 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}
7 cryo_pos Cryo positioner Signal X06DA-ES-CS:POS-SET baseline state no no {"type":positioner}
8 det_cov Detector cover Signal X06DA-ES-DETCOV:SET baseline state no no {"type":positioner}
9 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}
10 fl_bright Frontlight Brightness Signal X06DA-ES-FL:SET baseline state no yes
11 xrf_pos XRF Positioner Signal X06DA-ES-XRF:POS-SET baseline state no no {"type":positioner}
@@ -0,0 +1,63 @@
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,757 +1,4 @@
sls_current:
description: sls current
deviceClass: ophyd.EpicsSignalRO
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
base_config:
- !include ./pxiii-standard-devices.yaml
states_config:
- !include ./pxiii-state-devices.yaml
+357
View File
@@ -0,0 +1,357 @@
"""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
+495
View File
@@ -0,0 +1,495 @@
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)
+252
View File
@@ -0,0 +1,252 @@
"""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)
+321
View File
@@ -0,0 +1,321 @@
"""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)
+251
View File
@@ -0,0 +1,251 @@
"""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)
+80
View File
@@ -0,0 +1,80 @@
"""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,
# }