diff --git a/pxii_bec/bec_ipython_client/startup/pre_startup.py b/pxii_bec/bec_ipython_client/startup/pre_startup.py index b835d3a..ea42d71 100644 --- a/pxii_bec/bec_ipython_client/startup/pre_startup.py +++ b/pxii_bec/bec_ipython_client/startup/pre_startup.py @@ -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): """ diff --git a/pxii_bec/device_configs/pxii-beamline-states.yaml b/pxii_bec/device_configs/pxii-beamline-states.yaml index 1f2e19b..136b0ee 100644 --- a/pxii_bec/device_configs/pxii-beamline-states.yaml +++ b/pxii_bec/device_configs/pxii-beamline-states.yaml @@ -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 diff --git a/pxii_bec/device_configs/pxii-devices.yaml b/pxii_bec/device_configs/pxii-devices.yaml index 8a7a824..7fa50c9 100644 --- a/pxii_bec/device_configs/pxii-devices.yaml +++ b/pxii_bec/device_configs/pxii-devices.yaml @@ -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 diff --git a/pxii_bec/macros/APscripts.py b/pxii_bec/macros/APscripts.py index 770b1c1..c3f35aa 100644 --- a/pxii_bec/macros/APscripts.py +++ b/pxii_bec/macros/APscripts.py @@ -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' diff --git a/pxii_bec/macros/beamline_planner.py b/pxii_bec/macros/beamline_planner.py index b62264a..96b22b6 100755 --- a/pxii_bec/macros/beamline_planner.py +++ b/pxii_bec/macros/beamline_planner.py @@ -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 diff --git a/pxii_bec/macros/build_devices.py b/pxii_bec/macros/build_devices.py index bba4f2a..434e955 100755 --- a/pxii_bec/macros/build_devices.py +++ b/pxii_bec/macros/build_devices.py @@ -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) diff --git a/pxii_bec/macros/daily.py b/pxii_bec/macros/daily.py new file mode 100644 index 0000000..2826182 --- /dev/null +++ b/pxii_bec/macros/daily.py @@ -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) + + + diff --git a/pxii_bec/macros/dependencies.py b/pxii_bec/macros/dependencies.py index 2ff2fd2..6e9e522 100755 --- a/pxii_bec/macros/dependencies.py +++ b/pxii_bec/macros/dependencies.py @@ -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")], diff --git a/pxii_bec/macros/katscripts.py b/pxii_bec/macros/katscripts.py index 513080a..ff32868 100755 --- a/pxii_bec/macros/katscripts.py +++ b/pxii_bec/macros/katscripts.py @@ -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() diff --git a/pxii_bec/macros/luts/20260828_ge_edge.csv b/pxii_bec/macros/luts/20260828_ge_edge.csv new file mode 100644 index 0000000..a77dc49 --- /dev/null +++ b/pxii_bec/macros/luts/20260828_ge_edge.csv @@ -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 diff --git a/pxii_bec/macros/mxcomm_scan.py b/pxii_bec/macros/mxcomm_scan.py index 92c49b3..ff38f04 100755 --- a/pxii_bec/macros/mxcomm_scan.py +++ b/pxii_bec/macros/mxcomm_scan.py @@ -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 diff --git a/pxii_bec/macros/position_device.py b/pxii_bec/macros/position_device.py index a7664de..eecdbac 100755 --- a/pxii_bec/macros/position_device.py +++ b/pxii_bec/macros/position_device.py @@ -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 - \ No newline at end of file + diff --git a/pxii_bec/macros/pxii_parameters.py b/pxii_bec/macros/pxii_parameters.py index 44b6b92..a6a4e82 100755 --- a/pxii_bec/macros/pxii_parameters.py +++ b/pxii_bec/macros/pxii_parameters.py @@ -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): diff --git a/pxii_bec/macros/set_kbox.sh b/pxii_bec/macros/set_kbox.sh index 83ae5c4..c071ac1 100755 --- a/pxii_bec/macros/set_kbox.sh +++ b/pxii_bec/macros/set_kbox.sh @@ -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'..." diff --git a/pxii_bec/macros/test_state_transitions.py b/pxii_bec/macros/test_state_transitions.py index 64b1944..dc11a12 100755 --- a/pxii_bec/macros/test_state_transitions.py +++ b/pxii_bec/macros/test_state_transitions.py @@ -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 = []