dls-dodal 1.27.0__py3-none-any.whl → 1.28.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.
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/METADATA +1 -1
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/RECORD +16 -16
- dodal/_version.py +2 -2
- dodal/beamlines/i03.py +18 -2
- dodal/beamlines/i22.py +43 -0
- dodal/beamlines/p38.py +29 -0
- dodal/devices/detector/detector.py +5 -1
- dodal/devices/fast_grid_scan.py +53 -34
- dodal/devices/i22/dcm.py +152 -0
- dodal/devices/motors.py +8 -4
- dodal/devices/oav/utils.py +60 -0
- dodal/devices/tetramm.py +6 -1
- dodal/devices/lower_gonio_stages.py +0 -8
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.27.0.dist-info → dls_dodal-1.28.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
dodal/__init__.py,sha256=y-VRpfiX-Lm5nchB9N0VfMy_6dwFqVxpSn5SiAQql9I,114
|
|
2
2
|
dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
|
|
3
|
-
dodal/_version.py,sha256=
|
|
3
|
+
dodal/_version.py,sha256=RW6USZoeFR_9ttdXBH9tb0lK1erQEYot3NzmBpWXDMs,413
|
|
4
4
|
dodal/adsim.py,sha256=OW2dcS7ciD4Yq9WFw4PN_c5Bwccrmu7R-zr-u6ZCbQM,497
|
|
5
5
|
dodal/cli.py,sha256=z0UBESrNrq6Kq4rttp4uHcwS1fnOnRkKBRDHSriPpGY,2058
|
|
6
6
|
dodal/log.py,sha256=grK5-c-V6UjMERwDqYPdKbc_BpycrNb8hP0uteLOVCY,8296
|
|
@@ -9,14 +9,14 @@ dodal/beamline_specific_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
9
9
|
dodal/beamline_specific_utils/i03.py,sha256=Ixe1anFQl-kwRJubmQx28TIW4Zw8qDxpElNNNapWQHI,396
|
|
10
10
|
dodal/beamlines/README.md,sha256=K9MkL_GomxlsoTB7Mz-_dJA5NNSbmCfMiutchGg3C8o,404
|
|
11
11
|
dodal/beamlines/__init__.py,sha256=U0dQYFEUloCdQOs24zyfpPTncJXOO4cDcfHSevVOAw4,2890
|
|
12
|
-
dodal/beamlines/i03.py,sha256=
|
|
12
|
+
dodal/beamlines/i03.py,sha256=LcE9Vir0cCjt9pxO2wcevlM0NTP6NBCxp6DNtShPV0E,16914
|
|
13
13
|
dodal/beamlines/i04.py,sha256=JOyNcUnC3wva4no2MHKp6b8gOKAcQXL_c4cBo7oneVs,13034
|
|
14
14
|
dodal/beamlines/i04_1.py,sha256=KDxSUQNhIs_NFiRaLY-Jiory0DeN7Y0ErvGuoTrwCDU,4731
|
|
15
15
|
dodal/beamlines/i20_1.py,sha256=XJpey1-XZnCVpjK6-tODRYeBofqV44BL8lK5OSdQgiI,746
|
|
16
|
-
dodal/beamlines/i22.py,sha256=
|
|
16
|
+
dodal/beamlines/i22.py,sha256=Lk5S5AHu9hCnqlJJHZj1fhSDm1sTOgEVMe1S20nVqeY,8786
|
|
17
17
|
dodal/beamlines/i23.py,sha256=iEFkrA4sPQsRLGAmeD263jPMX4u2SF1NK4_KYqnVwow,1402
|
|
18
18
|
dodal/beamlines/i24.py,sha256=LIe8tu_ZJsoeQH7tYRZHSvqQ9C9zBGOXO6rb1DPCYjQ,4595
|
|
19
|
-
dodal/beamlines/p38.py,sha256=
|
|
19
|
+
dodal/beamlines/p38.py,sha256=TC78u4GwEnj6X0r5cnHhqNdBbbDRnh8lY8pEucBZjEU,8006
|
|
20
20
|
dodal/beamlines/p45.py,sha256=TNIkC-SBfj0ayZtlLLXW9xCSi5CzJkO8XpAMIo8fjao,2957
|
|
21
21
|
dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
|
|
22
22
|
dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
|
|
@@ -40,15 +40,14 @@ dodal/devices/cryostream.py,sha256=6MU4rXIOL33C-8F3DVfAtv0ZnwiysTtawjkeePd5IrQ,3
|
|
|
40
40
|
dodal/devices/dcm.py,sha256=vfyGYDzfSwTiNqlzkfNjkrL-Q1hNVSgJddvJ5Un_lvg,1610
|
|
41
41
|
dodal/devices/eiger.py,sha256=NE4tHdqgUZpUxJLQbd5lLUIHZcpeotppexJGlDNByzM,13868
|
|
42
42
|
dodal/devices/eiger_odin.py,sha256=U5Byb7uNwDdNscBRp7yBYQrsjKrKXl2l5WdSpL09lAw,6980
|
|
43
|
-
dodal/devices/fast_grid_scan.py,sha256=
|
|
43
|
+
dodal/devices/fast_grid_scan.py,sha256=qp0jdzhTjkDtaf7ngdPcegcFLlp1EmWUDbU_knCBDpc,13438
|
|
44
44
|
dodal/devices/fluorescence_detector_motion.py,sha256=RrXfPmJzWnAjcjp9u0AnJEfjvWPMKburVTySB2hxYbw,181
|
|
45
45
|
dodal/devices/flux.py,sha256=RtPStHw7Mad0igVKntKWVZfuZn2clokVJqH14HLix6M,198
|
|
46
46
|
dodal/devices/focusing_mirror.py,sha256=aRqBkE3OgaXpH6lP3v1VbSYgHsMMbSsPPXzeyAGf_Pg,6435
|
|
47
47
|
dodal/devices/ipin.py,sha256=OGMXwAE4KDDonZRPFkUmR9Vsk6X4Ox-hEvPT5drP-mQ,208
|
|
48
48
|
dodal/devices/linkam3.py,sha256=TPhiQ1D9i_HIlKHAlfnVfX7H6aPOAeXPEJLdmvwdKWQ,3776
|
|
49
49
|
dodal/devices/logging_ophyd_device.py,sha256=xw4lbyqq5_ehESGterVEfubJsBiJTWvBp5b9k62gSkg,666
|
|
50
|
-
dodal/devices/
|
|
51
|
-
dodal/devices/motors.py,sha256=aKtMv5q_4b1eFhzyuk2-D6zDsY_6cqAmG59y5LWUz1s,1328
|
|
50
|
+
dodal/devices/motors.py,sha256=T0wKGpRKhgduAQj3jE8CGmxy3cWMAFl9_glyjVZwjnA,1473
|
|
52
51
|
dodal/devices/p45.py,sha256=jzBW2fGRhIbGzSRs5Fgupxro6aqE611n1RTcrTTG-yY,1047
|
|
53
52
|
dodal/devices/qbpm1.py,sha256=OY7-WbdxMiLGUK8Z57ezwqSXbHxoPP-y3GvBgj9kgMA,220
|
|
54
53
|
dodal/devices/robot.py,sha256=V5Gk-e1ZczU7y8SqU4_1YXYQJ6knoVFtXLZmIDY9MI4,2530
|
|
@@ -59,7 +58,7 @@ dodal/devices/slits.py,sha256=URru9VN2N19KqeUPDZaBmyKYn0_JJiE0Vko4sZpfsl8,601
|
|
|
59
58
|
dodal/devices/smargon.py,sha256=ml96h7E1C31qPo8jocAepSouIVXgpIR0vuMF99nZjqM,2964
|
|
60
59
|
dodal/devices/status.py,sha256=TuUGidZ4Ar-WCRc_sX0wn58DmL6brj1pMr8rNF5Z6VU,1198
|
|
61
60
|
dodal/devices/synchrotron.py,sha256=E5vcSum-zoD5vIZxa2Xcl0gAkeRqY6a-AfZQICCwLHg,1947
|
|
62
|
-
dodal/devices/tetramm.py,sha256=
|
|
61
|
+
dodal/devices/tetramm.py,sha256=Xdy3dXFo4Wn6HHsRo4e1tTgMzvDa8MwkVvcDFZxFrYQ,8280
|
|
63
62
|
dodal/devices/thawer.py,sha256=L5OYSdzGvx6dIkGgcTbITAbFAm0OKEVVqYBb4MPstOg,382
|
|
64
63
|
dodal/devices/turbo_slit.py,sha256=W3ZRIqDhq4iMhr5GcIiWvl2U1GaPtGanqkL7upQOZTY,1132
|
|
65
64
|
dodal/devices/undulator.py,sha256=kn84MQpuBHtQj7H7HeBoAYKXu5buGKvTgs3tf2gdEdw,2074
|
|
@@ -77,11 +76,12 @@ dodal/devices/detector/__init__.py,sha256=XEwjopgTtBq93RRuFthVVVI9DT1jUvpOJzWOHa
|
|
|
77
76
|
dodal/devices/detector/det_dim_constants.py,sha256=MZ4w2nsTKzj4eN7yGsSs1pqKWIuU4vc6UzcSll02uWg,2305
|
|
78
77
|
dodal/devices/detector/det_dist_to_beam_converter.py,sha256=f6JFp-eEB2v8NzZg27UrN0VDP5CMjRnaPU6BTA7_n_s,1937
|
|
79
78
|
dodal/devices/detector/det_resolution.py,sha256=aQkKp24LpRGiwzPAQM3wLVa4ANw32HdrKc2kftHfKQA,3253
|
|
80
|
-
dodal/devices/detector/detector.py,sha256=
|
|
79
|
+
dodal/devices/detector/detector.py,sha256=arP27DbrgOjYZhE6Ibp9kDBglfmqZpPBk53S5ItsrvE,4756
|
|
81
80
|
dodal/devices/detector/detector_motion.py,sha256=REREva2kyPcIzOZmahN9rT0jDSuUbV0qUDl4IcBnutA,1221
|
|
82
81
|
dodal/devices/i03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
82
|
dodal/devices/i04/transfocator.py,sha256=uieByXIj0JRbmvMB_om5NOAEbEJkzfkCD24bl2aEo1g,3154
|
|
84
83
|
dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
|
+
dodal/devices/i22/dcm.py,sha256=ZJL-K7GdJxyH-0wKsV0psX8iaFYJINpqBZljfAyuLbs,6046
|
|
85
85
|
dodal/devices/i22/fswitch.py,sha256=AdYtnkCBuhivyJGZqelg_7sjB2pHN7vl1JTtlO4vHo4,3061
|
|
86
86
|
dodal/devices/i23/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
87
|
dodal/devices/i23/gonio.py,sha256=cxqD2Kd578c4-K4h2sHdJjoap2gPGC46Qr4SPudHLTs,864
|
|
@@ -97,7 +97,7 @@ dodal/devices/oav/oav_calculations.py,sha256=wt71vFcyQrr98FvX8oyUM2n5vmKi3K7PyOT
|
|
|
97
97
|
dodal/devices/oav/oav_detector.py,sha256=JtzRdFQVXUdVK4Qyd9knDhsfkK6tsXoD_rIWDpLdpD4,3654
|
|
98
98
|
dodal/devices/oav/oav_errors.py,sha256=cc4mGnaTiAc5WIlOt_BIYOc7CRSkrCdnBaavfAJ0pXY,754
|
|
99
99
|
dodal/devices/oav/oav_parameters.py,sha256=4XybkhKeG7IEjPRfx0PVM9KNenuyN0rAGWBZG7H3zvQ,7941
|
|
100
|
-
dodal/devices/oav/utils.py,sha256=
|
|
100
|
+
dodal/devices/oav/utils.py,sha256=BkTk0aTqqhIHCZInhcUAYjCRPxumPOlTg9m21skncTc,3018
|
|
101
101
|
dodal/devices/oav/pin_image_recognition/__init__.py,sha256=qEX3BRnrcP1BLZD-f_smHiMMPLJPkWQZQbIWTbW25JA,6499
|
|
102
102
|
dodal/devices/oav/pin_image_recognition/manual_test.py,sha256=h1Rto6ZDCB3jWhjSy9N8ECxRN583iYDJr9LxrTJ8kfE,903
|
|
103
103
|
dodal/devices/oav/pin_image_recognition/utils.py,sha256=-7-Zs-331UVTq_AZrfdF-zwZdmMn7eitTkBSqnBrxnk,8620
|
|
@@ -114,9 +114,9 @@ dodal/devices/zocalo/zocalo_results.py,sha256=U4Vk4OF-eL8w0BR-fbw3k4jyRo6G3Ywaf8
|
|
|
114
114
|
dodal/parameters/experiment_parameter_base.py,sha256=O7JamfuJ5cYHkPf9tsHJPqn-OMHTAGouigvM1cDFehE,313
|
|
115
115
|
dodal/plans/check_topup.py,sha256=VOkHak88_r-pdTsSnwAJnbvlK2_UhKnO5I36pJmWKvQ,2985
|
|
116
116
|
dodal/plans/data_session_metadata.py,sha256=QNx9rb1EfGBHb21eFekIi7KjNhC0PL-SVKBCggDuNeg,1650
|
|
117
|
-
dls_dodal-1.
|
|
118
|
-
dls_dodal-1.
|
|
119
|
-
dls_dodal-1.
|
|
120
|
-
dls_dodal-1.
|
|
121
|
-
dls_dodal-1.
|
|
122
|
-
dls_dodal-1.
|
|
117
|
+
dls_dodal-1.28.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
118
|
+
dls_dodal-1.28.0.dist-info/METADATA,sha256=1EiYYnvAHwt0rilBYosSJaPDpF34SdatvnYUuqud9lE,16837
|
|
119
|
+
dls_dodal-1.28.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
120
|
+
dls_dodal-1.28.0.dist-info/entry_points.txt,sha256=wpzz9FsTiYxI8OBwLKX9V9ResLwThBSmtRMcPwII0FA,46
|
|
121
|
+
dls_dodal-1.28.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
|
|
122
|
+
dls_dodal-1.28.0.dist-info/RECORD,,
|
dodal/_version.py
CHANGED
dodal/beamlines/i03.py
CHANGED
|
@@ -17,6 +17,7 @@ from dodal.devices.eiger import EigerDetector
|
|
|
17
17
|
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
18
18
|
from dodal.devices.flux import Flux
|
|
19
19
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, VFMMirrorVoltages
|
|
20
|
+
from dodal.devices.motors import XYZPositioner
|
|
20
21
|
from dodal.devices.oav.oav_detector import OAV, OAVConfigParams
|
|
21
22
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
22
23
|
from dodal.devices.qbpm1 import QBPM1
|
|
@@ -208,7 +209,7 @@ def zebra_fast_grid_scan(
|
|
|
208
209
|
return device_instantiation(
|
|
209
210
|
device_factory=ZebraFastGridScan,
|
|
210
211
|
name="zebra_fast_grid_scan",
|
|
211
|
-
prefix="-MO-SGON-01:
|
|
212
|
+
prefix="-MO-SGON-01:",
|
|
212
213
|
wait=wait_for_connection,
|
|
213
214
|
fake=fake_with_ophyd_sim,
|
|
214
215
|
)
|
|
@@ -224,7 +225,7 @@ def panda_fast_grid_scan(
|
|
|
224
225
|
return device_instantiation(
|
|
225
226
|
device_factory=PandAFastGridScan,
|
|
226
227
|
name="panda_fast_grid_scan",
|
|
227
|
-
prefix="-MO-SGON-01:
|
|
228
|
+
prefix="-MO-SGON-01:",
|
|
228
229
|
wait=wait_for_connection,
|
|
229
230
|
fake=fake_with_ophyd_sim,
|
|
230
231
|
)
|
|
@@ -495,3 +496,18 @@ def thawer(
|
|
|
495
496
|
wait_for_connection,
|
|
496
497
|
fake_with_ophyd_sim,
|
|
497
498
|
)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def lower_gonio_positioner(
|
|
502
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
503
|
+
) -> XYZPositioner:
|
|
504
|
+
"""Get the i03 lower gonio device, instantiate it if it hasn't already been.
|
|
505
|
+
If this is called when already instantiated in i03, it will return the existing object.
|
|
506
|
+
"""
|
|
507
|
+
return device_instantiation(
|
|
508
|
+
XYZPositioner,
|
|
509
|
+
"lower_gonio_positioner",
|
|
510
|
+
"-MO-GONP-01:",
|
|
511
|
+
wait_for_connection,
|
|
512
|
+
fake_with_ophyd_sim,
|
|
513
|
+
)
|
dodal/beamlines/i22.py
CHANGED
|
@@ -12,9 +12,11 @@ from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beam
|
|
|
12
12
|
from dodal.common.beamlines.device_helpers import numbered_slits
|
|
13
13
|
from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitDirectoryProvider
|
|
14
14
|
from dodal.devices.focusing_mirror import FocusingMirror
|
|
15
|
+
from dodal.devices.i22.dcm import CrystalMetadata, DoubleCrystalMonochromator
|
|
15
16
|
from dodal.devices.i22.fswitch import FSwitch
|
|
16
17
|
from dodal.devices.linkam3 import Linkam3
|
|
17
18
|
from dodal.devices.slits import Slits
|
|
19
|
+
from dodal.devices.synchrotron import Synchrotron
|
|
18
20
|
from dodal.devices.tetramm import TetrammDetector
|
|
19
21
|
from dodal.devices.undulator import Undulator
|
|
20
22
|
from dodal.log import set_beamline as set_log_beamline
|
|
@@ -53,6 +55,18 @@ def saxs(
|
|
|
53
55
|
)
|
|
54
56
|
|
|
55
57
|
|
|
58
|
+
def synchrotron(
|
|
59
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
60
|
+
) -> Synchrotron:
|
|
61
|
+
return device_instantiation(
|
|
62
|
+
Synchrotron,
|
|
63
|
+
"synchrotron",
|
|
64
|
+
"",
|
|
65
|
+
wait_for_connection,
|
|
66
|
+
fake_with_ophyd_sim,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
56
70
|
def waxs(
|
|
57
71
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
58
72
|
) -> PilatusDetector:
|
|
@@ -122,6 +136,34 @@ def hfm(
|
|
|
122
136
|
)
|
|
123
137
|
|
|
124
138
|
|
|
139
|
+
def dcm(
|
|
140
|
+
wait_for_connection: bool = True,
|
|
141
|
+
fake_with_ophyd_sim: bool = False,
|
|
142
|
+
) -> DoubleCrystalMonochromator:
|
|
143
|
+
return device_instantiation(
|
|
144
|
+
DoubleCrystalMonochromator,
|
|
145
|
+
"dcm",
|
|
146
|
+
"",
|
|
147
|
+
wait_for_connection,
|
|
148
|
+
fake_with_ophyd_sim,
|
|
149
|
+
bl_prefix=False,
|
|
150
|
+
motion_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
|
|
151
|
+
temperature_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-DI-DCM-01:",
|
|
152
|
+
crystal_1_metadata=CrystalMetadata(
|
|
153
|
+
usage="Bragg",
|
|
154
|
+
type="silicon",
|
|
155
|
+
reflection=(1, 1, 1),
|
|
156
|
+
d_spacing=3.13475,
|
|
157
|
+
),
|
|
158
|
+
crystal_2_metadata=CrystalMetadata(
|
|
159
|
+
usage="Bragg",
|
|
160
|
+
type="silicon",
|
|
161
|
+
reflection=(1, 1, 1),
|
|
162
|
+
d_spacing=3.13475,
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
125
167
|
def undulator(
|
|
126
168
|
wait_for_connection: bool = True,
|
|
127
169
|
fake_with_ophyd_sim: bool = False,
|
|
@@ -283,6 +325,7 @@ def panda4(
|
|
|
283
325
|
)
|
|
284
326
|
|
|
285
327
|
|
|
328
|
+
@skip_device
|
|
286
329
|
def oav(
|
|
287
330
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
288
331
|
) -> AravisDetector:
|
dodal/beamlines/p38.py
CHANGED
|
@@ -12,6 +12,7 @@ from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beam
|
|
|
12
12
|
from dodal.common.beamlines.device_helpers import numbered_slits
|
|
13
13
|
from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitDirectoryProvider
|
|
14
14
|
from dodal.devices.focusing_mirror import FocusingMirror
|
|
15
|
+
from dodal.devices.i22.dcm import CrystalMetadata, DoubleCrystalMonochromator
|
|
15
16
|
from dodal.devices.i22.fswitch import FSwitch
|
|
16
17
|
from dodal.devices.linkam3 import Linkam3
|
|
17
18
|
from dodal.devices.slits import Slits
|
|
@@ -214,6 +215,34 @@ def hfm(
|
|
|
214
215
|
)
|
|
215
216
|
|
|
216
217
|
|
|
218
|
+
def dcm(
|
|
219
|
+
wait_for_connection: bool = True,
|
|
220
|
+
fake_with_ophyd_sim: bool = True,
|
|
221
|
+
) -> DoubleCrystalMonochromator:
|
|
222
|
+
return device_instantiation(
|
|
223
|
+
DoubleCrystalMonochromator,
|
|
224
|
+
"dcm",
|
|
225
|
+
"",
|
|
226
|
+
wait_for_connection,
|
|
227
|
+
fake_with_ophyd_sim,
|
|
228
|
+
bl_prefix=False,
|
|
229
|
+
motion_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
|
|
230
|
+
temperature_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-DI-DCM-01:",
|
|
231
|
+
crystal_1_metadata=CrystalMetadata(
|
|
232
|
+
usage="Bragg",
|
|
233
|
+
type="silicon",
|
|
234
|
+
reflection=(1, 1, 1),
|
|
235
|
+
d_spacing=3.13475,
|
|
236
|
+
),
|
|
237
|
+
crystal_2_metadata=CrystalMetadata(
|
|
238
|
+
usage="Bragg",
|
|
239
|
+
type="silicon",
|
|
240
|
+
reflection=(1, 1, 1),
|
|
241
|
+
d_spacing=3.13475,
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
217
246
|
def undulator(
|
|
218
247
|
wait_for_connection: bool = True,
|
|
219
248
|
fake_with_ophyd_sim: bool = True,
|
|
@@ -67,7 +67,11 @@ class DetectorParams(BaseModel):
|
|
|
67
67
|
def _parse_detector_size_constants(
|
|
68
68
|
cls, det_type: str, values: dict[str, Any]
|
|
69
69
|
) -> DetectorSizeConstants:
|
|
70
|
-
return
|
|
70
|
+
return (
|
|
71
|
+
det_type
|
|
72
|
+
if isinstance(det_type, DetectorSizeConstants)
|
|
73
|
+
else constants_from_type(det_type)
|
|
74
|
+
)
|
|
71
75
|
|
|
72
76
|
@validator("directory", pre=True)
|
|
73
77
|
def _parse_directory(cls, directory: str, values: dict[str, Any]) -> str:
|
dodal/devices/fast_grid_scan.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from abc import ABC
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Any, Generic, TypeVar
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
@@ -9,6 +9,7 @@ from ophyd_async.core import (
|
|
|
9
9
|
Device,
|
|
10
10
|
Signal,
|
|
11
11
|
SignalR,
|
|
12
|
+
SignalRW,
|
|
12
13
|
SoftSignalBackend,
|
|
13
14
|
StandardReadable,
|
|
14
15
|
wait_for_value,
|
|
@@ -16,8 +17,9 @@ from ophyd_async.core import (
|
|
|
16
17
|
from ophyd_async.epics.signal import (
|
|
17
18
|
epics_signal_r,
|
|
18
19
|
epics_signal_rw,
|
|
20
|
+
epics_signal_rw_rbv,
|
|
21
|
+
epics_signal_x,
|
|
19
22
|
)
|
|
20
|
-
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
21
23
|
from pydantic import validator
|
|
22
24
|
from pydantic.dataclasses import dataclass
|
|
23
25
|
|
|
@@ -212,7 +214,7 @@ class PandAGridScanParams(GridScanParamsCommon):
|
|
|
212
214
|
class MotionProgram(Device):
|
|
213
215
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
214
216
|
super().__init__(name)
|
|
215
|
-
self.running = epics_signal_r(
|
|
217
|
+
self.running = epics_signal_r(int, prefix + "PROGBITS")
|
|
216
218
|
self.program_number = epics_signal_r(float, prefix + "CS1:PROG_NUM")
|
|
217
219
|
|
|
218
220
|
|
|
@@ -240,38 +242,33 @@ class FastGridScanCommon(StandardReadable, ABC, Generic[ParamType]):
|
|
|
240
242
|
See https://github.com/DiamondLightSource/hyperion/wiki/Coordinate-Systems for more
|
|
241
243
|
"""
|
|
242
244
|
|
|
243
|
-
def __init__(self, prefix: str, name: str = "") -> None:
|
|
244
|
-
|
|
245
|
-
self.x_steps = epics_signal_rw_rbv(int, "X_NUM_STEPS")
|
|
245
|
+
def __init__(self, prefix: str, smargon_prefix: str, name: str = "") -> None:
|
|
246
|
+
self.x_steps = epics_signal_rw_rbv(int, f"{prefix}X_NUM_STEPS")
|
|
246
247
|
self.y_steps = epics_signal_rw_rbv(
|
|
247
|
-
int, "
|
|
248
|
+
int, f"{prefix}Y_NUM_STEPS"
|
|
248
249
|
) # Number of vertical steps during the first grid scan
|
|
249
250
|
self.z_steps = epics_signal_rw_rbv(
|
|
250
|
-
int, "
|
|
251
|
+
int, f"{prefix}Z_NUM_STEPS"
|
|
251
252
|
) # Number of vertical steps during the second grid scan, after the rotation in omega
|
|
252
|
-
self.x_step_size = epics_signal_rw_rbv(float, "X_STEP_SIZE")
|
|
253
|
-
self.y_step_size = epics_signal_rw_rbv(float, "Y_STEP_SIZE")
|
|
254
|
-
self.z_step_size = epics_signal_rw_rbv(float, "Z_STEP_SIZE")
|
|
255
|
-
self.x_start = epics_signal_rw_rbv(float, "X_START")
|
|
256
|
-
self.y1_start = epics_signal_rw_rbv(float, "Y_START")
|
|
257
|
-
self.y2_start = epics_signal_rw_rbv(float, "Y2_START")
|
|
258
|
-
self.z1_start = epics_signal_rw_rbv(float, "Z_START")
|
|
259
|
-
self.z2_start = epics_signal_rw_rbv(float, "Z2_START")
|
|
260
|
-
|
|
261
|
-
self.
|
|
262
|
-
int, "POS_COUNTER", write_pv="POS_COUNTER_WRITE"
|
|
263
|
-
)
|
|
264
|
-
self.x_counter = epics_signal_r(int, "X_COUNTER")
|
|
265
|
-
self.y_counter = epics_signal_r(int, "Y_COUNTER")
|
|
266
|
-
self.scan_invalid = epics_signal_r(float, "SCAN_INVALID")
|
|
253
|
+
self.x_step_size = epics_signal_rw_rbv(float, f"{prefix}X_STEP_SIZE")
|
|
254
|
+
self.y_step_size = epics_signal_rw_rbv(float, f"{prefix}Y_STEP_SIZE")
|
|
255
|
+
self.z_step_size = epics_signal_rw_rbv(float, f"{prefix}Z_STEP_SIZE")
|
|
256
|
+
self.x_start = epics_signal_rw_rbv(float, f"{prefix}X_START")
|
|
257
|
+
self.y1_start = epics_signal_rw_rbv(float, f"{prefix}Y_START")
|
|
258
|
+
self.y2_start = epics_signal_rw_rbv(float, f"{prefix}Y2_START")
|
|
259
|
+
self.z1_start = epics_signal_rw_rbv(float, f"{prefix}Z_START")
|
|
260
|
+
self.z2_start = epics_signal_rw_rbv(float, f"{prefix}Z2_START")
|
|
261
|
+
|
|
262
|
+
self.scan_invalid = epics_signal_r(float, f"{prefix}SCAN_INVALID")
|
|
267
263
|
|
|
268
|
-
self.run_cmd =
|
|
269
|
-
self.
|
|
270
|
-
self.status = epics_signal_r(float, "SCAN_STATUS")
|
|
264
|
+
self.run_cmd = epics_signal_x(f"{prefix}RUN.PROC")
|
|
265
|
+
self.status = epics_signal_r(int, f"{prefix}SCAN_STATUS")
|
|
271
266
|
|
|
272
267
|
self.expected_images = ExpectedImages(parent=self)
|
|
273
268
|
|
|
274
|
-
self.motion_program = MotionProgram(
|
|
269
|
+
self.motion_program = MotionProgram(smargon_prefix)
|
|
270
|
+
|
|
271
|
+
self.position_counter = self._create_position_counter(prefix)
|
|
275
272
|
|
|
276
273
|
# Kickoff timeout in seconds
|
|
277
274
|
self.KICKOFF_TIMEOUT: float = 5.0
|
|
@@ -291,6 +288,7 @@ class FastGridScanCommon(StandardReadable, ABC, Generic[ParamType]):
|
|
|
291
288
|
"z1_start": self.z1_start,
|
|
292
289
|
"z2_start": self.z2_start,
|
|
293
290
|
}
|
|
291
|
+
super().__init__(name)
|
|
294
292
|
|
|
295
293
|
@AsyncStatus.wrap
|
|
296
294
|
async def kickoff(self):
|
|
@@ -301,7 +299,7 @@ class FastGridScanCommon(StandardReadable, ABC, Generic[ParamType]):
|
|
|
301
299
|
await wait_for_value(self.motion_program.running, 0, self.KICKOFF_TIMEOUT)
|
|
302
300
|
|
|
303
301
|
LOGGER.debug("Running scan")
|
|
304
|
-
await self.run_cmd.
|
|
302
|
+
await self.run_cmd.trigger()
|
|
305
303
|
LOGGER.info("Waiting for FGS to start")
|
|
306
304
|
await wait_for_value(self.status, 1, self.KICKOFF_TIMEOUT)
|
|
307
305
|
LOGGER.debug("FGS kicked off")
|
|
@@ -310,6 +308,10 @@ class FastGridScanCommon(StandardReadable, ABC, Generic[ParamType]):
|
|
|
310
308
|
async def complete(self):
|
|
311
309
|
await wait_for_value(self.status, 0, self.COMPLETE_STATUS)
|
|
312
310
|
|
|
311
|
+
@abstractmethod
|
|
312
|
+
def _create_position_counter(self, prefix: str) -> SignalRW[int]:
|
|
313
|
+
pass
|
|
314
|
+
|
|
313
315
|
|
|
314
316
|
class ZebraFastGridScan(FastGridScanCommon[ZebraGridScanParams]):
|
|
315
317
|
"""Device for standard Zebra FGS. In this scan, the goniometer's velocity profile follows a parabolic shape between X steps,
|
|
@@ -317,29 +319,46 @@ class ZebraFastGridScan(FastGridScanCommon[ZebraGridScanParams]):
|
|
|
317
319
|
"""
|
|
318
320
|
|
|
319
321
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
320
|
-
|
|
321
|
-
|
|
322
|
+
full_prefix = prefix + "FGS:"
|
|
322
323
|
# Time taken to travel between X steps
|
|
323
|
-
self.dwell_time_ms = epics_signal_rw_rbv(float, "DWELL_TIME")
|
|
324
|
+
self.dwell_time_ms = epics_signal_rw_rbv(float, f"{full_prefix}DWELL_TIME")
|
|
325
|
+
|
|
326
|
+
self.x_counter = epics_signal_r(int, f"{full_prefix}X_COUNTER")
|
|
327
|
+
self.y_counter = epics_signal_r(int, f"{full_prefix}Y_COUNTER")
|
|
328
|
+
|
|
329
|
+
super().__init__(full_prefix, prefix, name)
|
|
330
|
+
|
|
324
331
|
self.movable_params["dwell_time_ms"] = self.dwell_time_ms
|
|
325
332
|
|
|
333
|
+
def _create_position_counter(self, prefix: str):
|
|
334
|
+
return epics_signal_rw(
|
|
335
|
+
int, f"{prefix}POS_COUNTER", write_pv=f"{prefix}POS_COUNTER_WRITE"
|
|
336
|
+
)
|
|
337
|
+
|
|
326
338
|
|
|
327
339
|
class PandAFastGridScan(FastGridScanCommon[PandAGridScanParams]):
|
|
328
340
|
"""Device for panda constant-motion scan"""
|
|
329
341
|
|
|
330
342
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
331
|
-
|
|
343
|
+
full_prefix = prefix + "PGS:"
|
|
332
344
|
self.time_between_x_steps_ms = (
|
|
333
345
|
epics_signal_rw_rbv( # Used by motion controller to set goniometer velocity
|
|
334
|
-
float, "TIME_BETWEEN_X_STEPS"
|
|
346
|
+
float, f"{full_prefix}TIME_BETWEEN_X_STEPS"
|
|
335
347
|
)
|
|
336
348
|
)
|
|
337
349
|
|
|
338
350
|
# Distance before and after the grid given to allow goniometer to reach desired speed while it is within the
|
|
339
351
|
# grid
|
|
340
|
-
self.run_up_distance_mm = epics_signal_rw_rbv(
|
|
352
|
+
self.run_up_distance_mm = epics_signal_rw_rbv(
|
|
353
|
+
float, f"{full_prefix}RUNUP_DISTANCE"
|
|
354
|
+
)
|
|
355
|
+
super().__init__(full_prefix, prefix, name)
|
|
356
|
+
|
|
341
357
|
self.movable_params["run_up_distance_mm"] = self.run_up_distance_mm
|
|
342
358
|
|
|
359
|
+
def _create_position_counter(self, prefix: str):
|
|
360
|
+
return epics_signal_rw(int, f"{prefix}Y_COUNTER")
|
|
361
|
+
|
|
343
362
|
|
|
344
363
|
def set_fast_grid_scan_params(scan: FastGridScanCommon[ParamType], params: ParamType):
|
|
345
364
|
to_move = []
|
dodal/devices/i22/dcm.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Dict, Literal
|
|
4
|
+
|
|
5
|
+
from bluesky.protocols import Reading
|
|
6
|
+
from event_model.documents.event_descriptor import DataKey
|
|
7
|
+
from ophyd_async.core import ConfigSignal, StandardReadable, soft_signal_r_and_setter
|
|
8
|
+
from ophyd_async.epics.motion import Motor
|
|
9
|
+
from ophyd_async.epics.signal import epics_signal_r
|
|
10
|
+
|
|
11
|
+
# Conversion constant for energy and wavelength, taken from the X-Ray data booklet
|
|
12
|
+
# Converts between energy in KeV and wavelength in angstrom
|
|
13
|
+
_CONVERSION_CONSTANT = 12.3984
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True, unsafe_hash=True)
|
|
17
|
+
class CrystalMetadata:
|
|
18
|
+
"""
|
|
19
|
+
Metadata used in the NeXus format,
|
|
20
|
+
see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
usage: Literal["Bragg", "Laue"] | None = None
|
|
24
|
+
type: str | None = None
|
|
25
|
+
reflection: tuple[int, int, int] | None = None
|
|
26
|
+
d_spacing: float | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DoubleCrystalMonochromator(StandardReadable):
|
|
30
|
+
"""
|
|
31
|
+
A double crystal monochromator (DCM), used to select the energy of the beam.
|
|
32
|
+
|
|
33
|
+
perp describes the gap between the 2 DCM crystals which has to change as you alter
|
|
34
|
+
the angle to select the requested energy.
|
|
35
|
+
|
|
36
|
+
offset ensures that the beam exits the DCM at the same point, regardless of energy.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
motion_prefix: str,
|
|
42
|
+
temperature_prefix: str,
|
|
43
|
+
crystal_1_metadata: CrystalMetadata | None = None,
|
|
44
|
+
crystal_2_metadata: CrystalMetadata | None = None,
|
|
45
|
+
prefix: str = "",
|
|
46
|
+
name: str = "",
|
|
47
|
+
) -> None:
|
|
48
|
+
with self.add_children_as_readables():
|
|
49
|
+
# Positionable Parameters
|
|
50
|
+
self.bragg = Motor(motion_prefix + "BRAGG")
|
|
51
|
+
self.offset = Motor(motion_prefix + "OFFSET")
|
|
52
|
+
self.perp = Motor(motion_prefix + "PERP")
|
|
53
|
+
self.energy = Motor(motion_prefix + "ENERGY")
|
|
54
|
+
self.crystal_1_roll = Motor(motion_prefix + "XTAL1:ROLL")
|
|
55
|
+
self.crystal_2_roll = Motor(motion_prefix + "XTAL2:ROLL")
|
|
56
|
+
self.crystal_2_pitch = Motor(motion_prefix + "XTAL2:PITCH")
|
|
57
|
+
|
|
58
|
+
# Temperatures
|
|
59
|
+
self.backplate_temp = epics_signal_r(float, temperature_prefix + "PT100-7")
|
|
60
|
+
self.perp_temp = epics_signal_r(float, temperature_prefix + "TC-1")
|
|
61
|
+
self.crystal_1_temp = epics_signal_r(float, temperature_prefix + "PT100-1")
|
|
62
|
+
self.crystal_1_heater_temp = epics_signal_r(
|
|
63
|
+
float, temperature_prefix + "PT100-2"
|
|
64
|
+
)
|
|
65
|
+
self.crystal_2_temp = epics_signal_r(float, temperature_prefix + "PT100-4")
|
|
66
|
+
self.crystal_2_heater_temp = epics_signal_r(
|
|
67
|
+
float, temperature_prefix + "PT100-5"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Soft metadata
|
|
71
|
+
# If supplied include crystal details in output of read_configuration
|
|
72
|
+
crystal_1_metadata = crystal_1_metadata or CrystalMetadata()
|
|
73
|
+
crystal_2_metadata = crystal_2_metadata or CrystalMetadata()
|
|
74
|
+
with self.add_children_as_readables(ConfigSignal):
|
|
75
|
+
if crystal_1_metadata.usage is not None:
|
|
76
|
+
self.crystal_1_usage, _ = soft_signal_r_and_setter(
|
|
77
|
+
str, initial_value=crystal_1_metadata.usage
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
self.crystal_1_usage = None
|
|
81
|
+
if crystal_1_metadata.type is not None:
|
|
82
|
+
self.crystal_1_type, _ = soft_signal_r_and_setter(
|
|
83
|
+
str, initial_value=crystal_1_metadata.type
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
self.crystal_1_type = None
|
|
87
|
+
if crystal_1_metadata.reflection is not None:
|
|
88
|
+
self.crystal_1_reflection, _ = soft_signal_r_and_setter(
|
|
89
|
+
str, initial_value=crystal_1_metadata.reflection
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
self.crystal_1_reflection = None
|
|
93
|
+
if crystal_1_metadata.d_spacing is not None:
|
|
94
|
+
self.crystal_1_d_spacing, _ = soft_signal_r_and_setter(
|
|
95
|
+
str, initial_value=crystal_1_metadata.d_spacing
|
|
96
|
+
)
|
|
97
|
+
else:
|
|
98
|
+
self.crystal_1_d_spacing = None
|
|
99
|
+
if crystal_2_metadata.usage is not None:
|
|
100
|
+
self.crystal_2_usage, _ = soft_signal_r_and_setter(
|
|
101
|
+
str, initial_value=crystal_2_metadata.usage
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
self.crystal_2_usage = None
|
|
105
|
+
if crystal_2_metadata.type is not None:
|
|
106
|
+
self.crystal_2_type, _ = soft_signal_r_and_setter(
|
|
107
|
+
str, initial_value=crystal_2_metadata.type
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
self.crystal_2_type = None
|
|
111
|
+
if crystal_2_metadata.reflection is not None:
|
|
112
|
+
self.crystal_2_reflection, _ = soft_signal_r_and_setter(
|
|
113
|
+
str, initial_value=crystal_2_metadata.reflection
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
self.crystal_2_reflection = None
|
|
117
|
+
if crystal_2_metadata.d_spacing is not None:
|
|
118
|
+
self.crystal_2_d_spacing, _ = soft_signal_r_and_setter(
|
|
119
|
+
str, initial_value=crystal_2_metadata.d_spacing
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
self.crystal_2_d_spacing = None
|
|
123
|
+
|
|
124
|
+
super().__init__(name)
|
|
125
|
+
|
|
126
|
+
async def describe(self) -> Dict[str, DataKey]:
|
|
127
|
+
default_describe = await super().describe()
|
|
128
|
+
return {
|
|
129
|
+
f"{self.name}-wavelength": DataKey(
|
|
130
|
+
dtype="number",
|
|
131
|
+
shape=[],
|
|
132
|
+
source=self.name,
|
|
133
|
+
units="angstrom",
|
|
134
|
+
),
|
|
135
|
+
**default_describe,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async def read(self) -> Dict[str, Reading]:
|
|
139
|
+
default_reading = await super().read()
|
|
140
|
+
energy: float = default_reading[f"{self.name}-energy"]["value"]
|
|
141
|
+
if energy > 0.0:
|
|
142
|
+
wavelength = _CONVERSION_CONSTANT / energy
|
|
143
|
+
else:
|
|
144
|
+
wavelength = 0.0
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
**default_reading,
|
|
148
|
+
f"{self.name}-wavelength": Reading(
|
|
149
|
+
value=wavelength,
|
|
150
|
+
timestamp=time.time(),
|
|
151
|
+
),
|
|
152
|
+
}
|
dodal/devices/motors.py
CHANGED
|
@@ -2,13 +2,17 @@ from dataclasses import dataclass
|
|
|
2
2
|
from typing import List, Tuple
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
-
from ophyd import
|
|
5
|
+
from ophyd import EpicsMotor
|
|
6
|
+
from ophyd_async.core import Device
|
|
7
|
+
from ophyd_async.epics.motion import Motor
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class XYZPositioner(Device):
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
def __init__(self, prefix: str, name: str):
|
|
12
|
+
self.x = Motor(prefix + "X")
|
|
13
|
+
self.y = Motor(prefix + "Y")
|
|
14
|
+
self.z = Motor(prefix + "Z")
|
|
15
|
+
super().__init__(name)
|
|
12
16
|
|
|
13
17
|
|
|
14
18
|
@dataclass
|
dodal/devices/oav/utils.py
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
from enum import IntEnum
|
|
2
|
+
from typing import Generator, Tuple
|
|
2
3
|
|
|
4
|
+
import bluesky.plan_stubs as bps
|
|
3
5
|
import numpy as np
|
|
6
|
+
from bluesky.utils import Msg
|
|
7
|
+
|
|
8
|
+
from dodal.devices.oav.oav_calculations import camera_coordinates_to_xyz
|
|
9
|
+
from dodal.devices.oav.oav_detector import OAVConfigParams
|
|
10
|
+
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
11
|
+
from dodal.devices.smargon import Smargon
|
|
12
|
+
|
|
13
|
+
Pixel = Tuple[int, int]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PinNotFoundException(Exception):
|
|
17
|
+
pass
|
|
4
18
|
|
|
5
19
|
|
|
6
20
|
def bottom_right_from_top_left(
|
|
@@ -47,3 +61,49 @@ class EdgeOutputArrayImageType(IntEnum):
|
|
|
47
61
|
PREPROCESSED = 2
|
|
48
62
|
CANNY_EDGES = 3
|
|
49
63
|
CLOSED_EDGES = 4
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_move_required_so_that_beam_is_at_pixel(
|
|
67
|
+
smargon: Smargon, pixel: Pixel, oav_params: OAVConfigParams
|
|
68
|
+
) -> Generator[Msg, None, np.ndarray]:
|
|
69
|
+
"""Calculate the required move so that the given pixel is in the centre of the beam."""
|
|
70
|
+
|
|
71
|
+
current_motor_xyz = np.array(
|
|
72
|
+
[
|
|
73
|
+
(yield from bps.rd(smargon.x)),
|
|
74
|
+
(yield from bps.rd(smargon.y)),
|
|
75
|
+
(yield from bps.rd(smargon.z)),
|
|
76
|
+
],
|
|
77
|
+
dtype=np.float64,
|
|
78
|
+
)
|
|
79
|
+
current_angle = yield from bps.rd(smargon.omega)
|
|
80
|
+
|
|
81
|
+
return calculate_x_y_z_of_pixel(current_motor_xyz, current_angle, pixel, oav_params)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def calculate_x_y_z_of_pixel(
|
|
85
|
+
current_x_y_z, current_omega, pixel: Pixel, oav_params: OAVConfigParams
|
|
86
|
+
) -> np.ndarray:
|
|
87
|
+
beam_distance_px: Pixel = oav_params.calculate_beam_distance(*pixel)
|
|
88
|
+
|
|
89
|
+
assert oav_params.micronsPerXPixel
|
|
90
|
+
assert oav_params.micronsPerYPixel
|
|
91
|
+
return current_x_y_z + camera_coordinates_to_xyz(
|
|
92
|
+
beam_distance_px[0],
|
|
93
|
+
beam_distance_px[1],
|
|
94
|
+
current_omega,
|
|
95
|
+
oav_params.micronsPerXPixel,
|
|
96
|
+
oav_params.micronsPerYPixel,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def wait_for_tip_to_be_found(
|
|
101
|
+
ophyd_pin_tip_detection: PinTipDetection,
|
|
102
|
+
) -> Generator[Msg, None, Pixel]:
|
|
103
|
+
yield from bps.trigger(ophyd_pin_tip_detection, wait=True)
|
|
104
|
+
found_tip = yield from bps.rd(ophyd_pin_tip_detection.triggered_tip)
|
|
105
|
+
if found_tip == ophyd_pin_tip_detection.INVALID_POSITION:
|
|
106
|
+
timeout = yield from bps.rd(ophyd_pin_tip_detection.validity_timeout)
|
|
107
|
+
raise PinNotFoundException(f"No pin found after {timeout} seconds")
|
|
108
|
+
|
|
109
|
+
return found_tip # type: ignore
|
dodal/devices/tetramm.py
CHANGED
|
@@ -115,8 +115,13 @@ class TetrammController(DetectorControl):
|
|
|
115
115
|
self,
|
|
116
116
|
num: int,
|
|
117
117
|
trigger: DetectorTrigger,
|
|
118
|
-
exposure: float,
|
|
118
|
+
exposure: float | None = None,
|
|
119
119
|
) -> AsyncStatus:
|
|
120
|
+
if exposure is None:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"Tetramm does not support arm without exposure time. "
|
|
123
|
+
"Is this a software scan? Tetramm only supports hardware scans."
|
|
124
|
+
)
|
|
120
125
|
self._validate_trigger(trigger)
|
|
121
126
|
|
|
122
127
|
# trigger mode must be set first and on its own!
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|