X10sa production 20260617t100740 #24
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,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 = []
|
||||
|
||||
Reference in New Issue
Block a user