diff --git a/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py b/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py index 82d79af25..c0a0d5d7d 100644 --- a/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +++ b/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py @@ -2,7 +2,7 @@ from collections.abc import Callable, Sequence from time import time -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, TypeVar import numpy as np from bluesky import preprocessors as bpp @@ -64,6 +64,9 @@ def ispyb_activation_wrapper(plan_generator: MsgGenerator, parameters): ) +T = TypeVar("T", bound="GridCommon") + + class GridscanISPyBCallback(BaseISPyBCallback): """Callback class to handle the deposition of experiment parameters into the ISPyB database. Listens for 'event' and 'descriptor' documents. Creates the ISpyB entry on @@ -81,12 +84,14 @@ class GridscanISPyBCallback(BaseISPyBCallback): def __init__( self, + param_type: type[T], *, emit: Callable[..., Any] | None = None, ) -> None: super().__init__(emit=emit) self.ispyb: StoreInIspyb self.ispyb_ids: IspybIds = IspybIds() + self.param_type = param_type self._start_of_fgs_uid: str | None = None self._processing_start_time: float | None = None @@ -101,7 +106,7 @@ def activity_gated_start(self, doc: RunStart): ) mx_bluesky_parameters = doc.get("mx_bluesky_parameters") assert isinstance(mx_bluesky_parameters, str) - self.params = GridCommon.model_validate_json(mx_bluesky_parameters) + self.params = self.param_type.model_validate_json(mx_bluesky_parameters) self.ispyb = StoreInIspyb(self.ispyb_config) data_collection_group_info = populate_data_collection_group(self.params) diff --git a/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py b/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py index 117f83094..9d03db56e 100644 --- a/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py +++ b/src/mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import ( PlanReactiveCallback, @@ -11,12 +11,16 @@ ) from mx_bluesky.common.external_interaction.nexus.write_nexus import NexusWriter from mx_bluesky.common.parameters.constants import DocDescriptorNames, PlanNameConstants -from mx_bluesky.common.parameters.gridscan import ThreeDGridScan +from mx_bluesky.common.parameters.gridscan import ( + SpecifiedThreeDGridScan, +) from mx_bluesky.common.utils.log import NEXUS_LOGGER if TYPE_CHECKING: from event_model.documents import Event, EventDescriptor, RunStart +T = TypeVar("T", bound="SpecifiedThreeDGridScan") + class GridscanNexusFileCallback(PlanReactiveCallback): """Callback class to handle the creation of Nexus files based on experiment \ @@ -35,8 +39,9 @@ class GridscanNexusFileCallback(PlanReactiveCallback): See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks """ - def __init__(self) -> None: + def __init__(self, param_type: type[T]) -> None: super().__init__(NEXUS_LOGGER) + self.param_type = param_type self.run_start_uid: str | None = None self.nexus_writer_1: NexusWriter | None = None self.nexus_writer_2: NexusWriter | None = None @@ -50,7 +55,7 @@ def activity_gated_start(self, doc: RunStart): NEXUS_LOGGER.info( f"Nexus writer received start document with experiment parameters {mx_bluesky_parameters}" ) - parameters = ThreeDGridScan.model_validate_json(mx_bluesky_parameters) + parameters = self.param_type.model_validate_json(mx_bluesky_parameters) d_size = parameters.detector_params.detector_size_constants.det_size_pixels grid_n_img_1 = parameters.scan_indices[1] grid_n_img_2 = parameters.num_images - grid_n_img_1 diff --git a/src/mx_bluesky/common/parameters/components.py b/src/mx_bluesky/common/parameters/components.py index d239cf494..b0dbd3b6e 100644 --- a/src/mx_bluesky/common/parameters/components.py +++ b/src/mx_bluesky/common/parameters/components.py @@ -29,7 +29,7 @@ GridscanParamConstants, ) -PARAMETER_VERSION = Version.parse("5.2.0") +PARAMETER_VERSION = Version.parse("5.3.0") class RotationAxis(StrEnum): @@ -151,6 +151,7 @@ class DiffractionExperiment( transmission_frac: float = Field(default=0.1) ispyb_experiment_type: IspybExperimentType storage_directory: str + use_roi_mode: bool = Field(default=GridscanParamConstants.USE_ROI) @model_validator(mode="before") @classmethod diff --git a/src/mx_bluesky/common/parameters/gridscan.py b/src/mx_bluesky/common/parameters/gridscan.py index 7e791d3a7..13f72d0ab 100644 --- a/src/mx_bluesky/common/parameters/gridscan.py +++ b/src/mx_bluesky/common/parameters/gridscan.py @@ -1,11 +1,6 @@ from __future__ import annotations -import os - from dodal.devices.aperturescatterguard import ApertureValue -from dodal.devices.detector import ( - DetectorParams, -) from dodal.devices.fast_grid_scan import ( ZebraGridScanParams, ) @@ -23,78 +18,29 @@ XyzStarts, ) from mx_bluesky.common.parameters.constants import ( - DetectorParamConstants, GridscanParamConstants, HardwareConstants, ) -from mx_bluesky.common.parameters.robot_load import RobotLoadAndEnergyChange + +"""Parameter models in this file are abstract. They should be inherited by a top-level model""" class GridCommon( DiffractionExperimentWithSample, OptionalGonioAngleStarts, ): + """Parameters used in every MX diffraction experiment using grids. This model should be used by plans which have no knowledge of the grid specifications - i.e before automatic grid detection has completed""" + grid_width_um: float = Field(default=GridscanParamConstants.WIDTH_UM) exposure_time_s: float = Field(default=GridscanParamConstants.EXPOSURE_TIME_S) - use_roi_mode: bool = Field(default=GridscanParamConstants.USE_ROI) ispyb_experiment_type: IspybExperimentType = Field( default=IspybExperimentType.GRIDSCAN_3D ) selected_aperture: ApertureValue | None = Field(default=ApertureValue.SMALL) - @property - def detector_params(self): - self.det_dist_to_beam_converter_path = ( - self.det_dist_to_beam_converter_path - or DetectorParamConstants.BEAM_XY_LUT_PATH - ) - optional_args = {} - if self.run_number: - optional_args["run_number"] = self.run_number - assert self.detector_distance_mm is not None, ( - "Detector distance must be filled before generating DetectorParams" - ) - os.makedirs(self.storage_directory, exist_ok=True) - return DetectorParams( - detector_size_constants=DetectorParamConstants.DETECTOR, - expected_energy_ev=self.demand_energy_ev, - exposure_time=self.exposure_time_s, - directory=self.storage_directory, - prefix=self.file_name, - detector_distance=self.detector_distance_mm, - omega_start=self.omega_start_deg or 0, - omega_increment=0, - num_images_per_trigger=1, - num_triggers=self.num_images, - use_roi_mode=self.use_roi_mode, - det_dist_to_beam_converter_path=self.det_dist_to_beam_converter_path, - trigger_mode=self.trigger_mode, - **optional_args, - ) - - -class RobotLoadThenCentre(GridCommon): - thawing_time: float = Field(default=HardwareConstants.THAWING_TIME) tip_offset_um: float = Field(default=HardwareConstants.TIP_OFFSET_UM) - def robot_load_params(self): - my_params = self.model_dump() - return RobotLoadAndEnergyChange(**my_params) - - def pin_centre_then_xray_centre_params(self): - my_params = self.model_dump() - del my_params["thawing_time"] - return PinTipCentreThenXrayCentre(**my_params) - - -class GridScanWithEdgeDetect(GridCommon): - box_size_um: float = Field(default=GridscanParamConstants.BOX_WIDTH_UM) - - -class PinTipCentreThenXrayCentre(GridCommon): - tip_offset_um: float = 0 - class SpecifiedGrid(XyzStarts, WithScan): """A specified grid is one which has defined values for the start position, @@ -102,7 +48,7 @@ class SpecifiedGrid(XyzStarts, WithScan): those parameters at some point (e.g. through optical pin detection).""" -class ThreeDGridScan( +class SpecifiedThreeDGridScan( GridCommon, SpecifiedGrid, SplitScan, diff --git a/src/mx_bluesky/common/parameters/robot_load.py b/src/mx_bluesky/common/parameters/robot_load.py deleted file mode 100644 index f522050fa..000000000 --- a/src/mx_bluesky/common/parameters/robot_load.py +++ /dev/null @@ -1,16 +0,0 @@ -from pydantic import Field - -from mx_bluesky.common.parameters.components import ( - MxBlueskyParameters, - WithOptionalEnergyChange, - WithSample, - WithSnapshot, - WithVisit, -) -from mx_bluesky.common.parameters.constants import HardwareConstants - - -class RobotLoadAndEnergyChange( - MxBlueskyParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit -): - thawing_time: float = Field(default=HardwareConstants.THAWING_TIME) diff --git a/src/mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py b/src/mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py index 930f4428b..6ccf4636d 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +++ b/src/mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py @@ -8,14 +8,14 @@ from mx_bluesky.common.utils.tracing import TRACER from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_x_y_z from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan def change_aperture_then_move_to_xtal( best_hit: XRayCentreResult, smargon: Smargon, aperture_scatterguard: ApertureScatterguard, - parameters: HyperionThreeDGridScan | None = None, + parameters: HyperionSpecifiedThreeDGridScan | None = None, ): """For the given x-ray centring result, * Change the aperture so that the beam size is comparable to the crystal size diff --git a/src/mx_bluesky/hyperion/experiment_plans/experiment_registry.py b/src/mx_bluesky/hyperion/experiment_plans/experiment_registry.py index af165dfa9..54503feb7 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/experiment_registry.py +++ b/src/mx_bluesky/hyperion/experiment_plans/experiment_registry.py @@ -5,11 +5,6 @@ import mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan as flyscan_xray_centre_plan import mx_bluesky.hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan -from mx_bluesky.common.parameters.gridscan import ( - GridScanWithEdgeDetect, - PinTipCentreThenXrayCentre, - RobotLoadThenCentre, -) from mx_bluesky.hyperion.experiment_plans import ( grid_detect_then_xray_centre_plan, load_centre_collect_full_plan, @@ -23,8 +18,13 @@ create_robot_load_and_centre_callbacks, create_rotation_callbacks, ) -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import ( + GridScanWithEdgeDetect, + HyperionSpecifiedThreeDGridScan, + PinTipCentreThenXrayCentre, +) from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan, RotationScan @@ -39,13 +39,13 @@ def do_nothing(): class ExperimentRegistryEntry(TypedDict): setup: Callable param_type: type[ - HyperionThreeDGridScan + HyperionSpecifiedThreeDGridScan | GridScanWithEdgeDetect | RotationScan | MultiRotationScan | PinTipCentreThenXrayCentre - | RobotLoadThenCentre | LoadCentreCollect + | RobotLoadThenCentre ] callbacks_factory: CallbacksFactory @@ -53,7 +53,7 @@ class ExperimentRegistryEntry(TypedDict): PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = { "flyscan_xray_centre": { "setup": flyscan_xray_centre_plan.create_devices, - "param_type": HyperionThreeDGridScan, + "param_type": HyperionSpecifiedThreeDGridScan, "callbacks_factory": create_gridscan_callbacks, }, "grid_detect_then_xray_centre": { diff --git a/src/mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py b/src/mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py index 6a965c959..eeec009d1 100755 --- a/src/mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +++ b/src/mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py @@ -79,7 +79,7 @@ ) from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from mx_bluesky.hyperion.utils.context import device_composite_from_context ZOCALO_MIN_TOTAL_COUNT_THRESHOLD = 3 @@ -133,7 +133,7 @@ def create_devices(context: BlueskyContext) -> FlyScanXRayCentreComposite: def flyscan_xray_centre_no_move( - composite: FlyScanXRayCentreComposite, parameters: HyperionThreeDGridScan + composite: FlyScanXRayCentreComposite, parameters: HyperionSpecifiedThreeDGridScan ) -> MsgGenerator: """Perform a flyscan and determine the centres of interest""" parameters.features.update_self_from_server() @@ -161,7 +161,7 @@ def flyscan_xray_centre_no_move( ) def run_gridscan_and_fetch_and_tidy( fgs_composite: FlyScanXRayCentreComposite, - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, feature_controlled: _FeatureControlled, ) -> MsgGenerator: yield from run_gridscan_and_fetch_results( @@ -175,7 +175,7 @@ def run_gridscan_and_fetch_and_tidy( def flyscan_xray_centre( composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, ) -> MsgGenerator: """Create the plan to run the grid scan based on provided parameters. @@ -183,7 +183,7 @@ def flyscan_xray_centre( at any point in it. Args: - parameters (ThreeDGridScan): The parameters to run the scan. + parameters (HyperionSpecifiedThreeDGridScan): The parameters to run the scan. Returns: Generator: The plan for the gridscan @@ -214,7 +214,7 @@ def flyscan_and_fetch_results() -> MsgGenerator: @bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_AND_MOVE}) def run_gridscan_and_fetch_results( fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, feature_controlled: _FeatureControlled, ) -> MsgGenerator: """A multi-run plan which runs a gridscan, gets the results from zocalo @@ -269,7 +269,7 @@ def run_gridscan_and_fetch_results( def _xrc_result_in_boxes_to_result_in_mm( - xrc_result: XrcResult, parameters: HyperionThreeDGridScan + xrc_result: XrcResult, parameters: HyperionSpecifiedThreeDGridScan ) -> XRayCentreResult: fgs_params = parameters.FGS_params xray_centre = fgs_params.grid_position_to_motor_position( @@ -311,7 +311,7 @@ def empty_plan(): @bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_MAIN}) def run_gridscan( fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, feature_controlled: _FeatureControlled, md={ # noqa "plan_name": CONST.PLAN.GRIDSCAN_MAIN, @@ -391,7 +391,7 @@ class _ExtraSetup(Protocol): def __call__( self, fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, ) -> MsgGenerator: ... setup_trigger: _ExtraSetup @@ -402,7 +402,7 @@ def __call__( def _get_feature_controlled( fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, ): if parameters.features.use_panda_for_gridscan: return _FeatureControlled( @@ -451,7 +451,7 @@ def _panda_tidy(fgs_composite: FlyScanXRayCentreComposite): def _zebra_triggering_setup( fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, ): yield from setup_zebra_for_gridscan( fgs_composite.zebra, fgs_composite.sample_shutter, wait=True @@ -460,7 +460,7 @@ def _zebra_triggering_setup( def _panda_triggering_setup( fgs_composite: FlyScanXRayCentreComposite, - parameters: HyperionThreeDGridScan, + parameters: HyperionSpecifiedThreeDGridScan, ): LOGGER.info("Setting up Panda for flyscan") diff --git a/src/mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py b/src/mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py index 74c7d2b78..3e1720907 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +++ b/src/mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py @@ -39,7 +39,6 @@ ispyb_activation_wrapper, ) from mx_bluesky.common.parameters.constants import OavConstants -from mx_bluesky.common.parameters.gridscan import GridScanWithEdgeDetect from mx_bluesky.common.utils.log import LOGGER from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import ( move_aperture_if_required, @@ -63,7 +62,8 @@ ) from mx_bluesky.hyperion.parameters.constants import CONST from mx_bluesky.hyperion.parameters.gridscan import ( - HyperionThreeDGridScan, + GridScanWithEdgeDetect, + HyperionSpecifiedThreeDGridScan, ) from mx_bluesky.hyperion.utils.context import device_composite_from_context @@ -103,10 +103,10 @@ def create_devices(context: BlueskyContext) -> GridDetectThenXRayCentreComposite def create_parameters_for_flyscan_xray_centre( grid_scan_with_edge_params: GridScanWithEdgeDetect, grid_parameters: GridParamUpdate, -) -> HyperionThreeDGridScan: +) -> HyperionSpecifiedThreeDGridScan: params_json = grid_scan_with_edge_params.model_dump() params_json.update(grid_parameters) - flyscan_xray_centre_parameters = HyperionThreeDGridScan(**params_json) + flyscan_xray_centre_parameters = HyperionSpecifiedThreeDGridScan(**params_json) LOGGER.info(f"Parameters for FGS: {flyscan_xray_centre_parameters}") return flyscan_xray_centre_parameters diff --git a/src/mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py b/src/mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py index 6306f7886..487d2ec65 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +++ b/src/mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py @@ -12,10 +12,6 @@ ispyb_activation_wrapper, ) from mx_bluesky.common.parameters.constants import OavConstants -from mx_bluesky.common.parameters.gridscan import ( - GridScanWithEdgeDetect, - PinTipCentreThenXrayCentre, -) from mx_bluesky.common.utils.log import LOGGER from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_phi_chi_omega from mx_bluesky.hyperion.device_setup_plans.utils import ( @@ -39,6 +35,10 @@ pin_tip_centre_plan, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.gridscan import ( + GridScanWithEdgeDetect, + PinTipCentreThenXrayCentre, +) from mx_bluesky.hyperion.utils.context import device_composite_from_context diff --git a/src/mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py b/src/mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py index bcc206ea6..ccd3c9ff0 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +++ b/src/mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py @@ -24,13 +24,13 @@ from dodal.devices.xbpm_feedback import XBPMFeedback from dodal.plan_stubs.motor_utils import MoveTooLarge, home_and_reset_wrapper -from mx_bluesky.common.parameters.robot_load import RobotLoadAndEnergyChange from mx_bluesky.common.utils.log import LOGGER from mx_bluesky.hyperion.experiment_plans.set_energy_plan import ( SetEnergyComposite, set_energy_plan, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange @pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True}) diff --git a/src/mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py b/src/mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py index bf732368b..2e1b4da78 100644 --- a/src/mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +++ b/src/mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py @@ -37,7 +37,6 @@ from ophyd_async.fastcs.panda import HDFPanda from mx_bluesky.common.parameters.constants import OavConstants -from mx_bluesky.common.parameters.gridscan import RobotLoadThenCentre from mx_bluesky.hyperion.device_setup_plans.utils import ( fill_in_energy_if_not_supplied, start_preparing_data_collection_then_do_plan, @@ -64,6 +63,7 @@ set_energy_plan, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre @pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True}) @@ -118,7 +118,7 @@ def _flyscan_plan_from_robot_load_params( ): yield from pin_centre_then_flyscan_plan( cast(GridDetectThenXRayCentreComposite, composite), - params.pin_centre_then_xray_centre_params(), + params.pin_centre_then_xray_centre_params, ) @@ -129,7 +129,7 @@ def _robot_load_then_flyscan_plan( ): yield from robot_load_and_change_energy_plan( cast(RobotLoadAndEnergyChangeComposite, composite), - params.robot_load_params(), + params.robot_load_params, ) yield from _flyscan_plan_from_robot_load_params(composite, params, oav_config_file) diff --git a/src/mx_bluesky/hyperion/external_interaction/callbacks/__main__.py b/src/mx_bluesky/hyperion/external_interaction/callbacks/__main__.py index 02d2ab1af..8f2bb3b5a 100644 --- a/src/mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +++ b/src/mx_bluesky/hyperion/external_interaction/callbacks/__main__.py @@ -39,6 +39,10 @@ ) from mx_bluesky.hyperion.parameters.cli import parse_callback_dev_mode_arg from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.gridscan import ( + GridCommonWithHyperionDetectorParams, + HyperionSpecifiedThreeDGridScan, +) LIVENESS_POLL_SECONDS = 1 ERROR_LOG_BUFFER_LINES = 5000 @@ -47,8 +51,10 @@ def setup_callbacks(): zocalo = ZocaloCallback() return [ - GridscanNexusFileCallback(), - GridscanISPyBCallback(emit=zocalo), + GridscanNexusFileCallback(param_type=HyperionSpecifiedThreeDGridScan), + GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams, emit=zocalo + ), RotationNexusFileCallback(), RotationISPyBCallback(emit=zocalo), LogUidTaggingCallback(), diff --git a/src/mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py b/src/mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py index 63595b49e..bf8e02501 100644 --- a/src/mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +++ b/src/mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py @@ -23,6 +23,10 @@ from mx_bluesky.hyperion.external_interaction.callbacks.sample_handling.sample_handling_callback import ( SampleHandlingCallback, ) +from mx_bluesky.hyperion.parameters.gridscan import ( + GridCommonWithHyperionDetectorParams, + HyperionSpecifiedThreeDGridScan, +) CallbacksFactory = Callable[[], tuple[CallbackBase, ...]] @@ -31,8 +35,10 @@ def create_robot_load_and_centre_callbacks() -> tuple[ GridscanNexusFileCallback, GridscanISPyBCallback, RobotLoadISPyBCallback ]: return ( - GridscanNexusFileCallback(), - GridscanISPyBCallback(emit=ZocaloCallback()), + GridscanNexusFileCallback(param_type=HyperionSpecifiedThreeDGridScan), + GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams, emit=ZocaloCallback() + ), RobotLoadISPyBCallback(), ) @@ -41,8 +47,10 @@ def create_gridscan_callbacks() -> tuple[ GridscanNexusFileCallback, GridscanISPyBCallback ]: return ( - GridscanNexusFileCallback(), - GridscanISPyBCallback(emit=ZocaloCallback()), + GridscanNexusFileCallback(param_type=HyperionSpecifiedThreeDGridScan), + GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams, emit=ZocaloCallback() + ), ) @@ -61,8 +69,10 @@ def create_load_centre_collect_callbacks() -> tuple[ SampleHandlingCallback, ]: return ( - GridscanNexusFileCallback(), - GridscanISPyBCallback(emit=ZocaloCallback()), + GridscanNexusFileCallback(param_type=HyperionSpecifiedThreeDGridScan), + GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams, emit=ZocaloCallback() + ), RobotLoadISPyBCallback(), RotationNexusFileCallback(), RotationISPyBCallback(emit=ZocaloCallback()), diff --git a/src/mx_bluesky/hyperion/parameters/components.py b/src/mx_bluesky/hyperion/parameters/components.py index 98076c218..77dde7f4d 100644 --- a/src/mx_bluesky/hyperion/parameters/components.py +++ b/src/mx_bluesky/hyperion/parameters/components.py @@ -1,7 +1,8 @@ -from pydantic import BaseModel, Field +from pydantic import Field +from mx_bluesky.common.parameters.components import WithPandaGridScan from mx_bluesky.hyperion.external_interaction.config_server import HyperionFeatureFlags -class WithHyperionFeatures(BaseModel): +class WithHyperionUDCFeatures(WithPandaGridScan): features: HyperionFeatureFlags = Field(default=HyperionFeatureFlags()) diff --git a/src/mx_bluesky/hyperion/parameters/gridscan.py b/src/mx_bluesky/hyperion/parameters/gridscan.py index 77e6b12ef..97a3240cf 100644 --- a/src/mx_bluesky/hyperion/parameters/gridscan.py +++ b/src/mx_bluesky/hyperion/parameters/gridscan.py @@ -7,23 +7,55 @@ PandAGridScanParams, ZebraGridScanParams, ) +from pydantic import Field -from mx_bluesky.common.parameters.components import ( - WithPandaGridScan, -) +from mx_bluesky.common.parameters.constants import GridscanParamConstants from mx_bluesky.common.parameters.gridscan import ( - ThreeDGridScan, + GridCommon, + SpecifiedThreeDGridScan, ) -from mx_bluesky.hyperion.parameters.components import WithHyperionFeatures +from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures from mx_bluesky.hyperion.parameters.constants import CONST, I03Constants -class HyperionThreeDGridScan( - ThreeDGridScan, - WithPandaGridScan, - WithHyperionFeatures, -): - """Hyperion's 3D grid scan varies from the common class due to: optionally using a PandA, optionally using dev_shm for GPU analysis, and using a config server for features""" +class GridCommonWithHyperionDetectorParams(GridCommon, WithHyperionUDCFeatures): + """Used by models which require detector parameters but have no specifications of the grid""" + + # These detector params only exist so that we can properly select enable_dev_shm. Remove in + # https://github.com/DiamondLightSource/hyperion/issues/1395""" + @property + def detector_params(self): + self.det_dist_to_beam_converter_path = ( + self.det_dist_to_beam_converter_path + or CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH + ) + optional_args = {} + if self.run_number: + optional_args["run_number"] = self.run_number + assert self.detector_distance_mm is not None, ( + "Detector distance must be filled before generating DetectorParams" + ) + return DetectorParams( + detector_size_constants=I03Constants.DETECTOR, + expected_energy_ev=self.demand_energy_ev, + exposure_time=self.exposure_time_s, + directory=self.storage_directory, + prefix=self.file_name, + detector_distance=self.detector_distance_mm, + omega_start=self.omega_start_deg or 0, + omega_increment=0, + num_images_per_trigger=1, + num_triggers=self.num_images, + use_roi_mode=self.use_roi_mode, + det_dist_to_beam_converter_path=self.det_dist_to_beam_converter_path, + trigger_mode=self.trigger_mode, + enable_dev_shm=self.features.compare_cpu_and_gpu_zocalo, + **optional_args, + ) + + +class HyperionSpecifiedThreeDGridScan(SpecifiedThreeDGridScan, WithHyperionUDCFeatures): + """Hyperion's 3D grid scan deviates from the common class due to: optionally using a PandA, optionally using dev_shm for GPU analysis, and using a config server for features""" # These detector params only exist so that we can properly select enable_dev_shm. Remove in # https://github.com/DiamondLightSource/hyperion/issues/1395""" @@ -103,3 +135,15 @@ def panda_FGS_params(self) -> PandAGridScanParams: class OddYStepsException(Exception): ... + + +class PinTipCentreThenXrayCentre( + GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures +): + tip_offset_um: float = 0 + + +class GridScanWithEdgeDetect( + GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures +): + box_size_um: float = Field(default=GridscanParamConstants.BOX_WIDTH_UM) diff --git a/src/mx_bluesky/hyperion/parameters/load_centre_collect.py b/src/mx_bluesky/hyperion/parameters/load_centre_collect.py index 73d6b2774..7874ee82d 100644 --- a/src/mx_bluesky/hyperion/parameters/load_centre_collect.py +++ b/src/mx_bluesky/hyperion/parameters/load_centre_collect.py @@ -8,7 +8,8 @@ WithSample, WithVisit, ) -from mx_bluesky.common.parameters.gridscan import ( +from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures +from mx_bluesky.hyperion.parameters.robot_load import ( RobotLoadThenCentre, ) from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan @@ -23,7 +24,11 @@ def construct_from_values(parent_context: dict, child_dict: dict, t: type[T]) -> class LoadCentreCollect( - MxBlueskyParameters, WithVisit, WithSample, WithCentreSelection + MxBlueskyParameters, + WithVisit, + WithSample, + WithCentreSelection, + WithHyperionUDCFeatures, ): """Experiment parameters to perform the combined robot load, pin-tip centre and rotation scan operations.""" diff --git a/src/mx_bluesky/hyperion/parameters/robot_load.py b/src/mx_bluesky/hyperion/parameters/robot_load.py new file mode 100644 index 000000000..3fbf54021 --- /dev/null +++ b/src/mx_bluesky/hyperion/parameters/robot_load.py @@ -0,0 +1,40 @@ +from pydantic import Field + +from mx_bluesky.common.parameters.components import ( + MxBlueskyParameters, + WithOptionalEnergyChange, + WithSample, + WithSnapshot, + WithVisit, +) +from mx_bluesky.common.parameters.constants import ( + HardwareConstants, +) +from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures +from mx_bluesky.hyperion.parameters.gridscan import ( + GridCommonWithHyperionDetectorParams, + PinTipCentreThenXrayCentre, +) + + +class RobotLoadAndEnergyChange( + MxBlueskyParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit +): + thawing_time: float = Field(default=HardwareConstants.THAWING_TIME) + + +class RobotLoadThenCentre( + GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures +): + thawing_time: float = Field(default=HardwareConstants.THAWING_TIME) + + @property + def robot_load_params(self) -> RobotLoadAndEnergyChange: + my_params = self.model_dump() + return RobotLoadAndEnergyChange(**my_params) + + @property + def pin_centre_then_xray_centre_params(self) -> PinTipCentreThenXrayCentre: + my_params = self.model_dump() + del my_params["thawing_time"] + return PinTipCentreThenXrayCentre(**my_params) diff --git a/src/mx_bluesky/hyperion/parameters/rotation.py b/src/mx_bluesky/hyperion/parameters/rotation.py index c62c8e039..225b6625c 100644 --- a/src/mx_bluesky/hyperion/parameters/rotation.py +++ b/src/mx_bluesky/hyperion/parameters/rotation.py @@ -26,7 +26,7 @@ SplitScan, WithScan, ) -from mx_bluesky.hyperion.parameters.components import WithHyperionFeatures +from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures from mx_bluesky.hyperion.parameters.constants import ( CONST, I03Constants, @@ -53,7 +53,7 @@ class RotationScanPerSweep(OptionalGonioAngleStarts, OptionalXyzStarts): nexus_vds_start_img: int = Field(default=0, ge=0) -class RotationExperiment(DiffractionExperimentWithSample, WithHyperionFeatures): +class RotationExperiment(DiffractionExperimentWithSample, WithHyperionUDCFeatures): shutter_opening_time_s: float = Field(default=CONST.I03.SHUTTER_TIME_S) rotation_increment_deg: float = Field(default=0.1, gt=0) ispyb_experiment_type: IspybExperimentType = Field( diff --git a/tests/conftest.py b/tests/conftest.py index a3c553011..a1647bec0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -83,7 +83,6 @@ PlanNameConstants, TriggerConstants, ) -from mx_bluesky.common.parameters.gridscan import GridScanWithEdgeDetect from mx_bluesky.common.utils.log import ( ALL_LOGGERS, ISPYB_ZOCALO_CALLBACK_LOGGER, @@ -100,7 +99,8 @@ ) from mx_bluesky.hyperion.external_interaction.config_server import HyperionFeatureFlags from mx_bluesky.hyperion.parameters.gridscan import ( - HyperionThreeDGridScan, + GridScanWithEdgeDetect, + HyperionSpecifiedThreeDGridScan, ) from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan, RotationScan @@ -247,7 +247,7 @@ def beamline_parameters(): @pytest.fixture def test_fgs_params(): - return HyperionThreeDGridScan( + return HyperionSpecifiedThreeDGridScan( **raw_params_from_file( "tests/test_data/parameter_json_files/good_test_parameters.json" ) @@ -255,7 +255,7 @@ def test_fgs_params(): @pytest.fixture -def test_panda_fgs_params(test_fgs_params: HyperionThreeDGridScan): +def test_panda_fgs_params(test_fgs_params: HyperionSpecifiedThreeDGridScan): test_fgs_params.features.use_panda_for_gridscan = True return test_fgs_params @@ -793,7 +793,7 @@ def panda_fast_grid_scan(RE): @pytest.fixture async def fake_fgs_composite( smargon: Smargon, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, RE: RunEngine, done_status, attenuator, @@ -1160,7 +1160,7 @@ class OavGridSnapshotTestEvents: def dummy_params(): - dummy_params = HyperionThreeDGridScan(**default_raw_gridscan_params()) + dummy_params = HyperionSpecifiedThreeDGridScan(**default_raw_gridscan_params()) return dummy_params @@ -1169,7 +1169,7 @@ def dummy_params_2d(): "tests/test_data/parameter_json_files/test_gridscan_param_defaults.json" ) raw_params["z_steps"] = 1 - return HyperionThreeDGridScan(**raw_params) + return HyperionSpecifiedThreeDGridScan(**raw_params) class TestData(OavGridSnapshotTestEvents): diff --git a/tests/system_tests/hyperion/experiment_plans/test_fgs_plan.py b/tests/system_tests/hyperion/experiment_plans/test_fgs_plan.py index 79ed76711..115e05226 100644 --- a/tests/system_tests/hyperion/experiment_plans/test_fgs_plan.py +++ b/tests/system_tests/hyperion/experiment_plans/test_fgs_plan.py @@ -36,7 +36,7 @@ create_gridscan_callbacks, ) from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from tests.conftest import default_raw_gridscan_params from ..external_interaction.conftest import ( # noqa @@ -47,7 +47,7 @@ @pytest.fixture def params(): - params = HyperionThreeDGridScan(**default_raw_gridscan_params()) + params = HyperionSpecifiedThreeDGridScan(**default_raw_gridscan_params()) params.beamline = CONST.SIM.BEAMLINE yield params @@ -151,7 +151,7 @@ def read_run(u, s, g, r, a, f, dcm, ap_sg, sm): async def test_xbpm_feedback_decorator( RE: RunEngine, fxc_composite: FlyScanXRayCentreComposite, - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, callbacks: tuple[GridscanNexusFileCallback, GridscanISPyBCallback], ): # This test is currently kind of more a unit test since we are faking XBPM feedback @@ -189,7 +189,7 @@ def test_full_plan_tidies_at_end( kickoff: MagicMock, wait: MagicMock, fxc_composite: FlyScanXRayCentreComposite, - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, RE: RunEngine, callbacks: tuple[GridscanNexusFileCallback, GridscanISPyBCallback], ): @@ -224,7 +224,7 @@ def test_full_plan_tidies_at_end_when_plan_fails( kickoff: MagicMock, wait: MagicMock, fxc_composite: FlyScanXRayCentreComposite, - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, RE: RunEngine, ): class _Exception(Exception): ... @@ -244,7 +244,7 @@ def test_GIVEN_scan_invalid_WHEN_plan_run_THEN_ispyb_entry_made_but_no_zocalo_en RE: RunEngine, fxc_composite: FlyScanXRayCentreComposite, fetch_comment: Callable, # noqa - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, callbacks: tuple[GridscanNexusFileCallback, GridscanISPyBCallback], ): _, ispyb_cb = callbacks @@ -274,7 +274,7 @@ async def test_complete_xray_centre_plan_with_no_callbacks_falls_back_to_centre( RE: RunEngine, fxc_composite: FlyScanXRayCentreComposite, zocalo_env: None, # noqa - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, callbacks, done_status, ): @@ -308,7 +308,7 @@ async def test_complete_xray_centre_plan_with_callbacks_moves_to_centre( RE: RunEngine, fxc_composite: FlyScanXRayCentreComposite, zocalo_env: None, # noqa - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, callbacks, done_status, ): diff --git a/tests/system_tests/hyperion/external_interaction/callbacks/test_external_callbacks.py b/tests/system_tests/hyperion/external_interaction/callbacks/test_external_callbacks.py index 20b930e9e..4b08a7243 100644 --- a/tests/system_tests/hyperion/external_interaction/callbacks/test_external_callbacks.py +++ b/tests/system_tests/hyperion/external_interaction/callbacks/test_external_callbacks.py @@ -32,7 +32,7 @@ rotation_scan, ) from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from mx_bluesky.hyperion.parameters.rotation import RotationScan from .....conftest import fake_read @@ -139,7 +139,7 @@ def plan(): async def test_external_callbacks_handle_gridscan_ispyb_and_zocalo( RE_with_external_callbacks: RunEngine, zocalo_env, # noqa - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, fgs_composite_for_fake_zocalo: FlyScanXRayCentreComposite, done_status, zocalo_device: ZocaloResults, diff --git a/tests/system_tests/hyperion/external_interaction/conftest.py b/tests/system_tests/hyperion/external_interaction/conftest.py index b566edcf0..56a6658d2 100644 --- a/tests/system_tests/hyperion/external_interaction/conftest.py +++ b/tests/system_tests/hyperion/external_interaction/conftest.py @@ -52,7 +52,7 @@ RotationScanComposite, ) from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from ....conftest import fake_read, pin_tip_edge_data, raw_params_from_file @@ -222,7 +222,7 @@ def fetch_blsample(sqlalchemy_sessionmaker) -> Callable[[int], BLSample]: @pytest.fixture def dummy_params(): - dummy_params = HyperionThreeDGridScan( + dummy_params = HyperionSpecifiedThreeDGridScan( **raw_params_from_file( "tests/test_data/parameter_json_files/test_gridscan_param_defaults.json" ) diff --git a/tests/system_tests/hyperion/external_interaction/test_ispyb_dev_connection.py b/tests/system_tests/hyperion/external_interaction/test_ispyb_dev_connection.py index cbb3a07de..dab9bad32 100644 --- a/tests/system_tests/hyperion/external_interaction/test_ispyb_dev_connection.py +++ b/tests/system_tests/hyperion/external_interaction/test_ispyb_dev_connection.py @@ -33,7 +33,6 @@ StoreInIspyb, ) from mx_bluesky.common.parameters.components import IspybExperimentType -from mx_bluesky.common.parameters.gridscan import GridScanWithEdgeDetect from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import ( GridDetectThenXRayCentreComposite, grid_detect_then_xray_centre, @@ -47,7 +46,8 @@ ) from mx_bluesky.hyperion.parameters.constants import CONST from mx_bluesky.hyperion.parameters.gridscan import ( - HyperionThreeDGridScan, + GridScanWithEdgeDetect, + HyperionSpecifiedThreeDGridScan, ) from mx_bluesky.hyperion.parameters.rotation import RotationScan @@ -126,7 +126,7 @@ def grid_detect_then_xray_centre_parameters(): def scan_xy_data_info_for_update( data_collection_group_id, - dummy_params: HyperionThreeDGridScan, + dummy_params: HyperionSpecifiedThreeDGridScan, scan_data_info_for_begin, ): scan_data_info_for_update = deepcopy(scan_data_info_for_begin) @@ -154,7 +154,9 @@ def scan_xy_data_info_for_update( def scan_data_infos_for_update_3d( - ispyb_ids, scan_xy_data_info_for_update, dummy_params: HyperionThreeDGridScan + ispyb_ids, + scan_xy_data_info_for_update, + dummy_params: HyperionSpecifiedThreeDGridScan, ): xz_data_collection_info = populate_xz_data_collection_info( dummy_params.detector_params @@ -337,7 +339,7 @@ def test_ispyb_deposition_in_gridscan( set_mock_value( grid_detect_then_xray_centre_composite.s4_slit_gaps.ygap.user_readback, 0.1 ) - ispyb_callback = GridscanISPyBCallback() + ispyb_callback = GridscanISPyBCallback(HyperionSpecifiedThreeDGridScan) RE.subscribe(ispyb_callback) RE( grid_detect_then_xray_centre( diff --git a/tests/system_tests/hyperion/external_interaction/test_load_centre_collect_full_plan.py b/tests/system_tests/hyperion/external_interaction/test_load_centre_collect_full_plan.py index be5a0697a..7ead04bcd 100644 --- a/tests/system_tests/hyperion/external_interaction/test_load_centre_collect_full_plan.py +++ b/tests/system_tests/hyperion/external_interaction/test_load_centre_collect_full_plan.py @@ -37,6 +37,7 @@ SampleHandlingCallback, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.gridscan import GridCommonWithHyperionDetectorParams from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect from ...conftest import ( @@ -221,7 +222,9 @@ def test_execute_load_centre_collect_full( fetch_datacollection_ids_for_group_id: Callable[..., Any], fetch_blsample: Callable[[int], BLSample], ): - ispyb_gridscan_cb = GridscanISPyBCallback() + ispyb_gridscan_cb = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_rotation_cb = RotationISPyBCallback() robot_load_cb = RobotLoadISPyBCallback() # robot_load_cb.expeye = MagicMock() @@ -353,7 +356,9 @@ def test_load_centre_collect_updates_bl_sample_status_pin_tip_detection_fail( fetch_blsample: Callable[..., Any], ): robot_load_cb = RobotLoadISPyBCallback() - ispyb_gridscan_cb = GridscanISPyBCallback() + ispyb_gridscan_cb = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) sample_handling_cb = SampleHandlingCallback() RE.subscribe(robot_load_cb) RE.subscribe(ispyb_gridscan_cb) @@ -406,7 +411,9 @@ def test_load_centre_collect_updates_bl_sample_status_grid_detection_fail_tip_no fetch_blsample: Callable[..., Any], ): robot_load_cb = RobotLoadISPyBCallback() - ispyb_gridscan_cb = GridscanISPyBCallback() + ispyb_gridscan_cb = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) sample_handling_cb = SampleHandlingCallback() RE.subscribe(robot_load_cb) RE.subscribe(ispyb_gridscan_cb) @@ -454,7 +461,9 @@ def test_load_centre_collect_updates_bl_sample_status_gridscan_no_diffraction( fetch_blsample: Callable[..., Any], ): robot_load_cb = RobotLoadISPyBCallback() - ispyb_gridscan_cb = GridscanISPyBCallback() + ispyb_gridscan_cb = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) sample_handling_cb = SampleHandlingCallback() RE.subscribe(robot_load_cb) RE.subscribe(ispyb_gridscan_cb) @@ -481,7 +490,9 @@ def test_load_centre_collect_updates_bl_sample_status_rotation_failure( fetch_blsample: Callable[..., Any], ): robot_load_cb = RobotLoadISPyBCallback() - ispyb_gridscan_cb = GridscanISPyBCallback() + ispyb_gridscan_cb = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) sample_handling_cb = SampleHandlingCallback() RE.subscribe(robot_load_cb) RE.subscribe(ispyb_gridscan_cb) diff --git a/tests/system_tests/hyperion/external_interaction/test_zocalo_system.py b/tests/system_tests/hyperion/external_interaction/test_zocalo_system.py index 9d3b73af5..2b0451eb7 100644 --- a/tests/system_tests/hyperion/external_interaction/test_zocalo_system.py +++ b/tests/system_tests/hyperion/external_interaction/test_zocalo_system.py @@ -19,7 +19,7 @@ create_gridscan_callbacks, ) from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from tests.conftest import create_dummy_scan_spec """ @@ -60,7 +60,7 @@ def fake_fgs_plan(): @pytest.fixture def run_zocalo_with_dev_ispyb( - dummy_params: HyperionThreeDGridScan, + dummy_params: HyperionSpecifiedThreeDGridScan, dummy_ispyb_3d, RE: RunEngine, zocalo_device: ZocaloResults, diff --git a/tests/test_data/parameter_json_files/good_test_load_centre_collect_params.json b/tests/test_data/parameter_json_files/good_test_load_centre_collect_params.json index 4b064ebef..fcd8dddb4 100644 --- a/tests/test_data/parameter_json_files/good_test_load_centre_collect_params.json +++ b/tests/test_data/parameter_json_files/good_test_load_centre_collect_params.json @@ -15,7 +15,9 @@ "exposure_time_s": 0.004, "use_roi_mode": false, "demand_energy_ev": 11100, - "run_number": 0 + "run_number": 0, + "features": {"use_panda_for_gridscan": false, "compare_cpu_and_gpu_zocalo": true}, + "panda_runup_distance_mm": 0.17 }, "multi_rotation_scan": { "comment": "Rotation", diff --git a/tests/unit_tests/common/external_interaction/callbacks/ispyb/conftest.py b/tests/unit_tests/common/external_interaction/callbacks/ispyb/conftest.py index caae596ac..fe5423529 100644 --- a/tests/unit_tests/common/external_interaction/callbacks/ispyb/conftest.py +++ b/tests/unit_tests/common/external_interaction/callbacks/ispyb/conftest.py @@ -10,7 +10,7 @@ ) from mx_bluesky.common.external_interaction.ispyb.ispyb_store import StoreInIspyb from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from ......conftest import ( TEST_DATA_COLLECTION_GROUP_ID, @@ -22,7 +22,7 @@ @pytest.fixture def dummy_params(): - dummy_params = HyperionThreeDGridScan(**default_raw_gridscan_params()) + dummy_params = HyperionSpecifiedThreeDGridScan(**default_raw_gridscan_params()) dummy_params.sample_id = TEST_SAMPLE_ID dummy_params.run_number = 0 return dummy_params diff --git a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_callback.py b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_callback.py index cec1799c2..28e96cb3a 100644 --- a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_callback.py +++ b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_callback.py @@ -3,6 +3,7 @@ from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import ( GridscanISPyBCallback, ) +from mx_bluesky.hyperion.parameters.gridscan import GridCommonWithHyperionDetectorParams from .....conftest import ( EXPECTED_START_TIME, @@ -56,7 +57,9 @@ ) class TestXrayCentreISPyBCallback: def test_activity_gated_start_3d(self, mock_ispyb_conn): - callback = GridscanISPyBCallback() + callback = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) callback.activity_gated_start(TestData.test_gridscan3d_start_document) # pyright: ignore mx_acq = mx_acquisition_from_conn(mock_ispyb_conn) assert_upsert_call_with( @@ -82,7 +85,9 @@ def test_activity_gated_start_3d(self, mock_ispyb_conn): mx_acq.upsert_data_collection.upsert_dc_grid.assert_not_called() def test_hardware_read_event_3d(self, mock_ispyb_conn): - callback = GridscanISPyBCallback() + callback = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) callback.activity_gated_start(TestData.test_gridscan3d_start_document) # pyright: ignore mx_acq = mx_acquisition_from_conn(mock_ispyb_conn) mx_acq.upsert_data_collection_group.reset_mock() @@ -113,7 +118,9 @@ def test_hardware_read_event_3d(self, mock_ispyb_conn): ) def test_flux_read_events_3d(self, mock_ispyb_conn): - callback = GridscanISPyBCallback() + callback = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) callback.activity_gated_start(TestData.test_gridscan3d_start_document) # pyright: ignore mx_acq = mx_acquisition_from_conn(mock_ispyb_conn) callback.activity_gated_descriptor( @@ -166,7 +173,9 @@ def test_flux_read_events_3d(self, mock_ispyb_conn): mx_acq.upsert_dc_grid.assert_not_called() def test_activity_gated_event_oav_snapshot_triggered(self, mock_ispyb_conn): - callback = GridscanISPyBCallback() + callback = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) callback.activity_gated_start(TestData.test_gridscan3d_start_document) # pyright: ignore mx_acq = mx_acquisition_from_conn(mock_ispyb_conn) mx_acq.upsert_data_collection_group.reset_mock() diff --git a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_handler.py b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_handler.py index 7578060f7..e090b6355 100644 --- a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_handler.py +++ b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_handler.py @@ -12,6 +12,7 @@ ) from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER from mx_bluesky.hyperion.external_interaction.callbacks.__main__ import setup_logging +from mx_bluesky.hyperion.parameters.gridscan import GridCommonWithHyperionDetectorParams from .....conftest import TestData @@ -52,7 +53,9 @@ class TestXrayCentreIspybHandler: def test_fgs_failing_results_in_bad_run_status_in_ispyb( self, ): - ispyb_handler = GridscanISPyBCallback() + ispyb_handler = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_handler.activity_gated_start(td.test_gridscan3d_start_document) ispyb_handler.activity_gated_descriptor( td.test_descriptor_document_pre_data_collection @@ -79,7 +82,9 @@ def test_fgs_failing_results_in_bad_run_status_in_ispyb( def test_fgs_raising_no_exception_results_in_good_run_status_in_ispyb( self, ): - ispyb_handler = GridscanISPyBCallback() + ispyb_handler = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_handler.activity_gated_start(td.test_gridscan3d_start_document) ispyb_handler.activity_gated_descriptor( td.test_descriptor_document_pre_data_collection @@ -111,12 +116,14 @@ def test_given_ispyb_callback_started_writing_to_ispyb_when_messages_logged_then gelf_handler: MagicMock = next( filter( lambda h: isinstance(h, GELFTCPHandler), - ISPYB_ZOCALO_CALLBACK_LOGGER.handlers, - ) # type: ignore + ISPYB_ZOCALO_CALLBACK_LOGGER.handlers, # type: ignore + ) ) gelf_handler.emit = MagicMock() - ispyb_handler = GridscanISPyBCallback() + ispyb_handler = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_handler.activity_gated_start(td.test_gridscan3d_start_document) ispyb_handler.activity_gated_descriptor( td.test_descriptor_document_pre_data_collection @@ -141,12 +148,14 @@ def test_given_ispyb_callback_finished_writing_to_ispyb_when_messages_logged_the gelf_handler: MagicMock = next( filter( lambda h: isinstance(h, GELFTCPHandler), - ISPYB_ZOCALO_CALLBACK_LOGGER.handlers, - ) # type: ignore + ISPYB_ZOCALO_CALLBACK_LOGGER.handlers, # type: ignore + ) ) gelf_handler.emit = MagicMock() - ispyb_handler = GridscanISPyBCallback() + ispyb_handler = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_handler.activity_gated_start(td.test_gridscan3d_start_document) ispyb_handler.activity_gated_descriptor( td.test_descriptor_document_pre_data_collection @@ -171,7 +180,9 @@ def test_given_ispyb_callback_finished_writing_to_ispyb_when_messages_logged_the def test_given_fgs_plan_finished_when_zocalo_results_event_then_expected_comment_deposited( self, mock_time ): - ispyb_handler = GridscanISPyBCallback() + ispyb_handler = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) ispyb_handler.activity_gated_start(td.test_gridscan3d_start_document) # type:ignore diff --git a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_mapping.py b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_mapping.py index 03c2a6588..69e9bc255 100644 --- a/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_mapping.py +++ b/tests/unit_tests/common/external_interaction/xray_centre/test_ispyb_mapping.py @@ -9,7 +9,7 @@ DataCollectionGridInfo, Orientation, ) -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from .....conftest import ( TEST_SAMPLE_ID, @@ -19,7 +19,7 @@ @pytest.fixture def dummy_params(): - dummy_params = HyperionThreeDGridScan(**default_raw_gridscan_params()) + dummy_params = HyperionSpecifiedThreeDGridScan(**default_raw_gridscan_params()) dummy_params.sample_id = TEST_SAMPLE_ID dummy_params.run_number = 0 return dummy_params @@ -67,7 +67,7 @@ def test_ispyb_deposition_rounds_position_to_int( ) def test_ispyb_deposition_rounds_box_size_int( bottom_right_from_top_left: MagicMock, - dummy_params: HyperionThreeDGridScan, + dummy_params: HyperionSpecifiedThreeDGridScan, raw, rounded, ): diff --git a/tests/unit_tests/common/external_interaction/xray_centre/test_nexus_handler.py b/tests/unit_tests/common/external_interaction/xray_centre/test_nexus_handler.py index acb940d99..350c8c4e5 100644 --- a/tests/unit_tests/common/external_interaction/xray_centre/test_nexus_handler.py +++ b/tests/unit_tests/common/external_interaction/xray_centre/test_nexus_handler.py @@ -8,6 +8,7 @@ from mx_bluesky.common.external_interaction.callbacks.xray_centre.nexus_callback import ( GridscanNexusFileCallback, ) +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from .....conftest import TestData @@ -23,7 +24,9 @@ def nexus_writer(): def test_writers_not_sDTypeLikeetup_on_plan_start_doc( nexus_writer: MagicMock, ): - nexus_handler = GridscanNexusFileCallback() + nexus_handler = GridscanNexusFileCallback( + param_type=HyperionSpecifiedThreeDGridScan + ) nexus_writer.assert_not_called() nexus_handler.activity_gated_start(TestData.test_start_document) nexus_writer.assert_not_called() @@ -36,7 +39,9 @@ def test_writers_dont_create_on_init_but_do_on_during_collection_read_event( mock_nexus_writer: MagicMock, ): mock_nexus_writer.side_effect = [MagicMock(), MagicMock()] - nexus_handler = GridscanNexusFileCallback() + nexus_handler = GridscanNexusFileCallback( + param_type=HyperionSpecifiedThreeDGridScan + ) assert nexus_handler.nexus_writer_1 is None assert nexus_handler.nexus_writer_2 is None @@ -73,7 +78,9 @@ def test_given_different_bit_depths_then_writers_created_wth_correct_VDS_size( vds_type: DTypeLike, ): mock_nexus_writer.side_effect = [MagicMock(), MagicMock()] - nexus_handler = GridscanNexusFileCallback() + nexus_handler = GridscanNexusFileCallback( + param_type=HyperionSpecifiedThreeDGridScan + ) nexus_handler.activity_gated_start(TestData.test_start_document) nexus_handler.activity_gated_descriptor( @@ -101,7 +108,9 @@ def test_beam_and_attenuator_set_on_ispyb_transmission_event( mock_nexus_writer: MagicMock, ): mock_nexus_writer.side_effect = [MagicMock(), MagicMock()] - nexus_handler = GridscanNexusFileCallback() + nexus_handler = GridscanNexusFileCallback( + param_type=HyperionSpecifiedThreeDGridScan + ) nexus_handler.activity_gated_start(TestData.test_start_document) nexus_handler.activity_gated_descriptor( @@ -120,7 +129,9 @@ def test_beam_and_attenuator_set_on_ispyb_transmission_event( def test_sensible_error_if_writing_triggered_before_params_received( nexus_writer: MagicMock, ): - nexus_handler = GridscanNexusFileCallback() + nexus_handler = GridscanNexusFileCallback( + param_type=HyperionSpecifiedThreeDGridScan + ) with pytest.raises(AssertionError) as excinfo: nexus_handler.activity_gated_descriptor( TestData.test_descriptor_document_during_data_collection diff --git a/tests/unit_tests/hyperion/device_setup_plans/test_manipulate_sample.py b/tests/unit_tests/hyperion/device_setup_plans/test_manipulate_sample.py index 04cea4328..f9a8b3c85 100644 --- a/tests/unit_tests/hyperion/device_setup_plans/test_manipulate_sample.py +++ b/tests/unit_tests/hyperion/device_setup_plans/test_manipulate_sample.py @@ -12,7 +12,7 @@ from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import ( FlyScanXRayCentreComposite, ) -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan @pytest.mark.parametrize( @@ -61,7 +61,7 @@ async def test_move_aperture_does_nothing_when_none_selected( @patch("bluesky.plan_stubs.abs_set", autospec=True) def test_move_x_y_z( bps_abs_set: MagicMock, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, fake_fgs_composite: FlyScanXRayCentreComposite, RE: RunEngine, motor_position: list[float], @@ -102,7 +102,7 @@ def test_move_x_y_z( @patch("bluesky.plan_stubs.abs_set", autospec=True) def test_move_phi_chi_omega( bps_abs_set: MagicMock, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, fake_fgs_composite: FlyScanXRayCentreComposite, RE: RunEngine, motor_position: list[float], diff --git a/tests/unit_tests/hyperion/experiment_plans/conftest.py b/tests/unit_tests/hyperion/experiment_plans/conftest.py index 2b3f15026..9c5cf53d0 100644 --- a/tests/unit_tests/hyperion/experiment_plans/conftest.py +++ b/tests/unit_tests/hyperion/experiment_plans/conftest.py @@ -47,7 +47,7 @@ create_gridscan_callbacks, ) from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan FLYSCAN_RESULT_HIGH = XRayCentreResult( centre_of_mass_mm=np.array([0.1, 0.2, 0.3]), @@ -181,7 +181,7 @@ async def mock_complete(results): def run_generic_ispyb_handler_setup( ispyb_handler: GridscanISPyBCallback, - params: HyperionThreeDGridScan, + params: HyperionSpecifiedThreeDGridScan, ): """This is useful when testing 'run_gridscan_and_move(...)' because this stuff happens at the start of the outer plan.""" diff --git a/tests/unit_tests/hyperion/experiment_plans/test_change_aperture_then_move_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_change_aperture_then_move_plan.py index 200a6442c..56d7c4ad5 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_change_aperture_then_move_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_change_aperture_then_move_plan.py @@ -8,7 +8,7 @@ change_aperture_then_move_to_xtal, ) from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan @pytest.fixture @@ -30,7 +30,7 @@ def test_change_aperture_then_move_to_xtal_happy_path( simple_flyscan_hit: XRayCentreResult, smargon: Smargon, aperture_scatterguard: ApertureScatterguard, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, set_stub_offsets: bool, ): test_fgs_params.features.set_stub_offsets = set_stub_offsets diff --git a/tests/unit_tests/hyperion/experiment_plans/test_flyscan_xray_centre_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_flyscan_xray_centre_plan.py index db0c21dfd..a1f088945 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_flyscan_xray_centre_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_flyscan_xray_centre_plan.py @@ -69,7 +69,10 @@ ) from mx_bluesky.hyperion.external_interaction.config_server import HyperionFeatureFlags from mx_bluesky.hyperion.parameters.constants import CONST -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import ( + GridCommonWithHyperionDetectorParams, + HyperionSpecifiedThreeDGridScan, +) from tests.conftest import ( RunEngineSimulator, create_dummy_scan_spec, @@ -103,7 +106,8 @@ def fgs_composite_with_panda_pcap(fake_fgs_composite: FlyScanXRayCentreComposite @pytest.fixture def fgs_params_use_panda( - test_fgs_params: HyperionThreeDGridScan, feature_flags: HyperionFeatureFlags + test_fgs_params: HyperionSpecifiedThreeDGridScan, + feature_flags: HyperionFeatureFlags, ): feature_flags.use_panda_for_gridscan = True test_fgs_params.features = feature_flags @@ -114,7 +118,7 @@ def fgs_params_use_panda( def test_fgs_params_panda_zebra( request: pytest.FixtureRequest, feature_flags: HyperionFeatureFlags, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, ): if request.param: feature_flags.use_panda_for_gridscan = request.param @@ -123,7 +127,7 @@ def test_fgs_params_panda_zebra( @pytest.fixture -def ispyb_plan(test_fgs_params: HyperionThreeDGridScan): +def ispyb_plan(test_fgs_params: HyperionSpecifiedThreeDGridScan): @bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_OUTER) @bpp.run_decorator( # attach experiment metadata to the start document md={ @@ -158,7 +162,7 @@ def mock_ispyb(): @pytest.fixture def feature_controlled( fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, ) -> _FeatureControlled: return _get_feature_controlled(fake_fgs_composite, test_fgs_params_panda_zebra) @@ -176,7 +180,7 @@ class TestFlyscanXrayCentrePlan: def test_eiger2_x_16_detector_specified( self, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, ): assert ( test_fgs_params.detector_params.detector_size_constants.det_type_string @@ -193,10 +197,12 @@ def test_when_run_gridscan_called_ispyb_deposition_made_and_records_errors( self, RE: RunEngine, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, mock_ispyb: MagicMock, ): - ispyb_callback = GridscanISPyBCallback() + ispyb_callback = GridscanISPyBCallback( + param_type=GridCommonWithHyperionDetectorParams + ) RE.subscribe(ispyb_callback) error = None @@ -217,7 +223,7 @@ def test_when_run_gridscan_called_ispyb_deposition_made_and_records_errors( def test_read_hardware_for_ispyb_updates_from_ophyd_devices( self, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, RE: RunEngine, ispyb_plan, ): @@ -338,7 +344,7 @@ async def test_results_adjusted_and_event_raised( run_gridscan: MagicMock, move_aperture: MagicMock, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, feature_controlled: _FeatureControlled, RE_with_subs: ReWithSubs, ): @@ -393,7 +399,7 @@ def test_results_adjusted_and_passed_to_move_xyz( run_gridscan: MagicMock, move_aperture: MagicMock, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, RE_with_subs: ReWithSubs, ): RE, _ = RE_with_subs @@ -431,7 +437,7 @@ def test_results_adjusted_and_passed_to_move_xyz( def test_results_passed_to_move_motors( self, bps_abs_set: MagicMock, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, fake_fgs_composite: FlyScanXRayCentreComposite, RE: RunEngine, ): @@ -485,7 +491,7 @@ def test_individual_plans_triggered_once_and_only_once_in_composite_run( move_aperture: MagicMock, RE_with_subs: ReWithSubs, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, ): RE, (_, ispyb_cb) = RE_with_subs @@ -517,7 +523,7 @@ async def test_when_gridscan_finished_then_dev_shm_disabled( run_gridscan: MagicMock, aperture_set: MagicMock, RE_with_subs: ReWithSubs, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, feature_controlled: _FeatureControlled, ): @@ -559,7 +565,7 @@ def test_when_gridscan_succeeds_ispyb_comment_appended_to( run_gridscan: MagicMock, aperture_set: MagicMock, RE_with_subs: ReWithSubs, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, feature_controlled: _FeatureControlled, ): @@ -594,7 +600,7 @@ def test_waits_for_motion_program( self, check_topup_and_wait, RE: RunEngine, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, fake_fgs_composite: FlyScanXRayCentreComposite, done_status: Status, ): @@ -641,7 +647,7 @@ def test_when_gridscan_finds_no_xtal_ispyb_comment_appended_to( move_xyz: MagicMock, run_gridscan: MagicMock, RE_with_subs: ReWithSubs, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, feature_controlled: _FeatureControlled, ): @@ -683,7 +689,7 @@ def test_when_gridscan_finds_no_xtal_exception_is_raised( move_xyz: MagicMock, run_gridscan: MagicMock, RE_with_subs: ReWithSubs, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, feature_controlled: _FeatureControlled, ): @@ -777,7 +783,7 @@ def test_when_grid_scan_ran_then_eiger_disarmed_before_zocalo_end( mock_kickoff, mock_abs_set, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, RE_with_subs: ReWithSubs, ): test_fgs_params.x_steps = 9 @@ -834,7 +840,7 @@ def test_flyscan_xray_centre_sets_directory_stages_arms_disarms_unstages_the_pan mock_set_panda_directory: MagicMock, done_status: Status, fgs_composite_with_panda_pcap: FlyScanXRayCentreComposite, - fgs_params_use_panda: HyperionThreeDGridScan, + fgs_params_use_panda: HyperionSpecifiedThreeDGridScan, sim_run_engine: RunEngineSimulator, ): sim_run_engine.add_handler("unstage", lambda _: done_status) @@ -897,7 +903,7 @@ def test_fgs_arms_eiger_without_grid_detect( mock_complete, mock_wait, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, RE: RunEngine, done_status: Status, feature_controlled: _FeatureControlled, @@ -934,7 +940,7 @@ def test_when_grid_scan_fails_with_exception_then_detector_disarmed_and_correct_ mock_wait, mock_kickoff, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, RE: RunEngine, feature_controlled: _FeatureControlled, ): @@ -1045,7 +1051,7 @@ def test_kickoff_and_complete_gridscan_triggers_zocalo( def test_read_hardware_during_collection_occurs_after_eiger_arm( self, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, sim_run_engine: RunEngineSimulator, feature_controlled: _FeatureControlled, ): @@ -1084,7 +1090,7 @@ def test_read_hardware_during_collection_occurs_after_eiger_arm( def test_if_smargon_speed_over_limit_then_log_error( self, mock_kickoff_and_complete: MagicMock, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, fake_fgs_composite: FlyScanXRayCentreComposite, feature_controlled: _FeatureControlled, RE: RunEngine, @@ -1111,7 +1117,7 @@ def test_if_smargon_speed_over_limit_then_log_error( def test_run_gridscan_and_fetch_results_discards_results_below_threshold( self, fake_fgs_composite: FlyScanXRayCentreComposite, - test_fgs_params_panda_zebra: HyperionThreeDGridScan, + test_fgs_params_panda_zebra: HyperionSpecifiedThreeDGridScan, feature_controlled: _FeatureControlled, RE: RunEngine, ): diff --git a/tests/unit_tests/hyperion/experiment_plans/test_grid_detect_then_xray_centre_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_grid_detect_then_xray_centre_plan.py index e3bc7fcc9..c328d39dc 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_grid_detect_then_xray_centre_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_grid_detect_then_xray_centre_plan.py @@ -17,7 +17,6 @@ from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import ( ispyb_activation_wrapper, ) -from mx_bluesky.common.parameters.gridscan import GridScanWithEdgeDetect from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import ( _fire_xray_centre_result_event, ) @@ -28,7 +27,8 @@ ) from mx_bluesky.hyperion.parameters.constants import CONST from mx_bluesky.hyperion.parameters.gridscan import ( - HyperionThreeDGridScan, + GridScanWithEdgeDetect, + HyperionSpecifiedThreeDGridScan, ) from ....conftest import OavGridSnapshotTestEvents @@ -40,7 +40,7 @@ def _fake_flyscan(*args): def test_full_grid_scan( - test_fgs_params: HyperionThreeDGridScan, test_config_files: dict[str, str] + test_fgs_params: HyperionSpecifiedThreeDGridScan, test_config_files: dict[str, str] ): devices = MagicMock() plan = grid_detect_then_xray_centre( @@ -134,7 +134,7 @@ def test_when_full_grid_scan_run_then_parameters_sent_to_fgs_as_expected( ) ) - params: HyperionThreeDGridScan = mock_flyscan.call_args[0][1] + params: HyperionSpecifiedThreeDGridScan = mock_flyscan.call_args[0][1] assert params.detector_params.num_triggers == 180 assert params.FGS_params.x_axis.full_steps == 15 diff --git a/tests/unit_tests/hyperion/experiment_plans/test_grid_detection_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_grid_detection_plan.py index 40be33a4b..2bbe54d10 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_grid_detection_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_grid_detection_plan.py @@ -31,7 +31,10 @@ get_min_and_max_y_of_pin, grid_detection_plan, ) -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import ( + GridCommonWithHyperionDetectorParams, + HyperionSpecifiedThreeDGridScan, +) from .conftest import assert_event @@ -227,12 +230,12 @@ async def test_when_grid_detection_plan_run_then_ispyb_callback_gets_correct_val fake_devices: tuple[OavGridDetectionComposite, MagicMock], RE: RunEngine, test_config_files: dict[str, str], - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, tmp_path: Path, ): params = OAVParameters("loopCentring", test_config_files["oav_config_json"]) composite, _ = fake_devices - cb = GridscanISPyBCallback() + cb = GridscanISPyBCallback(param_type=GridCommonWithHyperionDetectorParams) RE.subscribe(cb) with patch.multiple(cb, activity_gated_start=DEFAULT, activity_gated_event=DEFAULT): @@ -287,7 +290,7 @@ def test_when_grid_detection_plan_run_then_grid_detection_callback_gets_correct_ fake_devices: tuple[OavGridDetectionComposite, MagicMock], RE: RunEngine, test_config_files: dict[str, str], - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, tmp_path: Path, ): params = OAVParameters("loopCentring", test_config_files["oav_config_json"]) diff --git a/tests/unit_tests/hyperion/experiment_plans/test_load_centre_collect_full_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_load_centre_collect_full_plan.py index 5350ca885..5522c3f5a 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_load_centre_collect_full_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_load_centre_collect_full_plan.py @@ -16,7 +16,6 @@ from ophyd_async.testing import set_mock_value from pydantic import ValidationError -from mx_bluesky.common.parameters.robot_load import RobotLoadAndEnergyChange from mx_bluesky.common.utils.exceptions import WarningException from mx_bluesky.hyperion.device_setup_plans.check_beamstop import BeamstopException from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import ( @@ -34,6 +33,7 @@ ) from mx_bluesky.hyperion.parameters.constants import CONST from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange from mx_bluesky.hyperion.parameters.rotation import ( MultiRotationScan, RotationScanPerSweep, diff --git a/tests/unit_tests/hyperion/experiment_plans/test_pin_centre_then_xray_centre_plan.py b/tests/unit_tests/hyperion/experiment_plans/test_pin_centre_then_xray_centre_plan.py index 6a1e647a1..ea6efc868 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_pin_centre_then_xray_centre_plan.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_pin_centre_then_xray_centre_plan.py @@ -11,9 +11,6 @@ from dodal.devices.smargon import Smargon from dodal.devices.synchrotron import SynchrotronMode -from mx_bluesky.common.parameters.gridscan import ( - PinTipCentreThenXrayCentre, -) from mx_bluesky.hyperion.device_setup_plans.check_beamstop import BeamstopException from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import ( _fire_xray_centre_result_event, @@ -27,6 +24,9 @@ pin_tip_centre_then_xray_centre, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.gridscan import ( + PinTipCentreThenXrayCentre, +) from ....conftest import raw_params_from_file, simulate_xrc_result from ....system_tests.hyperion.external_interaction.conftest import ( diff --git a/tests/unit_tests/hyperion/experiment_plans/test_robot_load_and_change_energy.py b/tests/unit_tests/hyperion/experiment_plans/test_robot_load_and_change_energy.py index bcd7f02a9..1b38a0467 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_robot_load_and_change_energy.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_robot_load_and_change_energy.py @@ -13,7 +13,6 @@ from ophyd.sim import NullStatus from ophyd_async.testing import set_mock_value -from mx_bluesky.common.parameters.robot_load import RobotLoadAndEnergyChange from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import ( RobotLoadAndEnergyChangeComposite, SampleLocation, @@ -25,6 +24,7 @@ from mx_bluesky.hyperion.external_interaction.callbacks.robot_load.ispyb_callback import ( RobotLoadISPyBCallback, ) +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange from ....conftest import raw_params_from_file diff --git a/tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py b/tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py index a65e7fd80..3479ed07e 100644 --- a/tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py +++ b/tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py @@ -8,10 +8,6 @@ from dodal.devices.i03.beamstop import BeamstopPositions from dodal.devices.robot import SampleLocation -from mx_bluesky.common.parameters.gridscan import ( - PinTipCentreThenXrayCentre, - RobotLoadThenCentre, -) from mx_bluesky.hyperion.device_setup_plans.check_beamstop import BeamstopException from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import ( _fire_xray_centre_result_event, @@ -24,6 +20,10 @@ robot_load_then_centre, ) from mx_bluesky.hyperion.parameters.constants import CONST +from mx_bluesky.hyperion.parameters.gridscan import ( + PinTipCentreThenXrayCentre, +) +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre from ....conftest import assert_none_matching, raw_params_from_file from .conftest import FLYSCAN_RESULT_LOW, FLYSCAN_RESULT_MED, sim_fire_event_on_open_run @@ -515,7 +515,7 @@ def test_tip_offset_um_passed_to_pin_tip_centre_plan( ): robot_load_then_centre_params.tip_offset_um = 100 assert ( - robot_load_then_centre_params.pin_centre_then_xray_centre_params().tip_offset_um + robot_load_then_centre_params.pin_centre_then_xray_centre_params.tip_offset_um == 100 ) diff --git a/tests/unit_tests/hyperion/external_interaction/conftest.py b/tests/unit_tests/hyperion/external_interaction/conftest.py index 71d7c0110..c2817cbdf 100644 --- a/tests/unit_tests/hyperion/external_interaction/conftest.py +++ b/tests/unit_tests/hyperion/external_interaction/conftest.py @@ -3,7 +3,7 @@ import pytest from mx_bluesky.common.utils.utils import convert_angstrom_to_eV -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from mx_bluesky.hyperion.parameters.rotation import RotationScan from ....conftest import ( @@ -32,7 +32,7 @@ def test_rotation_params(): @pytest.fixture(params=[1050]) def test_fgs_params(request): assert request.param % 25 == 0, "Please use a multiple of 25 images" - params = HyperionThreeDGridScan(**default_raw_gridscan_params()) + params = HyperionSpecifiedThreeDGridScan(**default_raw_gridscan_params()) params.demand_energy_ev = convert_angstrom_to_eV(1.0) params.use_roi_mode = True first_scan_img = (request.param // 10) * 6 diff --git a/tests/unit_tests/hyperion/external_interaction/nexus/test_write_nexus.py b/tests/unit_tests/hyperion/external_interaction/nexus/test_write_nexus.py index 02ba42d6f..d3e191734 100644 --- a/tests/unit_tests/hyperion/external_interaction/nexus/test_write_nexus.py +++ b/tests/unit_tests/hyperion/external_interaction/nexus/test_write_nexus.py @@ -21,7 +21,7 @@ create_beam_and_attenuator_parameters, ) from mx_bluesky.common.external_interaction.nexus.write_nexus import NexusWriter -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan """It's hard to effectively unit test the nexus writing so these are really system tests that confirms that we're passing the right sorts of data to nexgen to get a sensible output. @@ -38,7 +38,7 @@ def assert_end_data_correct(nexus_writer: NexusWriter): assert "end_time_estimated" in entry -def create_nexus_writer(parameters: HyperionThreeDGridScan, writer_num): +def create_nexus_writer(parameters: HyperionSpecifiedThreeDGridScan, writer_num): d_size = parameters.detector_params.detector_size_constants.det_size_pixels n_img = ( parameters.scan_indices[1] @@ -71,7 +71,7 @@ def create_nexus_writer(parameters: HyperionThreeDGridScan, writer_num): @contextmanager -def create_nexus_writers(parameters: HyperionThreeDGridScan): +def create_nexus_writers(parameters: HyperionSpecifiedThreeDGridScan): writers = [create_nexus_writer(parameters, i) for i in [1, 2]] writers[1].start_index = parameters.scan_indices[1] try: @@ -84,7 +84,7 @@ def create_nexus_writers(parameters: HyperionThreeDGridScan): @pytest.fixture -def dummy_nexus_writers(test_fgs_params: HyperionThreeDGridScan): +def dummy_nexus_writers(test_fgs_params: HyperionSpecifiedThreeDGridScan): with create_nexus_writers(test_fgs_params) as ( nexus_writer_1, nexus_writer_2, @@ -93,7 +93,9 @@ def dummy_nexus_writers(test_fgs_params: HyperionThreeDGridScan): @pytest.fixture -def dummy_nexus_writers_with_more_images(test_fgs_params: HyperionThreeDGridScan): +def dummy_nexus_writers_with_more_images( + test_fgs_params: HyperionSpecifiedThreeDGridScan, +): x, y, z = 45, 35, 25 test_fgs_params.x_steps = x test_fgs_params.y_steps = y @@ -106,7 +108,7 @@ def dummy_nexus_writers_with_more_images(test_fgs_params: HyperionThreeDGridScan @pytest.fixture -def single_dummy_file(test_fgs_params: HyperionThreeDGridScan): +def single_dummy_file(test_fgs_params: HyperionSpecifiedThreeDGridScan): test_fgs_params.use_roi_mode = True d_size = test_fgs_params.detector_params.detector_size_constants.det_size_pixels data_shape = (test_fgs_params.scan_indices[1], d_size.width, d_size.height) @@ -128,7 +130,7 @@ def single_dummy_file(test_fgs_params: HyperionThreeDGridScan): indirect=["test_fgs_params"], ) def test_given_number_of_images_above_1000_then_expected_datafiles_used( - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, expected_num_of_files: Literal[3, 4, 9], single_dummy_file: NexusWriter, ): @@ -146,7 +148,7 @@ def test_given_number_of_images_above_1000_then_expected_datafiles_used( def test_given_dummy_data_then_datafile_written_correctly( - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, dummy_nexus_writers: tuple[NexusWriter, NexusWriter], ): nexus_writer_1, nexus_writer_2 = dummy_nexus_writers @@ -322,7 +324,7 @@ def assert_contains_external_link(data_path, entry_name, file_name): def test_nexus_writer_files_are_formatted_as_expected( - test_fgs_params: HyperionThreeDGridScan, single_dummy_file: NexusWriter + test_fgs_params: HyperionSpecifiedThreeDGridScan, single_dummy_file: NexusWriter ): for file in [single_dummy_file.nexus_file, single_dummy_file.master_file]: file_name = os.path.basename(file.name) @@ -342,7 +344,7 @@ def test_nexus_writer_writes_width_and_height_correctly(single_dummy_file: Nexus @patch.dict(os.environ, {"BEAMLINE": "I03"}) def test_nexus_writer_writes_beamline_name_correctly( - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, ): d_size = test_fgs_params.detector_params.detector_size_constants.det_size_pixels data_shape = (test_fgs_params.num_images, d_size.width, d_size.height) @@ -410,7 +412,7 @@ def test_given_some_datafiles_outside_of_VDS_range_THEN_they_are_not_in_nexus_fi def test_given_data_files_not_yet_written_when_nexus_files_created_then_nexus_files_still_written( - test_fgs_params: HyperionThreeDGridScan, + test_fgs_params: HyperionSpecifiedThreeDGridScan, ): test_fgs_params.file_name = "non_existant_file" with create_nexus_writers(test_fgs_params) as ( diff --git a/tests/unit_tests/hyperion/parameters/test_parameter_model.py b/tests/unit_tests/hyperion/parameters/test_parameter_model.py index 7124ee86f..9ac8c2370 100644 --- a/tests/unit_tests/hyperion/parameters/test_parameter_model.py +++ b/tests/unit_tests/hyperion/parameters/test_parameter_model.py @@ -6,17 +6,36 @@ from dodal.devices.aperturescatterguard import ApertureValue from pydantic import ValidationError +from mx_bluesky.common.external_interaction.callbacks.common.grid_detection_callback import ( + GridParamUpdate, +) from mx_bluesky.common.parameters.constants import GridscanParamConstants -from mx_bluesky.common.parameters.gridscan import RobotLoadThenCentre +from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import ( + create_parameters_for_flyscan_xray_centre, +) +from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan import ( + create_parameters_for_grid_detection, +) from mx_bluesky.hyperion.parameters.gridscan import ( - HyperionThreeDGridScan, + HyperionSpecifiedThreeDGridScan, OddYStepsException, ) +from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect +from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre from mx_bluesky.hyperion.parameters.rotation import RotationScan from ....conftest import raw_params_from_file +@pytest.fixture +def load_centre_collect_params_with_panda(): + params = raw_params_from_file( + "tests/test_data/parameter_json_files/good_test_load_centre_collect_params.json" + ) + params["robot_load_then_centre"]["features"]["use_panda_for_gridscan"] = True + return LoadCentreCollect(**params) + + @pytest.fixture def minimal_3d_gridscan_params(): return { @@ -36,8 +55,24 @@ def minimal_3d_gridscan_params(): } +def get_empty_grid_parameters() -> GridParamUpdate: + return { + "x_start_um": 1, + "y_start_um": 1, + "y2_start_um": 1, + "z_start_um": 1, + "z2_start_um": 1, + "x_steps": 1, + "y_steps": 1, + "z_steps": 1, + "x_step_size_um": 1, + "y_step_size_um": 1, + "z_step_size_um": 1, + } + + def test_minimal_3d_gridscan_params(minimal_3d_gridscan_params): - test_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + test_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert {"sam_x", "sam_y", "sam_z"} == set(test_params.scan_points.keys()) assert test_params.scan_indices == [0, 35] assert test_params.num_images == (5 * 7 + 5 * 9) @@ -45,16 +80,16 @@ def test_minimal_3d_gridscan_params(minimal_3d_gridscan_params): def test_cant_do_panda_fgs_with_odd_y_steps(minimal_3d_gridscan_params): - test_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + test_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) with pytest.raises(OddYStepsException): _ = test_params.panda_FGS_params assert test_params.FGS_params def test_serialise_deserialise(minimal_3d_gridscan_params): - test_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + test_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) serialised = json.loads(test_params.model_dump_json()) - deserialised = HyperionThreeDGridScan(**serialised) + deserialised = HyperionSpecifiedThreeDGridScan(**serialised) assert deserialised.demand_energy_ev is None assert deserialised.visit == "cm12345" assert deserialised.x_start_um == 0.123 @@ -63,16 +98,16 @@ def test_serialise_deserialise(minimal_3d_gridscan_params): def test_param_version(minimal_3d_gridscan_params): with pytest.raises(ValidationError): minimal_3d_gridscan_params["parameter_model_version"] = "4.3.0" - _ = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + _ = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) minimal_3d_gridscan_params["parameter_model_version"] = "5.0.0" - _ = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + _ = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) minimal_3d_gridscan_params["parameter_model_version"] = "5.3.0" - _ = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + _ = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) minimal_3d_gridscan_params["parameter_model_version"] = "5.3.7" - _ = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + _ = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) with pytest.raises(ValidationError): minimal_3d_gridscan_params["parameter_model_version"] = "6.3.7" - _ = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + _ = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) def test_robot_load_then_centre_params(): @@ -89,7 +124,7 @@ def test_robot_load_then_centre_params(): def test_default_snapshot_path(minimal_3d_gridscan_params): - gridscan_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + gridscan_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert gridscan_params.snapshot_directory == Path( "/tmp/dls/i03/data/2024/cm31105-4/xraycentring/123456/snapshots" ) @@ -97,7 +132,7 @@ def test_default_snapshot_path(minimal_3d_gridscan_params): params_with_snapshot_path = dict(minimal_3d_gridscan_params) params_with_snapshot_path["snapshot_directory"] = "/tmp/my_snapshots" - gridscan_params_with_snapshot_path = HyperionThreeDGridScan( + gridscan_params_with_snapshot_path = HyperionSpecifiedThreeDGridScan( **params_with_snapshot_path ) assert gridscan_params_with_snapshot_path.snapshot_directory == Path( @@ -126,14 +161,14 @@ def test_selected_aperture_uses_default(): def test_feature_flags_overriden_if_supplied(minimal_3d_gridscan_params): - test_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + test_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert test_params.features.use_panda_for_gridscan is False assert test_params.features.compare_cpu_and_gpu_zocalo is False minimal_3d_gridscan_params["features"] = { "use_panda_for_gridscan": True, "compare_cpu_and_gpu_zocalo": True, } - test_params = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + test_params = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert test_params.features.compare_cpu_and_gpu_zocalo assert test_params.features.use_panda_for_gridscan # Config server shouldn't update values which were explicitly provided @@ -146,11 +181,35 @@ def test_feature_flags_overriden_if_supplied(minimal_3d_gridscan_params): def test_gpu_enabled_if_use_gpu_or_compare_gpu_enabled(_, minimal_3d_gridscan_params): minimal_3d_gridscan_params["detector_distance_mm"] = 100 - grid_scan = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + grid_scan = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert not grid_scan.detector_params.enable_dev_shm minimal_3d_gridscan_params["features"] = { "compare_cpu_and_gpu_zocalo": True, } - grid_scan = HyperionThreeDGridScan(**minimal_3d_gridscan_params) + grid_scan = HyperionSpecifiedThreeDGridScan(**minimal_3d_gridscan_params) assert grid_scan.detector_params.enable_dev_shm + + +def test_hyperion_params_correctly_carried_through_UDC_parameter_models( + load_centre_collect_params_with_panda: LoadCentreCollect, +): + robot_load_then_centre_params = ( + load_centre_collect_params_with_panda.robot_load_then_centre + ) + assert robot_load_then_centre_params.detector_params.enable_dev_shm + pin_tip_then_xrc_params = ( + robot_load_then_centre_params.pin_centre_then_xray_centre_params + ) + assert pin_tip_then_xrc_params.detector_params.enable_dev_shm + grid_detect_then_xrc_params = create_parameters_for_grid_detection( + pin_tip_then_xrc_params + ) + assert pin_tip_then_xrc_params.detector_params.enable_dev_shm + flyscan_xrc_params = create_parameters_for_flyscan_xray_centre( + grid_detect_then_xrc_params, get_empty_grid_parameters() + ) + assert flyscan_xrc_params.detector_params.enable_dev_shm + assert flyscan_xrc_params.panda_runup_distance_mm == 0.17 + assert flyscan_xrc_params.features.use_panda_for_gridscan + assert flyscan_xrc_params.features.compare_cpu_and_gpu_zocalo diff --git a/tests/unit_tests/hyperion/test_main_system.py b/tests/unit_tests/hyperion/test_main_system.py index 9792606a6..ea9d3fc10 100644 --- a/tests/unit_tests/hyperion/test_main_system.py +++ b/tests/unit_tests/hyperion/test_main_system.py @@ -31,7 +31,7 @@ ) from mx_bluesky.hyperion.experiment_plans.experiment_registry import PLAN_REGISTRY from mx_bluesky.hyperion.parameters.cli import parse_cli_args -from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan +from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan from mx_bluesky.hyperion.utils.context import device_composite_from_context from ...conftest import raw_params_from_file @@ -125,7 +125,7 @@ def mock_dict_values(d: dict): }, "fgs_real_params": { "setup": MagicMock(), - "param_type": HyperionThreeDGridScan, + "param_type": HyperionSpecifiedThreeDGridScan, "experiment_param_type": MagicMock(), "callback_collection_type": MagicMock(), }, @@ -474,7 +474,7 @@ def fake_create_devices(context) -> FakeComposite: autospec=True, ) def test_when_blueskyrunner_initiated_and_skip_flag_is_set_then_setup_called_upon_start( - mock_setup, test_fgs_params: HyperionThreeDGridScan + mock_setup, test_fgs_params: HyperionSpecifiedThreeDGridScan ): mock_setup = MagicMock() with patch.dict(