Skip to content
This repository was archived by the owner on Sep 2, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions deploy/deploy_hyperion.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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"]
Copy link
Contributor Author

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.

setfacl_params = ",".join(
[f"g:{group}:rwx" for group in groups_to_give_permission]
)
Expand Down Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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"

Expand Down
2 changes: 1 addition & 1 deletion run_hyperion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need input from ispyb team to fix?

export ISPYB_CONFIG_PATH

fi
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ install_requires =
xarray
doct
databroker
dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@b58451b5902db75b9d7cf1c40740bdeac3e53348
dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@39084723b73adec1df9199b9fe601d68242eeb3d
pydantic<2.0 # See https://github.com/DiamondLightSource/hyperion/issues/774
scipy

Expand Down
4 changes: 4 additions & 0 deletions src/hyperion/experiment_plans/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
pin_tip_centre_then_xray_centre,
)
from hyperion.experiment_plans.rotation_scan_plan import rotation_scan
from hyperion.experiment_plans.vmxm_flyscan_xray_centre_plan import (
vmxm_flyscan_xray_centre,
)

__all__ = [
"flyscan_xray_centre",
"grid_detect_then_xray_centre",
"rotation_scan",
"pin_tip_centre_then_xray_centre",
"vmxm_flyscan_xray_centre",
]
69 changes: 41 additions & 28 deletions src/hyperion/experiment_plans/experiment_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 (
Expand Down Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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()]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from bluesky.run_engine import RunEngine
from dodal.beamlines import i03
from dodal.devices.backlight import Backlight
from dodal.devices.fast_grid_scan import GridAxis
from dodal.devices.fast_grid_scan_common import GridAxis
from dodal.devices.oav.oav_detector import OAV
from dodal.devices.oav.oav_parameters import OAVParameters
from dodal.devices.smargon import Smargon
Expand Down
225 changes: 225 additions & 0 deletions src/hyperion/experiment_plans/vmxm_flyscan_xray_centre_plan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
from __future__ import annotations
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 _xray_centre_plan on VMXm, as it doesn't actually do xray centring at all - it does real data collections! So just vmxm_fast_grid_scan maybe. Will also need updating in GDA if changed.


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))
Loading