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 7a0b6c757..26fc3fe08 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 @@ -135,7 +135,7 @@ def flyscan_xray_centre( parameters.features.update_self_from_server() composite.eiger.set_detector_parameters(parameters.detector_params) composite.zocalo.zocalo_environment = parameters.zocalo_environment - composite.zocalo.use_cpu_and_gpu = parameters.compare_cpu_and_gpu_results + composite.zocalo.use_cpu_and_gpu = parameters.features.compare_cpu_and_gpu_zocalo feature_controlled = _get_feature_controlled(composite, parameters) diff --git a/src/mx_bluesky/hyperion/external_interaction/config_server.py b/src/mx_bluesky/hyperion/external_interaction/config_server.py index cfd89e161..d8f721179 100644 --- a/src/mx_bluesky/hyperion/external_interaction/config_server.py +++ b/src/mx_bluesky/hyperion/external_interaction/config_server.py @@ -1,5 +1,5 @@ from daq_config_server.client import ConfigServer -from pydantic import BaseModel +from pydantic import BaseModel, Field, model_validator from mx_bluesky.hyperion.log import LOGGER from mx_bluesky.hyperion.parameters.constants import CONST @@ -17,19 +17,31 @@ def config_server() -> ConfigServer: class FeatureFlags(BaseModel): # The default value will be used as the fallback when doing a best-effort fetch # from the service - use_panda_for_gridscan: bool = False - use_gpu_for_gridscan: bool = False - set_stub_offsets: bool = False + use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN + compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO + set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS + # Feature values supplied at construction will override values from the config server + overriden_features: dict = Field(default_factory=dict, exclude=True) + + @model_validator(mode="before") @classmethod - def _get_flags(cls): - flags = config_server().best_effort_get_all_feature_flags() - return {f: flags[f] for f in flags if f in cls.__fields__.keys()} + def mark_overridden_features(cls, values): + assert isinstance(values, dict) + values["overriden_features"] = values.copy() + return values @classmethod - def best_effort(cls): - return cls(**cls._get_flags()) + def _get_flags(cls): + flags = config_server().best_effort_get_all_feature_flags() + return {f: flags[f] for f in flags if f in cls.model_fields.keys()} def update_self_from_server(self): + """Used to update the feature flags from the server during a plan. Where there are flags which were explicitly set from externally supplied parameters, these values will be used instead.""" for flag, value in self._get_flags().items(): - setattr(self, flag, value) + updated_value = ( + value + if flag not in self.overriden_features.keys() + else self.overriden_features[flag] + ) + setattr(self, flag, updated_value) diff --git a/src/mx_bluesky/hyperion/parameters/constants.py b/src/mx_bluesky/hyperion/parameters/constants.py index aa6e06fb5..b7dda335e 100644 --- a/src/mx_bluesky/hyperion/parameters/constants.py +++ b/src/mx_bluesky/hyperion/parameters/constants.py @@ -114,6 +114,7 @@ class I03Constants: SHUTTER_TIME_S = 0.06 USE_PANDA_FOR_GRIDSCAN = False THAWING_TIME = 20 + SET_STUB_OFFSETS = False # Turns on GPU processing for zocalo and logs a comparison between GPU and CPU- # processed results. GPU results never used in analysis for now diff --git a/src/mx_bluesky/hyperion/parameters/gridscan.py b/src/mx_bluesky/hyperion/parameters/gridscan.py index e6c4d7c90..1d280f647 100644 --- a/src/mx_bluesky/hyperion/parameters/gridscan.py +++ b/src/mx_bluesky/hyperion/parameters/gridscan.py @@ -37,10 +37,6 @@ class GridCommon( panda_runup_distance_mm: float = Field( default=CONST.HARDWARE.PANDA_FGS_RUN_UP_DEFAULT ) - use_panda: bool = Field(default=CONST.I03.USE_PANDA_FOR_GRIDSCAN) - compare_cpu_and_gpu_results: bool = Field( - default=CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO - ) ispyb_experiment_type: IspybExperimentType = Field( default=IspybExperimentType.GRIDSCAN_3D ) @@ -73,7 +69,7 @@ def detector_params(self): 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.compare_cpu_and_gpu_results, + enable_dev_shm=self.features.compare_cpu_and_gpu_zocalo, **optional_args, ) diff --git a/tests/conftest.py b/tests/conftest.py index de94051b2..e4e27e41f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -229,7 +229,7 @@ def test_fgs_params(): @pytest.fixture def test_panda_fgs_params(test_fgs_params: ThreeDGridScan): - test_fgs_params.use_panda = True + test_fgs_params.features.use_panda_for_gridscan = True return test_fgs_params @@ -940,9 +940,7 @@ def assert_events_and_data_in_order( @pytest.fixture def feature_flags(): - return FeatureFlags( - **{field_name: False for field_name in FeatureFlags.model_fields.keys()} - ) + return FeatureFlags() def assert_none_matching( diff --git a/tests/test_data/parameter_json_files/example_load_centre_collect_params.json b/tests/test_data/parameter_json_files/example_load_centre_collect_params.json index 538b47549..2e7e7c10e 100644 --- a/tests/test_data/parameter_json_files/example_load_centre_collect_params.json +++ b/tests/test_data/parameter_json_files/example_load_centre_collect_params.json @@ -14,7 +14,6 @@ "transmission_frac": 1.0, "omega_start_deg": 0, "chi_start_deg": 30, - "use_panda": false }, "multi_rotation_scan": { "comment": "Hyperion Rotation Scan - ", diff --git a/tests/unit_tests/hyperion/parameters/test_parameter_model.py b/tests/unit_tests/hyperion/parameters/test_parameter_model.py index 7d07c7bc1..558d69b82 100644 --- a/tests/unit_tests/hyperion/parameters/test_parameter_model.py +++ b/tests/unit_tests/hyperion/parameters/test_parameter_model.py @@ -123,6 +123,23 @@ def test_selected_aperture_uses_default(): assert params.selected_aperture == ApertureValue.LARGE +def test_feature_flags_overriden_if_supplied(minimal_3d_gridscan_params): + test_params = ThreeDGridScan(**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 = ThreeDGridScan(**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 + test_params.features.update_self_from_server() + assert test_params.features.compare_cpu_and_gpu_zocalo + assert test_params.features.use_panda_for_gridscan + + @patch("mx_bluesky.hyperion.parameters.gridscan.os") def test_gpu_enabled_if_use_gpu_or_compare_gpu_enabled(_, minimal_3d_gridscan_params): minimal_3d_gridscan_params["detector_distance_mm"] = 100 @@ -130,6 +147,8 @@ def test_gpu_enabled_if_use_gpu_or_compare_gpu_enabled(_, minimal_3d_gridscan_pa grid_scan = ThreeDGridScan(**minimal_3d_gridscan_params) assert not grid_scan.detector_params.enable_dev_shm - minimal_3d_gridscan_params["compare_cpu_and_gpu_results"] = True + minimal_3d_gridscan_params["features"] = { + "compare_cpu_and_gpu_zocalo": True, + } grid_scan = ThreeDGridScan(**minimal_3d_gridscan_params) assert grid_scan.detector_params.enable_dev_shm