dls-dodal 1.37.0__py3-none-any.whl → 1.39.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.37.0.dist-info → dls_dodal-1.39.0.dist-info}/METADATA +3 -2
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.39.0.dist-info}/RECORD +29 -23
- dodal/_version.py +2 -2
- dodal/beamlines/i03.py +29 -7
- dodal/beamlines/i04.py +13 -2
- dodal/beamlines/i13_1.py +20 -2
- dodal/beamlines/i24.py +13 -1
- dodal/beamlines/training_rig.py +10 -1
- dodal/devices/eiger.py +21 -12
- dodal/devices/fast_grid_scan.py +13 -2
- dodal/devices/flux.py +10 -3
- dodal/devices/i04/transfocator.py +22 -29
- dodal/devices/i13_1/__init__.py +0 -0
- dodal/devices/i13_1/merlin.py +33 -0
- dodal/devices/i13_1/merlin_controller.py +52 -0
- dodal/devices/i13_1/merlin_io.py +17 -0
- dodal/devices/i24/beam_center.py +1 -1
- dodal/devices/p45.py +31 -20
- dodal/devices/s4_slit_gaps.py +8 -4
- dodal/devices/util/lookup_tables.py +14 -10
- dodal/devices/zebra/__init__.py +0 -0
- dodal/devices/{zebra.py → zebra/zebra.py} +3 -32
- dodal/devices/zebra/zebra_constants_mapping.py +96 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.39.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.39.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.39.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.39.0.dist-info}/top_level.txt +0 -0
- /dodal/devices/{zebra_controlled_shutter.py → zebra/zebra_controlled_shutter.py} +0 -0
- /dodal/{devices/util → plans}/save_panda.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dls-dodal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.39.0
|
|
4
4
|
Summary: Ophyd devices and other utils that could be used across DLS beamlines
|
|
5
5
|
Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
|
|
6
6
|
License: Apache License
|
|
@@ -216,7 +216,7 @@ Description-Content-Type: text/markdown
|
|
|
216
216
|
License-File: LICENSE
|
|
217
217
|
Requires-Dist: click
|
|
218
218
|
Requires-Dist: ophyd
|
|
219
|
-
Requires-Dist: ophyd-async
|
|
219
|
+
Requires-Dist: ophyd-async==0.9.0a1
|
|
220
220
|
Requires-Dist: bluesky
|
|
221
221
|
Requires-Dist: pyepics
|
|
222
222
|
Requires-Dist: dataclasses-json
|
|
@@ -237,6 +237,7 @@ Requires-Dist: scanspec>=0.7.3
|
|
|
237
237
|
Provides-Extra: dev
|
|
238
238
|
Requires-Dist: black; extra == "dev"
|
|
239
239
|
Requires-Dist: diff-cover; extra == "dev"
|
|
240
|
+
Requires-Dist: import-linter; extra == "dev"
|
|
240
241
|
Requires-Dist: mypy; extra == "dev"
|
|
241
242
|
Requires-Dist: myst-parser; extra == "dev"
|
|
242
243
|
Requires-Dist: ophyd_async[sim]; extra == "dev"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
dodal/__init__.py,sha256=Ksms_WJF8LTkbm38gEpm1jBpGqcQ8NGvmb2ZJlOE1j8,198
|
|
2
2
|
dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
|
|
3
|
-
dodal/_version.py,sha256=
|
|
3
|
+
dodal/_version.py,sha256=axP7CWypT2Bz3lKPHWWB933rMLqtEo77MpRXglYR8Ng,413
|
|
4
4
|
dodal/cli.py,sha256=NieWNUgLUxyck1rHoFAPJjX1xXLzHNdQ-s4wvxYFfps,3757
|
|
5
5
|
dodal/log.py,sha256=ry8WMq1S4WMIAPqtqGeKuegMRN7Jy3qdVTJlkpKXkL8,9503
|
|
6
6
|
dodal/utils.py,sha256=h2sNmTlsaznfxusV1Xj_mXtNjzsWjWAgmps6I0YNA3U,18097
|
|
@@ -11,18 +11,18 @@ dodal/beamlines/__init__.py,sha256=FsS1hMz9nqwTP12UtCJsfVn712mFElcBq2kKKpscp9k,3
|
|
|
11
11
|
dodal/beamlines/adsim.py,sha256=DUAFS1ueoZ6DK2cmZkiEm3NElnaro1mUvyodv14pSmU,1839
|
|
12
12
|
dodal/beamlines/b01_1.py,sha256=0gLjg0O9ttMjHzszSyJ_GT3fnoAB6u4aJ4MdAfjJbHA,1788
|
|
13
13
|
dodal/beamlines/i02_1.py,sha256=d2IyqFMgeaSEyZYm7GMSjTKr7_02SakyC_oARx-XwnY,1204
|
|
14
|
-
dodal/beamlines/i03.py,sha256=
|
|
15
|
-
dodal/beamlines/i04.py,sha256=
|
|
14
|
+
dodal/beamlines/i03.py,sha256=qm6bAY_M-EZ7ZSxBH3iwOxP9X_xyPXtzzzXGAHKSvcI,19397
|
|
15
|
+
dodal/beamlines/i04.py,sha256=3_cMBAnRuLkzC9ELf0-a-Rq2c76YPNTIJomHqIjys5U,14926
|
|
16
16
|
dodal/beamlines/i10.py,sha256=lkn_xg0pt-vFuWkUGyl62A0xT-Rzs71JztJ1EeQkMi0,11487
|
|
17
|
-
dodal/beamlines/i13_1.py,sha256=
|
|
17
|
+
dodal/beamlines/i13_1.py,sha256=MYl2TLomSXvAdEAEMWbNfEIcX46elaugbKtkehLvB8Q,2371
|
|
18
18
|
dodal/beamlines/i20_1.py,sha256=MaPgONHqpoZuBtkiKEzYtViJnKBM2_ekeP4OdbmuXHE,1158
|
|
19
19
|
dodal/beamlines/i22.py,sha256=ED6TtjwZzGn0Hot1WSgUhdOQ4amLDjkse5hBqEBD6Zg,7619
|
|
20
20
|
dodal/beamlines/i23.py,sha256=2j5qLoqE_hg9ETHqNkOVu7LLkVB8qalgXeORnVYKN_I,1075
|
|
21
|
-
dodal/beamlines/i24.py,sha256=
|
|
21
|
+
dodal/beamlines/i24.py,sha256=tao1YIZS0amhS8EHYOQ7-22twmPujC8fAvcGncDsm0A,8851
|
|
22
22
|
dodal/beamlines/p38.py,sha256=JJbclLYoRdIxcpzpW4oTj77YJ001CdEAM0bKRk7seYI,8735
|
|
23
23
|
dodal/beamlines/p45.py,sha256=N4SDTIFok3uMqb37higZHMr3xRjxItsT4ib_KacKKAE,2935
|
|
24
24
|
dodal/beamlines/p99.py,sha256=k24QhYpoOHBd0188Fu3wvmpT6dsu8okiIVqVVckdBkw,1063
|
|
25
|
-
dodal/beamlines/training_rig.py,sha256=
|
|
25
|
+
dodal/beamlines/training_rig.py,sha256=74lrNa_qNksA1eOsSZnhhcwAXcMJdw4fBc0a-w4IV5M,1897
|
|
26
26
|
dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
|
|
27
27
|
dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
|
|
28
28
|
dodal/common/crystal_metadata.py,sha256=XGr-X81G9SZvPx5b4nBCH4FOnywyX_zYVy6zwDxIMVM,1926
|
|
@@ -46,23 +46,23 @@ dodal/devices/bimorph_mirror.py,sha256=kG9waIdTkKglUrvY_wD9w533oKPqa7fct1-wa_GCF
|
|
|
46
46
|
dodal/devices/cryostream.py,sha256=K-ldpredpeDTzNt4qtQMg99nKJNjBYoXBbK0WJGexzw,656
|
|
47
47
|
dodal/devices/dcm.py,sha256=JbyxLnrS68nnnv39l9XEWgJgXUBqxX6aFo19MZnL36E,2574
|
|
48
48
|
dodal/devices/diamond_filter.py,sha256=A--RHd7WuH-IBhvCyENcRCTP4K-mm_Kqpa0pojpHZow,1098
|
|
49
|
-
dodal/devices/eiger.py,sha256=
|
|
49
|
+
dodal/devices/eiger.py,sha256=YPXriWxsMwRxRcXrdvMzs4Ho5EMqTMbshMir1L0dFmw,15738
|
|
50
50
|
dodal/devices/eiger_odin.py,sha256=ytUH_18YuM1nJDhplS6OTdtADloYvHpO6ppENjVd4jU,7411
|
|
51
|
-
dodal/devices/fast_grid_scan.py,sha256=
|
|
51
|
+
dodal/devices/fast_grid_scan.py,sha256=3obvHokmUf46MehQ6z--wIPthZaVSfc3idNKNnnax6s,11661
|
|
52
52
|
dodal/devices/fluorescence_detector_motion.py,sha256=-1qCSvW0PdT0m6BcoLxrtc0OJ5UDIBsEe11EOLr-gFw,501
|
|
53
|
-
dodal/devices/flux.py,sha256=
|
|
53
|
+
dodal/devices/flux.py,sha256=1CDsq9yU2-ho8MfYBl50Tl9ABZwpUBHnV486PQXKNoQ,462
|
|
54
54
|
dodal/devices/focusing_mirror.py,sha256=vdUPkwyCAZBSR3LQ-EojDOoxVy1ZmOaD_nevETbj7BA,6592
|
|
55
55
|
dodal/devices/hutch_shutter.py,sha256=WXY9JwqAa5prbf72IP7_MTKndPDtAltCpPJlNbq-F_0,3313
|
|
56
56
|
dodal/devices/ipin.py,sha256=eq5jlKw7WGQi8VLrAWpaAIsZmfiVf-5Q0td_B22H6A4,473
|
|
57
57
|
dodal/devices/linkam3.py,sha256=2sf-_heIsDg4qmqae-w9C2Py8pG8bPB3mT0TFPQIzd0,3869
|
|
58
58
|
dodal/devices/logging_ophyd_device.py,sha256=dUVE-XhWA56WUXez0mrc4sf322CXY3MVLreTycO5j_A,668
|
|
59
59
|
dodal/devices/motors.py,sha256=mduFm9vTZfu9rhwL93AMZpDzGd2TASdqalWzRaMoqec,1114
|
|
60
|
-
dodal/devices/p45.py,sha256=
|
|
60
|
+
dodal/devices/p45.py,sha256=hNCfWb8xubuHO8uJ5MpHPurp-r1ss7JMgbZQwHVJg-w,1743
|
|
61
61
|
dodal/devices/pgm.py,sha256=am-AST9iTqma1PkGOKLozqAokZWbJUbM3TNcqXzB-6A,1132
|
|
62
62
|
dodal/devices/pressure_jump_cell.py,sha256=ONvSHpnS-kA8hjOgyIks-J2n02pP6LhLm2SY1zC-i_8,9437
|
|
63
63
|
dodal/devices/qbpm.py,sha256=FfrWWAHHtYv3fGRT1qljyPpAwoHJYfbooT9CfKg-oXI,465
|
|
64
64
|
dodal/devices/robot.py,sha256=Pw6k8rFGr2-hkM2TVkQw2Y_dYIdXdXN7QtqjSglkp3g,5289
|
|
65
|
-
dodal/devices/s4_slit_gaps.py,sha256=
|
|
65
|
+
dodal/devices/s4_slit_gaps.py,sha256=4KdarIQoRqX4ry3LUS1Km7fkjUFahA0VuTd2DvYEqQ8,446
|
|
66
66
|
dodal/devices/scatterguard.py,sha256=jx03in9QgaThWxD4t1S8_Llent2kWrn_hThJ9KkUWTk,330
|
|
67
67
|
dodal/devices/scintillator.py,sha256=PlD6cnJ39PTB_e7QrRspPliLYE4kL_K7ziJURzuxgdA,365
|
|
68
68
|
dodal/devices/slits.py,sha256=b_7ku2sHlzhMHTvWrwiRwee6ufrbxNX9JB_Z0lvk15o,1105
|
|
@@ -77,8 +77,6 @@ dodal/devices/undulator_dcm.py,sha256=zulVn1wvu4-WEpf0BgLiDet58IsaKV7KW6qruAdRR_
|
|
|
77
77
|
dodal/devices/watsonmarlow323_pump.py,sha256=rwU94YE6esgGLYdh-pe8nBo_3tvgp6brrrbPDrqp5_M,1406
|
|
78
78
|
dodal/devices/webcam.py,sha256=mef075ynDbzZ4pNAjfxR_9tdTTqF_rM7hAOVEEOV-Do,2408
|
|
79
79
|
dodal/devices/xbpm_feedback.py,sha256=j8MHhhE0feoe6R54zPKqS5EbQ0bEDR-nOpLHzHhnHHQ,1156
|
|
80
|
-
dodal/devices/zebra.py,sha256=sPMAKaZOrBHQy5V9ue4-TKE9r29OG8nTZCzQQC7OMFQ,9637
|
|
81
|
-
dodal/devices/zebra_controlled_shutter.py,sha256=5-SH5HoXp_6P-xAtfDFJKQq6mBDwreubuCULSz78fgw,1852
|
|
82
80
|
dodal/devices/areadetector/plugins/CAM.py,sha256=sZzJm5Ez3eWfXZi_EB67wluhZmMQm1UyOc2bJFfzd1U,964
|
|
83
81
|
dodal/devices/areadetector/plugins/MJPG.py,sha256=QTsxCoWbofNpLMGPoOR2hWoM33KyntuLepbF0YmX0KE,3031
|
|
84
82
|
dodal/devices/attenuator/attenuator.py,sha256=eHJpM-E4XQfzy1mxGRk754y3n9q6i3youkCqQg_6SUM,3986
|
|
@@ -98,7 +96,7 @@ dodal/devices/detector/detector.py,sha256=syzkl52kGaMINXCXEviFuYPbgNatm5tioVPDmj
|
|
|
98
96
|
dodal/devices/detector/detector_motion.py,sha256=UGDQriDWRluDZOZh1mDX9w_fPjMD-_BGe11kA36Kezs,1616
|
|
99
97
|
dodal/devices/i03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
100
98
|
dodal/devices/i03/beamstop.py,sha256=D1-QeGNpNlUE1qtFz-XxgzQGZbvM5bdb09f69yDB7U0,2802
|
|
101
|
-
dodal/devices/i04/transfocator.py,sha256=
|
|
99
|
+
dodal/devices/i04/transfocator.py,sha256=sVI4Bgv-2-DH4-F1nIXMp5Aktevrm3agZnCA-WgjmW8,3780
|
|
102
100
|
dodal/devices/i10/i10_apple2.py,sha256=pEZes8wVCPHiOOcuVhEtqPvtnyphMxqbdp39mDp6xXQ,13165
|
|
103
101
|
dodal/devices/i10/i10_setting_data.py,sha256=69XWgE-YNTiW7C3t67MNcTL5JDDhOo7h-X7DCTpFE5g,164
|
|
104
102
|
dodal/devices/i10/mirrors.py,sha256=E0M5keGI3LGaDHyXQkCCyj6xmixNY1xTSkIaaYwtnP8,794
|
|
@@ -106,13 +104,17 @@ dodal/devices/i10/slits.py,sha256=4X50bGiJhTIHxhsOrv-8DATBkQPwQgEaFMNa2OsPrFY,12
|
|
|
106
104
|
dodal/devices/i10/rasor/rasor_current_amp.py,sha256=hImaPI3veKiS5YVfYwv-qrQ1AYNBjFVxG_MwTQqtkcc,2368
|
|
107
105
|
dodal/devices/i10/rasor/rasor_motors.py,sha256=0w31rKDuzRL-9tGbLDj0JZljaDjfXvKHQyzMs6fc3sw,1653
|
|
108
106
|
dodal/devices/i10/rasor/rasor_scaler_cards.py,sha256=wchXaIAWKLg_K14Zez4ZUmYLLk5pqL_QXegYLQO_6AY,463
|
|
107
|
+
dodal/devices/i13_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
|
+
dodal/devices/i13_1/merlin.py,sha256=Pi-nEqk6OOv3oOBYVb5lemQJiM03KsFbbR7pBAFg5Wg,982
|
|
109
|
+
dodal/devices/i13_1/merlin_controller.py,sha256=8uf9r-2RwpFy7DPT_rmv6AjfHPF_QyfHhIS0dqX73UM,1673
|
|
110
|
+
dodal/devices/i13_1/merlin_io.py,sha256=0To4dzeg1GNRTlsdKL7RbF2aXFyLlACGh9ZhEvIOhUc,531
|
|
109
111
|
dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
110
112
|
dodal/devices/i22/dcm.py,sha256=SQDh-Sj1OvplHZ9yTWblJwv8PJrUqxseDPupZOWmcLo,4701
|
|
111
113
|
dodal/devices/i22/fswitch.py,sha256=LSMoo9aDkH0SLcojbUh2NxTWIpUXHZxauTqThc3XtSk,3073
|
|
112
114
|
dodal/devices/i22/nxsas.py,sha256=a8oJXl5uhkh9zcb9rSZmVooU-SplzzO3EsAaHJZRfrQ,6086
|
|
113
115
|
dodal/devices/i24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
114
116
|
dodal/devices/i24/aperture.py,sha256=XlnOyQsvdTom1dJHVUg8CUSthq3jlBlZFOUaa9b1eZ4,837
|
|
115
|
-
dodal/devices/i24/beam_center.py,sha256=
|
|
117
|
+
dodal/devices/i24/beam_center.py,sha256=m6LWsG9e_lhtPfZ8pc_hoLNyTYQQGGdRNav8J_2scTo,483
|
|
116
118
|
dodal/devices/i24/beamstop.py,sha256=89ncXUisia1rn1Faf5iWg3k0QW6Rm99j1vq9A8l9Xv8,1221
|
|
117
119
|
dodal/devices/i24/dcm.py,sha256=Q3qqlgsiLJga2cgI8L4jczjyUgQixJh6QWg7shrFpTQ,1988
|
|
118
120
|
dodal/devices/i24/dual_backlight.py,sha256=CbQ9mYUNhhozVdNXqR5ac73tEIAWT2RnEpRwXB3EFog,2049
|
|
@@ -141,12 +143,15 @@ dodal/devices/training_rig/sample_stage.py,sha256=jktTp837ij8wor5LidE3AajCk95L7D
|
|
|
141
143
|
dodal/devices/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
142
144
|
dodal/devices/util/adjuster_plans.py,sha256=XpJ1YJKoOCFzj2sonkZYJAdewi3jRaok_2gOmNsfeS0,956
|
|
143
145
|
dodal/devices/util/epics_util.py,sha256=A8iNL79PnxntuxPTKA9oLGaDRKhnXaaeAVJwS6FNAWA,4687
|
|
144
|
-
dodal/devices/util/lookup_tables.py,sha256=
|
|
146
|
+
dodal/devices/util/lookup_tables.py,sha256=3gU9cOBhHBu1S6XqXHWNjCNkV7F4Z-eDlDfesvKbMg4,2185
|
|
145
147
|
dodal/devices/util/motor_utils.py,sha256=pNY-aUk9LxaIWeDr5rpMS6udiB9j19wcCXkNDLp1uA0,257
|
|
146
|
-
dodal/devices/util/save_panda.py,sha256=PHFlkerBhkkU0-o5dNEdi2P95_jD9Lk8yYgaqn9R97o,2538
|
|
147
148
|
dodal/devices/util/test_utils.py,sha256=x0QVKVeST4T-wpsVSSm-169MyNRXlmybVWnPTefv1as,565
|
|
148
149
|
dodal/devices/xspress3/xspress3.py,sha256=75RdPuHpES4Xi-Lcywz0XUhaN2G3vZSoc-dzgcxfNvs,4636
|
|
149
150
|
dodal/devices/xspress3/xspress3_channel.py,sha256=w8tAx2lz5kJ_LeJ_eb_4o--Dtt8MRijsYNgDG6oEIVg,1626
|
|
151
|
+
dodal/devices/zebra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
152
|
+
dodal/devices/zebra/zebra.py,sha256=_OA34T9CcgwXxyajVKai2jz4nHVDaEvMkb5eG5eAYKw,9192
|
|
153
|
+
dodal/devices/zebra/zebra_constants_mapping.py,sha256=DCWMvBFvmN90rBpZ4aOVF_hbKm4K6QWubsG811R-MK8,4170
|
|
154
|
+
dodal/devices/zebra/zebra_controlled_shutter.py,sha256=5-SH5HoXp_6P-xAtfDFJKQq6mBDwreubuCULSz78fgw,1852
|
|
150
155
|
dodal/devices/zocalo/__init__.py,sha256=dRAZ9o7B9TACqyE7aanT3yzvqWtt019YgV5ZJY7Ylso,517
|
|
151
156
|
dodal/devices/zocalo/zocalo_constants.py,sha256=vu7Xjz7UNEpBUWEEBxDvP4bVFkZIN6NLGfQDpWbCjH8,98
|
|
152
157
|
dodal/devices/zocalo/zocalo_interaction.py,sha256=GFukU9xqagQtVSDg5BrL23jxl1w8wjs4b4NLLqdFfpk,3584
|
|
@@ -158,11 +163,12 @@ dodal/plan_stubs/data_session.py,sha256=33wPwbs0mtMnle0H76mH_RNTc5omld7gNSJ9BvRd
|
|
|
158
163
|
dodal/plan_stubs/motor_utils.py,sha256=4c93U_WgjfmX12uNiztVW2oKxGVWa_SKQdJYCUNmsGU,4653
|
|
159
164
|
dodal/plan_stubs/wrapped.py,sha256=nriHKX4BF010CmrhdoUhY3-txClW5W8TPLz64kE_AXU,4533
|
|
160
165
|
dodal/plans/__init__.py,sha256=nH1jNxw3DzDMg9O8Uda0kqKIalRVEWBrq07OLY6Ey38,93
|
|
166
|
+
dodal/plans/save_panda.py,sha256=PHFlkerBhkkU0-o5dNEdi2P95_jD9Lk8yYgaqn9R97o,2538
|
|
161
167
|
dodal/plans/scanspec.py,sha256=Q0AcvTKRT401iGMRDSqK-D523UX5_ofiVMZ_rNXKOx8,2074
|
|
162
168
|
dodal/plans/wrapped.py,sha256=BPMw__RcWvk9v5XnhMsi9_k4KsDEbmXogzD2n1ecbUg,2098
|
|
163
|
-
dls_dodal-1.
|
|
164
|
-
dls_dodal-1.
|
|
165
|
-
dls_dodal-1.
|
|
166
|
-
dls_dodal-1.
|
|
167
|
-
dls_dodal-1.
|
|
168
|
-
dls_dodal-1.
|
|
169
|
+
dls_dodal-1.39.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
170
|
+
dls_dodal-1.39.0.dist-info/METADATA,sha256=f1fvkdiyW_ca594EvxsHQeU_S9w_omhpDw0Ph2bdfo0,16696
|
|
171
|
+
dls_dodal-1.39.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
172
|
+
dls_dodal-1.39.0.dist-info/entry_points.txt,sha256=bycw_EKUzup_rxfCetOwcauXV4kLln_OPpPT8jEnr-I,94
|
|
173
|
+
dls_dodal-1.39.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
|
|
174
|
+
dls_dodal-1.39.0.dist-info/RECORD,,
|
dodal/_version.py
CHANGED
dodal/beamlines/i03.py
CHANGED
|
@@ -40,8 +40,13 @@ from dodal.devices.undulator_dcm import UndulatorDCM
|
|
|
40
40
|
from dodal.devices.webcam import Webcam
|
|
41
41
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
42
42
|
from dodal.devices.xspress3.xspress3 import Xspress3
|
|
43
|
-
from dodal.devices.zebra import Zebra
|
|
44
|
-
from dodal.devices.
|
|
43
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
44
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
45
|
+
ZebraMapping,
|
|
46
|
+
ZebraSources,
|
|
47
|
+
ZebraTTLOutputs,
|
|
48
|
+
)
|
|
49
|
+
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
45
50
|
from dodal.devices.zocalo import ZocaloResults
|
|
46
51
|
from dodal.log import set_beamline as set_log_beamline
|
|
47
52
|
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
|
|
@@ -58,6 +63,12 @@ set_utils_beamline(BL)
|
|
|
58
63
|
|
|
59
64
|
set_path_provider(PandASubpathProvider())
|
|
60
65
|
|
|
66
|
+
I03_ZEBRA_MAPPING = ZebraMapping(
|
|
67
|
+
outputs=ZebraTTLOutputs(TTL_DETECTOR=1, TTL_SHUTTER=2, TTL_XSPRESS3=3, TTL_PANDA=4),
|
|
68
|
+
sources=ZebraSources(),
|
|
69
|
+
AND_GATE_FOR_AUTO_SHUTTER=2,
|
|
70
|
+
)
|
|
71
|
+
|
|
61
72
|
|
|
62
73
|
def aperture_scatterguard(
|
|
63
74
|
wait_for_connection: bool = True,
|
|
@@ -324,7 +335,9 @@ def synchrotron(
|
|
|
324
335
|
|
|
325
336
|
|
|
326
337
|
def undulator(
|
|
327
|
-
wait_for_connection: bool = True,
|
|
338
|
+
wait_for_connection: bool = True,
|
|
339
|
+
fake_with_ophyd_sim: bool = False,
|
|
340
|
+
daq_configuration_path: str | None = None,
|
|
328
341
|
) -> Undulator:
|
|
329
342
|
"""Get the i03 undulator device, instantiate it if it hasn't already been.
|
|
330
343
|
If this is called when already instantiated in i03, it will return the existing object.
|
|
@@ -336,12 +349,15 @@ def undulator(
|
|
|
336
349
|
wait_for_connection,
|
|
337
350
|
fake_with_ophyd_sim,
|
|
338
351
|
bl_prefix=False,
|
|
339
|
-
|
|
352
|
+
# evaluate here not as parameter default to enable post-import mocking
|
|
353
|
+
id_gap_lookup_table_path=f"{daq_configuration_path or DAQ_CONFIGURATION_PATH}/lookup/BeamLine_Undulator_toGap.txt",
|
|
340
354
|
)
|
|
341
355
|
|
|
342
356
|
|
|
343
357
|
def undulator_dcm(
|
|
344
|
-
wait_for_connection: bool = True,
|
|
358
|
+
wait_for_connection: bool = True,
|
|
359
|
+
fake_with_ophyd_sim: bool = False,
|
|
360
|
+
daq_configuration_path: str | None = None,
|
|
345
361
|
) -> UndulatorDCM:
|
|
346
362
|
"""Get the i03 undulator DCM device, instantiate it if it hasn't already been.
|
|
347
363
|
If this is called when already instantiated in i03, it will return the existing object.
|
|
@@ -352,9 +368,14 @@ def undulator_dcm(
|
|
|
352
368
|
prefix="",
|
|
353
369
|
wait=wait_for_connection,
|
|
354
370
|
fake=fake_with_ophyd_sim,
|
|
355
|
-
undulator=undulator(
|
|
371
|
+
undulator=undulator(
|
|
372
|
+
wait_for_connection,
|
|
373
|
+
fake_with_ophyd_sim,
|
|
374
|
+
daq_configuration_path=daq_configuration_path,
|
|
375
|
+
),
|
|
356
376
|
dcm=dcm(wait_for_connection, fake_with_ophyd_sim),
|
|
357
|
-
|
|
377
|
+
# evaluate here not as parameter default to enable post-import mocking
|
|
378
|
+
daq_configuration_path=daq_configuration_path or DAQ_CONFIGURATION_PATH,
|
|
358
379
|
)
|
|
359
380
|
|
|
360
381
|
|
|
@@ -368,6 +389,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
368
389
|
"-EA-ZEBRA-01:",
|
|
369
390
|
wait_for_connection,
|
|
370
391
|
fake_with_ophyd_sim,
|
|
392
|
+
mapping=I03_ZEBRA_MAPPING,
|
|
371
393
|
)
|
|
372
394
|
|
|
373
395
|
|
dodal/beamlines/i04.py
CHANGED
|
@@ -28,8 +28,13 @@ from dodal.devices.synchrotron import Synchrotron
|
|
|
28
28
|
from dodal.devices.thawer import Thawer
|
|
29
29
|
from dodal.devices.undulator import Undulator
|
|
30
30
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
31
|
-
from dodal.devices.zebra import Zebra
|
|
32
|
-
from dodal.devices.
|
|
31
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
32
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
33
|
+
ZebraMapping,
|
|
34
|
+
ZebraSources,
|
|
35
|
+
ZebraTTLOutputs,
|
|
36
|
+
)
|
|
37
|
+
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
33
38
|
from dodal.log import set_beamline as set_log_beamline
|
|
34
39
|
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
|
|
35
40
|
|
|
@@ -47,6 +52,11 @@ BL = get_beamline_name("s04")
|
|
|
47
52
|
set_log_beamline(BL)
|
|
48
53
|
set_utils_beamline(BL)
|
|
49
54
|
|
|
55
|
+
I04_ZEBRA_MAPPING = ZebraMapping(
|
|
56
|
+
outputs=(ZebraTTLOutputs(TTL_DETECTOR=1, TTL_FAST_SHUTTER=2, TTL_XSPRESS3=3)),
|
|
57
|
+
sources=ZebraSources(),
|
|
58
|
+
)
|
|
59
|
+
|
|
50
60
|
|
|
51
61
|
def smargon(
|
|
52
62
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
@@ -341,6 +351,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
341
351
|
"-EA-ZEBRA-01:",
|
|
342
352
|
wait_for_connection,
|
|
343
353
|
fake_with_ophyd_sim,
|
|
354
|
+
mapping=I04_ZEBRA_MAPPING,
|
|
344
355
|
)
|
|
345
356
|
|
|
346
357
|
|
dodal/beamlines/i13_1.py
CHANGED
|
@@ -8,7 +8,8 @@ from dodal.common.beamlines.beamline_utils import (
|
|
|
8
8
|
set_path_provider,
|
|
9
9
|
)
|
|
10
10
|
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
|
|
11
|
-
from dodal.common.visit import StaticVisitPathProvider
|
|
11
|
+
from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider
|
|
12
|
+
from dodal.devices.i13_1.merlin import Merlin
|
|
12
13
|
from dodal.devices.motors import XYZPositioner
|
|
13
14
|
from dodal.log import set_beamline as set_log_beamline
|
|
14
15
|
from dodal.utils import get_beamline_name
|
|
@@ -19,7 +20,8 @@ set_utils_beamline(BL)
|
|
|
19
20
|
set_path_provider(
|
|
20
21
|
StaticVisitPathProvider(
|
|
21
22
|
BL,
|
|
22
|
-
Path("/data/2024/cm37257-
|
|
23
|
+
Path("/dls/i13-1/data/2024/cm37257-5/tmp/"), # latest commissioning visit
|
|
24
|
+
client=LocalDirectoryServiceClient(),
|
|
23
25
|
)
|
|
24
26
|
)
|
|
25
27
|
|
|
@@ -64,3 +66,19 @@ def side_camera(
|
|
|
64
66
|
wait=wait_for_connection,
|
|
65
67
|
fake=fake_with_ophyd_sim,
|
|
66
68
|
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def merlin(
|
|
72
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
73
|
+
) -> Merlin:
|
|
74
|
+
return device_instantiation(
|
|
75
|
+
Merlin,
|
|
76
|
+
prefix="BL13J-EA-DET-04:",
|
|
77
|
+
name="merlin",
|
|
78
|
+
bl_prefix=False,
|
|
79
|
+
drv_suffix="CAM:",
|
|
80
|
+
hdf_suffix="HDF5:",
|
|
81
|
+
path_provider=get_path_provider(),
|
|
82
|
+
wait=wait_for_connection,
|
|
83
|
+
fake=fake_with_ophyd_sim,
|
|
84
|
+
)
|
dodal/beamlines/i24.py
CHANGED
|
@@ -16,7 +16,12 @@ from dodal.devices.i24.pmac import PMAC
|
|
|
16
16
|
from dodal.devices.i24.vgonio import VerticalGoniometer
|
|
17
17
|
from dodal.devices.oav.oav_detector import OAV
|
|
18
18
|
from dodal.devices.oav.oav_parameters import OAVConfig
|
|
19
|
-
from dodal.devices.zebra import Zebra
|
|
19
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
20
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
21
|
+
ZebraMapping,
|
|
22
|
+
ZebraSources,
|
|
23
|
+
ZebraTTLOutputs,
|
|
24
|
+
)
|
|
20
25
|
from dodal.log import set_beamline as set_log_beamline
|
|
21
26
|
from dodal.utils import get_beamline_name, skip_device
|
|
22
27
|
|
|
@@ -25,10 +30,16 @@ ZOOM_PARAMS_FILE = (
|
|
|
25
30
|
)
|
|
26
31
|
DISPLAY_CONFIG = "/dls_sw/i24/software/gda_versions/var/display.configuration"
|
|
27
32
|
|
|
33
|
+
|
|
28
34
|
BL = get_beamline_name("s24")
|
|
29
35
|
set_log_beamline(BL)
|
|
30
36
|
set_utils_beamline(BL)
|
|
31
37
|
|
|
38
|
+
I24_ZEBRA_MAPPING = ZebraMapping(
|
|
39
|
+
outputs=ZebraTTLOutputs(TTL_EIGER=1, TTL_PILATUS=2, TTL_FAST_SHUTTER=4),
|
|
40
|
+
sources=ZebraSources(),
|
|
41
|
+
)
|
|
42
|
+
|
|
32
43
|
|
|
33
44
|
def attenuator(
|
|
34
45
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
@@ -191,6 +202,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
191
202
|
"-EA-ZEBRA-01:",
|
|
192
203
|
wait_for_connection,
|
|
193
204
|
fake_with_ophyd_sim,
|
|
205
|
+
mapping=I24_ZEBRA_MAPPING,
|
|
194
206
|
)
|
|
195
207
|
|
|
196
208
|
|
dodal/beamlines/training_rig.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
from ophyd_async.epics.adaravis import AravisDetector
|
|
4
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
4
5
|
|
|
5
6
|
from dodal.common.beamlines.beamline_utils import (
|
|
6
7
|
device_factory,
|
|
@@ -33,7 +34,7 @@ set_utils_beamline(BL)
|
|
|
33
34
|
set_path_provider(
|
|
34
35
|
StaticVisitPathProvider(
|
|
35
36
|
BL,
|
|
36
|
-
Path("/
|
|
37
|
+
Path("/data"),
|
|
37
38
|
client=LocalDirectoryServiceClient(),
|
|
38
39
|
)
|
|
39
40
|
)
|
|
@@ -52,3 +53,11 @@ def det() -> AravisDetector:
|
|
|
52
53
|
drv_suffix="DET:",
|
|
53
54
|
hdf_suffix=HDF5_PREFIX,
|
|
54
55
|
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@device_factory()
|
|
59
|
+
def panda() -> HDFPanda:
|
|
60
|
+
return HDFPanda(
|
|
61
|
+
prefix=f"{PREFIX.beamline_prefix}-MO-PANDA-01:",
|
|
62
|
+
path_provider=get_path_provider(),
|
|
63
|
+
)
|
dodal/devices/eiger.py
CHANGED
|
@@ -62,6 +62,9 @@ class EigerDetector(Device):
|
|
|
62
62
|
arming_status = Status()
|
|
63
63
|
arming_status.set_finished()
|
|
64
64
|
|
|
65
|
+
disarming_status = Status()
|
|
66
|
+
disarming_status.set_finished()
|
|
67
|
+
|
|
65
68
|
def __init__(self, beamline: str = "i03", *args, **kwargs):
|
|
66
69
|
super().__init__(*args, **kwargs)
|
|
67
70
|
self.beamline = beamline
|
|
@@ -140,6 +143,7 @@ class EigerDetector(Device):
|
|
|
140
143
|
def unstage(self) -> bool:
|
|
141
144
|
assert self.detector_params is not None
|
|
142
145
|
try:
|
|
146
|
+
self.disarming_status = Status()
|
|
143
147
|
self.wait_on_arming_if_started()
|
|
144
148
|
if self.detector_params.trigger_mode == TriggerMode.FREE_RUN:
|
|
145
149
|
# In free run mode we have to manually stop odin
|
|
@@ -158,23 +162,28 @@ class EigerDetector(Device):
|
|
|
158
162
|
self.timeouts.general_status_timeout
|
|
159
163
|
)
|
|
160
164
|
self.disable_roi_mode()
|
|
165
|
+
self.disarming_status.set_finished()
|
|
161
166
|
return status_ok
|
|
162
167
|
|
|
163
168
|
def stop(self, *args):
|
|
164
169
|
"""Emergency stop the device, mainly used to clean up after error."""
|
|
165
170
|
LOGGER.info("Eiger stop() called - cleaning up...")
|
|
166
|
-
self.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
171
|
+
if not self.disarming_status.done:
|
|
172
|
+
LOGGER.info("Eiger still disarming, waiting on disarm")
|
|
173
|
+
self.disarming_status.wait(self.timeouts.arming_timeout)
|
|
174
|
+
else:
|
|
175
|
+
self.wait_on_arming_if_started()
|
|
176
|
+
stop_status = self.odin.stop()
|
|
177
|
+
self.odin.file_writer.start_timeout.set(1).wait(
|
|
178
|
+
self.timeouts.general_status_timeout
|
|
179
|
+
)
|
|
180
|
+
self.disarm_detector()
|
|
181
|
+
stop_status &= self.disable_roi_mode()
|
|
182
|
+
stop_status.wait(self.timeouts.general_status_timeout)
|
|
183
|
+
# See https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
184
|
+
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
185
|
+
self.odin.fan.dev_shm_enable.set(0).wait()
|
|
186
|
+
LOGGER.info("Eiger has successfully been stopped")
|
|
178
187
|
|
|
179
188
|
def disable_roi_mode(self):
|
|
180
189
|
return self.change_roi_mode(False)
|
dodal/devices/fast_grid_scan.py
CHANGED
|
@@ -45,8 +45,19 @@ class GridAxis:
|
|
|
45
45
|
# refering to the first position
|
|
46
46
|
return self.steps_to_motor_position(self.full_steps - 1)
|
|
47
47
|
|
|
48
|
-
def is_within(self, steps):
|
|
49
|
-
|
|
48
|
+
def is_within(self, steps: float):
|
|
49
|
+
"""
|
|
50
|
+
Determine whether a single axis coordinate is within the grid.
|
|
51
|
+
The coordinate is from a continuous coordinate space based on the
|
|
52
|
+
XRC grid where the origin corresponds to the centre of the first grid box.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
steps: The coordinate to check
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
True if the coordinate falls within the grid.
|
|
59
|
+
"""
|
|
60
|
+
return -0.5 <= steps <= self.full_steps - 0.5
|
|
50
61
|
|
|
51
62
|
|
|
52
63
|
class GridScanParamsCommon(AbstractExperimentWithBeamParams):
|
dodal/devices/flux.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import (
|
|
2
|
+
StandardReadable,
|
|
3
|
+
StandardReadableFormat,
|
|
4
|
+
)
|
|
5
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
2
6
|
|
|
3
7
|
|
|
4
|
-
class Flux(
|
|
8
|
+
class Flux(StandardReadable):
|
|
5
9
|
"""Simple device to get the flux reading"""
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
12
|
+
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
|
|
13
|
+
self.flux_reading = epics_signal_r(float, prefix + "SAMP")
|
|
14
|
+
super().__init__(name=name)
|
|
@@ -37,32 +37,18 @@ class Transfocator(StandardReadable):
|
|
|
37
37
|
|
|
38
38
|
super().__init__(name=name)
|
|
39
39
|
|
|
40
|
-
async def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await self.number_filters_sp.set(value)
|
|
53
|
-
await self.start.set(1)
|
|
54
|
-
LOGGER.info("Waiting for start_rbv to change to 1")
|
|
55
|
-
await wait_for_value(self.start_rbv, 1, self.TIMEOUT)
|
|
56
|
-
LOGGER.info("Waiting for start_rbv to change to 0")
|
|
57
|
-
await wait_for_value(self.start_rbv, 0, self.TIMEOUT)
|
|
58
|
-
self.latest_pred_vertical_num_lenses = value
|
|
59
|
-
is_set_filters_done = True
|
|
60
|
-
|
|
61
|
-
# The value hasn't changed so assume the device is already set up correctly
|
|
62
|
-
async for value in observe_value(self.predicted_vertical_num_lenses):
|
|
63
|
-
await set_based_on_prediction(value)
|
|
64
|
-
if is_set_filters_done:
|
|
65
|
-
break
|
|
40
|
+
async def set_based_on_prediction(self, value: float):
|
|
41
|
+
# We can only put an integer number of lenses in the beam but the
|
|
42
|
+
# calculation in the IOC returns the theoretical float number of lenses
|
|
43
|
+
value = round(value)
|
|
44
|
+
LOGGER.info(f"Transfocator setting {value} filters")
|
|
45
|
+
await self.number_filters_sp.set(value)
|
|
46
|
+
await self.start.set(1)
|
|
47
|
+
LOGGER.info("Waiting for start_rbv to change to 1")
|
|
48
|
+
await wait_for_value(self.start_rbv, 1, self.TIMEOUT)
|
|
49
|
+
LOGGER.info("Waiting for start_rbv to change to 0")
|
|
50
|
+
await wait_for_value(self.start_rbv, 0, self.TIMEOUT)
|
|
51
|
+
self.latest_pred_vertical_num_lenses = value
|
|
66
52
|
|
|
67
53
|
@AsyncStatus.wrap
|
|
68
54
|
async def set(self, value: float):
|
|
@@ -81,10 +67,17 @@ class Transfocator(StandardReadable):
|
|
|
81
67
|
|
|
82
68
|
if await self.beamsize_set_microns.get_value() != value:
|
|
83
69
|
# Logic in the IOC calculates predicted_vertical_num_lenses when beam_set_microns changes
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
|
|
71
|
+
# Register an observer before setting beamsize_set_microns to ensure we don't miss changes
|
|
72
|
+
predicted_vertical_num_lenses_iterator = observe_value(
|
|
73
|
+
self.predicted_vertical_num_lenses, timeout=self.TIMEOUT
|
|
87
74
|
)
|
|
75
|
+
# Keep initial prediction before setting to later compare with change after setting
|
|
76
|
+
current_prediction = await anext(predicted_vertical_num_lenses_iterator)
|
|
77
|
+
await self.beamsize_set_microns.set(value)
|
|
78
|
+
accepted_prediction = await anext(predicted_vertical_num_lenses_iterator)
|
|
79
|
+
if not math.isclose(current_prediction, accepted_prediction, abs_tol=1e-8):
|
|
80
|
+
await self.set_based_on_prediction(accepted_prediction)
|
|
88
81
|
|
|
89
82
|
number_filters_rbv, vertical_lens_size_rbv = await asyncio.gather(
|
|
90
83
|
self.number_filters_sp.get_value(),
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from ophyd_async.core import PathProvider, StandardDetector
|
|
2
|
+
from ophyd_async.epics import adcore
|
|
3
|
+
|
|
4
|
+
from dodal.devices.i13_1.merlin_controller import MerlinController
|
|
5
|
+
from dodal.devices.i13_1.merlin_io import MerlinDriverIO
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Merlin(StandardDetector):
|
|
9
|
+
_controller: MerlinController
|
|
10
|
+
_writer: adcore.ADHDFWriter
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
prefix: str,
|
|
15
|
+
path_provider: PathProvider,
|
|
16
|
+
drv_suffix="CAM:",
|
|
17
|
+
hdf_suffix="HDF:",
|
|
18
|
+
name: str = "",
|
|
19
|
+
):
|
|
20
|
+
self.drv = MerlinDriverIO(prefix + drv_suffix)
|
|
21
|
+
self.hdf = adcore.NDFileHDFIO(prefix + hdf_suffix)
|
|
22
|
+
|
|
23
|
+
super().__init__(
|
|
24
|
+
MerlinController(self.drv),
|
|
25
|
+
adcore.ADHDFWriter(
|
|
26
|
+
self.hdf,
|
|
27
|
+
path_provider,
|
|
28
|
+
lambda: self.name,
|
|
29
|
+
adcore.ADBaseDatasetDescriber(self.drv),
|
|
30
|
+
),
|
|
31
|
+
config_sigs=(self.drv.acquire_period, self.drv.acquire_time),
|
|
32
|
+
name=name,
|
|
33
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from ophyd_async.core import (
|
|
5
|
+
DEFAULT_TIMEOUT,
|
|
6
|
+
AsyncStatus,
|
|
7
|
+
DetectorController,
|
|
8
|
+
TriggerInfo,
|
|
9
|
+
)
|
|
10
|
+
from ophyd_async.epics import adcore
|
|
11
|
+
|
|
12
|
+
from dodal.devices.i13_1.merlin_io import MerlinDriverIO, MerlinImageMode
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MerlinController(DetectorController):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
driver: MerlinDriverIO,
|
|
19
|
+
good_states: frozenset[adcore.DetectorState] = adcore.DEFAULT_GOOD_STATES,
|
|
20
|
+
) -> None:
|
|
21
|
+
self.driver = driver
|
|
22
|
+
self.good_states = good_states
|
|
23
|
+
self.frame_timeout: float = 0
|
|
24
|
+
self._arm_status: AsyncStatus | None = None
|
|
25
|
+
for drv_child in self.driver.children():
|
|
26
|
+
logging.debug(drv_child)
|
|
27
|
+
|
|
28
|
+
def get_deadtime(self, exposure: float | None) -> float:
|
|
29
|
+
return 0.002
|
|
30
|
+
|
|
31
|
+
async def prepare(self, trigger_info: TriggerInfo):
|
|
32
|
+
self.frame_timeout = (
|
|
33
|
+
DEFAULT_TIMEOUT + await self.driver.acquire_time.get_value()
|
|
34
|
+
)
|
|
35
|
+
await asyncio.gather(
|
|
36
|
+
self.driver.num_images.set(trigger_info.total_number_of_triggers),
|
|
37
|
+
self.driver.image_mode.set(MerlinImageMode.MULTIPLE),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
async def arm(self):
|
|
41
|
+
self._arm_status = await adcore.start_acquiring_driver_and_ensure_status(
|
|
42
|
+
self.driver, good_states=self.good_states, timeout=self.frame_timeout
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def wait_for_idle(self):
|
|
46
|
+
if self._arm_status:
|
|
47
|
+
await self._arm_status
|
|
48
|
+
|
|
49
|
+
async def disarm(self):
|
|
50
|
+
# We can't use caput callback as we already used it in arm() and we can't have
|
|
51
|
+
# 2 or they will deadlock
|
|
52
|
+
await adcore.stop_busy_record(self.driver.acquire, False, timeout=1)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ophyd_async.core import StrictEnum
|
|
2
|
+
from ophyd_async.epics import adcore
|
|
3
|
+
from ophyd_async.epics.core import epics_signal_rw_rbv
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MerlinImageMode(StrictEnum):
|
|
7
|
+
SINGLE = "Single"
|
|
8
|
+
MULTIPLE = "Multiple"
|
|
9
|
+
CONTINUOUS = "Continuous"
|
|
10
|
+
THRESHOLD = "Threshold"
|
|
11
|
+
BACKGROUND = "Background"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MerlinDriverIO(adcore.ADBaseIO):
|
|
15
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
16
|
+
super().__init__(prefix, name)
|
|
17
|
+
self.image_mode = epics_signal_rw_rbv(MerlinImageMode, prefix + "ImageMode")
|
dodal/devices/i24/beam_center.py
CHANGED
|
@@ -7,6 +7,6 @@ from ophyd_async.epics.core import epics_signal_rw
|
|
|
7
7
|
|
|
8
8
|
class DetectorBeamCenter(StandardReadable):
|
|
9
9
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
10
|
-
self.beam_x = epics_signal_rw(float, prefix + "BeamX")
|
|
10
|
+
self.beam_x = epics_signal_rw(float, prefix + "BeamX") # in pixels
|
|
11
11
|
self.beam_y = epics_signal_rw(float, prefix + "BeamY")
|
|
12
12
|
super().__init__(name)
|
dodal/devices/p45.py
CHANGED
|
@@ -1,44 +1,55 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from ophyd.areadetector.base import ADComponent as Cpt
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
class SampleY(
|
|
5
|
+
class SampleY(StandardReadable):
|
|
7
6
|
"""
|
|
8
7
|
Motors for controlling the sample's y position and stretch in the y axis.
|
|
9
8
|
"""
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
11
|
+
with self.add_children_as_readables():
|
|
12
|
+
self.base = Motor(prefix + "CS:Y")
|
|
13
|
+
self.stretch = Motor(prefix + "CS:Y:STRETCH")
|
|
14
|
+
self.top = Motor(prefix + "Y:TOP")
|
|
15
|
+
self.bottom = Motor(prefix + "Y:BOT")
|
|
16
|
+
super().__init__(name=name)
|
|
15
17
|
|
|
16
18
|
|
|
17
|
-
class SampleTheta(
|
|
19
|
+
class SampleTheta(StandardReadable):
|
|
18
20
|
"""
|
|
19
21
|
Motors for controlling the sample's theta position and skew
|
|
20
22
|
"""
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
25
|
+
with self.add_children_as_readables():
|
|
26
|
+
self.base = Motor(prefix + "THETA:POS")
|
|
27
|
+
self.skew = Motor(prefix + "THETA:SKEW")
|
|
28
|
+
self.top = Motor(prefix + "THETA:TOP")
|
|
29
|
+
self.bottom = Motor(prefix + "THETA:BOT")
|
|
30
|
+
super().__init__(name=name)
|
|
26
31
|
|
|
27
32
|
|
|
28
|
-
class TomoStageWithStretchAndSkew(
|
|
33
|
+
class TomoStageWithStretchAndSkew(StandardReadable):
|
|
29
34
|
"""
|
|
30
35
|
Grouping of motors for the P45 tomography stage
|
|
31
36
|
"""
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
39
|
+
with self.add_children_as_readables():
|
|
40
|
+
self.x = Motor(prefix + "X")
|
|
41
|
+
self.y = SampleY(prefix)
|
|
42
|
+
self.theta = SampleTheta(prefix)
|
|
43
|
+
super().__init__(name=name)
|
|
36
44
|
|
|
37
45
|
|
|
38
|
-
class Choppers(
|
|
46
|
+
class Choppers(StandardReadable):
|
|
39
47
|
"""
|
|
40
48
|
Grouping for the P45 chopper motors
|
|
41
49
|
"""
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
52
|
+
with self.add_children_as_readables():
|
|
53
|
+
self.x = Motor(prefix + "ENDAT")
|
|
54
|
+
self.y = Motor(prefix + "BISS")
|
|
55
|
+
super().__init__(name=name)
|
dodal/devices/s4_slit_gaps.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
class S4SlitGaps(
|
|
5
|
+
class S4SlitGaps(StandardReadable):
|
|
5
6
|
"""Note that the S4 slits have a different PV fromat to other beamline slits"""
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
9
|
+
with self.add_children_as_readables():
|
|
10
|
+
self.xgap = Motor(prefix + "XGAP")
|
|
11
|
+
self.ygap = Motor(prefix + "YGAP")
|
|
12
|
+
super().__init__(name=name)
|
|
@@ -32,28 +32,32 @@ async def energy_distance_table(lookup_table_path: str) -> np.ndarray:
|
|
|
32
32
|
return loadtxt(StringIO(raw_table), comments=["#", "Units"])
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def
|
|
35
|
+
def parse_lookup_table(filename: str) -> list[Sequence]:
|
|
36
|
+
"""Parse a generic lookup table with a number of columns >= 2 and return a list \
|
|
37
|
+
in column major order of the values in it."""
|
|
38
|
+
LOGGER.info(f"Parsing lookup table file {filename}")
|
|
39
|
+
|
|
40
|
+
lut_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
41
|
+
return list(lut_vals)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def linear_interpolation_lut(
|
|
45
|
+
s_values: Sequence, t_values: Sequence
|
|
46
|
+
) -> Callable[[float], float]:
|
|
36
47
|
"""Returns a callable that converts values by linear interpolation of lookup table
|
|
37
48
|
values.
|
|
38
49
|
|
|
39
50
|
If the value falls outside the lookup table then the closest value will be used."""
|
|
40
|
-
LOGGER.info(f"Using lookup table {filename}")
|
|
41
|
-
s_and_t_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
42
|
-
|
|
43
|
-
s_values: Sequence
|
|
44
|
-
t_values: Sequence
|
|
45
|
-
s_values, t_values = s_and_t_vals
|
|
46
|
-
|
|
47
51
|
# numpy interp expects x-values to be increasing
|
|
48
52
|
if not np.all(np.diff(s_values) > 0):
|
|
49
53
|
LOGGER.info(
|
|
50
|
-
|
|
54
|
+
"Configuration values in the lookup table are not ascending, trying reverse order..."
|
|
51
55
|
)
|
|
52
56
|
s_values = list(reversed(s_values))
|
|
53
57
|
t_values = list(reversed(t_values))
|
|
54
58
|
if not np.all(np.diff(s_values) > 0):
|
|
55
59
|
raise AssertionError(
|
|
56
|
-
|
|
60
|
+
"Configuration lookup table does not monotonically increase or decrease."
|
|
57
61
|
)
|
|
58
62
|
|
|
59
63
|
def s_to_t2(s: float) -> float:
|
|
File without changes
|
|
@@ -14,37 +14,7 @@ from ophyd_async.core import (
|
|
|
14
14
|
)
|
|
15
15
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
# Sources
|
|
19
|
-
DISCONNECT = 0
|
|
20
|
-
IN1_TTL = 1
|
|
21
|
-
IN2_TTL = 4
|
|
22
|
-
IN3_TTL = 7
|
|
23
|
-
IN4_TTL = 10
|
|
24
|
-
PC_ARM = 29
|
|
25
|
-
PC_GATE = 30
|
|
26
|
-
PC_PULSE = 31
|
|
27
|
-
AND3 = 34
|
|
28
|
-
AND4 = 35
|
|
29
|
-
OR1 = 36
|
|
30
|
-
PULSE1 = 52
|
|
31
|
-
PULSE2 = 53
|
|
32
|
-
SOFT_IN1 = 60
|
|
33
|
-
SOFT_IN2 = 61
|
|
34
|
-
SOFT_IN3 = 62
|
|
35
|
-
|
|
36
|
-
# Instrument specific
|
|
37
|
-
TTL_DETECTOR = 1
|
|
38
|
-
TTL_SHUTTER = 2
|
|
39
|
-
TTL_XSPRESS3 = 3
|
|
40
|
-
TTL_PANDA = 4
|
|
41
|
-
|
|
42
|
-
# The AND gate that controls the automatic shutter
|
|
43
|
-
AUTO_SHUTTER_GATE = 2
|
|
44
|
-
|
|
45
|
-
# The first two inputs of the auto shutter gate.
|
|
46
|
-
AUTO_SHUTTER_INPUT_1 = 1
|
|
47
|
-
AUTO_SHUTTER_INPUT_2 = 2
|
|
17
|
+
from dodal.devices.zebra.zebra_constants_mapping import ZebraMapping
|
|
48
18
|
|
|
49
19
|
|
|
50
20
|
class ArmSource(StrictEnum):
|
|
@@ -303,7 +273,8 @@ class SoftInputs(StandardReadable):
|
|
|
303
273
|
class Zebra(StandardReadable):
|
|
304
274
|
"""The Zebra device."""
|
|
305
275
|
|
|
306
|
-
def __init__(self, name: str, prefix: str) -> None:
|
|
276
|
+
def __init__(self, mapping: ZebraMapping, name: str, prefix: str) -> None:
|
|
277
|
+
self.mapping = mapping
|
|
307
278
|
self.pc = PositionCompare(prefix, name)
|
|
308
279
|
self.output = ZebraOutputPanel(prefix, name)
|
|
309
280
|
self.inputs = SoftInputs(prefix, name)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, model_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ZebraMappingValidations(BaseModel):
|
|
7
|
+
"""Raises an exception if field set to -1 is accessed, and validate against
|
|
8
|
+
multiple fields mapping to the same integer"""
|
|
9
|
+
|
|
10
|
+
def __getattribute__(self, name: str):
|
|
11
|
+
"""To protect against mismatch between the Zebra configuration that a plan expects and the Zebra which has
|
|
12
|
+
been instantiated, raise exception if a field which has been set to -1 is accessed."""
|
|
13
|
+
value = object.__getattribute__(self, name)
|
|
14
|
+
if not name.startswith("__"):
|
|
15
|
+
if value == -1:
|
|
16
|
+
raise UnmappedZebraException(
|
|
17
|
+
f"'{type(self).__name__}.{name}' was accessed but is set to -1. Please check the zebra mappings against the zebra's physical configuration"
|
|
18
|
+
)
|
|
19
|
+
return value
|
|
20
|
+
|
|
21
|
+
@model_validator(mode="after")
|
|
22
|
+
def ensure_no_duplicate_connections(self):
|
|
23
|
+
"""Check that TTL outputs and sources are mapped to unique integers"""
|
|
24
|
+
|
|
25
|
+
integer_fields = {
|
|
26
|
+
key: value
|
|
27
|
+
for key, value in self.model_dump().items()
|
|
28
|
+
if isinstance(value, int) and value != -1
|
|
29
|
+
}
|
|
30
|
+
counted_vals = Counter(integer_fields.values())
|
|
31
|
+
integer_fields_with_duplicates = {
|
|
32
|
+
k: v for k, v in integer_fields.items() if counted_vals[v] > 1
|
|
33
|
+
}
|
|
34
|
+
if len(integer_fields_with_duplicates):
|
|
35
|
+
raise ValueError(
|
|
36
|
+
f"Each field in {type(self)} must be mapped to a unique integer. Duplicate fields: {integer_fields_with_duplicates}"
|
|
37
|
+
)
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ZebraTTLOutputs(ZebraMappingValidations):
|
|
42
|
+
"""Maps hardware to the Zebra TTL output (1-4) that they're physically wired to, or
|
|
43
|
+
None if that hardware is not connected. A value of -1 means this hardware is not connected."""
|
|
44
|
+
|
|
45
|
+
TTL_EIGER: int = Field(default=-1, ge=-1, le=4)
|
|
46
|
+
TTL_PILATUS: int = Field(default=-1, ge=-1, le=4)
|
|
47
|
+
TTL_FAST_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
48
|
+
TTL_DETECTOR: int = Field(default=-1, ge=-1, le=4)
|
|
49
|
+
TTL_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
50
|
+
TTL_XSPRESS3: int = Field(default=-1, ge=-1, le=4)
|
|
51
|
+
TTL_PANDA: int = Field(default=-1, ge=-1, le=4)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ZebraSources(ZebraMappingValidations):
|
|
55
|
+
"""Maps internal Zebra signal source to their integer PV value"""
|
|
56
|
+
|
|
57
|
+
DISCONNECT: int = Field(default=0, ge=0, le=63)
|
|
58
|
+
IN1_TTL: int = Field(default=1, ge=0, le=63)
|
|
59
|
+
IN2_TTL: int = Field(default=63, ge=0, le=63)
|
|
60
|
+
IN3_TTL: int = Field(default=7, ge=0, le=63)
|
|
61
|
+
IN4_TTL: int = Field(default=10, ge=0, le=63)
|
|
62
|
+
PC_ARM: int = Field(default=29, ge=0, le=63)
|
|
63
|
+
PC_GATE: int = Field(default=30, ge=0, le=63)
|
|
64
|
+
PC_PULSE: int = Field(default=31, ge=0, le=63)
|
|
65
|
+
AND3: int = Field(default=34, ge=0, le=63)
|
|
66
|
+
AND4: int = Field(default=35, ge=0, le=63)
|
|
67
|
+
OR1: int = Field(default=36, ge=0, le=63)
|
|
68
|
+
PULSE1: int = Field(default=52, ge=0, le=63)
|
|
69
|
+
PULSE2: int = Field(default=53, ge=0, le=63)
|
|
70
|
+
SOFT_IN1: int = Field(default=60, ge=0, le=63)
|
|
71
|
+
SOFT_IN2: int = Field(default=61, ge=0, le=63)
|
|
72
|
+
SOFT_IN3: int = Field(default=62, ge=0, le=63)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ZebraMapping(ZebraMappingValidations):
|
|
76
|
+
"""Mappings to locate a Zebra device's Ophyd signals based on a specific
|
|
77
|
+
Zebra's hardware configuration and wiring.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# Zebra ophyd signal for connection can be accessed
|
|
81
|
+
# with, eg, zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR]
|
|
82
|
+
outputs: ZebraTTLOutputs = ZebraTTLOutputs()
|
|
83
|
+
|
|
84
|
+
# Zebra ophyd signal sources can be mapped to a zebra output by doing, eg,
|
|
85
|
+
# bps.abs_set(zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
|
|
86
|
+
# zebra.mapping.sources.AND3)
|
|
87
|
+
sources: ZebraSources = ZebraSources()
|
|
88
|
+
|
|
89
|
+
# Which of the Zebra's four AND gates is used to control the automatic shutter, if it's being used.
|
|
90
|
+
# After defining, the correct GateControl device can be accessed with, eg,
|
|
91
|
+
# zebra.logic_gates.and_gates[zebra.mapping.AND_GATE_FOR_AUTO_SHUTTER]. Set to -1 if not being used.
|
|
92
|
+
AND_GATE_FOR_AUTO_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class UnmappedZebraException(Exception):
|
|
96
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|