-
Notifications
You must be signed in to change notification settings - Fork 5
Initial VMXm FGS plan #942
base: main
Are you sure you want to change the base?
Changes from all commits
b3f08e2
325d810
627e3c7
2b750e0
2812e00
a27463b
f3d0bd8
35ee736
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| from git import Repo | ||
| from packaging.version import Version | ||
|
|
||
| recognised_beamlines = ["dev", "i03", "i04"] | ||
| recognised_beamlines = ["dev", "i03", "i02-1", "i04"] | ||
|
|
||
|
|
||
| class repo: | ||
|
|
@@ -32,7 +32,7 @@ def deploy(self, url): | |
| deploy_repo.git.checkout(self.latest_version_str) | ||
|
|
||
| print("Setting permissions") | ||
| groups_to_give_permission = ["i03_staff", "gda2", "dls_dasc"] | ||
| groups_to_give_permission = ["i02-1_staff", "gda2", "dls_dasc"] | ||
| setfacl_params = ",".join( | ||
| [f"g:{group}:rwx" for group in groups_to_give_permission] | ||
| ) | ||
|
|
@@ -67,6 +67,10 @@ def get_hyperion_release_dir_from_args(repo: repo) -> str: | |
| if args.beamline == "dev": | ||
| print("Running as dev") | ||
| return "/tmp/hyperion_release_test/bluesky" | ||
| elif args.beamline == "i03": | ||
| return f"/dls_sw/{args.beamline}/software/bluesky" | ||
| elif args.beamline == "i02-1": | ||
| return f"/dls_sw/{args.beamline}/software/bluesky" | ||
|
Comment on lines
+70
to
+73
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this, it doesn't do anything, it's obsolete. |
||
| else: | ||
| return f"/dls_sw/{args.beamline}/software/bluesky" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,7 +92,7 @@ if [[ $START == 1 ]]; then | |
| exit 1 | ||
| fi | ||
|
|
||
| ISPYB_CONFIG_PATH="/dls_sw/dasc/mariadb/credentials/ispyb-artemis-${BEAMLINE}.cfg" | ||
| ISPYB_CONFIG_PATH="/dls_sw/dasc/mariadb/credentials/ispyb-artemis-i03.cfg" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need input from ispyb team to fix? |
||
| export ISPYB_CONFIG_PATH | ||
|
|
||
| fi | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,13 @@ | |
|
|
||
| from dodal.devices.fast_grid_scan import GridScanParams | ||
|
|
||
| import hyperion.experiment_plans.flyscan_xray_centre_plan as flyscan_xray_centre_plan | ||
| import hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan | ||
| from hyperion.experiment_plans import ( | ||
| flyscan_xray_centre_plan, | ||
| grid_detect_then_xray_centre_plan, | ||
| pin_centre_then_xray_centre_plan, | ||
| stepped_grid_scan_plan, | ||
| vmxm_flyscan_xray_centre_plan, | ||
| ) | ||
| from hyperion.external_interaction.callbacks.abstract_plan_callback_collection import ( | ||
| NullPlanCallbackCollection, | ||
|
|
@@ -18,6 +19,7 @@ | |
| RotationCallbackCollection, | ||
| ) | ||
| from hyperion.external_interaction.callbacks.xray_centre.callback_collection import ( | ||
| VmxmFastGridScanCallbackCollection, | ||
| XrayCentreCallbackCollection, | ||
| ) | ||
| from hyperion.parameters.plan_specific.grid_scan_with_edge_detect_params import ( | ||
|
|
@@ -51,36 +53,47 @@ def do_nothing(): | |
|
|
||
| EXPERIMENT_TYPES = Union[GridScanParams, RotationScanParams, SteppedGridScanParams] | ||
| PLAN_REGISTRY: dict[str, dict[str, Callable]] = { | ||
| "flyscan_xray_centre": { | ||
| "setup": flyscan_xray_centre_plan.create_devices, | ||
| # FIXME - HACK - plans commented out here because VMXm complains about no | ||
| # aperture_scatterguard which is needed for some plans. | ||
| # Need a way to either mark plans as being relevant only on some beamlines, or | ||
| # generally allow hyperion to *start* even if some plans reference nonexistent | ||
| # devices (and then fail at runtime if that plan is actually used). | ||
|
Comment on lines
+56
to
+60
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per code comment - definitely needs fixing before merge. |
||
| # "flyscan_xray_centre": { | ||
| # "setup": flyscan_xray_centre_plan.create_devices, | ||
| # "internal_param_type": GridscanInternalParameters, | ||
| # "experiment_param_type": GridScanParams, | ||
| # "callback_collection_type": XrayCentreCallbackCollection, | ||
| # }, | ||
| "vmxm_flyscan_xray_centre": { | ||
| "setup": vmxm_flyscan_xray_centre_plan.create_devices, | ||
| "internal_param_type": GridscanInternalParameters, | ||
| "experiment_param_type": GridScanParams, | ||
| "callback_collection_type": XrayCentreCallbackCollection, | ||
| }, | ||
| "grid_detect_then_xray_centre": { | ||
| "setup": grid_detect_then_xray_centre_plan.create_devices, | ||
| "internal_param_type": GridScanWithEdgeDetectInternalParameters, | ||
| "experiment_param_type": GridScanWithEdgeDetectParams, | ||
| "callback_collection_type": NullPlanCallbackCollection, | ||
| }, | ||
| "rotation_scan": { | ||
| "setup": rotation_scan_plan.create_devices, | ||
| "internal_param_type": RotationInternalParameters, | ||
| "experiment_param_type": RotationScanParams, | ||
| "callback_collection_type": RotationCallbackCollection, | ||
| }, | ||
| "pin_tip_centre_then_xray_centre": { | ||
| "setup": pin_centre_then_xray_centre_plan.create_devices, | ||
| "internal_param_type": PinCentreThenXrayCentreInternalParameters, | ||
| "experiment_param_type": PinCentreThenXrayCentreParams, | ||
| "callback_collection_type": NullPlanCallbackCollection, | ||
| }, | ||
| "stepped_grid_scan": { | ||
| "setup": stepped_grid_scan_plan.create_devices, | ||
| "internal_param_type": SteppedGridScanInternalParameters, | ||
| "experiment_param_type": SteppedGridScanParams, | ||
| "callback_collection_type": NullPlanCallbackCollection, | ||
| "callback_collection_type": VmxmFastGridScanCallbackCollection, | ||
| }, | ||
| # "grid_detect_then_xray_centre": { | ||
| # "setup": grid_detect_then_xray_centre_plan.create_devices, | ||
| # "internal_param_type": GridScanWithEdgeDetectInternalParameters, | ||
| # "experiment_param_type": GridScanWithEdgeDetectParams, | ||
| # "callback_collection_type": NullPlanCallbackCollection, | ||
| # }, | ||
| # "rotation_scan": { | ||
| # "setup": rotation_scan_plan.create_devices, | ||
| # "internal_param_type": RotationInternalParameters, | ||
| # "experiment_param_type": RotationScanParams, | ||
| # "callback_collection_type": RotationCallbackCollection, | ||
| # }, | ||
| # "pin_tip_centre_then_xray_centre": { | ||
| # "setup": pin_centre_then_xray_centre_plan.create_devices, | ||
| # "internal_param_type": PinCentreThenXrayCentreInternalParameters, | ||
| # "experiment_param_type": PinCentreThenXrayCentreParams, | ||
| # "callback_collection_type": NullPlanCallbackCollection, | ||
| # }, | ||
| # "stepped_grid_scan": { | ||
| # "setup": stepped_grid_scan_plan.create_devices, | ||
| # "internal_param_type": SteppedGridScanInternalParameters, | ||
| # "experiment_param_type": SteppedGridScanParams, | ||
| # "callback_collection_type": NullPlanCallbackCollection, | ||
| # }, | ||
| } | ||
| EXPERIMENT_NAMES = list(PLAN_REGISTRY.keys()) | ||
| EXPERIMENT_TYPE_LIST = [p["experiment_param_type"] for p in PLAN_REGISTRY.values()] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| from __future__ import annotations | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this whole file: there's obviously a lot of duplication, but also a lot of instrument-specific functionality. Probably spin out an issue to come up with the right set of abstractions. Also probably shouldn't be called |
||
|
|
||
| import argparse | ||
| import dataclasses | ||
| from typing import TYPE_CHECKING, Any | ||
|
|
||
| import bluesky.plan_stubs as bps | ||
| import bluesky.preprocessors as bpp | ||
| from blueapi.core import BlueskyContext, MsgGenerator | ||
| from bluesky.run_engine import RunEngine | ||
| from bluesky.utils import ProgressBarManager | ||
| from dodal.devices.backlight import VmxmBacklight | ||
| from dodal.devices.eiger import EigerDetector | ||
| from dodal.devices.fast_grid_scan_2d import FastGridScan2D | ||
| from dodal.devices.fast_grid_scan_2d import ( | ||
| set_fast_grid_scan_params as set_flyscan_params, | ||
| ) | ||
| from dodal.devices.synchrotron import Synchrotron | ||
| from dodal.devices.vmxm.vmxm_attenuator import VmxmAttenuator | ||
| from dodal.devices.vmxm.vmxm_sample_motors import VmxmSampleMotors | ||
| from dodal.devices.zebra import ( | ||
| Zebra, | ||
| ) | ||
|
|
||
| import hyperion.log | ||
| from hyperion.exceptions import WarningException | ||
| from hyperion.external_interaction.callbacks.xray_centre.callback_collection import ( | ||
| VmxmFastGridScanCallbackCollection, | ||
| ) | ||
| from hyperion.parameters import external_parameters | ||
| from hyperion.parameters.constants import ISPYB_HARDWARE_READ_PLAN, SIM_BEAMLINE | ||
| from hyperion.tracing import TRACER | ||
| from hyperion.utils.context import device_composite_from_context, setup_context | ||
|
|
||
| if TYPE_CHECKING: | ||
| from hyperion.parameters.plan_specific.gridscan_internal_params import ( | ||
| GridscanInternalParameters, | ||
| ) | ||
|
|
||
|
|
||
| @dataclasses.dataclass | ||
| class VmxmFlyScanXRayCentreComposite: | ||
| """All devices which are directly or indirectly required by this plan""" | ||
|
|
||
| attenuator: VmxmAttenuator | ||
| backlight: VmxmBacklight | ||
| eiger: EigerDetector | ||
| fast_grid_scan: FastGridScan2D | ||
| sample_motors: VmxmSampleMotors | ||
| synchrotron: Synchrotron | ||
| zebra: Zebra | ||
|
|
||
|
|
||
| def create_devices(context: BlueskyContext) -> VmxmFlyScanXRayCentreComposite: | ||
| """Creates the devices required for the plan and connect to them""" | ||
| return device_composite_from_context(context, VmxmFlyScanXRayCentreComposite) | ||
|
|
||
|
|
||
| def wait_for_gridscan_valid(fgs_motors: FastGridScan2D, timeout=0.5): | ||
| hyperion.log.LOGGER.info("Waiting for valid fgs_params") | ||
| SLEEP_PER_CHECK = 0.1 | ||
| times_to_check = int(timeout / SLEEP_PER_CHECK) | ||
| for _ in range(times_to_check): | ||
| scan_invalid = yield from bps.rd(fgs_motors.scan_invalid) | ||
| pos_counter = yield from bps.rd(fgs_motors.position_counter) | ||
| hyperion.log.LOGGER.debug( | ||
| f"Scan invalid: {scan_invalid} and position counter: {pos_counter}" | ||
| ) | ||
| if not scan_invalid and pos_counter == 0: | ||
| hyperion.log.LOGGER.info("Gridscan scan valid and position counter reset") | ||
| return | ||
| yield from bps.sleep(SLEEP_PER_CHECK) | ||
| raise WarningException("Scan invalid") | ||
|
|
||
|
|
||
| def tidy_up_plans(fgs_composite: VmxmFlyScanXRayCentreComposite): | ||
| hyperion.log.LOGGER.info("Tidying up Zebra") | ||
| yield from tidyup_vmxm_zebra_after_gridscan(fgs_composite.zebra) | ||
|
|
||
|
|
||
| @bpp.set_run_key_decorator("run_gridscan") | ||
| @bpp.run_decorator(md={"subplan_name": "run_gridscan"}) | ||
| def run_gridscan( | ||
| fgs_composite: VmxmFlyScanXRayCentreComposite, | ||
| parameters: GridscanInternalParameters, | ||
| md={ | ||
| "plan_name": "run_gridscan", | ||
| }, | ||
| ): | ||
| fgs_motors = fgs_composite.fast_grid_scan | ||
|
|
||
| yield from bps.mv( | ||
| fgs_composite.attenuator, | ||
| parameters.hyperion_params.ispyb_params.transmission_fraction, | ||
| ) | ||
|
|
||
| yield from bps.create(name=ISPYB_HARDWARE_READ_PLAN) | ||
| yield from bps.read(fgs_composite.synchrotron.machine_status.synchrotron_mode) | ||
| yield from bps.save() | ||
|
|
||
| # TODO: Check topup gate | ||
| yield from set_flyscan_params(fgs_motors, parameters.experiment_params) | ||
| yield from bps.mv(fgs_composite.sample_motors.omega, parameters.get_omega_start(1)) | ||
| yield from wait_for_gridscan_valid(fgs_motors) | ||
|
|
||
| @bpp.set_run_key_decorator("do_fgs") | ||
| @bpp.run_decorator(md={"subplan_name": "do_fgs"}) | ||
| @bpp.contingency_decorator( | ||
| except_plan=lambda e: (yield from bps.stop(fgs_composite.eiger)), | ||
| else_plan=lambda: (yield from bps.unstage(fgs_composite.eiger)), | ||
| ) | ||
| def do_fgs(): | ||
| yield from bps.wait() # Wait for all moves to complete | ||
| hyperion.log.LOGGER.info("Kicking off") | ||
| yield from bps.kickoff(fgs_motors) | ||
|
|
||
| yield from bps.complete(fgs_motors, wait=True) | ||
|
|
||
| hyperion.log.LOGGER.info("Waiting for arming to finish") | ||
| yield from bps.wait("ready_for_data_collection") | ||
| yield from bps.stage(fgs_composite.eiger) | ||
|
|
||
| with TRACER.start_span("do_fgs"): | ||
| yield from do_fgs() | ||
|
|
||
|
|
||
| def setup_vmxm_zebra_for_gridscan( | ||
| zebra: Zebra, group="setup_zebra_for_gridscan", wait=False | ||
| ): | ||
| # note: VMXm-specific | ||
| vmxm_zebra_input = 4 | ||
| vmxm_zebra_output = 1 | ||
| yield from bps.abs_set( | ||
| zebra.output.out_pvs[vmxm_zebra_input], vmxm_zebra_output, group=group | ||
| ) | ||
|
|
||
| if wait: | ||
| yield from bps.wait(group) | ||
|
|
||
|
|
||
| def tidyup_vmxm_zebra_after_gridscan( | ||
| zebra: Zebra, group="tidyup_vmxm_zebra_after_gridscan", wait=False | ||
| ): # note: VMXm-specific | ||
| vmxm_zebra_input = 4 | ||
| vmxm_zebra_output = 36 | ||
| yield from bps.abs_set( | ||
| zebra.output.out_pvs[vmxm_zebra_input], vmxm_zebra_output, group=group | ||
| ) | ||
|
|
||
| if wait: | ||
| yield from bps.wait(group) | ||
|
|
||
|
|
||
| @bpp.set_run_key_decorator("run_gridscan_and_move") | ||
| @bpp.run_decorator(md={"subplan_name": "run_gridscan_and_move"}) | ||
| def run_gridscan_and_move( | ||
| fgs_composite: VmxmFlyScanXRayCentreComposite, | ||
| parameters: GridscanInternalParameters, | ||
| subscriptions: VmxmFastGridScanCallbackCollection, | ||
| ): | ||
| yield from setup_vmxm_zebra_for_gridscan(fgs_composite.zebra) | ||
|
|
||
| hyperion.log.LOGGER.info("Starting grid scan") | ||
|
|
||
| yield from run_gridscan(fgs_composite, parameters) | ||
|
|
||
|
|
||
| def vmxm_flyscan_xray_centre( | ||
| composite: VmxmFlyScanXRayCentreComposite, | ||
| parameters: Any, | ||
| ) -> MsgGenerator: | ||
| """Create the plan to run the grid scan based on provided parameters. | ||
|
|
||
| The ispyb handler should be added to the whole gridscan as we want to capture errors | ||
| at any point in it. | ||
|
|
||
| Args: | ||
| parameters (FGSInternalParameters): The parameters to run the scan. | ||
|
|
||
| Returns: | ||
| Generator: The plan for the gridscan | ||
| """ | ||
| composite.eiger.set_detector_parameters(parameters.hyperion_params.detector_params) | ||
|
|
||
| subscriptions = VmxmFastGridScanCallbackCollection.from_params(parameters) | ||
|
|
||
| @bpp.subs_decorator( # subscribe the RE to nexus, ispyb callbacks | ||
| list(subscriptions) # must be the outermost decorator to receive the metadata | ||
| ) | ||
| @bpp.set_run_key_decorator("run_gridscan_move_and_tidy") | ||
| @bpp.run_decorator( # attach experiment metadata to the start document | ||
| md={ | ||
| "subplan_name": "run_gridscan_move_and_tidy", | ||
| "hyperion_internal_parameters": parameters.json(), | ||
| } | ||
| ) | ||
| @bpp.finalize_decorator(lambda: tidy_up_plans(composite)) | ||
| def run_gridscan_and_move_and_tidy(fgs_composite, params, comms): | ||
| yield from run_gridscan_and_move(fgs_composite, params, comms) | ||
|
|
||
| return run_gridscan_and_move_and_tidy(composite, parameters, subscriptions) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument( | ||
| "--beamline", | ||
| help="The beamline prefix this is being run on", | ||
| default=SIM_BEAMLINE, | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| RE = RunEngine({}) | ||
| RE.waiting_hook = ProgressBarManager() | ||
| from hyperion.parameters.plan_specific.gridscan_internal_params import ( | ||
| GridscanInternalParameters, | ||
| ) | ||
|
|
||
| parameters = GridscanInternalParameters(**external_parameters.from_file()) | ||
| subscriptions = VmxmFastGridScanCallbackCollection.from_params(parameters) | ||
|
|
||
| context = setup_context(wait_for_connection=True) | ||
| composite = create_devices(context) | ||
|
|
||
| RE(vmxm_flyscan_xray_centre(composite, parameters)) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix this before merge. But don't just add vmxm/i03 to the list as that would give i03 permissions on vmxm and vice-versa.
Probably
f"{beamline}_staff"would work, check that group exists for all supported beamlines.