X10sa production 20260617t100740 #24

Merged
perl_d merged 2 commits from x10sa_production_20260617T100740 into main 2026-09-02 09:35:17 +02:00
15 changed files with 856 additions and 282 deletions
@@ -4,19 +4,11 @@ is started. It can be used to add additional command line arguments.
"""
import os
import sys
from pathlib import Path
from bec_lib.service_config import ServiceConfig
import pxii_bec
_package_dir = Path(pxii_bec.__file__).resolve().parent
_scripts_dir = _package_dir / "scripts"
if str(_scripts_dir) not in sys.path:
sys.path.insert(0, str(_scripts_dir))
def extend_command_line_args(parser):
"""
@@ -205,7 +205,25 @@ states:
# smargon_chi: mount
# smargon_phi: mount
xrf_pos: out
det_diode:
allow_modifiers: true
bl_pos: out
bl_bright: 'off'
bs_pos: in
bs_z: safe
coll_y: out
cryo_pos: in
det_cov: 'close'
diag_y: out
fl_bright: 'off'
aerotech_x: in
# aerotech_u: mount
# smargon_x: mount
# smargon_y: mount
# smargon_chi: mount
# smargon_phi: mount
xrf_pos: out
+19 -10
View File
@@ -55,8 +55,8 @@ aerotech:
deviceConfig:
prefix: http://mx-x10sa-queue-01:5234
deviceTags:
- aerotech
- motors
- aerotech
enabled: true
onFailure: buffer
readoutPriority: baseline
@@ -65,15 +65,15 @@ aerotech:
mount: 0
work: 0
x:
in: 0.0
in: -8.1e-06
out: -10
safe: -50
y:
mount: -0.0
work: -0.027
work: -0.02600108
z:
mount: 0
work: -0.01
work: -0.00900383
bcu_bpm1:
description: BCU BPM Channel 1
deviceClass: ophyd.EpicsSignalRO
@@ -257,7 +257,6 @@ bl_bright:
onFailure: buffer
readoutPriority: baseline
userParameter:
move_method: signal
'off': 0.0
'on': 1.3
tol: 0.01
@@ -303,7 +302,7 @@ bs_x:
onFailure: buffer
readoutPriority: baseline
userParameter:
in: 0.361
in: 0.39119736
bs_y:
description: Beamstop Y
deviceClass: ophyd_devices.EpicsMotor
@@ -315,7 +314,7 @@ bs_y:
onFailure: buffer
readoutPriority: baseline
userParameter:
in: 0.258
in: 0.76699895
bs_z:
description: Beamstop Z
deviceClass: ophyd_devices.EpicsMotor
@@ -445,7 +444,7 @@ coll_x:
onFailure: buffer
readoutPriority: baseline
userParameter:
in: -1.297
in: 0.67471002
coll_y:
description: Collimator Y
deviceClass: ophyd_devices.EpicsMotor
@@ -457,12 +456,23 @@ coll_y:
onFailure: buffer
readoutPriority: baseline
userParameter:
in: 39.002
in: 39.02
intermediate: 32
out: 20.002
park: 1
tol: 0.05
type: continuous
coll_y_in_position:
description: Collimator Y In Position
deviceClass: ophyd_devices.EpicsSignal
deviceConfig:
auto_monitor: true
read_pv: X10SA-ES-COL:POS-SET-SEQ.DO2
deviceTags:
- se
enabled: true
onFailure: buffer
readoutPriority: baseline
cryo_pos:
description: Cryo positioner
deviceClass: ophyd.EpicsSignal
@@ -830,7 +840,6 @@ fl_bright:
onFailure: buffer
readoutPriority: baseline
userParameter:
move_method: signal
'off': 0.0
'on': 3.0
tol: 0.01
+4 -3
View File
@@ -428,7 +428,7 @@ def fit_plothist(hindex: int, signal_name: str, model="gauss", ibg=0):
#########################
def fit_plot(data_x, data_y, model="gauss", ibg=1, fitrange=0, fitclick=0):
def fit_plot(data_x, data_y, model="gauss", ibg=1, silent=0,fitrange=0, fitclick=0):
"""
Get data for a completed scan, gaussian, voigt or lorentzian fit,
default = gauss, plus linear background
@@ -555,8 +555,9 @@ def fit_plot(data_x, data_y, model="gauss", ibg=1, fitrange=0, fitclick=0):
returncenvar = pre+"center"
gcen = g.params[returncenvar].value
print('gcen =', gcen)
print(g.fit_report())
print('gcen =', gcen)
if (not silent):
print(g.fit_report())
# fit_id = pre+'_center'
+10 -4
View File
@@ -2,6 +2,7 @@
from collections import defaultdict, deque
from enum import Enum
# from pxii_bec.scripts import beamline_context as bl
# from enums import BeamlineState, TemperatureMode
# from matcher import DeviceMatcher, nonzero_is_on
@@ -65,10 +66,15 @@ class StateChangePlanner:
def move_to(self, state_name, modifier=None):
"""Move devices to the correct positions to achieve a given state"""
# Close the fast shutter before moving anything
dev.bcu_shutter.put(0)
if isinstance(state_name, str):
state_name = BeamlineState(state_name)
target = self._merged_state(state_name, modifier)
plan = self._plan(target)
print("PLAN:")
@@ -76,12 +82,12 @@ class StateChangePlanner:
print(f"Stage {i + 1}: {stage}")
for stage in plan:
for dev, pos in stage:
d = self.devices[dev]
for pd_devs, pos in stage:
d = self.devices[pd_devs]
if not d.is_at(pos):
if self.debug:
print(f"→ Moving {dev} -> {pos}")
print(f"→ Moving {pd_devs} -> {pos}")
# print(" Before:", self.get_states())
try:
@@ -89,7 +95,7 @@ class StateChangePlanner:
except Exception as e:
print(f"Exception occurred: {e}")
print(f"\nFAILED MOVE: {dev} -> {pos}")
print(f"\nFAILED MOVE: {pd_devs} -> {pos}")
print("States at failure:", self.get_positions())
raise
+2 -27
View File
@@ -1,35 +1,10 @@
"""Build the sample environment devices"""
import os
import sys
from pathlib import Path
from pxii_bec.macros.position_device import PositionDevice, motor_resolver
import yaml
from pxii_bec.scripts import beamline_context as bl
# from position_device import PositionDevice
def motor_resolver(bec_name):
"""Used to handle aerotech and smargon motors"""
candidates = [bec_name, bec_name.replace("_", ".")]
for path in candidates:
try:
obj = dev
for part in path.split("."):
obj = getattr(obj, part)
return obj
except Exception:
pass
raise ValueError(f"Cannot resolve motor for '{bec_name}'")
def build_devices(yaml_file):
"""Build devices from the beamline states yaml"""
@@ -174,7 +149,7 @@ def save_and_reload():
Save current configuration to YAML and rebuild
the beamline environment using the same deployment.
"""
bl.initialise()
print(f"(saving changes to {bl.env.devices_file})")
bec.config.save_current_session(bl.env.devices_file)
+505
View File
@@ -0,0 +1,505 @@
""" Files needed for the daily setup routine for local contacts """
import time
from pxii_bec.scripts import beamline_context as bl
from pxii_bec.macros.beamline_planner import BeamlineState
def daily_setup(energy=12400):
""" The daily setup workflow """
plot1, plot2, plot3, plot4, log, progress = select_daily_setup_gui()
messages = []
progress_state = {
"Set energy": "todo",
"Align beamstop": "todo",
"Measure beam position": "todo",
"Align collimator": "todo",
"Measure flux": "todo",
"Save new positions to BEC": "todo",
# "Align rotation axis": "todo",
}
update_log(log, messages, "Starting daily beamline setup")
clear_daily_plots
# # Step 1: set beamline energy
set_progress(progress, progress_state, "Set energy", "running")
daily_energy(energy,plot_widget=plot1)
set_progress(progress, progress_state, "Set energy", "done")
update_log(log, messages, f"Beamline energy is {get_current_energy():.5g} eV")
# Step 2: align beamstop
clear_daily_plots()
set_progress(progress, progress_state, "Align beamstop", "running")
bs_result = daily_beamstop()
set_progress(progress, progress_state, "Align beamstop", "done")
update_log(log, messages, f"Beamstop centred: "
f"X centre: {bs_result['x_position']:.4g}, "
f"Y centre: {bs_result['y_position']:.4g}"
)
save_current_position(dev.bs_x, 'in')
save_current_position(dev.bs_y, 'in')
set_progress(progress, progress_state, "Align beamstop", "done")
# Step 3: measure beam position
set_progress(progress, progress_state, "Measure beam position", "running")
pos_result = daily_beampos()
update_log(log, messages, "Beam centres: ")
for zoom in CameraZoom:
update_log(log, messages, f"{zoom.label} zoom: ({pos_result[zoom.label]['x']:.4g}, {pos_result[zoom.label]['y']:.4g})")
set_progress(progress, progress_state, "Measure beam position", "done")
# Step 4: Align collimator
# set_progress(progress, progress_state, "Align collimator", "running")
# coll_result = daily_coll()
# update_log(log, messages, f"Collimator alignment: "
# f"X centre: {coll_result['x_position']:.4g},\n"
# f" X width = {coll_result['x_width']:.4f} mm\n"
# f" Y centre = {coll_result['y_position']:.4f} mm\n"
# f" Y width = {coll_result['y_width']:.4f} mm\n"
# f" Y/X width ratio = {coll_result['y_width'] / coll_result['x_width']:.3f}"
# )
update_log(log, messages, "Collimator alignment was skipped")
# save_current_position(dev.coll_x, 'in')
# save_current_position(dev.coll_y, 'in')
# set_progress(progress, progress_state, "Align collimator", "done")
# Step 5: measure flux
set_progress(progress, progress_state, "Measure flux", "running")
flux1,flux2 = bpm2flux()
update_log(log, messages, f"Flux at 100% transmission is {flux2:.3g} ph/s")
set_progress(progress, progress_state, "Measure flux", "done")
# Step 6: save new positions and reload
set_progress(progress, progress_state, "Save new positions to BEC", "running")
save_and_reload()
update_log(log, messages, f"Positions have been saved in BEC, please update in Aare")
set_progress(progress, progress_state, "Save new positions to BEC", "done")
# Move back to sample alignment
bl.planner.move_to(BeamlineState.SAMPLE_ALIGNMENT)
def select_daily_setup_gui_old():
"""Return widgets belonging to the Daily Setup GUI."""
window_name = "DailySetup"
open_windows = bec.gui.windows
if open_windows.get(window_name) is None:
gui = bec.gui.new(window_name)
plot1 = gui.new(
widget = "Waveform",
object_name = "Plot1"
)
plot2 = gui.new(
widget = "Waveform",
object_name = "Plot2"
)
results = gui.new(
widget = "TextBox",
object_name = "Results",
where = "bottom",
)
log = gui.new(
widget = "TextBox",
object_name = "Info",
where = "bottom",
)
progress = gui.new(
widget = "TextBox",
object_name = "Progress",
where = "left",
)
else:
gui = open_windows[window_name]
plot1 = gui.Plot1
plot2 = gui.Plot2
log = gui.Info
results = gui.Results
progress = gui.Progress
return plot1, plot2, results, log, progress
def select_daily_setup_gui():
"""Return widgets belonging to the Daily Setup GUI."""
window_name = "DailySetup"
open_windows = bec.gui.windows
if open_windows.get(window_name) is None:
gui = bec.gui.new(window_name)
# Row 1
plot1 = gui.new(
widget="Waveform",
object_name="Beamstop_X",
)
plot2 = gui.new(
widget="Waveform",
object_name="Beamstop_Y",
relative_to="Beamstop_X",
where="right",
)
# Row 2 - start a new full-width row
plot3 = gui.new(
widget="Waveform",
object_name="Collimator_X",
where="bottom",
)
plot4 = gui.new(
widget="Waveform",
object_name="Collimator_Y",
relative_to="Collimator_X",
where="right",
)
# Row 3 - start another full-width row
log = gui.new(
widget="TextBox",
object_name="Info",
where="bottom",
)
progress = gui.new(
widget="TextBox",
object_name="Progress",
relative_to="Info",
where="right",
)
gui.set_layout_ratios(
horizontal=[1, 1],
vertical=[2, 2, 1],
)
else:
gui = open_windows[window_name]
plot1 = gui.Beamstop_X
plot2 = gui.Beamstop_Y
plot3 = gui.Collimator_X
plot4 = gui.Collimator_Y
log = gui.Info
progress = gui.Progress
return plot1, plot2, plot3, plot4, log, progress
def clear_daily_plots():
plot1, plot2, plot3, plot4, log, progress = select_daily_setup_gui()
plot1.clear_all()
plot2.clear_all()
plot3.clear_all()
plot4.clear_all()
def update_log(log_box, messages, message):
"""Add new message to the daily setup log """
messages.append(message)
log_box.set_plain_text("\n".join(messages))
def update_progress(progress_box, progress_state):
""" Sets up the status icons for the progress tracker"""
status = {
"todo": "\u25CB",
"running": "\u25B6",
"done": "\u2713",
"warning": "\u26A0",
"failed": "\u2717",
}
text = "\n".join(
f"{status[state]} {label}"
for label, state in progress_state.items()
)
progress_box.set_plain_text(text)
def set_progress(progress_box, progress_state, step, status):
"""Change the status of one step and update the display."""
progress_state[step] = status
update_progress(progress_box, progress_state)
def plot_daily_setup_scan(
motor_name,
signal_name,
plot="x",
title=None,
):
"""Plot live scan data in one of the Daily Setup waveform widgets."""
plot1, plot2, plot3, plot4, log, progress = select_daily_setup_gui()
if plot.lower() == "beamstop_x":
wf = plot1
elif plot.lower() == "beamstop_y":
wf = plot2
elif plot.lower() == "collimator_x":
wf = plot3
elif plot.lower() == "collimator_y":
wf = plot4
else:
raise ValueError("plot must be 'x' or 'y'")
wf.clear_all()
if title is None:
title = f"{motor_name} scan"
wf.title = title
wf.x_label = motor_name
wf.y_label = signal_name
wf.plot(
device_x=motor_name,
device_y=signal_name,
)
def daily_energy(energy, plot_widget=None):
""" Set the beamline to the required energy """
current_energy = get_current_energy()
if abs(energy - current_energy) > 1:
bl_energy(energy, window_name="DailySetup", plot_widget=plot_widget)
else:
gap_actual = dev.id_gap.position
gap_req = new_calc_gap(energy)
if abs(gap_actual-gap_req) > 0.05:
umv(dev.id_gap, gap_req)
mono_pitch_scan(window_name="DailySetup", plot_widget=plot_widget)
def set_zoom(zoom):
"""Set sample camera zoom level."""
if isinstance(zoom, str):
zoom = CameraZoom.from_label(zoom)
umv(dev.scam_zoom, zoom.position)
else:
umv(dev.scam_zoom, zoom)
def daily_beampos():
"""Measure beam positions at different zoom levels"""
results = {}
# Ensure shutter and detector cover are closed before changing states
dev.bcu_shutter.put(0)
bl.d['det_cov'].move('close')
try:
# set transmission to 10%
dev.transm.put(0.1)
# move to beam visualisation
bl.planner.move_to(BeamlineState.BEAM_VISUALISATION)
# open shutter
dev.bcu_shutter.put(1)
for zoom in CameraZoom:
print(F"Moving to {zoom.label}")
umv(dev.scam_zoom, zoom.position)
# set autoexposure
auto_exposure(cam="samcam", max_iter=25)
time.sleep(0.2)
# take readings
x = dev.samcam_x.read()['samcam_x']['value']
y = dev.samcam_y.read()['samcam_y']['value']
# append results
results[zoom.label] = {'x': x, 'y': y}
print(f" {zoom.label}: x = {x:.4g}, y = {y:.4g}")
return results
finally:
dev.bcu_shutter.put(0)
def daily_coll():
"""Centre the collimator in X and Y using the I1 diode."""
plot1, plot2, plot3, plot4, log, progress = select_daily_setup_gui()
result = {
"success": False,
"start_intensity": None,
"y_start_intensity": None,
"y_end_intensity": None,
"x_start_intensity": None,
"x_end_intensity": None,
"y_position": None,
"x_position": None,
}
dev.bcu_shutter.put(0)
try:
if not bl.planner.is_state(BeamlineState.FLUX_MEASUREMENT):
bl.planner.move_to(BeamlineState.FLUX_MEASUREMENT)
dev.bcu_shutter.put(1)
dev.transm.put(0.1)
time.sleep(0.2)
result["start_intensity"] = read_i1()
print(f"Starting intensity is {result['start_intensity']:.4g}")
bl.d["coll_y"].move("in")
# Centre Y
result["y_start_intensity"] = read_i1()
print(
"Intensity with collimator in before Y scan: "
f"{result['y_start_intensity']:.4g}"
)
y_result = find_feature(
dev.coll_y,
dev.i1,
-0.3,
0.3,
30,
feature="peak",
relative=True,
confirm=False,
plot_widget=plot4,
)
result["y_position"] = y_result["centre"]
result["y_end_intensity"] = read_i1()
result["y_width"] = y_result["width"]
print(
"Intensity with collimator in after Y scan: "
f"{result['y_end_intensity']:.4g}"
)
# Centre X
result["x_start_intensity"] = read_i1()
print(
"Intensity with collimator in before X scan: "
f"{result['x_start_intensity']:.4g}"
)
x_result = find_feature(
dev.coll_x,
dev.i1,
-0.3,
0.3,
30,
feature="peak",
relative=True,
confirm=False,
plot_widget=plot3,
)
result["x_position"] = x_result["centre"]
result["x_end_intensity"] = read_i1()
result["x_width"] = x_result["width"]
print(
"Intensity with collimator in after X scan: "
f"{result['x_end_intensity']:.4g}"
)
result["success"] = True
return result
finally:
dev.bcu_shutter.put(0)
def daily_beamstop():
"""Centre the beamstop against the detector
cover, i2"""
plot1, plot2, plot3, plot4, log, progress = select_daily_setup_gui()
result = {
# "success": False,
# "x_position": None,
"y_position": None,
"intensity after alignment": None
}
dev.bcu_shutter.put(0)
dev.transm.put(0.1)
try:
# if not bl.planner.is_state(BeamlineState.BEAMSTOP_ALIGNMENT):
# bl.planner.move_to(BeamlineState.BEAMSTOP_ALIGNMENT)
# set_zoom('2x')
# auto_exposure('samcam', max_iter=20)
# bl.d['bl_pos'].move('out')
# bl.d['det_cov'].move('close')
# dev.bcu_shutter.put(1)
if not bl.planner.is_state(BeamlineState.DET_DIODE):
bl.planner.move_to(BeamlineState.DET_DIODE)
# set_zoom('2x')
# auto_exposure('samcam', max_iter=20)
# bl.d['bl_pos'].move('out')
bl.d['det_cov'].move('close')
dev.bcu_shutter.put(1)
time.sleep(0.2)
# Centre Y
y_result = find_feature(
dev.bs_y,
dev.i2,
-1,
1,
30,
settle=0.3,
feature="dip",
relative=True,
confirm=False,
window_name="DailySetup",
plot_widget=plot2,
)
# Wait for bs_y to setlle
time.sleep(2)
# Centre X
x_result = find_feature(
dev.bs_x,
dev.i2,
-0.2,
1.2,
30,
feature="edge_offset",
offset = Beamstop.x_offset,
relative=True,
confirm=False,
window_name="DailySetup",
plot_widget=plot1,
)
result["x_position"] = x_result["centre"]
result["y_position"] = y_result["centre"]
result["intensity after alignment"] = read_i2()
print(
"Intensity after Y scan: "
f"{result['intensity after alignment']:.4g}\n"
f"Centred position is {result["x_position"]:.5g}, {result["y_position"]:.5g}"
)
return result
finally:
dev.bcu_shutter.put(0)
+2 -2
View File
@@ -9,8 +9,8 @@ def planner_deps():
("aerotech_x", "out"): [("diag_y", "out"), ("bs_z", "safe")],
("diag_y", "scint"): [("aerotech_x", "out"), ("bs_z", "safe"), ("cryo_pos", "out")],
("diag_y", "i1"): [("aerotech_x", "out"), ("bs_z", "safe"), ("cryo_pos", "out")],
("bs_pos", "out"): [("bs_z", "safe"),("bl_pos", "in")],
("bs_pos", "in"): [("bs_z", "safe"),("bl_pos", "in")],
("bs_pos", "out"): [("bs_z", "safe")],
("bs_pos", "in"): [("bs_z", "safe")],
("diag_y", "out"): [("bs_z", "safe")],
("diag_y", "park"): [("bs_z", "safe")],
("coll_y", "out"): [("bs_z", "safe")],
+146 -203
View File
@@ -8,8 +8,10 @@ import matplotlib.pyplot as plt
from scipy.signal import find_peaks as fp
import pandas as pd
from scipy.optimize import linear_sum_assignment
from pathlib import Path
from pxii_bec.scripts import beamline_context as bl
from pxii_bec.macros.beamline_planner import BeamlineState
def bragg_scan():
"""Energy scans from 6 to 18 keV at various gap positions"""
@@ -29,6 +31,89 @@ def bragg_scan():
)
gap += 0.5
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)
def move_xeye(direction):
"""Move the xeye in or out"""
@@ -256,8 +341,8 @@ def write_beamsize():
def scan_Ge():
scanbefore = 30 # eV
scanafter = 30 # eV
scanbefore = 12 # eV
scanafter = 12 # eV
stepsize = 0.2 # eV
# Edge sgould be at 11103.1
actual_edge_Ge = 11103.1 # eV
@@ -268,30 +353,17 @@ def scan_Ge():
print(f"Current estimate of edge is {current_bragg:.5g} mrad\n")
xdata = []
ydata = []
filedir, fname = fnow()
filename = f"{filedir}{fname}_ge_edge.csv"
filename = f"{bl.env.lut_dir}/{filenow(date_only=True)}_ge_edge.csv"
print(filename)
with open(filename, 'w') as f:
f.write(f"Energy,Bragg,bcu_bpmsum\n")
# scanstart = edge_Ge + scanafter
# scanend = edge_Ge - scanbefore
# bragg_start = convert_from_energy(scanstart)["bragg_angle_mrad"]
# bragg_end = convert_from_energy(scanend)["bragg_angle_mrad"]
# stepnumber = abs(int((scanend - scanstart) / stepsize))
# print(f"Changing energy to {scanstart}")
# bl_energy(scanstart)
# # scan_gap()
# umv(dev.ss_f4_x, 6) # Put Ge filter in place
# print(f"scanning from {bragg_start} to {bragg_end} with {stepnumber} steps")
# s = scans.line_scan(dev.dcm_bragg, bragg_start, bragg_end, steps=stepnumber, relative=False)
# print(s)
# umv(dev.ss_f4_x, 2)
plot_live_data_bec(dev.dcm_bragg,dev.bcu_bpmsum)
scanpoints = np.linspace(current_bragg - 0.5, current_bragg + 0.5, 300)
plot_live_data(dev.dcm_bragg,dev.bcu_bpmsum)
scanpoints = np.linspace(current_bragg - 0.5, current_bragg + 0.5, 100)
start_energy = convert_from_bragg(current_bragg+0.5)["energy_ev"]
bl_energy(start_energy)
dev.transm.put(1.0) # Take all the filters out
umv(dev.ss_f4_x, 6) # Put Ge filter in place
for bragg in scanpoints:
@@ -310,7 +382,7 @@ def scan_Ge():
"motor_device": dev.dcm_bragg,
"scan_number": "Current",
}
dev.transm.put(0.1) # set transmission back to 0.1
# Define and fit model to scan data
fit_params = create_fit_parameters(deriv = True,
negative = False,
@@ -320,7 +392,7 @@ def scan_Ge():
# Plot the fitted data if plot = True
plot_fitted_data_bec(data, fit_result)
plot_fitted_data(data, fit_result)
@@ -1003,23 +1075,30 @@ def mirror_pitch(mirror = 'vfm'):
bl_energy(12400)
results = np.array(results)
def read_samcam_scint(planner,zoom=800):
# set transmission tp 10%
dev.transm.put(0.1)
# set camera zoom
umv(dev.scam_zoom, zoom)
# move to beam visualisation, ensure shutter is closed first
def read_scintXY(zoom=800):
""" Get the X and Y beam positions from the sample camera at
a sepcified zoom. Default zoom is 800"""
# Ensure shutter and detector cover are closed before changing states
dev.bcu_shutter.put(0)
planner.move_to(BeamlineState.BEAM_VISUALISATION)
# open shutter
dev.bcu_shutter.put(1)
# set autoexposure
auto_exposure(cam="samcam", max_iter=25)
time.sleep(0.2)
x = dev.samcam_x.read()['samcam_x']['value']
y = dev.samcam_y.read()['samcam_y']['value']
dev.bcu_shutter.put(0)
return x, y
bl.d['det_cov'].move('close')
try:
# set transmission to 10%
dev.transm.put(0.1)
# set camera zoom
umv(dev.scam_zoom, zoom)
# move to beam visualisation
bl.planner.move_to(BeamlineState.BEAM_VISUALISATION)
# open shutter
dev.bcu_shutter.put(1)
# set autoexposure
auto_exposure(cam="samcam", max_iter=25)
time.sleep(0.2)
x = dev.samcam_x.read()['samcam_x']['value']
y = dev.samcam_y.read()['samcam_y']['value']
return x, y
finally:
dev.bcu_shutter.put(0)
def find_best_roll(low = 6000, high = 20000):
# low_scanpoints = np.linspace(2.0, 7.0, 11)
@@ -1398,14 +1477,14 @@ def get_mirror_data(history_index: int):
# }
def record_beampos_until(stop_time_str, planner, env, interval_minutes=10):
def record_beampos_until(stop_time_str, interval_minutes=10):
"""
Runs `record_beam()` every `interval_minutes` minutes
until the next occurrence of the given stop time (HH:MM).
"""
# Prepare the file
filename = env.lut_dir / "beampos" / f"beampos_{filenow()}.csv"
filename = bl.env.lut_dir / "beampos" / f"beampos_{filenow()}.csv"
scam_zoom = dev.scam_zoom.read()['scam_zoom']['value']
umv(dev.scam_zoom, 800)
beam_size = "25 x 25"
@@ -1430,7 +1509,7 @@ def record_beampos_until(stop_time_str, planner, env, interval_minutes=10):
# Change to beam visualisation state, ensure shutter is closed first
dev.bcu_shutter.put(0)
planner.move_to(BeamlineState.BEAM_VISUALISATION)
bl.planner.move_to(BeamlineState.BEAM_VISUALISATION)
# Start recording beam position
print(f"Starting now ({now:%Y-%m-%d %H:%M}), running until {end_time:%Y-%m-%d %H:%M}")
@@ -1445,7 +1524,7 @@ def record_beampos_until(stop_time_str, planner, env, interval_minutes=10):
time.sleep(interval_minutes * 60)
print(f"Finished — reached {end_time:%H:%M}.")
planner.move_to(BeamlineState.MANUAL_SAMPLE_EXCHANGE)
bl.planner.move_to(BeamlineState.MANUAL_SAMPLE_EXCHANGE)
@@ -1459,26 +1538,28 @@ def record_beam(filename):
umv(dev.bcu_bpm_x, BPM_X_Calibration.centred_position)
umv(dev.bcu_bpm_y, BPM_Y_Calibration.centred_position)
# Open shutter and record positions
dev.bcu_shutter.put(1)
auto_exposure(cam="samcam")
time.sleep(2)
now = datetime.now()
try:
# Open shutter and record positions
dev.bcu_shutter.put(1)
auto_exposure(cam="samcam")
time.sleep(2)
now = datetime.now()
# Append data to the file
with open(filename, "a", encoding="utf-8") as f:
fnow = now.strftime("%H:%M:%S")
xpos_cam = dev.samcam_x.read()["samcam_x"]["value"]
ypos_cam = dev.samcam_y.read()["samcam_y"]["value"]
xpos_bpm, ypos_bpm = get_bcu_beampos()
print(f"Time is {fnow}, ScinX position is {xpos_cam:.5g}, ScinY position is {ypos_cam:.5g}")
print(f"BPM X is: {xpos_bpm}, BPM Y is {ypos_bpm}")
f.write(
# f"{fnow}, {xpos: .5g}, {ypos: .4g}, {xpos_cam: .5g}, {ypos_cam: .4g}\n"
f"{fnow},{xpos_cam: .5g},{ypos_cam: .4g},{xpos_bpm: .5g},{ypos_bpm: .5g}\n"
)
# Close shutter
dev.bcu_shutter.put(0)
# Append data to the file
with open(filename, "a", encoding="utf-8") as f:
fnow = now.strftime("%H:%M:%S")
xpos_cam = dev.samcam_x.read()["samcam_x"]["value"]
ypos_cam = dev.samcam_y.read()["samcam_y"]["value"]
xpos_bpm, ypos_bpm = get_bcu_beampos()
print(f"Time is {fnow}, ScinX position is {xpos_cam:.5g}, ScinY position is {ypos_cam:.5g}")
print(f"BPM X is: {xpos_bpm}, BPM Y is {ypos_bpm}")
f.write(
# f"{fnow}, {xpos: .5g}, {ypos: .4g}, {xpos_cam: .5g}, {ypos_cam: .4g}\n"
f"{fnow},{xpos_cam: .5g},{ypos_cam: .4g},{xpos_bpm: .5g},{ypos_bpm: .5g}\n"
)
finally:
# Close shutter
dev.bcu_shutter.put(0)
def analyse_beampos(file):
@@ -1576,114 +1657,6 @@ def scan_scin_focus(planner, type = 'fine'):
go_to_peak(dev.diag_z, dev.scam, min, max, steps, relative=True, gomax=True, confirm=False)
dev.bcu_shutter.put(0)
def daily_setup(energy=12400):
wf, results, log, progress = select_daily_setup_gui()
messages = []
progress_state = {
"Set energy": "todo",
"Measure flux": "todo",
"Measure beam position": "todo",
"Align collimator": "todo",
"Check beamstop": "todo",
"Align rotation axis": "todo",
}
update_log(log, messages, "Starting daily beamline setup")
# Step 1: set beamline
set_progress(progress, progress_state, "Set energy", "running")
current_energy = get_current_energy()
if abs(energy - current_energy) > 1:
bl_energy(energy, window_name="DailySetup")
else:
gap_actual = dev.id_gap.position
gap_req = new_calc_gap(energy)
if abs(gap_actual-gap_req) > 0.05:
umv(dev.id_gap, gap_req)
mono_pitch_scan(window_name="DailySetup")
set_progress(progress, progress_state, "Set energy", "done")
update_log(log, messages, f"Beamline energy is {energy} eV")
# Step 2: measure flux
set_progress(progress, progress_state, "Measure flux", "running")
flux1,flux2 = bpm2flux()
update_log(log, messages, f"Flux at 100% transmission is {flux2:.3g} ph/s")
set_progress(progress, progress_state, "Measure flux", "done")
# Step 3: measure beam position
def update_log(log_box, messages, message):
messages.append(message)
log_box.set_plain_text("\n".join(messages))
def update_progress(progress_box, progress_state):
status = {
"todo": "\u25CB",
"running": "\u25B6",
"done": "\u2713",
"warning": "\u26A0",
"failed": "\u2717",
}
text = "\n".join(
f"{status[state]} {label}"
for label, state in progress_state.items()
)
progress_box.set_plain_text(text)
def set_progress(progress_box, progress_state, step, status):
"""Change the status of one step and update the display."""
progress_state[step] = status
update_progress(progress_box, progress_state)
def select_daily_setup_gui():
"""Return widgets belonging to the Daily Setup GUI."""
window_name = "DailySetup"
open_windows = bec.gui.windows
if open_windows.get(window_name) is None:
gui = bec.gui.new(window_name)
plot = gui.new(
widget = "Waveform",
object_name = "Plot"
)
results = gui.new(
widget = "TextBox",
object_name = "Results",
where = "bottom",
)
log = gui.new(
widget = "TextBox",
object_name = "Info",
where = "bottom",
)
progress = gui.new(
widget = "TextBox",
object_name = "Progress",
where = "left",
)
else:
gui = open_windows[window_name]
plot = gui.Plot
log = gui.Info
results = gui.Results
progress = gui.Progress
return plot, results, log, progress
def bpm_errors(ch1, ch2, ch3, ch4):
total = ch1 + ch2 + ch3 + ch4
@@ -1758,41 +1731,11 @@ def centre_bcu_bpm_y():
umv(dev.bcu_bpm_y, centre)
return centre
def gap_check():
gaps = []
for repeat in range(6000, 30000, 2000):
gap = float(new_calc_gap(repeat))
gaps.append(gap)
print(gaps)
def read_i1():
return dev.i1.read()['i1']['value']
def cen_coll(d, planner):
""" Centre collimator by scanning against i1 diode """
dev.bcu_shutter.put(0)
planner.move_to(BeamlineState.FLUX_MEASUREMENT)
# Centre in Y
dev.bcu_shutter.put(1)
start_inten = read_i1()
print(f"Starting intensity is {start_inten:.4g}")
d['coll_y'].move('in')
coll_start_inten = read_i1()
print(f"Intensity with collimator in before Y scan: {coll_start_inten}")
go_to_peak(dev.coll_y, dev.i1, -0.4, 0.4, 20, relative=True, confirm=False)
coll_end_inten = read_i1()
print(f"Intensity with collimator in after Y scan: {coll_end_inten}")
# Centre in X
coll_start_inten = read_i1()
print(f"Intensity with collimator in before X scan: {coll_start_inten}")
go_to_peak(dev.coll_x, dev.i1, -0.5, 0.5, 20, relative=True, confirm=False)
coll_end_inten = read_i1()
print(f"Intensity with collimator in after X scan: {coll_end_inten}")
dev.bcu_shutter.put(0)
def read_i2():
return dev.i2.read()['i2']['value']
def quick_test():
bl.planner.closest_states()
+101
View File
@@ -0,0 +1,101 @@
Energy,Bragg,bcu_bpmsum
11125.71,178.69,8.61
11125.09,178.70,4.35
11124.47,178.71,3.02
11123.85,178.72,2.34
11123.22,178.73,1.91
11122.60,178.74,1.68
11121.98,178.76,1.54
11121.36,178.77,1.46
11120.74,178.78,1.18
11120.12,178.79,0.96
11119.49,178.80,0.83
11118.87,178.81,0.56
11118.25,178.82,0.53
11117.63,178.83,0.47
11117.01,178.84,0.30
11116.39,178.85,0.36
11115.77,178.86,0.40
11115.15,178.87,0.41
11114.52,178.88,0.34
11113.90,178.89,0.22
11113.28,178.90,0.31
11112.66,178.91,0.28
11112.04,178.92,0.27
11111.42,178.93,0.25
11110.80,178.94,0.20
11110.18,178.95,0.18
11109.56,178.96,0.16
11108.94,178.97,0.29
11108.32,178.98,0.43
11107.70,178.99,0.89
11107.08,179.00,2.56
11106.46,179.01,13.47
11105.84,179.02,50.67
11105.22,179.03,151.83
11104.60,179.04,341.29
11103.98,179.05,612.45
11103.36,179.06,943.72
11102.74,179.07,1288.62
11102.12,179.08,1618.21
11101.50,179.09,1929.28
11100.88,179.10,2210.10
11100.26,179.11,2469.30
11099.64,179.12,2707.38
11099.02,179.13,2927.46
11098.40,179.14,3131.78
11097.78,179.15,3325.73
11097.17,179.16,3511.21
11096.55,179.17,3693.46
11095.93,179.18,3866.64
11095.31,179.19,4032.72
11094.69,179.20,4185.47
11094.07,179.21,4338.38
11093.45,179.22,4482.10
11092.83,179.23,4625.46
11092.22,179.24,4764.60
11091.60,179.25,4895.34
11090.98,179.26,5021.51
11090.36,179.27,5147.06
11089.74,179.28,5277.17
11089.13,179.29,5405.57
11088.51,179.30,5535.01
11087.89,179.31,5660.25
11087.27,179.32,5784.48
11086.65,179.33,5908.97
11086.04,179.34,6030.56
11085.42,179.35,6149.84
11084.80,179.36,6252.02
11084.18,179.37,6352.90
11083.57,179.38,6470.80
11082.95,179.39,6574.31
11082.33,179.40,6668.26
11081.71,179.41,6780.97
11081.10,179.42,6897.50
11080.48,179.43,7008.82
11079.86,179.44,7127.37
11079.25,179.45,7211.71
11078.63,179.46,7317.96
11078.01,179.47,7408.69
11077.40,179.48,7480.76
11076.78,179.49,7589.85
11076.16,179.50,7668.56
11075.55,179.51,7754.67
11074.93,179.52,7827.98
11074.31,179.53,7895.88
11073.70,179.54,7956.73
11073.08,179.55,8017.89
11072.46,179.56,8071.37
11071.85,179.57,8128.70
11071.23,179.58,8192.94
11070.62,179.59,8258.81
11070.00,179.60,8326.71
11069.38,179.61,8385.86
11068.77,179.62,8447.53
11068.15,179.63,8507.91
11067.54,179.64,8565.40
11066.92,179.65,8610.29
11066.31,179.66,8647.74
11065.69,179.67,8681.90
11065.08,179.68,8718.17
11064.46,179.69,8744.09
1 Energy Bragg bcu_bpmsum
2 11125.71 178.69 8.61
3 11125.09 178.70 4.35
4 11124.47 178.71 3.02
5 11123.85 178.72 2.34
6 11123.22 178.73 1.91
7 11122.60 178.74 1.68
8 11121.98 178.76 1.54
9 11121.36 178.77 1.46
10 11120.74 178.78 1.18
11 11120.12 178.79 0.96
12 11119.49 178.80 0.83
13 11118.87 178.81 0.56
14 11118.25 178.82 0.53
15 11117.63 178.83 0.47
16 11117.01 178.84 0.30
17 11116.39 178.85 0.36
18 11115.77 178.86 0.40
19 11115.15 178.87 0.41
20 11114.52 178.88 0.34
21 11113.90 178.89 0.22
22 11113.28 178.90 0.31
23 11112.66 178.91 0.28
24 11112.04 178.92 0.27
25 11111.42 178.93 0.25
26 11110.80 178.94 0.20
27 11110.18 178.95 0.18
28 11109.56 178.96 0.16
29 11108.94 178.97 0.29
30 11108.32 178.98 0.43
31 11107.70 178.99 0.89
32 11107.08 179.00 2.56
33 11106.46 179.01 13.47
34 11105.84 179.02 50.67
35 11105.22 179.03 151.83
36 11104.60 179.04 341.29
37 11103.98 179.05 612.45
38 11103.36 179.06 943.72
39 11102.74 179.07 1288.62
40 11102.12 179.08 1618.21
41 11101.50 179.09 1929.28
42 11100.88 179.10 2210.10
43 11100.26 179.11 2469.30
44 11099.64 179.12 2707.38
45 11099.02 179.13 2927.46
46 11098.40 179.14 3131.78
47 11097.78 179.15 3325.73
48 11097.17 179.16 3511.21
49 11096.55 179.17 3693.46
50 11095.93 179.18 3866.64
51 11095.31 179.19 4032.72
52 11094.69 179.20 4185.47
53 11094.07 179.21 4338.38
54 11093.45 179.22 4482.10
55 11092.83 179.23 4625.46
56 11092.22 179.24 4764.60
57 11091.60 179.25 4895.34
58 11090.98 179.26 5021.51
59 11090.36 179.27 5147.06
60 11089.74 179.28 5277.17
61 11089.13 179.29 5405.57
62 11088.51 179.30 5535.01
63 11087.89 179.31 5660.25
64 11087.27 179.32 5784.48
65 11086.65 179.33 5908.97
66 11086.04 179.34 6030.56
67 11085.42 179.35 6149.84
68 11084.80 179.36 6252.02
69 11084.18 179.37 6352.90
70 11083.57 179.38 6470.80
71 11082.95 179.39 6574.31
72 11082.33 179.40 6668.26
73 11081.71 179.41 6780.97
74 11081.10 179.42 6897.50
75 11080.48 179.43 7008.82
76 11079.86 179.44 7127.37
77 11079.25 179.45 7211.71
78 11078.63 179.46 7317.96
79 11078.01 179.47 7408.69
80 11077.40 179.48 7480.76
81 11076.78 179.49 7589.85
82 11076.16 179.50 7668.56
83 11075.55 179.51 7754.67
84 11074.93 179.52 7827.98
85 11074.31 179.53 7895.88
86 11073.70 179.54 7956.73
87 11073.08 179.55 8017.89
88 11072.46 179.56 8071.37
89 11071.85 179.57 8128.70
90 11071.23 179.58 8192.94
91 11070.62 179.59 8258.81
92 11070.00 179.60 8326.71
93 11069.38 179.61 8385.86
94 11068.77 179.62 8447.53
95 11068.15 179.63 8507.91
96 11067.54 179.64 8565.40
97 11066.92 179.65 8610.29
98 11066.31 179.66 8647.74
99 11065.69 179.67 8681.90
100 11065.08 179.68 8718.17
101 11064.46 179.69 8744.09
+10 -8
View File
@@ -239,7 +239,6 @@ def go_to_peak(
# Plot the fitted data if plot = True
if plot:
plot_fitted_data(data, fit_result, window_name=window_name, plot_widget=plot_widget)
@@ -248,7 +247,7 @@ def go_to_peak(
if gomax:
value = fit_result["x_max"]
print(f"Max position is at {value}")
move_scan_to_position(data["motor_device"], data["motor_name"], fit_result["x_max"], data)
move_to_scan_position(data["motor_device"], data["motor_name"], fit_result["x_max"], data)
else:
if gap:
if fit_result["centre"] < 4.5:
@@ -374,11 +373,13 @@ def find_feature(
# Set up live plot BEFORE starting the scan
# -------------------------------------------------
if plot:
if plot_widget is not None:
plot_live_data(plot_widget, motor_name, signal_name, title=f"{motor_name} scan")
else:
plot_live_data_bec(motor_name, signal_name, window_name=window_name)
plot_live_data(
motor_name,
signal_name,
window_name = window_name,
plot_widget = plot_widget,
title = f"{motor_name} scans"
)
# Perform scan
scan_result = scans.line_scan(
motor_device, start, stop, steps=steps, relative=relative, settling_time=settle
@@ -414,10 +415,11 @@ def find_feature(
print(f"Centre = {result['centre']:.4f}")
elif feature == "edge_offset":
print(f"Edge = {result['edge']:.4f}")
print(f"Offset is {offset}")
print(f"Centre = {result['centre']:.4f}")
# Move safely to centre
move_to_position(data["motor_device"], data["motor_name"], result["centre"], data)
move_to_scan_position(data["motor_device"], data["motor_name"], result["centre"], data)
if plot and plot_widget is not None:
# Replace the live subscription with static completed scan data
+32 -5
View File
@@ -2,9 +2,27 @@
from dataclasses import dataclass, field
from typing import Callable, List, Dict, Optional, Union
from bec_lib.logger import bec_logger
from bec_lib.device import Device
import time
def motor_resolver(bec_name):
"""Used to handle aerotech and smargon motors"""
candidates = [bec_name, bec_name.replace("_", ".")]
for path in candidates:
try:
obj = dev
for part in path.split("."):
obj = getattr(obj, part)
return obj
except Exception:
pass
raise ValueError(f"Cannot resolve motor for '{bec_name}'")
@dataclass
class PositionDevice:
@@ -34,11 +52,20 @@ class PositionDevice:
if isinstance(target, str):
name = target.lower()
try:
bec_logger.logger.info(f"attempting to find position {name} from bec device {self.bec_name} userParameter.")
bec_device: Device = dev[self.bec_name]
position = bec_device.user_parameter[target]
if name not in self.positions:
raise ValueError(f"Unknown position '{target}'")
bec_logger.logger.info(f"obtained position {position} - compare to cached value {self.positions.get(target)}")
return position
except Exception as e:
bec_logger.logger.debug(f"Failed to fetch user parameter for device {self.bec_name} and target {target} from bec, falling back to cached position {e}")
return self.positions[name]
if name not in self.positions:
raise ValueError(f"Unknown position '{target}'")
return self.positions[name]
if isinstance(target, (float, int)):
if not self.allow_arbitrary:
@@ -103,4 +130,4 @@ class PositionDevice:
pos = self._resolve_target(target)
return abs(self.actual - pos) <= self.tol
+3 -2
View File
@@ -178,7 +178,8 @@ class CamConversion:
class BPM_X_Calibration:
coeffs = (0.11079256, -0.02493623, -0.00799871, -0.00482772, 0.16569134, 0.44192518)
signal_limit = 0.90
centred_position = 0.441
# centred_position = 0.441
centred_position = -0.009 # updated on 31st Aug26
crosshair_signal = 0.000731
crosshair_bpm_position = 0.444
@@ -194,7 +195,7 @@ class BPM_Y_Calibration:
# @dataclass(frozen=True)
class Beamstop:
x_offset = -0.5
x_offset = -0.65
class CameraZoom(Enum):
+2 -5
View File
@@ -46,27 +46,24 @@ main() {
echo "Device: $DEVICE_NAME"
echo "Value : $SET_VALUE"
# --- Your logic here ---
# Example placeholder:
if [[ $DEVICE_NAME == "colli_in" ]]; then
echo "caput X10SA-ES-COL:POS-SET-SEQ.DO2 $SET_VALUE"
caput X10SA-ES-COL:POS-SET-SEQ.DO2 $SET_VALUE
fi
if [[ $DEVICE_NAME == "colli_out" ]]; then
echo "caput X10SA-ES-COL:POS-SET-SEQ.DO1 $SET_VALUE"
caput X10SA-ES-COL:POS-SET-SEQ.DO1 $SET_VALUE
fi
#
if [[ $DEVICE_NAME == "scinti_in" ]]; then
echo "caput X10SA-ES-SCL:POS-SET-SEQ.DO2 $SET_VALUE"
caput X10SA-ES-SCL:POS-SET-SEQ.DO2 $SET_VALUE
fi
if [[ $DEVICE_NAME == "diode_in" ]]; then
echo "caput X10SA-ES-SCL:POS-SET-SEQ.DO3 $SET_VALUE"
caput X10SA-ES-SCL:POS-SET-SEQ.DO3 $SET_VALUE
fi
if [[ $DEVICE_NAME == "scinti_out" || $DEVICE_NAME == "diode_out" ]]; then
echo "caput X10SA-ES-SCL:POS-SET-SEQ.DO1 $SET_VALUE"
caput X10SA-ES-SCL:POS-SET-SEQ.DO1 $SET_VALUE
fi
#
echo "Setting device '$DEVICE_NAME' to '$SET_VALUE'..."
+1 -4
View File
@@ -1,13 +1,10 @@
"""Test state changes"""
import random
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
from pxii_bec.scripts import beamline_context as bl
from pxii_bec.macros.beamline_planner import BeamlineState
def state_test(number_tries=20):
tested_states = []