mx-bluesky 1.2.0__py3-none-any.whl → 1.4.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.
Files changed (77) hide show
  1. mx_bluesky/__init__.py +8 -3
  2. mx_bluesky/__main__.py +12 -7
  3. mx_bluesky/_version.py +2 -2
  4. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
  5. mx_bluesky/beamlines/i04/thawing_plan.py +48 -10
  6. mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
  7. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +68 -90
  8. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +1 -1
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +104 -126
  10. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +139 -162
  11. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +25 -36
  12. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +24 -34
  13. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +14 -11
  14. mx_bluesky/beamlines/i24/serial/log.py +58 -49
  15. mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
  16. mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
  17. mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +31 -7
  18. mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
  19. mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
  20. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +1 -1
  21. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +8 -18
  22. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +2 -2
  23. mx_bluesky/common/__init__.py +0 -0
  24. mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
  25. mx_bluesky/common/parameters/components.py +221 -0
  26. mx_bluesky/common/parameters/constants.py +133 -0
  27. mx_bluesky/common/plans/__init__.py +1 -0
  28. mx_bluesky/common/plans/do_fgs.py +121 -0
  29. mx_bluesky/common/utils/log.py +116 -0
  30. mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
  31. mx_bluesky/hyperion/__main__.py +11 -9
  32. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +31 -26
  33. mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
  34. mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
  35. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +1 -2
  36. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +48 -17
  37. mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
  38. mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
  39. mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
  40. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +25 -83
  41. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +7 -5
  42. mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +19 -18
  43. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +8 -5
  44. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
  45. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +17 -17
  46. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +15 -11
  47. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +6 -3
  48. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +6 -4
  49. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +3 -3
  50. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
  51. mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
  52. mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +18 -13
  53. mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
  54. mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
  55. mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +1 -1
  56. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +4 -3
  57. mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +23 -18
  58. mx_bluesky/hyperion/external_interaction/config_server.py +22 -10
  59. mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
  60. mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
  61. mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
  62. mx_bluesky/hyperion/log.py +0 -84
  63. mx_bluesky/hyperion/parameters/components.py +1 -243
  64. mx_bluesky/hyperion/parameters/constants.py +22 -118
  65. mx_bluesky/hyperion/parameters/gridscan.py +13 -9
  66. mx_bluesky/hyperion/parameters/load_centre_collect.py +3 -3
  67. mx_bluesky/hyperion/parameters/robot_load.py +3 -3
  68. mx_bluesky/hyperion/parameters/rotation.py +9 -5
  69. mx_bluesky/hyperion/utils/utils.py +17 -0
  70. mx_bluesky/hyperion/utils/validation.py +5 -6
  71. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/METADATA +4 -2
  72. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/RECORD +76 -70
  73. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/WHEEL +1 -1
  74. mx_bluesky/example.py +0 -19
  75. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/LICENSE +0 -0
  76. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/entry_points.txt +0 -0
  77. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,254 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
- from abc import abstractmethod
5
- from collections.abc import Sequence
6
- from enum import StrEnum
7
- from pathlib import Path
8
- from typing import SupportsInt, TypeVar
9
-
10
- from dodal.devices.aperturescatterguard import ApertureValue
11
- from dodal.devices.detector import (
12
- DetectorParams,
13
- TriggerMode,
14
- )
15
3
  from pydantic import (
16
4
  BaseModel,
17
- ConfigDict,
18
5
  Field,
19
- field_serializer,
20
- field_validator,
21
- model_validator,
22
6
  )
23
- from scanspec.core import AxesPoints
24
- from semver import Version
25
7
 
26
8
  from mx_bluesky.hyperion.external_interaction.config_server import FeatureFlags
27
- from mx_bluesky.hyperion.parameters.constants import CONST
28
-
29
- T = TypeVar("T")
30
-
31
-
32
- class ParameterVersion(Version):
33
- @classmethod
34
- def _parse(cls, version):
35
- if isinstance(version, cls):
36
- return version
37
- return cls.parse(version)
38
-
39
-
40
- PARAMETER_VERSION = ParameterVersion.parse("5.1.0")
41
-
42
-
43
- class RotationAxis(StrEnum):
44
- OMEGA = "omega"
45
- PHI = "phi"
46
- CHI = "chi"
47
- KAPPA = "kappa"
48
-
49
-
50
- class XyzAxis(StrEnum):
51
- X = "sam_x"
52
- Y = "sam_y"
53
- Z = "sam_z"
54
-
55
-
56
- class IspybExperimentType(StrEnum):
57
- # Enum values from ispyb column data type
58
- SAD = "SAD" # at or slightly above the peak
59
- SAD_INVERSE_BEAM = "SAD - Inverse Beam"
60
- OSC = "OSC" # "native" (in the absence of a heavy atom)
61
- COLLECT_MULTIWEDGE = (
62
- "Collect - Multiwedge" # "poorly determined" ~ EDNA complex strategy???
63
- )
64
- MAD = "MAD"
65
- HELICAL = "Helical"
66
- MULTI_POSITIONAL = "Multi-positional"
67
- MESH = "Mesh"
68
- BURN = "Burn"
69
- MAD_INVERSE_BEAM = "MAD - Inverse Beam"
70
- CHARACTERIZATION = "Characterization"
71
- DEHYDRATION = "Dehydration"
72
- TOMO = "tomo"
73
- EXPERIMENT = "experiment"
74
- EM = "EM"
75
- PDF = "PDF"
76
- PDF_BRAGG = "PDF+Bragg"
77
- BRAGG = "Bragg"
78
- SINGLE_PARTICLE = "single particle"
79
- SERIAL_FIXED = "Serial Fixed"
80
- SERIAL_JET = "Serial Jet"
81
- STANDARD = "Standard" # Routine structure determination experiment
82
- TIME_RESOLVED = "Time Resolved" # Investigate the change of a system over time
83
- DLS_ANVIL_HP = "Diamond Anvil High Pressure" # HP sample environment pressure cell
84
- CUSTOM = "Custom" # Special or non-standard data collection
85
- XRF_MAP = "XRF map"
86
- ENERGY_SCAN = "Energy scan"
87
- XRF_SPECTRUM = "XRF spectrum"
88
- XRF_MAP_XAS = "XRF map xas"
89
- MESH_3D = "Mesh3D"
90
- SCREENING = "Screening"
91
- STILL = "Still"
92
- SSX_CHIP = "SSX-Chip"
93
- SSX_JET = "SSX-Jet"
94
9
 
95
- # Aliases for historic hyperion experiment type mapping
96
- ROTATION = "SAD"
97
- GRIDSCAN_2D = "mesh"
98
- GRIDSCAN_3D = "Mesh3D"
99
-
100
-
101
- class HyperionParameters(BaseModel):
102
- model_config = ConfigDict(
103
- arbitrary_types_allowed=True,
104
- extra="allow",
105
- )
106
-
107
- def __hash__(self) -> int:
108
- return self.json().__hash__()
109
10
 
11
+ class WithFeatures(BaseModel):
110
12
  features: FeatureFlags = Field(default=FeatureFlags())
111
- parameter_model_version: ParameterVersion
112
-
113
- @field_serializer("parameter_model_version")
114
- def serialize_parameter_version(self, version: ParameterVersion):
115
- return str(version)
116
-
117
- @field_validator("parameter_model_version", mode="before")
118
- @classmethod
119
- def _validate_version(cls, version_str: str):
120
- version = ParameterVersion.parse(version_str)
121
- assert (
122
- version >= ParameterVersion(major=PARAMETER_VERSION.major)
123
- ), f"Parameter version too old! This version of hyperion uses {PARAMETER_VERSION}"
124
- assert (
125
- version <= ParameterVersion(major=PARAMETER_VERSION.major + 1)
126
- ), f"Parameter version too new! This version of hyperion uses {PARAMETER_VERSION}"
127
- return version
128
-
129
- @classmethod
130
- def from_json(cls, input: str | None):
131
- assert input is not None
132
- return cls(**json.loads(input))
133
-
134
-
135
- class WithSnapshot(BaseModel):
136
- snapshot_directory: Path
137
- snapshot_omegas_deg: list[float] | None = None
138
-
139
- @property
140
- def take_snapshots(self) -> bool:
141
- return bool(self.snapshot_omegas_deg)
142
-
143
-
144
- class WithOptionalEnergyChange(BaseModel):
145
- demand_energy_ev: float | None = Field(default=None, gt=0)
146
-
147
-
148
- class WithVisit(BaseModel):
149
- visit: str = Field(min_length=1)
150
- zocalo_environment: str = Field(default=CONST.ZOCALO_ENV)
151
- beamline: str = Field(default=CONST.I03.BEAMLINE, pattern=r"BL\d{2}[BIJS]")
152
- det_dist_to_beam_converter_path: str = Field(
153
- default=CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
154
- )
155
- insertion_prefix: str = Field(
156
- default=CONST.I03.INSERTION_PREFIX, pattern=r"SR\d{2}[BIJS]"
157
- )
158
- detector_distance_mm: float | None = Field(default=None, gt=0)
159
-
160
-
161
- class DiffractionExperiment(
162
- HyperionParameters, WithSnapshot, WithOptionalEnergyChange, WithVisit
163
- ):
164
- """For all experiments which use beam"""
165
-
166
- file_name: str
167
- exposure_time_s: float = Field(gt=0)
168
- comment: str = Field(default="")
169
- trigger_mode: TriggerMode = Field(default=TriggerMode.FREE_RUN)
170
- run_number: int | None = Field(default=None, ge=0)
171
- selected_aperture: ApertureValue | None = Field(default=None)
172
- transmission_frac: float = Field(default=0.1)
173
- ispyb_experiment_type: IspybExperimentType
174
- storage_directory: str
175
-
176
- @model_validator(mode="before")
177
- @classmethod
178
- def validate_snapshot_directory(cls, values):
179
- snapshot_dir = values.get(
180
- "snapshot_directory", Path(values["storage_directory"], "snapshots")
181
- )
182
- values["snapshot_directory"] = (
183
- snapshot_dir if isinstance(snapshot_dir, Path) else Path(snapshot_dir)
184
- )
185
- return values
186
-
187
- @property
188
- def num_images(self) -> int:
189
- return 0
190
-
191
- @property
192
- @abstractmethod
193
- def detector_params(self) -> DetectorParams: ...
194
-
195
-
196
- class WithScan(BaseModel):
197
- """For experiments where the scan is known"""
198
-
199
- @property
200
- @abstractmethod
201
- def scan_points(self) -> AxesPoints: ...
202
-
203
- @property
204
- @abstractmethod
205
- def num_images(self) -> int: ...
206
-
207
-
208
- class SplitScan(BaseModel):
209
- @property
210
- @abstractmethod
211
- def scan_indices(self) -> Sequence[SupportsInt]:
212
- """Should return the first index of each scan (i.e. for each nexus file)"""
213
- ...
214
-
215
-
216
- class WithSample(BaseModel):
217
- sample_id: int
218
- sample_puck: int | None = None
219
- sample_pin: int | None = None
220
-
221
-
222
- class DiffractionExperimentWithSample(DiffractionExperiment, WithSample): ...
223
-
224
-
225
- class WithOavCentring(BaseModel):
226
- oav_centring_file: str = Field(default=CONST.I03.OAV_CENTRING_FILE)
227
-
228
-
229
- class OptionalXyzStarts(BaseModel):
230
- x_start_um: float | None = None
231
- y_start_um: float | None = None
232
- z_start_um: float | None = None
233
-
234
-
235
- class XyzStarts(BaseModel):
236
- x_start_um: float
237
- y_start_um: float
238
- z_start_um: float
239
-
240
- def _start_for_axis(self, axis: XyzAxis) -> float:
241
- match axis:
242
- case XyzAxis.X:
243
- return self.x_start_um
244
- case XyzAxis.Y:
245
- return self.y_start_um
246
- case XyzAxis.Z:
247
- return self.z_start_um
248
-
249
-
250
- class OptionalGonioAngleStarts(BaseModel):
251
- omega_start_deg: float | None = None
252
- phi_start_deg: float | None = None
253
- chi_start_deg: float | None = None
254
- kappa_start_deg: float | None = None
@@ -1,107 +1,21 @@
1
1
  import os
2
- from enum import Enum
3
2
 
4
- from dodal.devices.aperturescatterguard import ApertureValue
5
3
  from dodal.devices.detector import EIGER2_X_16M_SIZE
6
4
  from pydantic.dataclasses import dataclass
7
5
 
8
- TEST_MODE = os.environ.get("HYPERION_TEST_MODE")
9
-
10
-
11
- @dataclass(frozen=True)
12
- class SimConstants:
13
- BEAMLINE = "BL03S"
14
- INSERTION_PREFIX = "SR03S"
15
- ZOCALO_ENV = "dev_artemis"
16
- # this one is for unit tests
17
- ISPYB_CONFIG = "tests/test_data/test_config.cfg"
18
- # this one is for system tests
19
- DEV_ISPYB_DATABASE_CFG = "/dls_sw/dasc/mariadb/credentials/ispyb-hyperion-dev.cfg"
20
-
21
-
22
- @dataclass(frozen=True)
23
- class PlanNameConstants:
24
- # Robot load subplan
25
- ROBOT_LOAD = "robot_load"
26
- # Gridscan
27
- GRID_DETECT_AND_DO_GRIDSCAN = "grid_detect_and_do_gridscan"
28
- GRID_DETECT_INNER = "grid_detect"
29
- GRIDSCAN_OUTER = "run_gridscan_move_and_tidy"
30
- GRIDSCAN_AND_MOVE = "run_gridscan_and_move"
31
- GRIDSCAN_MAIN = "run_gridscan"
32
- DO_FGS = "do_fgs"
33
- # Rotation scan
34
- ROTATION_MULTI = "multi_rotation_wrapper"
35
- ROTATION_OUTER = "rotation_scan_with_cleanup"
36
- ROTATION_MAIN = "rotation_scan_main"
37
-
38
-
39
- @dataclass(frozen=True)
40
- class PlanGroupCheckpointConstants:
41
- # For places to synchronise / stop and wait in plans, use as bluesky group names
42
- GRID_READY_FOR_DC = "grid_ready_for_data_collection"
43
- ROTATION_READY_FOR_DC = "rotation_ready_for_data_collection"
44
- MOVE_GONIO_TO_START = "move_gonio_to_start"
45
- READY_FOR_OAV = "ready_for_oav"
46
-
47
-
48
- @dataclass(frozen=True)
49
- class DocDescriptorNames:
50
- # Robot load event descriptor
51
- ROBOT_LOAD = "robot_load"
52
- # For callbacks to use
53
- OAV_ROTATION_SNAPSHOT_TRIGGERED = "rotation_snapshot_triggered"
54
- OAV_GRID_SNAPSHOT_TRIGGERED = "snapshot_to_ispyb"
55
- HARDWARE_READ_PRE = "read_hardware_for_callbacks_pre_collection"
56
- HARDWARE_READ_DURING = "read_hardware_for_callbacks_during_collection"
57
- ZOCALO_HW_READ = "zocalo_read_hardware_plan"
58
-
59
-
60
- @dataclass(frozen=True)
61
- class HardwareConstants:
62
- OAV_REFRESH_DELAY = 0.3
63
- PANDA_FGS_RUN_UP_DEFAULT = 0.17
64
- CRYOJET_MARGIN_MM = 0.2
65
-
66
-
67
- @dataclass(frozen=True)
68
- class TriggerConstants:
69
- ZOCALO = "trigger_zocalo_on"
70
-
71
-
72
- @dataclass(frozen=True)
73
- class GridscanParamConstants:
74
- WIDTH_UM = 600.0
75
- EXPOSURE_TIME_S = 0.004
76
- USE_ROI = True
77
- BOX_WIDTH_UM = 20.0
78
- OMEGA_1 = 0.0
79
- OMEGA_2 = 90.0
80
-
81
-
82
- @dataclass(frozen=True)
83
- class RotationParamConstants:
84
- DEFAULT_APERTURE_POSITION = ApertureValue.LARGE
85
-
6
+ from mx_bluesky.common.parameters.constants import (
7
+ DocDescriptorNames,
8
+ EnvironmentConstants,
9
+ ExperimentParamConstants,
10
+ HardwareConstants,
11
+ OavConstants,
12
+ PlanGroupCheckpointConstants,
13
+ PlanNameConstants,
14
+ SimConstants,
15
+ TriggerConstants,
16
+ )
86
17
 
87
- @dataclass(frozen=True)
88
- class DetectorParamConstants:
89
- BEAM_XY_LUT_PATH = (
90
- "tests/test_data/test_det_dist_converter.txt"
91
- if TEST_MODE
92
- else "/dls_sw/i03/software/daq_configuration/lookup/DetDistToBeamXYConverter.txt"
93
- )
94
-
95
-
96
- @dataclass(frozen=True)
97
- class ExperimentParamConstants:
98
- DETECTOR = DetectorParamConstants()
99
- GRIDSCAN = GridscanParamConstants()
100
- ROTATION = RotationParamConstants()
101
-
102
-
103
- _test_oav_file = "tests/test_data/test_OAVCentring.json"
104
- _live_oav_file = "/dls_sw/i03/software/daq_configuration/json/OAVCentring_hyperion.json"
18
+ TEST_MODE = os.environ.get("HYPERION_TEST_MODE")
105
19
 
106
20
 
107
21
  @dataclass(frozen=True)
@@ -110,16 +24,22 @@ class I03Constants:
110
24
  BEAMLINE = "BL03S" if TEST_MODE else "BL03I"
111
25
  DETECTOR = EIGER2_X_16M_SIZE
112
26
  INSERTION_PREFIX = "SR03S" if TEST_MODE else "SR03I"
113
- OAV_CENTRING_FILE = _test_oav_file if TEST_MODE else _live_oav_file
27
+ OAV_CENTRING_FILE = OavConstants.OAV_CONFIG_JSON
114
28
  SHUTTER_TIME_S = 0.06
115
29
  USE_PANDA_FOR_GRIDSCAN = False
116
- USE_GPU_FOR_GRIDSCAN_ANALYSIS = False
117
30
  THAWING_TIME = 20
118
- USE_CPU_AND_GPU_ZOCALO = False
31
+ SET_STUB_OFFSETS = False
32
+
33
+ # Turns on GPU processing for zocalo and logs a comparison between GPU and CPU-
34
+ # processed results. GPU results never used in analysis for now
35
+ COMPARE_CPU_AND_GPU_ZOCALO = False
119
36
 
120
37
 
121
38
  @dataclass(frozen=True)
122
39
  class HyperionConstants:
40
+ DESCRIPTORS = DocDescriptorNames()
41
+ TRIGGER = TriggerConstants()
42
+ ZOCALO_ENV = EnvironmentConstants.ZOCALO_ENV
123
43
  HARDWARE = HardwareConstants()
124
44
  I03 = I03Constants()
125
45
  PARAM = ExperimentParamConstants()
@@ -136,23 +56,7 @@ class HyperionConstants:
136
56
  )
137
57
  GRAYLOG_PORT = 12232
138
58
  PARAMETER_SCHEMA_DIRECTORY = "src/hyperion/parameters/schemas/"
139
- ZOCALO_ENV = "dev_artemis" if TEST_MODE else "artemis"
59
+ LOG_FILE_NAME = "hyperion.log"
140
60
 
141
61
 
142
62
  CONST = HyperionConstants()
143
-
144
-
145
- class Actions(Enum):
146
- START = "start"
147
- STOP = "stop"
148
- SHUTDOWN = "shutdown"
149
- STATUS = "status"
150
-
151
-
152
- class Status(Enum):
153
- WARN = "Warn"
154
- FAILED = "Failed"
155
- SUCCESS = "Success"
156
- BUSY = "Busy"
157
- ABORTING = "Aborting"
158
- IDLE = "Idle"
@@ -14,32 +14,35 @@ from pydantic import Field, PrivateAttr
14
14
  from scanspec.core import Path as ScanPath
15
15
  from scanspec.specs import Line, Static
16
16
 
17
- from mx_bluesky.hyperion.parameters.components import (
17
+ from mx_bluesky.common.parameters.components import (
18
18
  DiffractionExperimentWithSample,
19
19
  IspybExperimentType,
20
20
  OptionalGonioAngleStarts,
21
21
  SplitScan,
22
- WithOavCentring,
23
22
  WithOptionalEnergyChange,
24
23
  WithScan,
25
24
  XyzStarts,
26
25
  )
26
+ from mx_bluesky.common.parameters.constants import GridscanParamConstants
27
+ from mx_bluesky.hyperion.parameters.components import WithFeatures
27
28
  from mx_bluesky.hyperion.parameters.constants import CONST, I03Constants
28
29
  from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange
29
30
 
30
31
 
32
+ # This will be restructed once Once https://github.com/DiamondLightSource/mx-bluesky/issues/323#issue-2500957290 is further along
33
+ # to handle slightly different parameters between different beamline implementations
31
34
  class GridCommon(
32
- DiffractionExperimentWithSample, OptionalGonioAngleStarts, WithOavCentring
35
+ DiffractionExperimentWithSample,
36
+ OptionalGonioAngleStarts,
37
+ WithFeatures,
33
38
  ):
34
39
  grid_width_um: float = Field(default=CONST.PARAM.GRIDSCAN.WIDTH_UM)
35
40
  exposure_time_s: float = Field(default=CONST.PARAM.GRIDSCAN.EXPOSURE_TIME_S)
36
41
  use_roi_mode: bool = Field(default=CONST.PARAM.GRIDSCAN.USE_ROI)
37
42
  panda_runup_distance_mm: float = Field(
38
- default=CONST.HARDWARE.PANDA_FGS_RUN_UP_DEFAULT
43
+ default=GridscanParamConstants.PANDA_RUN_UP_DISTANCE_MM
39
44
  )
40
- use_panda: bool = Field(default=CONST.I03.USE_PANDA_FOR_GRIDSCAN)
41
- use_gpu: bool = Field(default=CONST.I03.USE_GPU_FOR_GRIDSCAN_ANALYSIS)
42
- use_cpu_and_gpu_zocalo: bool = Field(default=CONST.I03.USE_CPU_AND_GPU_ZOCALO)
45
+
43
46
  ispyb_experiment_type: IspybExperimentType = Field(
44
47
  default=IspybExperimentType.GRIDSCAN_3D
45
48
  )
@@ -72,12 +75,13 @@ class GridCommon(
72
75
  use_roi_mode=self.use_roi_mode,
73
76
  det_dist_to_beam_converter_path=self.det_dist_to_beam_converter_path,
74
77
  trigger_mode=self.trigger_mode,
75
- enable_dev_shm=self.use_gpu,
78
+ enable_dev_shm=self.features.compare_cpu_and_gpu_zocalo,
76
79
  **optional_args,
77
80
  )
78
81
 
79
82
 
80
- class GridScanWithEdgeDetect(GridCommon): ...
83
+ class GridScanWithEdgeDetect(GridCommon):
84
+ box_size_um: float = Field(default=CONST.PARAM.GRIDSCAN.BOX_WIDTH_UM)
81
85
 
82
86
 
83
87
  class PinTipCentreThenXrayCentre(GridCommon):
@@ -2,8 +2,8 @@ from typing import TypeVar
2
2
 
3
3
  from pydantic import BaseModel, model_validator
4
4
 
5
- from mx_bluesky.hyperion.parameters.components import (
6
- HyperionParameters,
5
+ from mx_bluesky.common.parameters.components import (
6
+ MxBlueskyParameters,
7
7
  WithSample,
8
8
  WithVisit,
9
9
  )
@@ -21,7 +21,7 @@ def construct_from_values(parent_context: dict, key: str, t: type[T]) -> T:
21
21
  return t(**values)
22
22
 
23
23
 
24
- class LoadCentreCollect(HyperionParameters, WithVisit, WithSample):
24
+ class LoadCentreCollect(MxBlueskyParameters, WithVisit, WithSample):
25
25
  """Experiment parameters to perform the combined robot load,
26
26
  pin-tip centre and rotation scan operations."""
27
27
 
@@ -1,7 +1,7 @@
1
1
  from pydantic import Field
2
2
 
3
- from mx_bluesky.hyperion.parameters.components import (
4
- HyperionParameters,
3
+ from mx_bluesky.common.parameters.components import (
4
+ MxBlueskyParameters,
5
5
  WithOptionalEnergyChange,
6
6
  WithSample,
7
7
  WithSnapshot,
@@ -11,6 +11,6 @@ from mx_bluesky.hyperion.parameters.constants import CONST
11
11
 
12
12
 
13
13
  class RobotLoadAndEnergyChange(
14
- HyperionParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit
14
+ MxBlueskyParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit
15
15
  ):
16
16
  thawing_time: float = Field(default=CONST.I03.THAWING_TIME)
@@ -17,7 +17,7 @@ from scanspec.core import AxesPoints
17
17
  from scanspec.core import Path as ScanPath
18
18
  from scanspec.specs import Line
19
19
 
20
- from mx_bluesky.hyperion.parameters.components import (
20
+ from mx_bluesky.common.parameters.components import (
21
21
  DiffractionExperimentWithSample,
22
22
  IspybExperimentType,
23
23
  OptionalGonioAngleStarts,
@@ -115,12 +115,16 @@ class MultiRotationScan(RotationExperiment, SplitScan):
115
115
 
116
116
  def _single_rotation_scan(self, scan: RotationScanPerSweep) -> RotationScan:
117
117
  # self has everything from RotationExperiment
118
- params = self.model_dump()
119
- del params["rotation_scans"]
118
+ allowed_keys = RotationScan.model_fields.keys()
119
+ params_dump = self.model_dump()
120
120
  # provided `scan` has everything from RotationScanPerSweep
121
- params.update(scan.model_dump())
121
+ scan_dump = scan.model_dump()
122
+ rotation_scan_kv_pairs = {
123
+ k: v for k, v in (params_dump | scan_dump).items() if k in allowed_keys
124
+ }
122
125
  # together they have everything for RotationScan
123
- return RotationScan(**params)
126
+ rotation_scan = RotationScan(**rotation_scan_kv_pairs)
127
+ return rotation_scan
124
128
 
125
129
  @model_validator(mode="after")
126
130
  @classmethod
@@ -1,3 +1,6 @@
1
+ import math
2
+ from math import asin
3
+
1
4
  from scanspec.core import AxesPoints, Axis
2
5
  from scipy.constants import physical_constants
3
6
 
@@ -23,3 +26,17 @@ def convert_angstrom_to_eV(wavelength: float) -> float:
23
26
  def number_of_frames_from_scan_spec(scan_points: AxesPoints[Axis]):
24
27
  ax = list(scan_points.keys())[0]
25
28
  return len(scan_points[ax])
29
+
30
+
31
+ def energy_to_bragg_angle(energy_kev: float, d_a: float) -> float:
32
+ """Compute the bragg angle given the energy in kev.
33
+
34
+ Args:
35
+ energy_kev: The energy in keV
36
+ d_a: The lattice spacing in Angstroms
37
+ Returns:
38
+ The bragg angle in degrees
39
+ """
40
+ wavelength_a = convert_eV_to_angstrom(energy_kev * 1000)
41
+ d = d_a
42
+ return asin(wavelength_a / (2 * d)) * 180 / math.pi
@@ -8,7 +8,7 @@ from unittest.mock import patch
8
8
  import bluesky.preprocessors as bpp
9
9
  from bluesky.run_engine import RunEngine
10
10
  from dodal.beamlines import i03
11
- from dodal.devices.oav.oav_parameters import OAVConfigParams
11
+ from dodal.devices.oav.oav_parameters import OAVConfig
12
12
  from ophyd_async.core import set_mock_value
13
13
 
14
14
  from mx_bluesky.hyperion.device_setup_plans.read_hardware_for_setup import (
@@ -23,8 +23,8 @@ from mx_bluesky.hyperion.external_interaction.callbacks.rotation.nexus_callback
23
23
  from mx_bluesky.hyperion.parameters.constants import CONST
24
24
  from mx_bluesky.hyperion.parameters.rotation import RotationScan
25
25
 
26
- DISPLAY_CONFIGURATION = "tests/devices/unit_tests/test_display.configuration"
27
- ZOOM_LEVELS_XML = "tests/devices/unit_tests/test_jCameraManZoomLevels.xml"
26
+ DISPLAY_CONFIGURATION = "tests/test_data/test_display.configuration"
27
+ ZOOM_LEVELS_XML = "tests/test_data/test_jCameraManZoomLevels.xml"
28
28
  TEST_DATA_DIRECTORY = Path("tests/test_data/nexus_files/rotation")
29
29
  TEST_METAFILE = "ins_8_5_meta.h5.gz"
30
30
  FAKE_DATAFILE = "../fake_data.h5"
@@ -94,15 +94,14 @@ def fake_create_rotation_devices():
94
94
  robot = i03.robot(fake_with_ophyd_sim=True)
95
95
  oav = i03.oav(
96
96
  fake_with_ophyd_sim=True,
97
- params=OAVConfigParams(
98
- zoom_params_file=ZOOM_LEVELS_XML, display_config=DISPLAY_CONFIGURATION
97
+ params=OAVConfig(
98
+ zoom_params_file=ZOOM_LEVELS_XML, display_config_file=DISPLAY_CONFIGURATION
99
99
  ),
100
100
  )
101
101
  xbpm_feedback = i03.xbpm_feedback(fake_with_ophyd_sim=True)
102
102
 
103
103
  set_mock_value(smargon.omega.max_velocity, 131)
104
104
  set_mock_value(dcm.energy_in_kev.user_readback, 12700)
105
- oav.zoom_controller.fvst.sim_put("1.0x") # type: ignore
106
105
 
107
106
  return RotationScanComposite(
108
107
  attenuator=attenuator,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mx-bluesky
3
- Version: 1.2.0
3
+ Version: 1.4.0
4
4
  Summary: Bluesky tools for MX Beamlines at DLS
5
5
  Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
6
6
  License: Apache License
@@ -226,6 +226,7 @@ Requires-Dist: opencv-python
226
226
  Requires-Dist: opentelemetry-distro
227
227
  Requires-Dist: opentelemetry-exporter-otlp
228
228
  Requires-Dist: pydantic
229
+ Requires-Dist: pydantic-extra-types
229
230
  Requires-Dist: pyepics
230
231
  Requires-Dist: pyzmq
231
232
  Requires-Dist: requests
@@ -237,12 +238,13 @@ Requires-Dist: daq-config-server >=0.1.1
237
238
  Requires-Dist: ophyd ==1.9.0
238
239
  Requires-Dist: ophyd-async >=0.3a5
239
240
  Requires-Dist: bluesky >=1.13.0a4
240
- Requires-Dist: dls-dodal ==1.33.0
241
+ Requires-Dist: dls-dodal ==1.35.0
241
242
  Provides-Extra: dev
242
243
  Requires-Dist: black ; extra == 'dev'
243
244
  Requires-Dist: build ; extra == 'dev'
244
245
  Requires-Dist: diff-cover ; extra == 'dev'
245
246
  Requires-Dist: GitPython ; extra == 'dev'
247
+ Requires-Dist: import-linter ; extra == 'dev'
246
248
  Requires-Dist: ipython ; extra == 'dev'
247
249
  Requires-Dist: mypy ; extra == 'dev'
248
250
  Requires-Dist: myst-parser ; extra == 'dev'