From 6ef70201509b34e32f50eb73ba0e5717aa9fa20a Mon Sep 17 00:00:00 2001 From: x06da Date: Wed, 27 May 2026 16:33:11 +0200 Subject: [PATCH] Transfer macros from pxii to pxiii --- pxiii_bec/device_configs/beamline_states.yaml | 151 ++ pxiii_bec/device_configs/create_yaml.py | 81 ++ .../device_configs/pxiii-standard-devices.csv | 127 ++ .../pxiii-standard-devices.yaml | 1225 +++++++++++++++++ .../device_configs/pxiii-state-devices.csv | 11 + .../device_configs/pxiii-state-devices.yaml | 63 + .../device_configs/x06da_device_config.yaml | 761 +--------- pxiii_bec/macros/calculator.py | 357 +++++ pxiii_bec/macros/check.py | 495 +++++++ pxiii_bec/macros/mx_basics.py | 252 ++++ pxiii_bec/macros/mx_methods.py | 321 +++++ pxiii_bec/macros/pxiii_energy.py | 251 ++++ pxiii_bec/macros/pxiii_parameters.py | 80 ++ 13 files changed, 3418 insertions(+), 757 deletions(-) create mode 100644 pxiii_bec/device_configs/beamline_states.yaml create mode 100644 pxiii_bec/device_configs/create_yaml.py create mode 100644 pxiii_bec/device_configs/pxiii-standard-devices.csv create mode 100644 pxiii_bec/device_configs/pxiii-standard-devices.yaml create mode 100644 pxiii_bec/device_configs/pxiii-state-devices.csv create mode 100644 pxiii_bec/device_configs/pxiii-state-devices.yaml create mode 100644 pxiii_bec/macros/calculator.py create mode 100644 pxiii_bec/macros/check.py create mode 100644 pxiii_bec/macros/mx_basics.py create mode 100644 pxiii_bec/macros/mx_methods.py create mode 100644 pxiii_bec/macros/pxiii_energy.py create mode 100644 pxiii_bec/macros/pxiii_parameters.py diff --git a/pxiii_bec/device_configs/beamline_states.yaml b/pxiii_bec/device_configs/beamline_states.yaml new file mode 100644 index 0000000..8015eab --- /dev/null +++ b/pxiii_bec/device_configs/beamline_states.yaml @@ -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 + + + + diff --git a/pxiii_bec/device_configs/create_yaml.py b/pxiii_bec/device_configs/create_yaml.py new file mode 100644 index 0000000..e1a6dc7 --- /dev/null +++ b/pxiii_bec/device_configs/create_yaml.py @@ -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() diff --git a/pxiii_bec/device_configs/pxiii-standard-devices.csv b/pxiii_bec/device_configs/pxiii-standard-devices.csv new file mode 100644 index 0000000..2dc1595 --- /dev/null +++ b/pxiii_bec/device_configs/pxiii-standard-devices.csv @@ -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,, diff --git a/pxiii_bec/device_configs/pxiii-standard-devices.yaml b/pxiii_bec/device_configs/pxiii-standard-devices.yaml new file mode 100644 index 0000000..59e6596 --- /dev/null +++ b/pxiii_bec/device_configs/pxiii-standard-devices.yaml @@ -0,0 +1,1225 @@ +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: + - SLS + readOnly: True + softwareTrigger: false + +fe_sl_xr: + description: FE Slit X Ring + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:TRXR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_yt: + description: FE Slit Y Top + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:TRYT'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_xw: + description: FE Slit X Wall + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:TRXW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_yb: + description: FE Slit Y Bottom + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:TRYB'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_xcen: + description: FE Slit X Centre + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:CENTERX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_xsize: + description: FE Slit X Size + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:SIZEX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_ycen: + description: FE Slit Y Centre + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:CENTERY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +fe_sl_ysize: + description: FE Slit Y Size + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-SLDI:SIZEY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - fe + readOnly: False + softwareTrigger: false + +tm_xu: + description: TorM Upstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRXU'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_xd: + description: TorM Downstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRXD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_yur: + description: TorM Upstream Ring Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRYUR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_yw: + description: TorM Wall Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRYUW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_yd: + description: TorM Downstream Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRYD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_b1: + description: TorM Bender + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:BEND1'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_yaw: + description: TorM Virtual Yaw + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:YAW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_roll: + description: TorM Virtual Roll + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:ROLL'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_pitch: + description: TorM Virtual Pitch + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:PITCH'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_x: + description: TorM Virtual X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +tm_y: + description: TorM Virtual Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-FE-MI1:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - tm + readOnly: False + softwareTrigger: false + +bsf_sl_xw: + description: BSF Slit outboard + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-BSFSLH:TRXW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bsf + readOnly: False + softwareTrigger: false + +bsf_sl_xr: + description: BSF Slit inboard + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-BSFSLH:TRXR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bsf + readOnly: False + softwareTrigger: false + +bsf_sl_xcen: + description: BSF X Centre + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-BSFSLH:CENTER'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bsf + readOnly: False + softwareTrigger: false + +bsf_sl_xsize: + description: BSF X Size + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-BSFSLH:SIZE'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bsf + readOnly: False + softwareTrigger: false + +bsf_f1_y: + description: BSF Filter 1 Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-BSFFI1:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bsf + readOnly: False + softwareTrigger: false + +dccm_theta1: + description: DCCM Theta Xtal1 + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-DCCM:ROTX-CR1'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_theta2: + description: DCCM Theta Xtal2 + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-DCCM:ROTX-CR2'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_rotz: + description: DCCM RotZ Xtal 2 + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-DCCM:ROTZ-CR2'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_xbpm1_y: + description: DCCM BPM1 Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-DCCMXBPM1:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_xbpm2_y: + description: DCCM BPM2 Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-OP-DCCMXBPM2:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_energy: + description: DCCM Energy + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-OP-DCCM:ENERGY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_di_top: + description: DCCM Diode Top + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM1T:READOUT', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_di_bot: + description: DCCM Diode Bottom + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM1B:READOUT', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_bpm1: + description: DCCM BPM Channel 1 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM2:Current1:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_bpm2: + description: DCCM BPM Channel 2 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM2:Current2:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_bpm3: + description: DCCM BPM Channel 3 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM2:Current3:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_bpm4: + description: DCCM BPM Channel 4 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM2:Current4:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +dccm_bpmsum: + description: DCCM BPM Summed + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-OP-DCCMXBPM2:SumAll:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - dccm + readOnly: False + softwareTrigger: false + +ss_bpm1: + description: SS BPM Channel 1 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSBPM:Current1:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +ss_bpm2: + description: SS BPM Channel 2 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSBPM:Current2:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +ss_bpm3: + description: SS BPM Channel 3 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSBPM:Current3:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +ss_bpm4: + description: SS BPM Channel 4 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSBPM:Current4:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +ss_bpmsum: + description: SS BPM Summed + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSBPM:SumAll:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +ss_bpm_x: + description: SS BPM X + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSBPM:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_bpm_y: + description: SS BPM Y + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSBPM:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_xw: + description: SS Slit Wall + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLH:TRXW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_xr: + description: SS Slit Ring + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLH:TRXR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_xcen: + description: SS Slit X Centre + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLH:CENTER'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_xsize: + description: SS Slit X Size + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLH:SIZE'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_yt: + description: SS Slit Top + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLV:TRYT'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_yb: + description: SS Slit Bottom + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLV:TRYB'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_ycen: + description: SS Slit Y Centre + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLV:CENTER'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_sl_ysize: + description: SS Slit Y Size + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSSLV:SIZE'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_xi_x: + description: SS X-ray Eye X + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSXI:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + userParameter: {"type": multi-position,"in": 7.5, "out": -2.1} + +ss_xi_y: + description: SS X-ray Eye Y + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-SSXI:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_xicam_x: + description: SS Camera X + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:Stats5:CentroidX_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: True + softwareTrigger: false + +ss_xicam_y: + description: SS Camera Y + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:Stats5:CentroidY_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: True + softwareTrigger: false + +ss_xicam_max: + description: SS Cam Max + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:Stats5:MaxValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - ss + readOnly: True + softwareTrigger: false + +ss_xicam_exp: + description: SS Camera Exposure + deviceClass: ophyd.EpicsSignal + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:cam1:AcquireTime', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_xicam_gain: + description: SS Camera Gain + deviceClass: ophyd.EpicsSignal + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:cam1:Gain', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: False + softwareTrigger: false + +ss_xicam_xsig: + description: SS Camera X Sigma + deviceClass: ophyd.EpicsSignal + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:Stats5:SigmaX_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: True + softwareTrigger: false + +ss_xicam_ysig: + description: SS Camera Y Sigma + deviceClass: ophyd.EpicsSignal + deviceConfig: {read_pv: 'X06DA-ES-SSCAM:Stats5:SigmaY_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - ss + readOnly: True + softwareTrigger: false + +vfm_xu: + description: VFM Upstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRXU'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_xd: + description: VFM Downstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRXD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_yur: + description: VFM Upstream Ring Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRYUR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_yw: + description: VFM Wall Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRYW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_ydr: + description: VFM Downstream Ring Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRYDR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_bu: + description: VFM Upstream Bender + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:BNDU'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_bd: + description: VFM Downstream Bender + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:BNDD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_yaw: + description: VFM Virtual Yaw + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:YAW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_roll: + description: VFM Virtual Roll + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:ROLL'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_pitch: + description: VFM Virtual Pitch + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:PITCH'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_x: + description: VFM Virtual X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +vfm_y: + description: VFM Virtual Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-VFM:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - vfm + readOnly: False + softwareTrigger: false + +hfm_xu: + description: HFM Upstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRXU'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_xd: + description: HFM Downstream X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRXD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_yuw: + description: HFM Upstream Wall Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRYUW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_yr: + description: HFM Ring Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRYR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_ydw: + description: HFM Downstream Wall Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRYDW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_bu: + description: HFM Upstream Bender + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:BNDU'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_bd: + description: HFM Downstream Bender + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:BNDD'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_yaw: + description: HFM Virtual Yaw + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:YAW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_roll: + description: HFM Virtual Roll + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:ROLL'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_pitch: + description: HFM Virtual Pitch + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:PITCH'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_x: + description: HFM Virtual X + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +hfm_y: + description: HFM Virtual Y + deviceClass: ophyd_devices.EpicsMotorEC + deviceConfig: {prefix: 'X06DA-ES-HFM:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - hfm + readOnly: False + softwareTrigger: false + +bcu_bpm1: + description: BCU BPM Channel 1 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-BCBPM:Current1:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +bcu_bpm2: + description: BCU BPM Channel 2 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-BCBPM:Current2:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +bcu_bpm3: + description: BCU BPM Channel 3 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-BCBPM:Current3:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +bcu_bpm4: + description: BCU BPM Channel 4 + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-BCBPM:Current4:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +bcu_bpmsum: + description: BCU BPM Summed + deviceClass: ophyd.EpicsSignalRO + deviceConfig: {read_pv: 'X06DA-ES-BCBPM:SumAll:MeanValue_RBV', auto_monitor: true} + onFailure: buffer + enabled: True + readoutPriority: monitored + deviceTags: + - bpm + readOnly: True + softwareTrigger: false + +bcu_bpm_x: + description: BCU BPM X + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCBPM:TRX'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_bpm_y: + description: BCU BPM Y + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCBPM:TRY'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_xw: + description: BCU Slit Wall + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLH:TRXW'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_xr: + description: BCU Slit Ring + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLH:TRXR'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_xcen: + description: BCU Slit X Centre + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLH:CENTER'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_xsize: + description: BCU Slit X Size + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLH:SIZE'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_yt: + description: BCU Slit top + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLV:TRYT'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_yb: + description: BCU Slit Bottom + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLV:TRYB'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_ycen: + description: BCU Slit Y Centre + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLV:CENTER'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +bcu_sl_ysize: + description: BCU Slit Y Size + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-BCSLV:SIZE'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - bcu + readOnly: False + softwareTrigger: false + +scam_zoom: + description: Sample Camera Zoom + deviceClass: ophyd_devices.EpicsMotor + deviceConfig: {prefix: 'X06DA-ES-MS:ZOOM'} + onFailure: buffer + enabled: True + readoutPriority: baseline + deviceTags: + - scam + readOnly: False + softwareTrigger: false + diff --git a/pxiii_bec/device_configs/pxiii-state-devices.csv b/pxiii_bec/device_configs/pxiii-state-devices.csv new file mode 100644 index 0000000..c64af6e --- /dev/null +++ b/pxiii_bec/device_configs/pxiii-state-devices.csv @@ -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}" diff --git a/pxiii_bec/device_configs/pxiii-state-devices.yaml b/pxiii_bec/device_configs/pxiii-state-devices.yaml new file mode 100644 index 0000000..bd0ef14 --- /dev/null +++ b/pxiii_bec/device_configs/pxiii-state-devices.yaml @@ -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 + diff --git a/pxiii_bec/device_configs/x06da_device_config.yaml b/pxiii_bec/device_configs/x06da_device_config.yaml index 762f498..a9b2d9e 100644 --- a/pxiii_bec/device_configs/x06da_device_config.yaml +++ b/pxiii_bec/device_configs/x06da_device_config.yaml @@ -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 \ No newline at end of file +base_config: + - !include ./pxiii-standard-devices.yaml +states_config: + - !include ./pxiii-state-devices.yaml diff --git a/pxiii_bec/macros/calculator.py b/pxiii_bec/macros/calculator.py new file mode 100644 index 0000000..9ff1f58 --- /dev/null +++ b/pxiii_bec/macros/calculator.py @@ -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 + diff --git a/pxiii_bec/macros/check.py b/pxiii_bec/macros/check.py new file mode 100644 index 0000000..6ac886e --- /dev/null +++ b/pxiii_bec/macros/check.py @@ -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) + + + + diff --git a/pxiii_bec/macros/mx_basics.py b/pxiii_bec/macros/mx_basics.py new file mode 100644 index 0000000..492234c --- /dev/null +++ b/pxiii_bec/macros/mx_basics.py @@ -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) + diff --git a/pxiii_bec/macros/mx_methods.py b/pxiii_bec/macros/mx_methods.py new file mode 100644 index 0000000..d697d18 --- /dev/null +++ b/pxiii_bec/macros/mx_methods.py @@ -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) diff --git a/pxiii_bec/macros/pxiii_energy.py b/pxiii_bec/macros/pxiii_energy.py new file mode 100644 index 0000000..e594f06 --- /dev/null +++ b/pxiii_bec/macros/pxiii_energy.py @@ -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) diff --git a/pxiii_bec/macros/pxiii_parameters.py b/pxiii_bec/macros/pxiii_parameters.py new file mode 100644 index 0000000..62733f0 --- /dev/null +++ b/pxiii_bec/macros/pxiii_parameters.py @@ -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, +# } -- 2.52.0