mx-bluesky 1.4.7__py3-none-any.whl → 1.4.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/aithre_lasershaping/__init__.py +8 -0
- mx_bluesky/beamlines/aithre_lasershaping/beamline_safe.py +36 -0
- mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +43 -0
- mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +4 -4
- mx_bluesky/beamlines/i04/thawing_plan.py +8 -2
- mx_bluesky/beamlines/i23/__init__.py +3 -0
- mx_bluesky/beamlines/i23/serial.py +71 -0
- mx_bluesky/beamlines/i24/serial/__init__.py +2 -0
- mx_bluesky/beamlines/i24/serial/blueapi_config.yaml +2 -1
- mx_bluesky/beamlines/i24/serial/dcid.py +5 -5
- mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DetStage.edl +2 -2
- mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +9 -9
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +25 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +2 -2
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +14 -14
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +5 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +29 -60
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +7 -1
- mx_bluesky/beamlines/i24/serial/log.py +9 -10
- mx_bluesky/beamlines/i24/serial/parameters/utils.py +36 -7
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +0 -1
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +4 -4
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +4 -12
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +2 -1
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +71 -11
- mx_bluesky/beamlines/i24/serial/write_nexus.py +3 -3
- mx_bluesky/{hyperion → common}/device_setup_plans/manipulate_sample.py +6 -14
- mx_bluesky/{hyperion → common}/device_setup_plans/setup_oav.py +12 -6
- mx_bluesky/{hyperion → common}/experiment_plans/change_aperture_then_move_plan.py +4 -5
- mx_bluesky/{hyperion → common}/experiment_plans/oav_grid_detection_plan.py +6 -6
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +6 -5
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +16 -47
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +4 -1
- mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +4 -4
- mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/common/parameters/components.py +22 -2
- mx_bluesky/common/parameters/constants.py +4 -16
- mx_bluesky/common/parameters/gridscan.py +36 -32
- mx_bluesky/common/plans/common_flyscan_xray_centre_plan.py +316 -0
- mx_bluesky/common/plans/inner_plans/__init__ .py +0 -0
- mx_bluesky/common/plans/read_hardware.py +3 -3
- mx_bluesky/common/utils/log.py +19 -15
- mx_bluesky/hyperion/__main__.py +6 -24
- mx_bluesky/hyperion/baton_handler.py +8 -3
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +4 -4
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +0 -33
- mx_bluesky/hyperion/device_setup_plans/smargon.py +2 -7
- mx_bluesky/hyperion/device_setup_plans/utils.py +6 -5
- mx_bluesky/hyperion/experiment_plans/__init__.py +1 -7
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -13
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +80 -87
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +183 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +50 -15
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +31 -7
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +1 -1
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +13 -14
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +9 -8
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +30 -71
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/external_interaction/agamemnon.py +78 -80
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +8 -6
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -3
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +6 -3
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +183 -31
- mx_bluesky/hyperion/external_interaction/config_server.py +4 -1
- mx_bluesky/hyperion/parameters/cli.py +4 -19
- mx_bluesky/hyperion/parameters/constants.py +1 -5
- mx_bluesky/hyperion/parameters/device_composites.py +40 -5
- mx_bluesky/hyperion/parameters/gridscan.py +9 -58
- mx_bluesky/hyperion/parameters/load_centre_collect.py +4 -4
- mx_bluesky/hyperion/parameters/rotation.py +9 -12
- mx_bluesky/hyperion/utils/context.py +2 -2
- mx_bluesky/hyperion/utils/validation.py +15 -19
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/METADATA +7 -6
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/RECORD +86 -83
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/WHEEL +1 -1
- mx_bluesky/common/external_interaction/test_config_server.py +0 -38
- mx_bluesky/hyperion/device_setup_plans/check_beamstop.py +0 -27
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +0 -467
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short1-laser.png → s1l.png} +0 -0
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short2-laser.png → s2l.png} +0 -0
- /mx_bluesky/{hyperion → common}/device_setup_plans/position_detector.py +0 -0
- /mx_bluesky/common/plans/{do_fgs.py → inner_plans/do_fgs.py} +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/top_level.txt +0 -0
|
@@ -9,8 +9,8 @@ from dodal.devices.oav.oav_detector import OAV
|
|
|
9
9
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
10
10
|
from dodal.devices.smargon import Smargon
|
|
11
11
|
|
|
12
|
+
from mx_bluesky.common.device_setup_plans.setup_oav import setup_general_oav_params
|
|
12
13
|
from mx_bluesky.common.parameters.components import WithSnapshot
|
|
13
|
-
from mx_bluesky.hyperion.device_setup_plans.setup_oav import setup_general_oav_params
|
|
14
14
|
from mx_bluesky.hyperion.parameters.constants import CONST, DocDescriptorNames
|
|
15
15
|
|
|
16
16
|
OAV_SNAPSHOT_SETUP_SHOT = "oav_snapshot_setup_shot"
|
|
@@ -29,13 +29,16 @@ def setup_beamline_for_OAV(
|
|
|
29
29
|
backlight: Backlight,
|
|
30
30
|
aperture_scatterguard: ApertureScatterguard,
|
|
31
31
|
group=CONST.WAIT.READY_FOR_OAV,
|
|
32
|
+
wait=False,
|
|
32
33
|
):
|
|
33
34
|
max_vel = yield from bps.rd(smargon.omega.max_velocity)
|
|
34
35
|
yield from bps.abs_set(smargon.omega.velocity, max_vel, group=group)
|
|
35
36
|
yield from bps.abs_set(backlight, BacklightPosition.IN, group=group)
|
|
36
37
|
yield from bps.abs_set(
|
|
37
|
-
aperture_scatterguard, ApertureValue.OUT_OF_BEAM, group=group
|
|
38
|
+
aperture_scatterguard.selected_aperture, ApertureValue.OUT_OF_BEAM, group=group
|
|
38
39
|
)
|
|
40
|
+
if wait:
|
|
41
|
+
yield from bps.wait(group)
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def oav_snapshot_plan(
|
|
@@ -45,9 +48,12 @@ def oav_snapshot_plan(
|
|
|
45
48
|
) -> MsgGenerator:
|
|
46
49
|
if not parameters.take_snapshots:
|
|
47
50
|
return
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
if parameters.use_grid_snapshots:
|
|
52
|
+
yield from _generate_oav_snapshots(composite, parameters)
|
|
53
|
+
else:
|
|
54
|
+
yield from _setup_oav(composite, parameters, oav_parameters)
|
|
55
|
+
for omega in parameters.snapshot_omegas_deg or []:
|
|
56
|
+
yield from _take_oav_snapshot(composite, omega)
|
|
51
57
|
|
|
52
58
|
|
|
53
59
|
def _setup_oav(
|
|
@@ -62,12 +68,24 @@ def _setup_oav(
|
|
|
62
68
|
)
|
|
63
69
|
|
|
64
70
|
|
|
71
|
+
def _generate_oav_snapshots(composite: OavSnapshotComposite, params: WithSnapshot):
|
|
72
|
+
"""Generate rotation snapshots from previously captured grid snapshots"""
|
|
73
|
+
yield from bps.abs_set(
|
|
74
|
+
composite.oav.snapshot.directory, str(params.snapshot_directory)
|
|
75
|
+
)
|
|
76
|
+
for _ in 0, 270:
|
|
77
|
+
yield from bps.create(DocDescriptorNames.OAV_ROTATION_SNAPSHOT_TRIGGERED)
|
|
78
|
+
yield from bps.read(composite.oav)
|
|
79
|
+
yield from bps.read(composite.smargon)
|
|
80
|
+
yield from bps.save()
|
|
81
|
+
|
|
82
|
+
|
|
65
83
|
def _take_oav_snapshot(composite: OavSnapshotComposite, omega: float):
|
|
84
|
+
"""Create new snapshots by triggering the OAV"""
|
|
66
85
|
yield from bps.abs_set(
|
|
67
86
|
composite.smargon.omega, omega, group=OAV_SNAPSHOT_SETUP_SHOT
|
|
68
87
|
)
|
|
69
|
-
|
|
70
|
-
filename = f"{time_now.strftime('%H%M%S%f')[:8]}_oav_snapshot_{omega:.0f}"
|
|
88
|
+
filename = _snapshot_filename(omega)
|
|
71
89
|
yield from bps.abs_set(
|
|
72
90
|
composite.oav.snapshot.filename,
|
|
73
91
|
filename,
|
|
@@ -78,3 +96,9 @@ def _take_oav_snapshot(composite: OavSnapshotComposite, omega: float):
|
|
|
78
96
|
yield from bps.create(DocDescriptorNames.OAV_ROTATION_SNAPSHOT_TRIGGERED)
|
|
79
97
|
yield from bps.read(composite.oav)
|
|
80
98
|
yield from bps.save()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _snapshot_filename(omega):
|
|
102
|
+
time_now = datetime.now()
|
|
103
|
+
filename = f"{time_now.strftime('%H%M%S%f')[:8]}_oav_snapshot_{omega:.0f}"
|
|
104
|
+
return filename
|
|
@@ -8,6 +8,10 @@ from bluesky.utils import MsgGenerator
|
|
|
8
8
|
from dodal.devices.eiger import EigerDetector
|
|
9
9
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
10
10
|
|
|
11
|
+
from mx_bluesky.common.device_setup_plans.manipulate_sample import move_phi_chi_omega
|
|
12
|
+
from mx_bluesky.common.experiment_plans.change_aperture_then_move_plan import (
|
|
13
|
+
change_aperture_then_move_to_xtal,
|
|
14
|
+
)
|
|
11
15
|
from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
12
16
|
ispyb_activation_wrapper,
|
|
13
17
|
)
|
|
@@ -15,13 +19,9 @@ from mx_bluesky.common.parameters.constants import OavConstants
|
|
|
15
19
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
16
20
|
from mx_bluesky.common.utils.log import LOGGER
|
|
17
21
|
from mx_bluesky.common.xrc_result import XRayCentreEventHandler
|
|
18
|
-
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_phi_chi_omega
|
|
19
22
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
20
23
|
start_preparing_data_collection_then_do_plan,
|
|
21
24
|
)
|
|
22
|
-
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
23
|
-
change_aperture_then_move_to_xtal,
|
|
24
|
-
)
|
|
25
25
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
26
26
|
GridDetectThenXRayCentreComposite,
|
|
27
27
|
detect_grid_and_do_gridscan,
|
|
@@ -16,10 +16,10 @@ from dodal.devices.oav.utils import (
|
|
|
16
16
|
)
|
|
17
17
|
from dodal.devices.smargon import Smargon
|
|
18
18
|
|
|
19
|
+
from mx_bluesky.common.device_setup_plans.setup_oav import pre_centring_setup_oav
|
|
19
20
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
20
21
|
from mx_bluesky.common.utils.exceptions import SampleException, catch_exception_and_warn
|
|
21
22
|
from mx_bluesky.common.utils.log import LOGGER
|
|
22
|
-
from mx_bluesky.hyperion.device_setup_plans.setup_oav import pre_centring_setup_oav
|
|
23
23
|
from mx_bluesky.hyperion.device_setup_plans.smargon import (
|
|
24
24
|
move_smargon_warn_on_out_of_range,
|
|
25
25
|
)
|
|
@@ -12,14 +12,15 @@ from blueapi.core import BlueskyContext
|
|
|
12
12
|
from bluesky.utils import Msg
|
|
13
13
|
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
14
14
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
15
|
-
from dodal.devices.
|
|
15
|
+
from dodal.devices.backlight import Backlight, BacklightPosition
|
|
16
16
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
17
|
+
from dodal.devices.i03.dcm import DCM
|
|
18
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
17
19
|
from dodal.devices.motors import XYZPositioner
|
|
18
20
|
from dodal.devices.oav.oav_detector import OAV
|
|
19
21
|
from dodal.devices.robot import BartRobot, SampleLocation
|
|
20
|
-
from dodal.devices.smargon import Smargon, StubPosition
|
|
22
|
+
from dodal.devices.smargon import CombinedMove, Smargon, StubPosition
|
|
21
23
|
from dodal.devices.thawer import Thawer
|
|
22
|
-
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
23
24
|
from dodal.devices.webcam import Webcam
|
|
24
25
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
25
26
|
from dodal.plan_stubs.motor_utils import MoveTooLarge, home_and_reset_wrapper
|
|
@@ -51,6 +52,7 @@ class RobotLoadAndEnergyChangeComposite:
|
|
|
51
52
|
oav: OAV
|
|
52
53
|
smargon: Smargon
|
|
53
54
|
aperture_scatterguard: ApertureScatterguard
|
|
55
|
+
backlight: Backlight
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
def create_devices(context: BlueskyContext) -> RobotLoadAndEnergyChangeComposite:
|
|
@@ -95,21 +97,14 @@ def prepare_for_robot_load(
|
|
|
95
97
|
aperture_scatterguard: ApertureScatterguard, smargon: Smargon
|
|
96
98
|
):
|
|
97
99
|
yield from bps.abs_set(
|
|
98
|
-
aperture_scatterguard
|
|
100
|
+
aperture_scatterguard.selected_aperture,
|
|
101
|
+
ApertureValue.OUT_OF_BEAM,
|
|
102
|
+
group="prepare_robot_load",
|
|
99
103
|
)
|
|
100
104
|
|
|
101
105
|
yield from bps.mv(smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD)
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
yield from bps.mv(
|
|
105
|
-
smargon.x, 0,
|
|
106
|
-
smargon.y, 0,
|
|
107
|
-
smargon.z, 0,
|
|
108
|
-
smargon.omega, 0,
|
|
109
|
-
smargon.chi, 0,
|
|
110
|
-
smargon.phi, 0
|
|
111
|
-
)
|
|
112
|
-
# fmt: on
|
|
107
|
+
yield from bps.mv(smargon, CombinedMove(x=0, y=0, z=0, chi=0, phi=0, omega=0))
|
|
113
108
|
|
|
114
109
|
yield from bps.wait("prepare_robot_load")
|
|
115
110
|
|
|
@@ -166,6 +161,8 @@ def robot_load_and_snapshots(
|
|
|
166
161
|
thawing_time: float,
|
|
167
162
|
demand_energy_ev: float | None,
|
|
168
163
|
):
|
|
164
|
+
yield from bps.abs_set(composite.backlight, BacklightPosition.IN, group="snapshot")
|
|
165
|
+
|
|
169
166
|
robot_load_plan = do_robot_load(
|
|
170
167
|
composite,
|
|
171
168
|
location,
|
|
@@ -189,6 +186,8 @@ def robot_load_and_snapshots(
|
|
|
189
186
|
except_plan=raise_exception_if_moved_out_of_cryojet,
|
|
190
187
|
)
|
|
191
188
|
|
|
189
|
+
yield from bps.wait(group="snapshot")
|
|
190
|
+
|
|
192
191
|
yield from take_robot_snapshots(composite.oav, composite.webcam, snapshot_directory)
|
|
193
192
|
|
|
194
193
|
yield from bps.create(name=CONST.DESCRIPTORS.ROBOT_LOAD)
|
|
@@ -10,13 +10,14 @@ from bluesky.utils import MsgGenerator
|
|
|
10
10
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
11
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
12
12
|
from dodal.devices.backlight import Backlight
|
|
13
|
-
from dodal.devices.dcm import DCM
|
|
14
13
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
15
14
|
from dodal.devices.eiger import EigerDetector
|
|
16
15
|
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
17
16
|
from dodal.devices.flux import Flux
|
|
18
17
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
19
|
-
from dodal.devices.i03
|
|
18
|
+
from dodal.devices.i03 import Beamstop
|
|
19
|
+
from dodal.devices.i03.dcm import DCM
|
|
20
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
20
21
|
from dodal.devices.motors import XYZPositioner
|
|
21
22
|
from dodal.devices.oav.oav_detector import OAV
|
|
22
23
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
@@ -26,7 +27,6 @@ from dodal.devices.smargon import Smargon
|
|
|
26
27
|
from dodal.devices.synchrotron import Synchrotron
|
|
27
28
|
from dodal.devices.thawer import Thawer
|
|
28
29
|
from dodal.devices.undulator import Undulator
|
|
29
|
-
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
30
30
|
from dodal.devices.webcam import Webcam
|
|
31
31
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
32
32
|
from dodal.devices.zebra.zebra import Zebra
|
|
@@ -112,6 +112,7 @@ def _flyscan_plan_from_robot_load_params(
|
|
|
112
112
|
yield from pin_centre_then_flyscan_plan(
|
|
113
113
|
cast(GridDetectThenXRayCentreComposite, composite),
|
|
114
114
|
params.pin_centre_then_xray_centre_params,
|
|
115
|
+
oav_config_file,
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
|
|
@@ -131,6 +132,7 @@ def _robot_load_then_flyscan_plan(
|
|
|
131
132
|
def robot_load_then_xray_centre(
|
|
132
133
|
composite: RobotLoadThenCentreComposite,
|
|
133
134
|
parameters: RobotLoadThenCentre,
|
|
135
|
+
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
134
136
|
) -> MsgGenerator:
|
|
135
137
|
"""Perform pin-tip detection followed by a flyscan to determine centres of interest.
|
|
136
138
|
Performs a robot load if necessary."""
|
|
@@ -154,10 +156,7 @@ def robot_load_then_xray_centre(
|
|
|
154
156
|
|
|
155
157
|
if doing_sample_load:
|
|
156
158
|
LOGGER.info("Pin not loaded, loading and centring")
|
|
157
|
-
plan = _robot_load_then_flyscan_plan(
|
|
158
|
-
composite,
|
|
159
|
-
parameters,
|
|
160
|
-
)
|
|
159
|
+
plan = _robot_load_then_flyscan_plan(composite, parameters, oav_config_file)
|
|
161
160
|
else:
|
|
162
161
|
# Robot load normally sets the energy so we should do this explicitly if no load is
|
|
163
162
|
# being done
|
|
@@ -168,7 +167,9 @@ def robot_load_then_xray_centre(
|
|
|
168
167
|
)
|
|
169
168
|
|
|
170
169
|
if doing_chi_change:
|
|
171
|
-
plan = _flyscan_plan_from_robot_load_params(
|
|
170
|
+
plan = _flyscan_plan_from_robot_load_params(
|
|
171
|
+
composite, parameters, oav_config_file
|
|
172
|
+
)
|
|
172
173
|
LOGGER.info("Pin already loaded but chi changed so centring")
|
|
173
174
|
else:
|
|
174
175
|
LOGGER.info("Pin already loaded and chi not changed so doing nothing")
|
|
@@ -10,16 +10,16 @@ from bluesky.utils import MsgGenerator
|
|
|
10
10
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
11
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
12
12
|
from dodal.devices.backlight import Backlight
|
|
13
|
-
from dodal.devices.dcm import DCM
|
|
14
13
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
15
14
|
from dodal.devices.eiger import EigerDetector
|
|
16
15
|
from dodal.devices.flux import Flux
|
|
17
|
-
from dodal.devices.i03
|
|
16
|
+
from dodal.devices.i03 import Beamstop
|
|
17
|
+
from dodal.devices.i03.dcm import DCM
|
|
18
18
|
from dodal.devices.oav.oav_detector import OAV
|
|
19
19
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
20
20
|
from dodal.devices.robot import BartRobot
|
|
21
21
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
22
|
-
from dodal.devices.smargon import Smargon
|
|
22
|
+
from dodal.devices.smargon import CombinedMove, Smargon
|
|
23
23
|
from dodal.devices.synchrotron import Synchrotron
|
|
24
24
|
from dodal.devices.undulator import Undulator
|
|
25
25
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
@@ -30,6 +30,10 @@ from dodal.plans.preprocessors.verify_undulator_gap import (
|
|
|
30
30
|
verify_undulator_gap_before_run_decorator,
|
|
31
31
|
)
|
|
32
32
|
|
|
33
|
+
from mx_bluesky.common.device_setup_plans.manipulate_sample import (
|
|
34
|
+
cleanup_sample_environment,
|
|
35
|
+
setup_sample_environment,
|
|
36
|
+
)
|
|
33
37
|
from mx_bluesky.common.parameters.components import WithSnapshot
|
|
34
38
|
from mx_bluesky.common.plans.read_hardware import (
|
|
35
39
|
read_hardware_for_zocalo,
|
|
@@ -41,12 +45,6 @@ from mx_bluesky.common.preprocessors.preprocessors import (
|
|
|
41
45
|
)
|
|
42
46
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
43
47
|
from mx_bluesky.common.utils.log import LOGGER
|
|
44
|
-
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
45
|
-
cleanup_sample_environment,
|
|
46
|
-
move_phi_chi_omega,
|
|
47
|
-
move_x_y_z,
|
|
48
|
-
setup_sample_environment,
|
|
49
|
-
)
|
|
50
48
|
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
51
49
|
arm_zebra,
|
|
52
50
|
setup_zebra_for_rotation,
|
|
@@ -62,8 +60,8 @@ from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
|
|
|
62
60
|
)
|
|
63
61
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
64
62
|
from mx_bluesky.hyperion.parameters.rotation import (
|
|
65
|
-
MultiRotationScan,
|
|
66
63
|
RotationScan,
|
|
64
|
+
SingleRotationScan,
|
|
67
65
|
)
|
|
68
66
|
|
|
69
67
|
|
|
@@ -118,7 +116,7 @@ class RotationMotionProfile:
|
|
|
118
116
|
|
|
119
117
|
|
|
120
118
|
def calculate_motion_profile(
|
|
121
|
-
params:
|
|
119
|
+
params: SingleRotationScan,
|
|
122
120
|
motor_time_to_speed_s: float,
|
|
123
121
|
max_velocity_deg_s: float,
|
|
124
122
|
) -> RotationMotionProfile:
|
|
@@ -212,7 +210,7 @@ def calculate_motion_profile(
|
|
|
212
210
|
|
|
213
211
|
def rotation_scan_plan(
|
|
214
212
|
composite: RotationScanComposite,
|
|
215
|
-
params:
|
|
213
|
+
params: SingleRotationScan,
|
|
216
214
|
motion_values: RotationMotionProfile,
|
|
217
215
|
):
|
|
218
216
|
"""A stub plan to collect diffraction images from a sample continuously rotating
|
|
@@ -319,7 +317,7 @@ def _cleanup_plan(composite: RotationScanComposite, **kwargs):
|
|
|
319
317
|
|
|
320
318
|
def _move_and_rotation(
|
|
321
319
|
composite: RotationScanComposite,
|
|
322
|
-
params:
|
|
320
|
+
params: SingleRotationScan,
|
|
323
321
|
oav_params: OAVParameters,
|
|
324
322
|
):
|
|
325
323
|
motor_time_to_speed = yield from bps.rd(composite.smargon.omega.acceleration_time)
|
|
@@ -330,19 +328,18 @@ def _move_and_rotation(
|
|
|
330
328
|
return num / 1000 if num else num
|
|
331
329
|
|
|
332
330
|
LOGGER.info("moving to position (if specified)")
|
|
333
|
-
yield from
|
|
334
|
-
composite.smargon,
|
|
335
|
-
_div_by_1000_if_not_none(params.x_start_um),
|
|
336
|
-
_div_by_1000_if_not_none(params.y_start_um),
|
|
337
|
-
_div_by_1000_if_not_none(params.z_start_um),
|
|
338
|
-
group=CONST.WAIT.MOVE_GONIO_TO_START,
|
|
339
|
-
)
|
|
340
|
-
yield from move_phi_chi_omega(
|
|
331
|
+
yield from bps.abs_set(
|
|
341
332
|
composite.smargon,
|
|
342
|
-
|
|
343
|
-
|
|
333
|
+
CombinedMove(
|
|
334
|
+
x=_div_by_1000_if_not_none(params.x_start_um),
|
|
335
|
+
y=_div_by_1000_if_not_none(params.y_start_um),
|
|
336
|
+
z=_div_by_1000_if_not_none(params.z_start_um),
|
|
337
|
+
phi=params.phi_start_deg,
|
|
338
|
+
chi=params.chi_start_deg,
|
|
339
|
+
),
|
|
344
340
|
group=CONST.WAIT.MOVE_GONIO_TO_START,
|
|
345
341
|
)
|
|
342
|
+
|
|
346
343
|
if params.take_snapshots:
|
|
347
344
|
yield from bps.wait(CONST.WAIT.MOVE_GONIO_TO_START)
|
|
348
345
|
yield from setup_beamline_for_OAV(
|
|
@@ -356,11 +353,7 @@ def _move_and_rotation(
|
|
|
356
353
|
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
357
354
|
)
|
|
358
355
|
yield from oav_snapshot_plan(composite, params, oav_params)
|
|
359
|
-
yield from rotation_scan_plan(
|
|
360
|
-
composite,
|
|
361
|
-
params,
|
|
362
|
-
motion_values,
|
|
363
|
-
)
|
|
356
|
+
yield from rotation_scan_plan(composite, params, motion_values)
|
|
364
357
|
|
|
365
358
|
|
|
366
359
|
def rotation_scan(
|
|
@@ -368,58 +361,24 @@ def rotation_scan(
|
|
|
368
361
|
parameters: RotationScan,
|
|
369
362
|
oav_params: OAVParameters | None = None,
|
|
370
363
|
) -> MsgGenerator:
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if not oav_params:
|
|
374
|
-
oav_params = OAVParameters(context="xrayCentring")
|
|
375
|
-
|
|
376
|
-
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
377
|
-
composite,
|
|
378
|
-
parameters.transmission_frac,
|
|
379
|
-
)
|
|
380
|
-
@verify_undulator_gap_before_run_decorator(composite)
|
|
381
|
-
@bpp.set_run_key_decorator("rotation_scan")
|
|
382
|
-
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
364
|
+
@bpp.set_run_key_decorator(CONST.PLAN.ROTATION_MULTI_OUTER)
|
|
365
|
+
@bpp.run_decorator(
|
|
383
366
|
md={
|
|
384
|
-
"
|
|
385
|
-
"mx_bluesky_parameters": parameters.model_dump_json(),
|
|
367
|
+
"activate_callbacks": ["BeamDrawingCallback"],
|
|
386
368
|
"with_snapshot": parameters.model_dump_json(
|
|
387
369
|
include=WithSnapshot.model_fields.keys() # type: ignore
|
|
388
370
|
),
|
|
389
|
-
"activate_callbacks": [
|
|
390
|
-
"BeamDrawingCallback",
|
|
391
|
-
"RotationISPyBCallback",
|
|
392
|
-
"RotationNexusFileCallback",
|
|
393
|
-
],
|
|
394
371
|
}
|
|
395
372
|
)
|
|
396
|
-
def
|
|
397
|
-
|
|
398
|
-
):
|
|
399
|
-
eiger: EigerDetector = composite.eiger
|
|
400
|
-
eiger.set_detector_parameters(params.detector_params)
|
|
401
|
-
|
|
402
|
-
@bpp.finalize_decorator(lambda: _cleanup_plan(composite))
|
|
403
|
-
def rotation_with_cleanup_and_stage(params: RotationScan):
|
|
404
|
-
yield from _move_and_rotation(composite, params, oav_params)
|
|
405
|
-
|
|
406
|
-
LOGGER.info("setting up and staging eiger...")
|
|
407
|
-
yield from start_preparing_data_collection_then_do_plan(
|
|
408
|
-
composite.beamstop,
|
|
409
|
-
eiger,
|
|
410
|
-
composite.detector_motion,
|
|
411
|
-
params.detector_distance_mm,
|
|
412
|
-
rotation_with_cleanup_and_stage(params),
|
|
413
|
-
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
414
|
-
)
|
|
415
|
-
yield from bps.unstage(eiger)
|
|
373
|
+
def _wrapped_rotation_scan():
|
|
374
|
+
yield from rotation_scan_internal(composite, parameters, oav_params)
|
|
416
375
|
|
|
417
|
-
yield from
|
|
376
|
+
yield from _wrapped_rotation_scan()
|
|
418
377
|
|
|
419
378
|
|
|
420
|
-
def
|
|
379
|
+
def rotation_scan_internal(
|
|
421
380
|
composite: RotationScanComposite,
|
|
422
|
-
parameters:
|
|
381
|
+
parameters: RotationScan,
|
|
423
382
|
oav_params: OAVParameters | None = None,
|
|
424
383
|
) -> MsgGenerator:
|
|
425
384
|
parameters.features.update_self_from_server()
|
|
@@ -457,7 +416,7 @@ def multi_rotation_scan(
|
|
|
457
416
|
}
|
|
458
417
|
)
|
|
459
418
|
def rotation_scan_core(
|
|
460
|
-
params:
|
|
419
|
+
params: SingleRotationScan,
|
|
461
420
|
):
|
|
462
421
|
yield from _move_and_rotation(composite, params, oav_params)
|
|
463
422
|
|
|
@@ -9,10 +9,10 @@ import bluesky.preprocessors as bpp
|
|
|
9
9
|
import pydantic
|
|
10
10
|
from bluesky import plan_stubs as bps
|
|
11
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
12
|
-
from dodal.devices.dcm import DCM
|
|
13
12
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
13
|
+
from dodal.devices.i03.dcm import DCM
|
|
14
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
14
15
|
from dodal.devices.undulator import Undulator
|
|
15
|
-
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
16
16
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
17
17
|
|
|
18
18
|
from mx_bluesky.common.parameters.constants import PlanNameConstants
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import json
|
|
3
3
|
import re
|
|
4
|
+
import traceback
|
|
5
|
+
from collections.abc import Sequence
|
|
4
6
|
from os import path
|
|
5
7
|
from typing import Any, TypeVar
|
|
6
8
|
|
|
@@ -12,11 +14,6 @@ from pydantic_extra_types.semantic_version import SemanticVersion
|
|
|
12
14
|
|
|
13
15
|
from mx_bluesky.common.parameters.components import (
|
|
14
16
|
PARAMETER_VERSION,
|
|
15
|
-
MxBlueskyParameters,
|
|
16
|
-
TopNByMaxCountSelection,
|
|
17
|
-
WithCentreSelection,
|
|
18
|
-
WithOptionalEnergyChange,
|
|
19
|
-
WithSample,
|
|
20
17
|
WithVisit,
|
|
21
18
|
)
|
|
22
19
|
from mx_bluesky.common.parameters.constants import (
|
|
@@ -24,9 +21,7 @@ from mx_bluesky.common.parameters.constants import (
|
|
|
24
21
|
)
|
|
25
22
|
from mx_bluesky.common.utils.log import LOGGER
|
|
26
23
|
from mx_bluesky.common.utils.utils import convert_angstrom_to_eV
|
|
27
|
-
from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures
|
|
28
24
|
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
29
|
-
from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre
|
|
30
25
|
|
|
31
26
|
T = TypeVar("T", bound=WithVisit)
|
|
32
27
|
AGAMEMNON_URL = "http://agamemnon.diamond.ac.uk/"
|
|
@@ -36,19 +31,6 @@ MULTIPIN_REGEX = rf"^{MULTIPIN_PREFIX}_(\d+)x(\d+(?:\.\d+)?)\+(\d+(?:\.\d+)?)$"
|
|
|
36
31
|
MX_GENERAL_ROOT_REGEX = r"^/dls/(?P<beamline>[^/]+)/data/[^/]*/(?P<visit>[^/]+)(?:/|$)"
|
|
37
32
|
|
|
38
33
|
|
|
39
|
-
class AgamemnonLoadCentreCollect(
|
|
40
|
-
MxBlueskyParameters,
|
|
41
|
-
WithVisit,
|
|
42
|
-
WithSample,
|
|
43
|
-
WithCentreSelection,
|
|
44
|
-
WithHyperionUDCFeatures,
|
|
45
|
-
WithOptionalEnergyChange,
|
|
46
|
-
):
|
|
47
|
-
"""Experiment parameters to compare against GDA populated LoadCentreCollect."""
|
|
48
|
-
|
|
49
|
-
robot_load_then_centre: RobotLoadThenCentre
|
|
50
|
-
|
|
51
|
-
|
|
52
34
|
@dataclasses.dataclass
|
|
53
35
|
class PinType:
|
|
54
36
|
expected_number_of_crystals: int
|
|
@@ -131,15 +113,6 @@ def get_withvisit_parameters_from_agamemnon(parameters: dict) -> tuple:
|
|
|
131
113
|
)
|
|
132
114
|
|
|
133
115
|
|
|
134
|
-
def get_withsample_parameters_from_agamemnon(parameters: dict) -> dict[str, Any]:
|
|
135
|
-
assert parameters.get("sample"), "instruction does not have a sample"
|
|
136
|
-
return {
|
|
137
|
-
"sample_id": parameters["sample"]["id"],
|
|
138
|
-
"sample_puck": parameters["sample"]["container"],
|
|
139
|
-
"sample_pin": parameters["sample"]["position"],
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
116
|
def get_withenergy_parameters_from_agamemnon(parameters: dict) -> dict[str, Any]:
|
|
144
117
|
try:
|
|
145
118
|
first_collection: dict = parameters["collection"][0]
|
|
@@ -155,69 +128,94 @@ def get_param_version() -> SemanticVersion:
|
|
|
155
128
|
return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))
|
|
156
129
|
|
|
157
130
|
|
|
158
|
-
def
|
|
159
|
-
parameters: dict,
|
|
160
|
-
) -> RobotLoadThenCentre:
|
|
161
|
-
visit, detector_distance = get_withvisit_parameters_from_agamemnon(parameters)
|
|
162
|
-
with_sample_params = get_withsample_parameters_from_agamemnon(parameters)
|
|
163
|
-
with_energy_params = get_withenergy_parameters_from_agamemnon(parameters)
|
|
164
|
-
visit_directory, file_name = path.split(parameters["prefix"])
|
|
165
|
-
return RobotLoadThenCentre(
|
|
166
|
-
parameter_model_version=get_param_version(),
|
|
167
|
-
storage_directory=visit_directory + "/xraycentring",
|
|
168
|
-
visit=visit,
|
|
169
|
-
detector_distance_mm=detector_distance,
|
|
170
|
-
snapshot_directory=visit_directory + "/snapshots",
|
|
171
|
-
file_name=file_name,
|
|
172
|
-
**with_energy_params,
|
|
173
|
-
**with_sample_params,
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def populate_parameters_from_agamemnon(agamemnon_params):
|
|
131
|
+
def populate_parameters_from_agamemnon(agamemnon_params) -> Sequence[LoadCentreCollect]:
|
|
178
132
|
visit, detector_distance = get_withvisit_parameters_from_agamemnon(agamemnon_params)
|
|
179
|
-
with_sample_params = get_withsample_parameters_from_agamemnon(agamemnon_params)
|
|
180
133
|
with_energy_params = get_withenergy_parameters_from_agamemnon(agamemnon_params)
|
|
181
134
|
pin_type = get_pin_type_from_agamemnon_parameters(agamemnon_params)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
135
|
+
collections = agamemnon_params["collection"]
|
|
136
|
+
visit_directory, file_name = path.split(agamemnon_params["prefix"])
|
|
137
|
+
|
|
138
|
+
return [
|
|
139
|
+
LoadCentreCollect.model_validate(
|
|
140
|
+
{
|
|
141
|
+
"parameter_model_version": get_param_version(),
|
|
142
|
+
"visit": visit,
|
|
143
|
+
"detector_distance_mm": detector_distance,
|
|
144
|
+
"sample_id": agamemnon_params["sample"]["id"],
|
|
145
|
+
"sample_puck": agamemnon_params["sample"]["container"],
|
|
146
|
+
"sample_pin": agamemnon_params["sample"]["position"],
|
|
147
|
+
"select_centres": {
|
|
148
|
+
"name": "TopNByMaxCount",
|
|
149
|
+
"n": pin_type.expected_number_of_crystals,
|
|
150
|
+
},
|
|
151
|
+
"robot_load_then_centre": {
|
|
152
|
+
"storage_directory": str(visit_directory) + "/xraycentring",
|
|
153
|
+
"file_name": file_name,
|
|
154
|
+
"tip_offset_um": pin_type.full_width / 2,
|
|
155
|
+
"grid_width_um": pin_type.full_width,
|
|
156
|
+
"omega_start_deg": 0.0,
|
|
157
|
+
"chi_start_deg": collection["chi"],
|
|
158
|
+
"transmission_frac": 1.0,
|
|
159
|
+
"features": {"use_gpu_results": True},
|
|
160
|
+
**with_energy_params,
|
|
161
|
+
},
|
|
162
|
+
"multi_rotation_scan": {
|
|
163
|
+
"comment": collection["comment"],
|
|
164
|
+
"storage_directory": str(visit_directory),
|
|
165
|
+
"exposure_time_s": collection["exposure_time"],
|
|
166
|
+
"file_name": file_name,
|
|
167
|
+
"transmission_frac": collection["transmission"],
|
|
168
|
+
"rotation_increment_deg": collection["omega_increment"],
|
|
169
|
+
"ispyb_experiment_type": collection["experiment_type"],
|
|
170
|
+
"snapshot_omegas_deg": [0.0, 90.0, 180.0, 270.0],
|
|
171
|
+
"rotation_scans": [
|
|
172
|
+
{
|
|
173
|
+
"scan_width_deg": (
|
|
174
|
+
collection["number_of_images"]
|
|
175
|
+
* collection["omega_increment"]
|
|
176
|
+
),
|
|
177
|
+
"omega_start_deg": collection["omega_start"],
|
|
178
|
+
"phi_start_deg": collection["phi_start"],
|
|
179
|
+
"chi_start_deg": collection["chi"],
|
|
180
|
+
"rotation_direction": "Positive",
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
**with_energy_params,
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
for collection in collections
|
|
188
|
+
]
|
|
196
189
|
|
|
197
190
|
|
|
198
|
-
def create_parameters_from_agamemnon() ->
|
|
191
|
+
def create_parameters_from_agamemnon() -> Sequence[LoadCentreCollect]:
|
|
199
192
|
beamline_name = get_beamline_name("i03")
|
|
200
193
|
agamemnon_params = get_next_instruction(beamline_name)
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
return (
|
|
195
|
+
populate_parameters_from_agamemnon(agamemnon_params) if agamemnon_params else []
|
|
196
|
+
)
|
|
203
197
|
|
|
204
198
|
|
|
205
|
-
def compare_params(load_centre_collect_params):
|
|
199
|
+
def compare_params(load_centre_collect_params: LoadCentreCollect):
|
|
206
200
|
try:
|
|
207
|
-
|
|
208
|
-
|
|
201
|
+
lcc_requests = create_parameters_from_agamemnon()
|
|
209
202
|
# Log differences against GDA populated parameters
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
f"Different parameters found when directly reading from Hyperion: {differences}"
|
|
203
|
+
if not lcc_requests:
|
|
204
|
+
LOGGER.info("Agamemnon returned no instructions")
|
|
205
|
+
else:
|
|
206
|
+
differences = DeepDiff(
|
|
207
|
+
lcc_requests[0], load_centre_collect_params, math_epsilon=1e-5
|
|
216
208
|
)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
if differences:
|
|
210
|
+
LOGGER.info(
|
|
211
|
+
f"Different parameters found when directly reading from Hyperion: {differences}"
|
|
212
|
+
)
|
|
213
|
+
except (ValueError, KeyError):
|
|
214
|
+
LOGGER.warning(f"Failed to compare parameters: {traceback.format_exc()}")
|
|
215
|
+
except Exception:
|
|
216
|
+
LOGGER.warning(
|
|
217
|
+
f"Unexpected error occurred. Failed to compare parameters: {traceback.format_exc()}"
|
|
218
|
+
)
|
|
221
219
|
|
|
222
220
|
|
|
223
221
|
def update_params_from_agamemnon(parameters: T) -> T:
|