mx-bluesky 0.3.1__py3-none-any.whl → 1.1.0__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/i04/__init__.py +3 -0
- mx_bluesky/{i04 → beamlines/i04}/thawing_plan.py +5 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/blueapi_config.yaml +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/dcid.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +7 -7
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +12 -9
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +245 -200
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +4 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/__init__.py +0 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +80 -70
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +20 -21
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_moveonclick.py +59 -39
- mx_bluesky/{i24 → beamlines/i24}/serial/log.py +1 -9
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +15 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/constants.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/experiment_parameters.py +4 -25
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/utils.py +5 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/run_serial.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv_abstract.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_detector.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/write_nexus.py +6 -3
- mx_bluesky/hyperion/__init__.py +1 -0
- mx_bluesky/hyperion/__main__.py +374 -0
- mx_bluesky/hyperion/device_setup_plans/__init__.py +0 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +134 -0
- mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +110 -0
- mx_bluesky/hyperion/device_setup_plans/position_detector.py +16 -0
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +60 -0
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +87 -0
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +210 -0
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +214 -0
- mx_bluesky/hyperion/device_setup_plans/smargon.py +25 -0
- mx_bluesky/hyperion/device_setup_plans/utils.py +44 -0
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +93 -0
- mx_bluesky/hyperion/exceptions.py +47 -0
- mx_bluesky/hyperion/experiment_plans/__init__.py +30 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +84 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +528 -0
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +209 -0
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +173 -0
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +81 -0
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +463 -0
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +119 -0
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +164 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +322 -0
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +436 -0
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +68 -0
- mx_bluesky/hyperion/external_interaction/__init__.py +9 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +10 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +148 -0
- mx_bluesky/hyperion/external_interaction/callbacks/aperture_change_callback.py +22 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +46 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +70 -0
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +203 -0
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +20 -0
- mx_bluesky/hyperion/external_interaction/callbacks/logging_callback.py +29 -0
- mx_bluesky/hyperion/external_interaction/callbacks/plan_reactive_callback.py +101 -0
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +174 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +17 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +102 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +269 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_mapping.py +53 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +95 -0
- mx_bluesky/hyperion/external_interaction/callbacks/zocalo_callback.py +92 -0
- mx_bluesky/hyperion/external_interaction/config_server.py +35 -0
- mx_bluesky/hyperion/external_interaction/exceptions.py +13 -0
- mx_bluesky/hyperion/external_interaction/ispyb/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/ispyb/data_model.py +95 -0
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +125 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +276 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +29 -0
- mx_bluesky/hyperion/external_interaction/nexus/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +148 -0
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +114 -0
- mx_bluesky/hyperion/log.py +99 -0
- mx_bluesky/hyperion/parameters/__init__.py +2 -0
- mx_bluesky/hyperion/parameters/cli.py +68 -0
- mx_bluesky/{parameters → hyperion/parameters}/components.py +77 -24
- mx_bluesky/hyperion/parameters/constants.py +158 -0
- mx_bluesky/hyperion/parameters/gridscan.py +216 -0
- mx_bluesky/hyperion/parameters/rotation.py +160 -0
- mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +964 -0
- mx_bluesky/hyperion/tracing.py +28 -0
- mx_bluesky/hyperion/utils/context.py +84 -0
- mx_bluesky/hyperion/utils/utils.py +25 -0
- mx_bluesky/hyperion/utils/validation.py +196 -0
- mx_bluesky/jupyter_example.ipynb +3 -2
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/METADATA +26 -11
- mx_bluesky-1.1.0.dist-info/RECORD +136 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/WHEEL +1 -1
- mx_bluesky-1.1.0.dist-info/entry_points.txt +8 -0
- mx_bluesky/i04/__init__.py +0 -3
- mx_bluesky/i24/serial/parameters/__init__.py +0 -15
- mx_bluesky/parameters/__init__.py +0 -31
- mx_bluesky-0.3.1.dist-info/RECORD +0 -67
- mx_bluesky-0.3.1.dist-info/entry_points.txt +0 -4
- /mx_bluesky/{i24 → beamlines}/__init__.py +0 -0
- /mx_bluesky/{i04 → beamlines/i04}/callbacks/murko_callback.py +0 -0
- /mx_bluesky/{i24/serial/extruder → beamlines/i24}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24/serial/fixed_target → beamlines/i24/serial/extruder}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/ME14E-GeneralPurpose.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/Shutter_Control.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/nudgechip.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short1-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short2-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/ft_utils.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/cs_maker.json +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/motor_direction.txt +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/minichip-oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_extruder.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_fixed_target.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_ssx.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/set_visit_directory.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/ca.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_zebra_plans.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/start_blueapi.sh +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from blueapi.core import BlueskyContext, MsgGenerator
|
|
7
|
+
from bluesky import plan_stubs as bps
|
|
8
|
+
from bluesky import preprocessors as bpp
|
|
9
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
10
|
+
from dodal.devices.attenuator import Attenuator
|
|
11
|
+
from dodal.devices.backlight import Backlight, BacklightPosition
|
|
12
|
+
from dodal.devices.dcm import DCM
|
|
13
|
+
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
14
|
+
from dodal.devices.eiger import EigerDetector
|
|
15
|
+
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
16
|
+
from dodal.devices.flux import Flux
|
|
17
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
18
|
+
from dodal.devices.oav.oav_parameters import OAV_CONFIG_JSON, OAVParameters
|
|
19
|
+
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
20
|
+
from dodal.devices.robot import BartRobot
|
|
21
|
+
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
22
|
+
from dodal.devices.smargon import Smargon
|
|
23
|
+
from dodal.devices.synchrotron import Synchrotron
|
|
24
|
+
from dodal.devices.undulator import Undulator
|
|
25
|
+
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
26
|
+
from dodal.devices.zebra import Zebra
|
|
27
|
+
from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
28
|
+
from dodal.devices.zocalo import ZocaloResults
|
|
29
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
30
|
+
|
|
31
|
+
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
32
|
+
move_aperture_if_required,
|
|
33
|
+
)
|
|
34
|
+
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
35
|
+
start_preparing_data_collection_then_do_plan,
|
|
36
|
+
)
|
|
37
|
+
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
38
|
+
FlyScanXRayCentreComposite as FlyScanXRayCentreComposite,
|
|
39
|
+
)
|
|
40
|
+
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
41
|
+
flyscan_xray_centre,
|
|
42
|
+
)
|
|
43
|
+
from mx_bluesky.hyperion.experiment_plans.oav_grid_detection_plan import (
|
|
44
|
+
OavGridDetectionComposite,
|
|
45
|
+
grid_detection_plan,
|
|
46
|
+
)
|
|
47
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.grid_detection_callback import (
|
|
48
|
+
GridDetectionCallback,
|
|
49
|
+
GridParamUpdate,
|
|
50
|
+
)
|
|
51
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
52
|
+
ispyb_activation_wrapper,
|
|
53
|
+
)
|
|
54
|
+
from mx_bluesky.hyperion.log import LOGGER
|
|
55
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
56
|
+
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
57
|
+
GridScanWithEdgeDetect,
|
|
58
|
+
ThreeDGridScan,
|
|
59
|
+
)
|
|
60
|
+
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclasses.dataclass
|
|
64
|
+
class GridDetectThenXRayCentreComposite:
|
|
65
|
+
"""All devices which are directly or indirectly required by this plan"""
|
|
66
|
+
|
|
67
|
+
aperture_scatterguard: ApertureScatterguard
|
|
68
|
+
attenuator: Attenuator
|
|
69
|
+
backlight: Backlight
|
|
70
|
+
dcm: DCM
|
|
71
|
+
detector_motion: DetectorMotion
|
|
72
|
+
eiger: EigerDetector
|
|
73
|
+
zebra_fast_grid_scan: ZebraFastGridScan
|
|
74
|
+
flux: Flux
|
|
75
|
+
oav: OAV
|
|
76
|
+
pin_tip_detection: PinTipDetection
|
|
77
|
+
smargon: Smargon
|
|
78
|
+
synchrotron: Synchrotron
|
|
79
|
+
s4_slit_gaps: S4SlitGaps
|
|
80
|
+
undulator: Undulator
|
|
81
|
+
xbpm_feedback: XBPMFeedback
|
|
82
|
+
zebra: Zebra
|
|
83
|
+
zocalo: ZocaloResults
|
|
84
|
+
panda: HDFPanda
|
|
85
|
+
panda_fast_grid_scan: PandAFastGridScan
|
|
86
|
+
robot: BartRobot
|
|
87
|
+
sample_shutter: ZebraShutter
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def create_devices(context: BlueskyContext) -> GridDetectThenXRayCentreComposite:
|
|
91
|
+
return device_composite_from_context(context, GridDetectThenXRayCentreComposite)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def create_parameters_for_flyscan_xray_centre(
|
|
95
|
+
grid_scan_with_edge_params: GridScanWithEdgeDetect,
|
|
96
|
+
grid_parameters: GridParamUpdate,
|
|
97
|
+
) -> ThreeDGridScan:
|
|
98
|
+
params_json = grid_scan_with_edge_params.model_dump()
|
|
99
|
+
params_json.update(grid_parameters)
|
|
100
|
+
flyscan_xray_centre_parameters = ThreeDGridScan(**params_json)
|
|
101
|
+
LOGGER.info(f"Parameters for FGS: {flyscan_xray_centre_parameters}")
|
|
102
|
+
return flyscan_xray_centre_parameters
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def detect_grid_and_do_gridscan(
|
|
106
|
+
composite: GridDetectThenXRayCentreComposite,
|
|
107
|
+
parameters: GridScanWithEdgeDetect,
|
|
108
|
+
oav_params: OAVParameters,
|
|
109
|
+
):
|
|
110
|
+
snapshot_template = f"{parameters.detector_params.prefix}_{parameters.detector_params.run_number}_{{angle}}"
|
|
111
|
+
|
|
112
|
+
grid_params_callback = GridDetectionCallback(composite.oav.parameters)
|
|
113
|
+
|
|
114
|
+
@bpp.subs_decorator([grid_params_callback])
|
|
115
|
+
def run_grid_detection_plan(
|
|
116
|
+
oav_params,
|
|
117
|
+
snapshot_template,
|
|
118
|
+
snapshot_dir: Path,
|
|
119
|
+
):
|
|
120
|
+
grid_detect_composite = OavGridDetectionComposite(
|
|
121
|
+
backlight=composite.backlight,
|
|
122
|
+
oav=composite.oav,
|
|
123
|
+
smargon=composite.smargon,
|
|
124
|
+
pin_tip_detection=composite.pin_tip_detection,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
yield from grid_detection_plan(
|
|
128
|
+
grid_detect_composite,
|
|
129
|
+
oav_params,
|
|
130
|
+
snapshot_template,
|
|
131
|
+
str(snapshot_dir),
|
|
132
|
+
grid_width_microns=parameters.grid_width_um,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
yield from run_grid_detection_plan(
|
|
136
|
+
oav_params,
|
|
137
|
+
snapshot_template,
|
|
138
|
+
parameters.snapshot_directory,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
yield from bps.abs_set(
|
|
142
|
+
composite.backlight, BacklightPosition.OUT, group=CONST.WAIT.GRID_READY_FOR_DC
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
yield from move_aperture_if_required(
|
|
146
|
+
composite.aperture_scatterguard,
|
|
147
|
+
parameters.selected_aperture,
|
|
148
|
+
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
yield from flyscan_xray_centre(
|
|
152
|
+
FlyScanXRayCentreComposite(
|
|
153
|
+
aperture_scatterguard=composite.aperture_scatterguard,
|
|
154
|
+
attenuator=composite.attenuator,
|
|
155
|
+
backlight=composite.backlight,
|
|
156
|
+
eiger=composite.eiger,
|
|
157
|
+
panda_fast_grid_scan=composite.panda_fast_grid_scan,
|
|
158
|
+
flux=composite.flux,
|
|
159
|
+
s4_slit_gaps=composite.s4_slit_gaps,
|
|
160
|
+
smargon=composite.smargon,
|
|
161
|
+
undulator=composite.undulator,
|
|
162
|
+
synchrotron=composite.synchrotron,
|
|
163
|
+
xbpm_feedback=composite.xbpm_feedback,
|
|
164
|
+
zebra=composite.zebra,
|
|
165
|
+
zocalo=composite.zocalo,
|
|
166
|
+
panda=composite.panda,
|
|
167
|
+
zebra_fast_grid_scan=composite.zebra_fast_grid_scan,
|
|
168
|
+
dcm=composite.dcm,
|
|
169
|
+
robot=composite.robot,
|
|
170
|
+
sample_shutter=composite.sample_shutter,
|
|
171
|
+
),
|
|
172
|
+
create_parameters_for_flyscan_xray_centre(
|
|
173
|
+
parameters, grid_params_callback.get_grid_parameters()
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def grid_detect_then_xray_centre(
|
|
179
|
+
composite: GridDetectThenXRayCentreComposite,
|
|
180
|
+
parameters: GridScanWithEdgeDetect,
|
|
181
|
+
oav_config: str = OAV_CONFIG_JSON,
|
|
182
|
+
) -> MsgGenerator:
|
|
183
|
+
"""
|
|
184
|
+
A plan which combines the collection of snapshots from the OAV and the determination
|
|
185
|
+
of the grid dimensions to use for the following grid scan.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
eiger: EigerDetector = composite.eiger
|
|
189
|
+
|
|
190
|
+
eiger.set_detector_parameters(parameters.detector_params)
|
|
191
|
+
|
|
192
|
+
oav_params = OAVParameters("xrayCentring", oav_config)
|
|
193
|
+
|
|
194
|
+
plan_to_perform = ispyb_activation_wrapper(
|
|
195
|
+
detect_grid_and_do_gridscan(
|
|
196
|
+
composite,
|
|
197
|
+
parameters,
|
|
198
|
+
oav_params,
|
|
199
|
+
),
|
|
200
|
+
parameters,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return start_preparing_data_collection_then_do_plan(
|
|
204
|
+
eiger,
|
|
205
|
+
composite.detector_motion,
|
|
206
|
+
parameters.detector_params.detector_distance,
|
|
207
|
+
plan_to_perform,
|
|
208
|
+
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
209
|
+
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import math
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import bluesky.plan_stubs as bps
|
|
8
|
+
import numpy as np
|
|
9
|
+
from blueapi.core import BlueskyContext
|
|
10
|
+
from dodal.devices.backlight import Backlight
|
|
11
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
12
|
+
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
13
|
+
from dodal.devices.oav.pin_image_recognition.utils import NONE_VALUE
|
|
14
|
+
from dodal.devices.oav.utils import PinNotFoundException, wait_for_tip_to_be_found
|
|
15
|
+
from dodal.devices.smargon import Smargon
|
|
16
|
+
|
|
17
|
+
from mx_bluesky.hyperion.device_setup_plans.setup_oav import (
|
|
18
|
+
pre_centring_setup_oav,
|
|
19
|
+
)
|
|
20
|
+
from mx_bluesky.hyperion.exceptions import catch_exception_and_warn
|
|
21
|
+
from mx_bluesky.hyperion.log import LOGGER
|
|
22
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
23
|
+
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclasses.dataclass
|
|
30
|
+
class OavGridDetectionComposite:
|
|
31
|
+
"""All devices which are directly or indirectly required by this plan"""
|
|
32
|
+
|
|
33
|
+
backlight: Backlight
|
|
34
|
+
oav: OAV
|
|
35
|
+
smargon: Smargon
|
|
36
|
+
pin_tip_detection: PinTipDetection
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def create_devices(context: BlueskyContext) -> OavGridDetectionComposite:
|
|
40
|
+
return device_composite_from_context(context, OavGridDetectionComposite)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_min_and_max_y_of_pin(
|
|
44
|
+
top: np.ndarray, bottom: np.ndarray, full_image_height_px: int
|
|
45
|
+
) -> tuple[int, int]:
|
|
46
|
+
"""Gives the minimum and maximum y that would cover the whole pin.
|
|
47
|
+
|
|
48
|
+
First filters out where no edge was found or the edge covers the full image.
|
|
49
|
+
If this results in no edges found then returns a min/max that covers the full image
|
|
50
|
+
"""
|
|
51
|
+
filtered_top = top[np.where((top != 0) & (top != NONE_VALUE))]
|
|
52
|
+
min_y = min(filtered_top) if len(filtered_top) else 0
|
|
53
|
+
filtered_bottom = bottom[
|
|
54
|
+
np.where((bottom != full_image_height_px) & (bottom != NONE_VALUE))
|
|
55
|
+
]
|
|
56
|
+
max_y = max(filtered_bottom) if len(filtered_bottom) else full_image_height_px
|
|
57
|
+
return min_y, max_y
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def grid_detection_plan(
|
|
61
|
+
composite: OavGridDetectionComposite,
|
|
62
|
+
parameters: OAVParameters,
|
|
63
|
+
snapshot_template: str,
|
|
64
|
+
snapshot_dir: str,
|
|
65
|
+
grid_width_microns: float,
|
|
66
|
+
box_size_um: float = 20,
|
|
67
|
+
):
|
|
68
|
+
"""
|
|
69
|
+
Creates the parameters for two grids that are 90 degrees from each other and
|
|
70
|
+
encompass the whole of the sample as it appears in the OAV.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
composite (OavGridDetectionComposite): Composite containing devices for doing a grid detection.
|
|
74
|
+
parameters (OAVParameters): Object containing parameters for setting up the OAV
|
|
75
|
+
snapshot_template (str): A template for the name of the snapshots, expected to be filled in with an angle
|
|
76
|
+
snapshot_dir (str): The location to save snapshots
|
|
77
|
+
grid_width_microns (int): The width of the grid to scan in microns
|
|
78
|
+
box_size_um (float): The size of each box of the grid in microns
|
|
79
|
+
"""
|
|
80
|
+
oav: OAV = composite.oav
|
|
81
|
+
smargon: Smargon = composite.smargon
|
|
82
|
+
pin_tip_detection: PinTipDetection = composite.pin_tip_detection
|
|
83
|
+
|
|
84
|
+
LOGGER.info("OAV Centring: Starting grid detection centring")
|
|
85
|
+
|
|
86
|
+
yield from bps.wait()
|
|
87
|
+
|
|
88
|
+
# Set relevant PVs to whatever the config dictates.
|
|
89
|
+
yield from pre_centring_setup_oav(oav, parameters, pin_tip_detection)
|
|
90
|
+
|
|
91
|
+
LOGGER.info("OAV Centring: Camera set up")
|
|
92
|
+
|
|
93
|
+
assert isinstance(oav.parameters.micronsPerXPixel, float)
|
|
94
|
+
box_size_x_pixels = box_size_um / oav.parameters.micronsPerXPixel
|
|
95
|
+
assert isinstance(oav.parameters.micronsPerYPixel, float)
|
|
96
|
+
box_size_y_pixels = box_size_um / oav.parameters.micronsPerYPixel
|
|
97
|
+
|
|
98
|
+
grid_width_pixels = int(grid_width_microns / oav.parameters.micronsPerXPixel)
|
|
99
|
+
|
|
100
|
+
# The FGS uses -90 so we need to match it
|
|
101
|
+
for angle in [0, -90]:
|
|
102
|
+
yield from bps.mv(smargon.omega, angle)
|
|
103
|
+
# need to wait for the OAV image to update
|
|
104
|
+
# See #673 for improvements
|
|
105
|
+
yield from bps.sleep(CONST.HARDWARE.OAV_REFRESH_DELAY)
|
|
106
|
+
|
|
107
|
+
tip_x_px, tip_y_px = yield from catch_exception_and_warn(
|
|
108
|
+
PinNotFoundException, wait_for_tip_to_be_found, pin_tip_detection
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
LOGGER.info(f"Tip is at x,y: {tip_x_px},{tip_y_px}")
|
|
112
|
+
|
|
113
|
+
top_edge = np.array((yield from bps.rd(pin_tip_detection.triggered_top_edge)))
|
|
114
|
+
bottom_edge = np.array(
|
|
115
|
+
(yield from bps.rd(pin_tip_detection.triggered_bottom_edge))
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
full_image_height_px = yield from bps.rd(oav.cam.array_size.array_size_y)
|
|
119
|
+
|
|
120
|
+
# only use the area from the start of the pin onwards
|
|
121
|
+
top_edge = top_edge[tip_x_px : tip_x_px + grid_width_pixels]
|
|
122
|
+
bottom_edge = bottom_edge[tip_x_px : tip_x_px + grid_width_pixels]
|
|
123
|
+
LOGGER.info(f"OAV Edge detection top: {list(top_edge)}")
|
|
124
|
+
LOGGER.info(f"OAV Edge detection bottom: {list(bottom_edge)}")
|
|
125
|
+
|
|
126
|
+
min_y, max_y = (
|
|
127
|
+
float(n)
|
|
128
|
+
for n in get_min_and_max_y_of_pin(
|
|
129
|
+
top_edge, bottom_edge, full_image_height_px
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
grid_height_px: float = max_y - min_y
|
|
134
|
+
|
|
135
|
+
y_steps: int = math.ceil(grid_height_px / box_size_y_pixels)
|
|
136
|
+
|
|
137
|
+
# Panda not configured to run a half complete snake so enforce even rows on first grid
|
|
138
|
+
# See https://github.com/DiamondLightSource/hyperion/wiki/PandA-constant%E2%80%90motion-scanning#motion-program-summary
|
|
139
|
+
if y_steps % 2 and angle == 0:
|
|
140
|
+
LOGGER.debug(
|
|
141
|
+
f"Forcing number of rows in first grid to be even: Adding an extra row onto bottom of first grid and shifting grid upwards by {box_size_y_pixels/2}"
|
|
142
|
+
)
|
|
143
|
+
y_steps += 1
|
|
144
|
+
min_y -= box_size_y_pixels / 2
|
|
145
|
+
max_y += box_size_y_pixels / 2
|
|
146
|
+
grid_height_px += box_size_y_pixels
|
|
147
|
+
|
|
148
|
+
LOGGER.info(f"Drawing snapshot {grid_width_pixels} by {grid_height_px}")
|
|
149
|
+
|
|
150
|
+
x_steps = math.ceil(grid_width_pixels / box_size_x_pixels)
|
|
151
|
+
|
|
152
|
+
upper_left = (tip_x_px, min_y)
|
|
153
|
+
|
|
154
|
+
yield from bps.abs_set(oav.grid_snapshot.top_left_x, upper_left[0])
|
|
155
|
+
yield from bps.abs_set(oav.grid_snapshot.top_left_y, upper_left[1])
|
|
156
|
+
yield from bps.abs_set(oav.grid_snapshot.box_width, box_size_x_pixels)
|
|
157
|
+
yield from bps.abs_set(oav.grid_snapshot.num_boxes_x, x_steps)
|
|
158
|
+
yield from bps.abs_set(oav.grid_snapshot.num_boxes_y, y_steps)
|
|
159
|
+
|
|
160
|
+
snapshot_filename = snapshot_template.format(angle=abs(angle))
|
|
161
|
+
|
|
162
|
+
yield from bps.abs_set(oav.grid_snapshot.filename, snapshot_filename)
|
|
163
|
+
yield from bps.abs_set(oav.grid_snapshot.directory, snapshot_dir)
|
|
164
|
+
yield from bps.trigger(oav.grid_snapshot, wait=True)
|
|
165
|
+
yield from bps.create(CONST.DESCRIPTORS.OAV_GRID_SNAPSHOT_TRIGGERED)
|
|
166
|
+
|
|
167
|
+
yield from bps.read(oav.grid_snapshot)
|
|
168
|
+
yield from bps.read(smargon)
|
|
169
|
+
yield from bps.save()
|
|
170
|
+
|
|
171
|
+
LOGGER.info(
|
|
172
|
+
f"Grid calculated at {angle}: {x_steps} by {y_steps} steps starting at {upper_left}px"
|
|
173
|
+
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from blueapi.core import MsgGenerator
|
|
5
|
+
from bluesky import plan_stubs as bps
|
|
6
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
7
|
+
from dodal.devices.backlight import Backlight, BacklightPosition
|
|
8
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
9
|
+
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
10
|
+
from dodal.devices.smargon import Smargon
|
|
11
|
+
|
|
12
|
+
from mx_bluesky.hyperion.device_setup_plans.setup_oav import setup_general_oav_params
|
|
13
|
+
from mx_bluesky.hyperion.parameters.components import WithSnapshot
|
|
14
|
+
from mx_bluesky.hyperion.parameters.constants import CONST, DocDescriptorNames
|
|
15
|
+
|
|
16
|
+
OAV_SNAPSHOT_SETUP_SHOT = "oav_snapshot_setup_shot"
|
|
17
|
+
OAV_SNAPSHOT_GROUP = "oav_snapshot_group"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class OavSnapshotComposite(Protocol):
|
|
21
|
+
smargon: Smargon
|
|
22
|
+
oav: OAV
|
|
23
|
+
aperture_scatterguard: ApertureScatterguard
|
|
24
|
+
backlight: Backlight
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def setup_beamline_for_OAV(
|
|
28
|
+
smargon: Smargon,
|
|
29
|
+
backlight: Backlight,
|
|
30
|
+
aperture_scatterguard: ApertureScatterguard,
|
|
31
|
+
group=CONST.WAIT.READY_FOR_OAV,
|
|
32
|
+
):
|
|
33
|
+
max_vel = yield from bps.rd(smargon.omega.max_velocity)
|
|
34
|
+
yield from bps.abs_set(smargon.omega.velocity, max_vel, group=group)
|
|
35
|
+
yield from bps.abs_set(backlight, BacklightPosition.IN, group=group)
|
|
36
|
+
yield from bps.abs_set(
|
|
37
|
+
aperture_scatterguard,
|
|
38
|
+
ApertureValue.ROBOT_LOAD,
|
|
39
|
+
group=group,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def oav_snapshot_plan(
|
|
44
|
+
composite: OavSnapshotComposite,
|
|
45
|
+
parameters: WithSnapshot,
|
|
46
|
+
oav_parameters: OAVParameters,
|
|
47
|
+
wait: bool = True,
|
|
48
|
+
) -> MsgGenerator:
|
|
49
|
+
if not parameters.take_snapshots:
|
|
50
|
+
return
|
|
51
|
+
yield from bps.wait(group=CONST.WAIT.READY_FOR_OAV)
|
|
52
|
+
yield from _setup_oav(composite, parameters, oav_parameters)
|
|
53
|
+
for omega in parameters.snapshot_omegas_deg or []:
|
|
54
|
+
yield from _take_oav_snapshot(composite, omega)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _setup_oav(
|
|
58
|
+
composite: OavSnapshotComposite,
|
|
59
|
+
parameters: WithSnapshot,
|
|
60
|
+
oav_parameters: OAVParameters,
|
|
61
|
+
):
|
|
62
|
+
yield from setup_general_oav_params(composite.oav, oav_parameters)
|
|
63
|
+
yield from bps.abs_set(
|
|
64
|
+
composite.oav.snapshot.directory, str(parameters.snapshot_directory)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _take_oav_snapshot(composite: OavSnapshotComposite, omega: float):
|
|
69
|
+
yield from bps.abs_set(
|
|
70
|
+
composite.smargon.omega, omega, group=OAV_SNAPSHOT_SETUP_SHOT
|
|
71
|
+
)
|
|
72
|
+
time_now = datetime.now()
|
|
73
|
+
filename = f"{time_now.strftime('%H%M%S')}_oav_snapshot_{omega:.0f}"
|
|
74
|
+
yield from bps.abs_set(
|
|
75
|
+
composite.oav.snapshot.filename, filename, group=OAV_SNAPSHOT_SETUP_SHOT
|
|
76
|
+
)
|
|
77
|
+
yield from bps.wait(group=OAV_SNAPSHOT_SETUP_SHOT)
|
|
78
|
+
yield from bps.trigger(composite.oav.snapshot, wait=True)
|
|
79
|
+
yield from bps.create(DocDescriptorNames.OAV_ROTATION_SNAPSHOT_TRIGGERED)
|
|
80
|
+
yield from bps.read(composite.oav.snapshot)
|
|
81
|
+
yield from bps.save()
|