Skip to content
Merged
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
4 changes: 4 additions & 0 deletions src/mx_bluesky/common/parameters/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
PARAMETER_VERSION = Version.parse("5.3.0")
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the version need bumping with these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Strictly speaking, I guess since the changes are additions to the interface rather than changes to existing it would be a micro-version increment.

TBH I think the parameter versioning is not terribly important at the moment. We don't persist these parameter models anywhere and so far the only users are GDA, the as-yet non-existent hyperion-supervisor, and the external callbacks (via bluesky events). These all get corresponding changes whenever the parameter models are changed. So the chance of client and servers interacting with a different version of the parameter model is pretty minimal.

PARAMETER_VERSION doesn't appear to have changed for almost exactly a year, and I'm sure we've made other changes since then so I think it is kind of just stuck on 5.3.0 for the time being until there is a need to change it.



def get_param_version() -> SemanticVersion:
return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))


class RotationAxis(StrEnum):
OMEGA = "omega"
PHI = "phi"
Expand Down
49 changes: 28 additions & 21 deletions src/mx_bluesky/hyperion/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
compare_params,
update_params_from_agamemnon,
)
from mx_bluesky.hyperion.in_process_runner import InProcessRunner
from mx_bluesky.hyperion.parameters.cli import (
HyperionArgs,
HyperionMode,
Expand Down Expand Up @@ -163,27 +164,33 @@ def main():
args = parse_cli_args()
initialise_globals(args)
hyperion_port = HyperionConstants.HYPERION_PORT
context = setup_context(dev_mode=args.dev_mode)

if args.mode == HyperionMode.GDA:
runner = GDARunner(context=context)
app = create_app(runner)
flask_thread = threading.Thread(
target=lambda: app.run(
host="0.0.0.0", port=hyperion_port, debug=True, use_reloader=False
),
daemon=True,
)
flask_thread.start()
LOGGER.info(
f"Hyperion now listening on {hyperion_port} ({'IN DEV' if args.dev_mode else ''})"
)
runner.wait_on_queue()
else:
plan_runner = PlanRunner(context, args.dev_mode)
create_server_for_udc(plan_runner)
_register_sigterm_handler(plan_runner)
run_forever(plan_runner)

match args.mode:
case HyperionMode.GDA:
context = setup_context(dev_mode=args.dev_mode)
runner = GDARunner(context=context)
app = create_app(runner)
flask_thread = threading.Thread(
target=lambda: app.run(
host="0.0.0.0", port=hyperion_port, debug=True, use_reloader=False
),
daemon=True,
)
flask_thread.start()
LOGGER.info(
f"Hyperion now listening on {hyperion_port} ({'IN DEV' if args.dev_mode else ''})"
)
runner.wait_on_queue()
case HyperionMode.UDC:
context = setup_context(dev_mode=args.dev_mode)
plan_runner = InProcessRunner(context, args.dev_mode)
create_server_for_udc(plan_runner)
_register_sigterm_handler(plan_runner)
run_forever(plan_runner)
case HyperionMode.SUPERVISOR:
raise RuntimeError(
"Supervisor mode not supported yet see https://github.com/DiamondLightSource/mx-bluesky/issues/1365"
)


def _register_sigterm_handler(runner: PlanRunner):
Expand Down
88 changes: 24 additions & 64 deletions src/mx_bluesky/hyperion/baton_handler.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,30 @@
from collections.abc import Sequence
from functools import partial
from typing import Any

from blueapi.core.context import BlueskyContext
from bluesky import plan_stubs as bps
from bluesky import preprocessors as bpp
from bluesky.utils import MsgGenerator, RunEngineInterrupted
from dodal.common.beamlines.commissioning_mode import set_commissioning_signal
from dodal.devices.aperturescatterguard import ApertureScatterguard
from dodal.devices.baton import Baton
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
from dodal.devices.motors import XYZStage
from dodal.devices.robot import BartRobot
from dodal.devices.smargon import Smargon

from mx_bluesky.common.device_setup_plans.robot_load_unload import robot_unload
from mx_bluesky.common.external_interaction.alerting import (
AlertService,
get_alerting_service,
)
from mx_bluesky.common.parameters.components import MxBlueskyParameters
from mx_bluesky.common.parameters.components import (
MxBlueskyParameters,
get_param_version,
)
from mx_bluesky.common.utils.context import (
device_composite_from_context,
find_device_in_context,
)
from mx_bluesky.common.utils.exceptions import BeamlineCheckFailureError
from mx_bluesky.common.utils.log import LOGGER
from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
create_devices,
load_centre_collect_full,
)
from mx_bluesky.hyperion.experiment_plans.udc_default_state import (
UDCDefaultDevices,
move_to_udc_default_state,
)
from mx_bluesky.hyperion.external_interaction.agamemnon import (
create_parameters_from_agamemnon,
)
from mx_bluesky.hyperion.external_interaction.alerting.constants import Subjects
from mx_bluesky.hyperion.parameters.components import Wait
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
from mx_bluesky.hyperion.parameters.components import UDCCleanup, UDCDefaultState
from mx_bluesky.hyperion.plan_runner import PlanError, PlanRunner
from mx_bluesky.hyperion.utils.context import (
clear_all_device_caches,
Expand Down Expand Up @@ -102,7 +87,14 @@ def collect() -> MsgGenerator:
"""
_raise_udc_start_alert(get_alerting_service())
yield from bpp.contingency_wrapper(
_move_to_udc_default_state(context),
runner.decode_and_execute(
None,
[
UDCDefaultState.model_validate(
{"parameter_model_version": get_param_version()}
)
],
),
except_plan=trap_default_state_exception,
auto_raise=False,
)
Expand All @@ -115,7 +107,14 @@ def collect() -> MsgGenerator:
baton, runner, current_visit
)
if current_visit:
yield from _clean_up_udc(runner.context, current_visit)
yield from runner.decode_and_execute(
current_visit,
[
UDCCleanup.model_validate(
{"parameter_model_version": get_param_version()}
)
],
)

def release_baton() -> MsgGenerator:
# If hyperion has given up the baton itself we need to also release requested
Expand Down Expand Up @@ -177,23 +176,9 @@ def _fetch_and_process_agamemnon_instruction(
) -> MsgGenerator[str | None]:
parameter_list: Sequence[MxBlueskyParameters] = create_parameters_from_agamemnon()
if parameter_list:
for parameters in parameter_list:
LOGGER.info(
f"Executing plan with parameters: {parameters.model_dump_json(indent=2)}"
)
match parameters:
case LoadCentreCollect():
current_visit = parameters.visit
devices: Any = create_devices(runner.context)
yield from runner.execute_plan(
partial(load_centre_collect_full, devices, parameters)
)
case Wait():
yield from runner.execute_plan(partial(_runner_sleep, parameters))
case _:
raise AssertionError(
f"Unsupported instruction decoded from agamemnon {type(parameters)}"
)
current_visit = yield from runner.decode_and_execute(
current_visit, parameter_list
)
else:
_raise_udc_completed_alert(get_alerting_service())
# Release the baton for orderly exit from the instruction loop
Expand Down Expand Up @@ -224,20 +209,11 @@ def _raise_udc_completed_alert(alert_service: AlertService):
)


def _runner_sleep(parameters: Wait) -> MsgGenerator:
yield from bps.sleep(parameters.duration_s)


def _is_requesting_baton(baton: Baton) -> MsgGenerator:
requested_user = yield from bps.rd(baton.requested_user)
return requested_user == HYPERION_USER


def _move_to_udc_default_state(context: BlueskyContext):
udc_default_devices = device_composite_from_context(context, UDCDefaultDevices)
yield from move_to_udc_default_state(udc_default_devices)


def _get_baton(context: BlueskyContext) -> Baton:
return find_device_in_context(context, "baton", Baton)

Expand All @@ -255,19 +231,3 @@ def _unrequest_baton(baton: Baton) -> MsgGenerator[str]:
yield from bps.abs_set(baton.requested_user, NO_USER)
return NO_USER
return requested_user


def _clean_up_udc(context: BlueskyContext, visit: str) -> MsgGenerator:
cleanup_group = "cleanup"
robot = find_device_in_context(context, "robot", BartRobot)
smargon = find_device_in_context(context, "smargon", Smargon)
aperture_scatterguard = find_device_in_context(
context, "aperture_scatterguard", ApertureScatterguard
)
lower_gonio = find_device_in_context(context, "lower_gonio", XYZStage)
detector_motion = find_device_in_context(context, "detector_motion", DetectorMotion)
yield from bps.abs_set(
detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
)
yield from robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
yield from bps.wait(cleanup_group)
2 changes: 1 addition & 1 deletion src/mx_bluesky/hyperion/blueapi_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ api:
logging:
graylog:
url: "tcp://graylog-log-target.diamond.ac.uk:12232"
enabled: true
enabled: true
19 changes: 19 additions & 0 deletions src/mx_bluesky/hyperion/blueapi_plans/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
process.
"""

from bluesky import plan_stubs as bps
from bluesky.utils import MsgGenerator
from dodal.common import inject
from dodal.devices.aperturescatterguard import ApertureScatterguard
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
from dodal.devices.motors import XYZStage
from dodal.devices.robot import BartRobot
from dodal.devices.smargon import Smargon
Expand All @@ -33,6 +35,7 @@
"LoadCentreCollectComposite",
"LoadCentreCollect",
"UDCDefaultDevices",
"clean_up_udc",
"load_centre_collect",
"move_to_udc_default_state",
"robot_unload",
Expand Down Expand Up @@ -68,6 +71,22 @@ def robot_unload(
yield from _robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)


def clean_up_udc(
visit: str,
cleanup_group="cleanup",
robot: BartRobot = inject("robot"),
smargon: Smargon = inject("smargon"),
aperture_scatterguard: ApertureScatterguard = inject("aperture_scatterguard"),
lower_gonio: XYZStage = inject("lower_gonio"),
detector_motion: DetectorMotion = inject("detector_motion"),
):
yield from bps.abs_set(
detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
)
yield from _robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
yield from bps.wait(cleanup_group)


def move_to_udc_default_state(
composite: UDCDefaultDevices = inject(),
) -> MsgGenerator:
Expand Down
11 changes: 3 additions & 8 deletions src/mx_bluesky/hyperion/external_interaction/agamemnon.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@
from deepdiff.diff import DeepDiff
from dodal.utils import get_beamline_name
from jsonschema import ValidationError
from pydantic_extra_types.semantic_version import SemanticVersion

from mx_bluesky.common.parameters.components import (
PARAMETER_VERSION,
MxBlueskyParameters,
WithVisit,
get_param_version,
)
from mx_bluesky.common.parameters.constants import (
GridscanParamConstants,
Expand Down Expand Up @@ -88,7 +87,7 @@ def create_parameters_from_agamemnon() -> Sequence[MxBlueskyParameters]:
Wait.model_validate(
{
"duration_s": data,
"parameter_model_version": _get_param_version(),
"parameter_model_version": get_param_version(),
}
)
]
Expand Down Expand Up @@ -228,10 +227,6 @@ def _get_withenergy_parameters_from_agamemnon(parameters: dict) -> dict[str, Any
return {"demand_energy_ev": None}


def _get_param_version() -> SemanticVersion:
return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))


def _populate_parameters_from_agamemnon(
agamemnon_params,
) -> Sequence[LoadCentreCollect]:
Expand All @@ -250,7 +245,7 @@ def _populate_parameters_from_agamemnon(
return [
LoadCentreCollect.model_validate(
{
"parameter_model_version": _get_param_version(),
"parameter_model_version": get_param_version(),
"visit": visit,
"detector_distance_mm": detector_distance,
"sample_id": agamemnon_params["sample"]["id"],
Expand Down
Loading
Loading