dls-dodal 1.68.0__py3-none-any.whl → 2.0.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.68.0.dist-info → dls_dodal-2.0.0.dist-info}/METADATA +1 -31
- dls_dodal-2.0.0.dist-info/RECORD +354 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +10 -17
- dodal/beamlines/adsim.py +40 -33
- dodal/beamlines/b01_1.py +11 -0
- dodal/beamlines/b07.py +17 -21
- dodal/beamlines/b07_1.py +20 -22
- dodal/beamlines/b07_shared.py +12 -0
- dodal/beamlines/b16.py +1 -1
- dodal/beamlines/b21.py +15 -6
- dodal/beamlines/i02_1.py +17 -45
- dodal/beamlines/i02_2.py +6 -12
- dodal/beamlines/i03.py +8 -5
- dodal/beamlines/i03_supervisor.py +19 -0
- dodal/beamlines/i04.py +87 -184
- dodal/beamlines/i05.py +9 -39
- dodal/beamlines/i05_1.py +4 -13
- dodal/beamlines/i05_shared.py +51 -0
- dodal/beamlines/i06_1.py +26 -0
- dodal/beamlines/{i06.py → i06_shared.py} +25 -14
- dodal/beamlines/i07.py +14 -16
- dodal/beamlines/i09.py +76 -29
- dodal/beamlines/i09_1.py +25 -56
- dodal/beamlines/i09_1_shared.py +61 -0
- dodal/beamlines/i09_2.py +6 -100
- dodal/beamlines/i09_2_shared.py +110 -0
- dodal/beamlines/i10.py +60 -54
- dodal/beamlines/i10_1.py +99 -10
- dodal/beamlines/{i10_optics.py → i10_shared.py} +80 -66
- dodal/beamlines/i11.py +31 -18
- dodal/beamlines/i13_1.py +1 -1
- dodal/beamlines/i15.py +6 -6
- dodal/beamlines/i15_1.py +6 -6
- dodal/beamlines/i16.py +11 -0
- dodal/beamlines/i17.py +37 -28
- dodal/beamlines/i18.py +3 -4
- dodal/beamlines/i19_1.py +95 -34
- dodal/beamlines/i19_2.py +68 -52
- dodal/beamlines/i19_optics.py +26 -13
- dodal/beamlines/i20_1.py +17 -11
- dodal/beamlines/i21.py +44 -29
- dodal/beamlines/i22.py +19 -4
- dodal/beamlines/i23.py +20 -27
- dodal/beamlines/i24.py +64 -113
- dodal/beamlines/k07.py +99 -5
- dodal/beamlines/p38.py +3 -3
- dodal/beamlines/p60.py +35 -14
- dodal/beamlines/p99.py +16 -15
- dodal/beamlines/training_rig.py +20 -12
- dodal/cli.py +36 -2
- dodal/common/__init__.py +2 -1
- dodal/common/beamlines/beamline_parameters.py +2 -1
- dodal/common/beamlines/beamline_utils.py +11 -9
- dodal/common/beamlines/commissioning_mode.py +6 -3
- dodal/common/coordination.py +12 -14
- dodal/common/crystal_metadata.py +5 -8
- dodal/common/device_utils.py +4 -3
- dodal/common/maths.py +87 -19
- dodal/common/udc_directory_provider.py +13 -8
- dodal/common/visit.py +18 -21
- dodal/common/watcher_utils.py +13 -12
- dodal/device_manager.py +94 -54
- dodal/devices/aperturescatterguard.py +26 -27
- dodal/devices/areadetector/plugins/cam.py +1 -3
- dodal/devices/areadetector/plugins/mjpg.py +6 -5
- dodal/devices/attenuator/attenuator.py +12 -11
- dodal/devices/beamlines/b07/__init__.py +3 -0
- dodal/devices/{b07_1 → beamlines/b07_1}/__init__.py +2 -2
- dodal/devices/{b07_1 → beamlines/b07_1}/ccmc.py +5 -10
- dodal/devices/{b16 → beamlines/b16}/detector.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/fast_grid_scan.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/sample_motors.py +1 -1
- dodal/devices/{i03 → beamlines/i03}/beamsize.py +11 -7
- dodal/devices/{i03 → beamlines/i03}/dcm.py +1 -2
- dodal/devices/{i03 → beamlines/i03}/undulator_dcm.py +4 -5
- dodal/devices/beamlines/i04/beam_centre.py +151 -0
- dodal/devices/{i04 → beamlines/i04}/beamsize.py +11 -7
- dodal/devices/beamlines/i04/max_pixel.py +25 -0
- dodal/devices/{i04 → beamlines/i04}/murko_results.py +23 -8
- dodal/devices/{i04 → beamlines/i04}/transfocator.py +10 -15
- dodal/devices/beamlines/i05/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/i06_enum.py +7 -0
- dodal/devices/{i07 → beamlines/i07}/dcm.py +2 -3
- dodal/devices/{i07 → beamlines/i07}/id.py +8 -9
- dodal/devices/beamlines/i09/__init__.py +3 -0
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_energy.py +5 -6
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_undulator_functions.py +19 -16
- dodal/devices/{i10 → beamlines/i10}/diagnostics.py +4 -3
- dodal/devices/{i10 → beamlines/i10}/i10_apple2.py +37 -51
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_current_amp.py +1 -24
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_motors.py +2 -2
- dodal/devices/{i10 → beamlines/i10}/slits.py +5 -3
- dodal/devices/beamlines/i10_1/__init__.py +9 -0
- dodal/devices/beamlines/i10_1/electromagnet/magnet.py +16 -0
- dodal/devices/beamlines/i10_1/electromagnet/stages.py +14 -0
- dodal/devices/beamlines/i10_1/scaler_cards.py +13 -0
- dodal/devices/{i11 → beamlines/i11}/cyberstar_blower.py +1 -1
- dodal/devices/{i11 → beamlines/i11}/diff_stages.py +4 -6
- dodal/devices/{i11 → beamlines/i11}/mythen.py +3 -4
- dodal/devices/{i11 → beamlines/i11}/nx100robot.py +6 -6
- dodal/devices/{i11 → beamlines/i11}/spinner.py +1 -1
- dodal/devices/{i13_1 → beamlines/i13_1}/merlin.py +1 -1
- dodal/devices/{i15 → beamlines/i15}/dcm.py +1 -2
- dodal/devices/{i15 → beamlines/i15}/focussing_mirror.py +5 -5
- dodal/devices/{i15 → beamlines/i15}/jack.py +2 -2
- dodal/devices/{i15 → beamlines/i15}/multilayer_mirror.py +1 -1
- dodal/devices/{i17 → beamlines/i17}/i17_apple2.py +16 -22
- dodal/devices/{i18 → beamlines/i18}/diode.py +1 -1
- dodal/devices/{i19 → beamlines/i19}/access_controlled/attenuator_motor_squad.py +12 -8
- dodal/devices/{i19 → beamlines/i19}/access_controlled/blueapi_device.py +16 -15
- dodal/devices/beamlines/i19/access_controlled/piezo_control.py +72 -0
- dodal/devices/{i19 → beamlines/i19}/access_controlled/shutter.py +11 -9
- dodal/devices/{i19 → beamlines/i19}/backlight.py +3 -1
- dodal/devices/{i19 → beamlines/i19}/mapt_configuration.py +2 -1
- dodal/devices/{i19 → beamlines/i19}/pin_col_stages.py +11 -8
- dodal/devices/beamlines/i19/pin_tip.py +32 -0
- dodal/devices/beamlines/i21/__init__.py +3 -0
- dodal/devices/{i22 → beamlines/i22}/dcm.py +1 -2
- dodal/devices/{i22 → beamlines/i22}/fswitch.py +1 -3
- dodal/devices/{i22 → beamlines/i22}/nxsas.py +5 -4
- dodal/devices/{i24 → beamlines/i24}/beam_center.py +1 -1
- dodal/devices/{i24 → beamlines/i24}/beamstop.py +2 -2
- dodal/devices/{i24 → beamlines/i24}/commissioning_jungfrau.py +12 -12
- dodal/devices/{i24 → beamlines/i24}/dcm.py +1 -3
- dodal/devices/{i24 → beamlines/i24}/dual_backlight.py +3 -3
- dodal/devices/{i24 → beamlines/i24}/pmac.py +9 -7
- dodal/devices/{p60 → beamlines/p60}/lab_xray_source.py +1 -1
- dodal/devices/beamlines/p99/__init__.py +0 -0
- dodal/devices/{p99 → beamlines/p99}/andor2_point.py +11 -15
- dodal/devices/bimorph_mirror.py +22 -20
- dodal/devices/collimation_table.py +3 -2
- dodal/devices/common_dcm.py +30 -20
- dodal/devices/controllers.py +2 -2
- dodal/devices/cryostream.py +8 -0
- dodal/devices/current_amplifiers/current_amplifier.py +16 -18
- dodal/devices/current_amplifiers/current_amplifier_detector.py +9 -10
- dodal/devices/current_amplifiers/femto.py +8 -9
- dodal/devices/current_amplifiers/sr570.py +16 -16
- dodal/devices/current_amplifiers/struck_scaler_counter.py +5 -5
- dodal/devices/detector/det_resolution.py +9 -8
- dodal/devices/detector/detector.py +4 -2
- dodal/devices/diamond_filter.py +3 -4
- dodal/devices/eiger.py +32 -17
- dodal/devices/eiger_odin.py +1 -1
- dodal/devices/electron_analyser/base/__init__.py +3 -3
- dodal/devices/electron_analyser/base/base_controller.py +32 -21
- dodal/devices/electron_analyser/base/base_detector.py +15 -20
- dodal/devices/electron_analyser/base/base_driver_io.py +39 -46
- dodal/devices/electron_analyser/base/base_enums.py +0 -5
- dodal/devices/electron_analyser/base/base_region.py +29 -31
- dodal/devices/electron_analyser/base/base_util.py +18 -16
- dodal/devices/electron_analyser/base/energy_sources.py +35 -40
- dodal/devices/electron_analyser/specs/specs_detector.py +7 -6
- dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +7 -6
- dodal/devices/eurotherm.py +3 -2
- dodal/devices/fast_grid_scan.py +31 -34
- dodal/devices/fast_shutter.py +125 -39
- dodal/devices/flux.py +1 -1
- dodal/devices/focusing_mirror.py +29 -11
- dodal/devices/hutch_shutter.py +6 -6
- dodal/devices/insertion_device/__init__.py +20 -8
- dodal/devices/insertion_device/apple2_controller.py +371 -0
- dodal/devices/insertion_device/apple2_undulator.py +184 -587
- dodal/devices/insertion_device/apple_knot_controller.py +222 -0
- dodal/devices/insertion_device/energy.py +161 -0
- dodal/devices/insertion_device/energy_motor_lookup.py +21 -28
- dodal/devices/insertion_device/lookup_table_models.py +47 -52
- dodal/devices/insertion_device/polarisation.py +36 -0
- dodal/devices/ipin.py +1 -1
- dodal/devices/linkam3.py +7 -5
- dodal/devices/motors.py +107 -19
- dodal/devices/mx_phase1/beamstop.py +2 -4
- dodal/devices/oav/oav_calculations.py +20 -13
- dodal/devices/oav/oav_detector.py +92 -22
- dodal/devices/oav/oav_parameters.py +4 -9
- dodal/devices/oav/oav_to_redis_forwarder.py +22 -18
- dodal/devices/oav/pin_image_recognition/__init__.py +4 -6
- dodal/devices/oav/pin_image_recognition/manual_test.py +1 -2
- dodal/devices/oav/pin_image_recognition/utils.py +30 -32
- dodal/devices/oav/snapshots/grid_overlay.py +10 -9
- dodal/devices/oav/snapshots/snapshot_image_processing.py +15 -13
- dodal/devices/oav/utils.py +20 -6
- dodal/devices/p45.py +3 -9
- dodal/devices/pgm.py +8 -14
- dodal/devices/pressure_jump_cell.py +93 -32
- dodal/devices/qbpm.py +1 -3
- dodal/devices/robot.py +45 -20
- dodal/devices/s4_slit_gaps.py +1 -1
- dodal/devices/selectable_source.py +41 -0
- dodal/devices/slits.py +2 -5
- dodal/devices/smargon.py +2 -3
- dodal/devices/temperture_controller/lakeshore/lakeshore.py +38 -64
- dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +21 -35
- dodal/devices/tetramm.py +7 -7
- dodal/devices/turbo_slit.py +8 -7
- dodal/devices/undulator.py +42 -56
- dodal/devices/util/adjuster_plans.py +2 -3
- dodal/devices/util/epics_util.py +10 -10
- dodal/devices/util/lookup_tables.py +17 -18
- dodal/devices/v2f.py +2 -3
- dodal/devices/watsonmarlow323_pump.py +1 -1
- dodal/devices/xbpm_feedback.py +3 -2
- dodal/devices/xspress3/xspress3.py +8 -11
- dodal/devices/xspress3/xspress3_channel.py +3 -6
- dodal/devices/zebra/zebra.py +21 -7
- dodal/devices/zebra/zebra_constants_mapping.py +12 -7
- dodal/devices/zebra/zebra_controlled_shutter.py +2 -1
- dodal/devices/zocalo/zocalo_interaction.py +14 -14
- dodal/devices/zocalo/zocalo_results.py +33 -33
- dodal/log.py +23 -20
- dodal/plan_stubs/check_topup.py +15 -15
- dodal/plan_stubs/data_session.py +6 -6
- dodal/plan_stubs/motor_utils.py +22 -18
- dodal/plan_stubs/pressure_jump_cell.py +18 -0
- dodal/plan_stubs/wrapped.py +40 -55
- dodal/plans/bimorph.py +63 -52
- dodal/plans/configure_arm_trigger_and_disarm_detector.py +0 -1
- dodal/plans/device_setup_plans/__init__.py +5 -0
- dodal/plans/device_setup_plans/setup_pin_tip_params.py +63 -0
- dodal/plans/preprocessors/verify_undulator_gap.py +10 -8
- dodal/plans/spec_path.py +3 -5
- dodal/plans/verify_undulator_gap.py +1 -2
- dodal/plans/wrapped.py +4 -3
- dodal/testing/__init__.py +0 -0
- dodal/testing/electron_analyser/device_factory.py +5 -7
- dodal/testing/fixtures/devices/apple2.py +38 -0
- dodal/testing/fixtures/run_engine.py +3 -7
- dodal/testing/fixtures/utils.py +1 -2
- dodal/utils.py +60 -58
- dls_dodal-1.68.0.dist-info/RECORD +0 -330
- dodal/beamline_specific_utils/i05_shared.py +0 -14
- dodal/devices/b07/__init__.py +0 -3
- dodal/devices/i04/max_pixel.py +0 -38
- dodal/devices/i05/__init__.py +0 -3
- dodal/devices/i09/__init__.py +0 -3
- dodal/devices/i21/__init__.py +0 -5
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/top_level.txt +0 -0
- /dodal/{beamline_specific_utils → devices/beamlines}/__init__.py +0 -0
- /dodal/devices/{b07 → beamlines/b07}/enums.py +0 -0
- /dodal/devices/{b07_1 → beamlines/b07_1}/enums.py +0 -0
- /dodal/devices/{b16 → beamlines/b16}/__init__.py +0 -0
- /dodal/devices/{i02_1 → beamlines/i02_1}/__init__.py +0 -0
- /dodal/devices/{i02_2 → beamlines/i02_2}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/constants.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/__init__.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/constants.py +0 -0
- /dodal/devices/{i05 → beamlines/i05}/enums.py +0 -0
- /dodal/devices/{i07 → beamlines/i07}/__init__.py +0 -0
- /dodal/devices/{i09 → beamlines/i09}/enums.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/__init__.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/enums.py +0 -0
- /dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/i09_apple2.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/i10_setting_data.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/mirrors.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/rasor_scaler_cards.py +0 -0
- /dodal/devices/{i11 → beamlines/i10_1/electromagnet}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i11}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i13_1}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i13_1}/merlin_controller.py +0 -0
- /dodal/devices/{i17 → beamlines/i15}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/laue.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/motors.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/rail.py +0 -0
- /dodal/devices/{i18 → beamlines/i17}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i18}/__init__.py +0 -0
- /dodal/devices/{i18 → beamlines/i18}/kb_mirror.py +0 -0
- /dodal/devices/{i19/access_controlled → beamlines/i19}/__init__.py +0 -0
- /dodal/devices/{i20_1 → beamlines/i19/access_controlled}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/access_controlled/hutch_access.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/beamstop.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/diffractometer.py +0 -0
- /dodal/devices/{i22 → beamlines/i20_1}/__init__.py +0 -0
- /dodal/devices/{i21 → beamlines/i21}/enums.py +0 -0
- /dodal/devices/{i24 → beamlines/i22}/__init__.py +0 -0
- /dodal/devices/{p99 → beamlines/i24}/__init__.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/aperture.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/focus_mirrors.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/vgonio.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/__init__.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/enums.py +0 -0
- /dodal/devices/{p99 → beamlines/p99}/sample_stage.py +0 -0
- /dodal/devices/insertion_device/{id_enum.py → enum.py} +0 -0
dodal/devices/undulator.py
CHANGED
|
@@ -41,9 +41,16 @@ def _get_gap_for_energy(
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
44
|
-
"""
|
|
45
|
-
Base class for undulator devices providing gap control and access management.
|
|
44
|
+
"""Base class for undulator devices providing gap control and access management.
|
|
46
45
|
This class expects target gap value [mm] passed in set method.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
prefix (str): PV prefix.
|
|
49
|
+
poles (int, optional): Number of magnetic poles built into the undulator.
|
|
50
|
+
length (float, optional): Length of the undulator in meters.
|
|
51
|
+
undulator_period(int, optional): Undulator period.
|
|
52
|
+
baton (Baton, optional): Baton object if provided.
|
|
53
|
+
name (str, optional): Name for device. Defaults to "".
|
|
47
54
|
"""
|
|
48
55
|
|
|
49
56
|
def __init__(
|
|
@@ -55,15 +62,6 @@ class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
|
55
62
|
baton: Baton | None = None,
|
|
56
63
|
name: str = "",
|
|
57
64
|
) -> None:
|
|
58
|
-
"""
|
|
59
|
-
Args:
|
|
60
|
-
prefix: PV prefix
|
|
61
|
-
poles (int, optional): Number of magnetic poles built into the undulator
|
|
62
|
-
length (float, optional): Length of the undulator in meters
|
|
63
|
-
undulator_period(int, optional): Undulator period
|
|
64
|
-
baton (optional): Baton object if provided.
|
|
65
|
-
name (str, optional): Name for device. Defaults to "".
|
|
66
|
-
"""
|
|
67
65
|
self.baton_ref = Reference(baton) if baton else None
|
|
68
66
|
|
|
69
67
|
with self.add_children_as_readables():
|
|
@@ -91,18 +89,16 @@ class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
|
91
89
|
@abstractmethod
|
|
92
90
|
@AsyncStatus.wrap
|
|
93
91
|
async def set(self, value: float) -> None:
|
|
94
|
-
"""
|
|
95
|
-
Move undulator to a given position.
|
|
92
|
+
"""Move undulator to a given position.
|
|
96
93
|
Abstract method - must be implemented by subclasses.
|
|
97
94
|
|
|
98
95
|
Args:
|
|
99
|
-
value:
|
|
96
|
+
value (float): Target Position - units depend on implementation.
|
|
100
97
|
"""
|
|
101
98
|
...
|
|
102
99
|
|
|
103
100
|
async def _set_gap(self, value: float) -> None:
|
|
104
|
-
"""
|
|
105
|
-
Set the undulator gap to a given value in mm.
|
|
101
|
+
"""Set the undulator gap to a given value in mm.
|
|
106
102
|
|
|
107
103
|
Args:
|
|
108
104
|
value: gap in mm
|
|
@@ -129,11 +125,11 @@ class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
|
129
125
|
LOGGER.warning("In test mode, not moving ID gap")
|
|
130
126
|
|
|
131
127
|
async def _check_gap_within_threshold(self, target_gap: float) -> bool:
|
|
132
|
-
"""
|
|
133
|
-
Check if the undulator gap is within the acceptable threshold of the target gap.
|
|
128
|
+
"""Check if the undulator gap is within the acceptable threshold of the target gap.
|
|
134
129
|
|
|
135
130
|
Args:
|
|
136
131
|
target_gap: target gap in mm
|
|
132
|
+
|
|
137
133
|
Returns:
|
|
138
134
|
True if the gap is within the threshold, False otherwise
|
|
139
135
|
"""
|
|
@@ -142,14 +138,14 @@ class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
|
142
138
|
return abs(target_gap - current_gap) <= tolerance
|
|
143
139
|
|
|
144
140
|
async def _is_commissioning_mode_enabled(self) -> bool | None:
|
|
145
|
-
"""
|
|
146
|
-
|
|
141
|
+
"""Asynchronously checks if commissioning mode is enabled via the baton
|
|
142
|
+
reference.
|
|
147
143
|
"""
|
|
148
144
|
return self.baton_ref and await self.baton_ref().commissioning.get_value()
|
|
149
145
|
|
|
150
146
|
async def raise_if_not_enabled(self) -> AccessError | None:
|
|
151
|
-
"""
|
|
152
|
-
|
|
147
|
+
"""Asynchronously raises AccessError if gap access is disabled and not in
|
|
148
|
+
commissioning mode.
|
|
153
149
|
"""
|
|
154
150
|
access_level = await self.gap_access.get_value()
|
|
155
151
|
commissioning_mode = await self._is_commissioning_mode_enabled()
|
|
@@ -158,10 +154,19 @@ class BaseUndulator(StandardReadable, Movable[float], ABC):
|
|
|
158
154
|
|
|
159
155
|
|
|
160
156
|
class UndulatorInKeV(BaseUndulator):
|
|
161
|
-
"""
|
|
162
|
-
|
|
157
|
+
"""An Undulator-type insertion device, used to control photon emission at a given
|
|
158
|
+
beam energy.
|
|
163
159
|
This class expects energy [keV] passed in set method and does conversion to gap
|
|
164
160
|
internally, for which it requires path to lookup table file in constructor.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
prefix (str): PV prefix.
|
|
164
|
+
id_gap_lookup_table_path (str): Path to a lookup table file.
|
|
165
|
+
poles (int, optional): Number of magnetic poles built into the undulator.
|
|
166
|
+
length (float, optional): Length of the undulator in meters.
|
|
167
|
+
undulator_period(int, optional): Undulator period.
|
|
168
|
+
baton (Baton, optional): Baton object if provided.
|
|
169
|
+
name (str, optional): Name for device. Defaults to "".
|
|
165
170
|
"""
|
|
166
171
|
|
|
167
172
|
def __init__(
|
|
@@ -174,18 +179,6 @@ class UndulatorInKeV(BaseUndulator):
|
|
|
174
179
|
baton: Baton | None = None,
|
|
175
180
|
name: str = "",
|
|
176
181
|
) -> None:
|
|
177
|
-
"""Constructor
|
|
178
|
-
|
|
179
|
-
Args:
|
|
180
|
-
prefix: PV prefix
|
|
181
|
-
id_gap_lookup_table_path (str): Path to a lookup table file
|
|
182
|
-
poles (int, optional): Number of magnetic poles built into the undulator
|
|
183
|
-
length (float, optional): Length of the undulator in meters
|
|
184
|
-
undulator_period(int, optional): Undulator period
|
|
185
|
-
baton (optional): Baton object if provided.
|
|
186
|
-
name (str, optional): Name for device. Defaults to "".
|
|
187
|
-
"""
|
|
188
|
-
|
|
189
182
|
self.id_gap_lookup_table_path = id_gap_lookup_table_path
|
|
190
183
|
super().__init__(
|
|
191
184
|
prefix=prefix,
|
|
@@ -198,11 +191,10 @@ class UndulatorInKeV(BaseUndulator):
|
|
|
198
191
|
|
|
199
192
|
@AsyncStatus.wrap
|
|
200
193
|
async def set(self, value: float):
|
|
201
|
-
"""
|
|
202
|
-
Check conditions and Set undulator gap to a given energy in keV
|
|
194
|
+
"""Check conditions and Set undulator gap to a given energy in keV.
|
|
203
195
|
|
|
204
196
|
Args:
|
|
205
|
-
value:
|
|
197
|
+
value (float): Energy in keV.
|
|
206
198
|
"""
|
|
207
199
|
# Convert energy in keV to gap in mm first
|
|
208
200
|
target_gap = await self._get_gap_to_match_energy(value)
|
|
@@ -212,9 +204,8 @@ class UndulatorInKeV(BaseUndulator):
|
|
|
212
204
|
await self._set_gap(target_gap)
|
|
213
205
|
|
|
214
206
|
async def _get_gap_to_match_energy(self, energy_kev: float) -> float:
|
|
215
|
-
"""
|
|
216
|
-
|
|
217
|
-
converts energies to undulator gap distance
|
|
207
|
+
"""Get a 2d np.array from lookup table that converts energies to undulator gap
|
|
208
|
+
distance.
|
|
218
209
|
"""
|
|
219
210
|
energy_to_distance_table: np.ndarray = await energy_distance_table(
|
|
220
211
|
self.id_gap_lookup_table_path
|
|
@@ -228,32 +219,27 @@ class UndulatorInKeV(BaseUndulator):
|
|
|
228
219
|
|
|
229
220
|
|
|
230
221
|
class UndulatorInMm(BaseUndulator):
|
|
231
|
-
"""
|
|
232
|
-
An Undulator-type insertion device, used to control photon emission.
|
|
222
|
+
"""An Undulator-type insertion device, used to control photon emission.
|
|
233
223
|
This class expects gap [mm] passed in set method.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
value (float): Value in mm.
|
|
234
227
|
"""
|
|
235
228
|
|
|
236
229
|
@AsyncStatus.wrap
|
|
237
230
|
async def set(self, value: float):
|
|
238
|
-
"""
|
|
239
|
-
Check conditions and Set undulator gap to a given value in mm
|
|
240
|
-
|
|
241
|
-
Args:
|
|
242
|
-
value: value in mm
|
|
243
|
-
"""
|
|
244
231
|
await self._set_gap(value)
|
|
245
232
|
|
|
246
233
|
|
|
247
234
|
class UndulatorOrder(StandardReadable, Locatable[int]):
|
|
248
|
-
"""
|
|
249
|
-
|
|
235
|
+
"""Represents the order of an undulator device. Allows setting and locating the
|
|
236
|
+
order.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
name (str): Name for device. Defaults to ""
|
|
250
240
|
"""
|
|
251
241
|
|
|
252
242
|
def __init__(self, name: str = "") -> None:
|
|
253
|
-
"""
|
|
254
|
-
Args:
|
|
255
|
-
name: Name for device. Defaults to ""
|
|
256
|
-
"""
|
|
257
243
|
with self.add_children_as_readables():
|
|
258
244
|
self.value = soft_signal_rw(int, initial_value=3)
|
|
259
245
|
super().__init__(name=name)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
All the methods in this module return a bluesky plan generator that adjusts a value
|
|
1
|
+
"""All the methods in this module return a bluesky plan generator that adjusts a value
|
|
3
2
|
according to some criteria either via feedback, preset positions, lookup tables etc.
|
|
4
3
|
"""
|
|
5
4
|
|
|
@@ -15,7 +14,7 @@ from dodal.log import LOGGER
|
|
|
15
14
|
def lookup_table_adjuster(
|
|
16
15
|
lookup_table: Callable[[float], float], output_device: Motor, input
|
|
17
16
|
):
|
|
18
|
-
"""Returns a callable that adjusts a value according to a lookup table"""
|
|
17
|
+
"""Returns a callable that adjusts a value according to a lookup table."""
|
|
19
18
|
|
|
20
19
|
def adjust(group=None) -> Generator[Msg, None, None]:
|
|
21
20
|
setpoint = lookup_table(input)
|
dodal/devices/util/epics_util.py
CHANGED
|
@@ -16,7 +16,7 @@ def epics_signal_put_wait(pv_name: str, wait: float = 3.0) -> Component[EpicsSig
|
|
|
16
16
|
"""Creates a `Component` around an `EpicsSignal` that waits for a callback on a put.
|
|
17
17
|
|
|
18
18
|
Args:
|
|
19
|
-
pv_name (str): The name of the PV for the `EpicsSignal
|
|
19
|
+
pv_name (str): The name of the PV for the `EpicsSignal`.
|
|
20
20
|
wait (str, optional): The timeout to wait for a callback. Defaults to 3.0.
|
|
21
21
|
|
|
22
22
|
Returns:
|
|
@@ -30,24 +30,24 @@ def run_functions_without_blocking(
|
|
|
30
30
|
timeout: float = 60.0,
|
|
31
31
|
associated_obj: OphydDevice | None = None,
|
|
32
32
|
) -> Status:
|
|
33
|
-
"""Creates and initiates an asynchronous chaining of functions which return a status
|
|
33
|
+
"""Creates and initiates an asynchronous chaining of functions which return a status.
|
|
34
34
|
|
|
35
35
|
Usage:
|
|
36
36
|
This function can be used to take a series of status-returning functions and run
|
|
37
37
|
them all sequentially and in the background by making use of callbacks. It also
|
|
38
|
-
ensures exceptions on each returned status are propagated
|
|
38
|
+
ensures exceptions on each returned status are propagated.
|
|
39
39
|
|
|
40
40
|
Args:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
functions_to_chain (Sequence(function - > StatusBase)): A list of functions
|
|
42
|
+
which each return a status object.
|
|
43
|
+
timeout (float, optional): The timeout period, defaults to 60.
|
|
44
|
+
associated_obj (OphydDevice, optional): The device that should be associated
|
|
45
|
+
with the returned status.
|
|
45
46
|
|
|
46
47
|
Returns:
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
Status: A status object which is marked as complete once all of the Status
|
|
49
|
+
objects returned by the unwrapped functions have completed.
|
|
49
50
|
"""
|
|
50
|
-
|
|
51
51
|
# The returned status - marked as finished at the end of the callback chain. If any
|
|
52
52
|
# intermediate statuses have an exception, the full_status will timeout.
|
|
53
53
|
full_status = Status(obj=associated_obj, timeout=timeout)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
All the public methods in this module return a lookup table of some kind that
|
|
1
|
+
"""All the public methods in this module return a lookup table of some kind that
|
|
3
2
|
converts the source value s to a target value t for different values of s.
|
|
4
3
|
"""
|
|
5
4
|
|
|
@@ -18,19 +17,18 @@ async def energy_distance_table(
|
|
|
18
17
|
comments: Sequence[str] = ["#", "Units"],
|
|
19
18
|
skiprows: int = 0,
|
|
20
19
|
) -> np.ndarray:
|
|
21
|
-
"""
|
|
22
|
-
Returns a numpy formatted lookup table for required positions of an ID gap to
|
|
20
|
+
"""Returns a numpy formatted lookup table for required positions of an ID gap to
|
|
23
21
|
provide emission at a given beam energy.
|
|
24
22
|
|
|
25
23
|
Args:
|
|
26
|
-
lookup_table_path: Path to lookup table
|
|
27
|
-
comments: Lines starting with any of these strings
|
|
28
|
-
|
|
24
|
+
lookup_table_path (str): Path to lookup table.
|
|
25
|
+
comments (Sequence[str], optional): Lines starting with any of these strings
|
|
26
|
+
will be ignored.
|
|
27
|
+
skiprows (int, optional): Number of rows to skip at the start of the file.
|
|
29
28
|
|
|
30
29
|
Returns:
|
|
31
|
-
ndarray: Lookup table
|
|
30
|
+
ndarray: Lookup table.
|
|
32
31
|
"""
|
|
33
|
-
|
|
34
32
|
# Slight cheat to make the file IO async, numpy doesn't do any real IO now, just
|
|
35
33
|
# decodes the text
|
|
36
34
|
async with aiofiles.open(lookup_table_path) as stream:
|
|
@@ -40,7 +38,8 @@ async def energy_distance_table(
|
|
|
40
38
|
|
|
41
39
|
def parse_lookup_table(filename: str) -> list[Sequence]:
|
|
42
40
|
"""Parse a generic lookup table with a number of columns >= 2 and return a list \
|
|
43
|
-
in column major order of the values in it.
|
|
41
|
+
in column major order of the values in it.
|
|
42
|
+
"""
|
|
44
43
|
LOGGER.info(f"Parsing lookup table file {filename}")
|
|
45
44
|
|
|
46
45
|
lut_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
@@ -53,7 +52,8 @@ def linear_interpolation_lut(
|
|
|
53
52
|
"""Returns a callable that converts values by linear interpolation of lookup table
|
|
54
53
|
values.
|
|
55
54
|
|
|
56
|
-
If the value falls outside the lookup table then the closest value will be used.
|
|
55
|
+
If the value falls outside the lookup table then the closest value will be used.
|
|
56
|
+
"""
|
|
57
57
|
# numpy interp expects x-values to be increasing
|
|
58
58
|
if not np.all(np.diff(s_values) > 0):
|
|
59
59
|
LOGGER.info(
|
|
@@ -75,17 +75,16 @@ def linear_interpolation_lut(
|
|
|
75
75
|
def linear_extrapolation_lut(
|
|
76
76
|
s_values: Sequence[float], t_values: Sequence[float]
|
|
77
77
|
) -> Callable[[float], float]:
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
the function is equivalent to that returned by linear_interpolation_lut
|
|
78
|
+
"""Return a callable that implements f(s) = t according to the conversion table data
|
|
79
|
+
supplied, with linear extrapolation outside that range. Inside the range of the
|
|
80
|
+
table, the function is equivalent to that returned by linear_interpolation_lut.
|
|
82
81
|
|
|
83
82
|
Args:
|
|
84
|
-
s_values:
|
|
85
|
-
t_values:
|
|
83
|
+
s_values (Sequence[float]): Values of the independent axis.
|
|
84
|
+
t_values (Sequence[float]): Values of the dependent axis.
|
|
86
85
|
|
|
87
86
|
Returns:
|
|
88
|
-
A callable that returns t for the given s
|
|
87
|
+
Callable: A callable that returns t for the given s.
|
|
89
88
|
"""
|
|
90
89
|
assert len(s_values) == len(t_values), (
|
|
91
90
|
"Lookup table does not have the same number of values for each axis"
|
dodal/devices/v2f.py
CHANGED
|
@@ -20,9 +20,8 @@ class V2FGain(StrictEnum):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class QDV2F(StandardReadable):
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
Two channel V2F - 50mHz
|
|
23
|
+
"""A Quantum Detectors V2F low noise voltage to frequency converter.
|
|
24
|
+
Two channel V2F - 50mHz.
|
|
26
25
|
"""
|
|
27
26
|
|
|
28
27
|
def __init__(
|
|
@@ -18,7 +18,7 @@ class WatsonMarlow323PumpState(StrictEnum):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class WatsonMarlow323Pump(StandardReadable):
|
|
21
|
-
"""Watson Marlow 323 Peristaltic Pump device"""
|
|
21
|
+
"""Watson Marlow 323 Peristaltic Pump device."""
|
|
22
22
|
|
|
23
23
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
24
24
|
with self.add_children_as_readables():
|
dodal/devices/xbpm_feedback.py
CHANGED
|
@@ -13,8 +13,9 @@ class Pause(StrictEnum):
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class XBPMFeedback(Device, Triggerable):
|
|
16
|
-
"""The XBPM feedback device is an IOC that moves the DCM, HFM and VFM to
|
|
17
|
-
hold the beam into place, as measured by the XBPM sensor.
|
|
16
|
+
"""The XBPM feedback device is an IOC that moves the DCM, HFM and VFM to
|
|
17
|
+
automatically hold the beam into place, as measured by the XBPM sensor.
|
|
18
|
+
"""
|
|
18
19
|
|
|
19
20
|
def __init__(self, prefix: str, name: str = "", baton: Baton | None = None) -> None:
|
|
20
21
|
self.pos_ok = epics_signal_r(float, prefix + "XBPM2POSITION_OK")
|
|
@@ -56,19 +56,16 @@ class DetectorState(StrictEnum):
|
|
|
56
56
|
class Xspress3(Device, Stageable):
|
|
57
57
|
"""Xpress/XpressMini is a region of interest (ROI) picker that sums the detector
|
|
58
58
|
output into a scaler with user-defined regions. It is often used as a signal
|
|
59
|
-
discriminator to provide better energy resolution and signal to noise in X-ray
|
|
59
|
+
discriminator to provide better energy resolution and signal to noise in X-ray
|
|
60
|
+
detection experiments.
|
|
60
61
|
This currently only provide staging functionality.
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
num_channels:
|
|
69
|
-
Number of channel xspress3 has, default is 1 for mini.
|
|
70
|
-
timeout:
|
|
71
|
-
How long to wait for before timing out for staging/arming of detector default is 1 sec
|
|
63
|
+
Args:
|
|
64
|
+
prefix (str): Beamline part of PV.
|
|
65
|
+
name (str, optional): Name of the device.
|
|
66
|
+
num_channels (int): Number of channel xspress3 has, default is 1 for mini.
|
|
67
|
+
timeout (float): How long to wait for before timing out for staging/arming of
|
|
68
|
+
detector, the default is 1 sec.
|
|
72
69
|
"""
|
|
73
70
|
|
|
74
71
|
def __init__(
|
|
@@ -8,9 +8,8 @@ class AcquireState(StrictEnum):
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Xspress3Channel(Device):
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
including the definition of ROI(region of interest).
|
|
11
|
+
"""Xspress3 Channel contains the truncated detector data and its collection conditions
|
|
12
|
+
including the definition of ROI(region of interest).
|
|
14
13
|
"""
|
|
15
14
|
|
|
16
15
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
@@ -30,9 +29,7 @@ class Xspress3Channel(Device):
|
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
class Xspress3ROIChannel(Device):
|
|
33
|
-
"""
|
|
34
|
-
This is the Xspress3 multi-channel analyzer range
|
|
35
|
-
"""
|
|
32
|
+
"""This is the Xspress3 multi-channel analyzer range."""
|
|
36
33
|
|
|
37
34
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
38
35
|
self.roi_start_x = epics_signal_rw(int, prefix + "MinX")
|
dodal/devices/zebra/zebra.py
CHANGED
|
@@ -7,11 +7,15 @@ from functools import partialmethod
|
|
|
7
7
|
from bluesky.protocols import Movable
|
|
8
8
|
from ophyd_async.core import (
|
|
9
9
|
AsyncStatus,
|
|
10
|
+
DeviceMock,
|
|
10
11
|
DeviceVector,
|
|
11
12
|
SignalRW,
|
|
12
13
|
StandardReadable,
|
|
13
14
|
StrictEnum,
|
|
15
|
+
callback_on_mock_put,
|
|
16
|
+
default_mock_class,
|
|
14
17
|
observe_value,
|
|
18
|
+
set_mock_value,
|
|
15
19
|
)
|
|
16
20
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
17
21
|
|
|
@@ -56,9 +60,8 @@ class I23Axes:
|
|
|
56
60
|
|
|
57
61
|
|
|
58
62
|
class RotationDirection(StrictEnum):
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
the initial angle to obtain the final angle.
|
|
63
|
+
"""Defines for a swept angle whether the scan width (sweep) is to be added or
|
|
64
|
+
subtracted from the initial angle to obtain the final angle.
|
|
62
65
|
"""
|
|
63
66
|
|
|
64
67
|
POSITIVE = "Positive"
|
|
@@ -88,9 +91,21 @@ class SoftInState(StrictEnum):
|
|
|
88
91
|
NO = "No"
|
|
89
92
|
|
|
90
93
|
|
|
94
|
+
class InstantArmMock(DeviceMock["ArmingDevice"]):
|
|
95
|
+
async def connect(self, device: ArmingDevice) -> None:
|
|
96
|
+
callback_on_mock_put(
|
|
97
|
+
device.arm_set, lambda *_, **__: set_mock_value(device.armed, 1)
|
|
98
|
+
)
|
|
99
|
+
callback_on_mock_put(
|
|
100
|
+
device.disarm_set, lambda *_, **__: set_mock_value(device.armed, 0)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@default_mock_class(InstantArmMock)
|
|
91
105
|
class ArmingDevice(StandardReadable, Movable[ArmDemand]):
|
|
92
106
|
"""A useful device that can abstract some of the logic of arming.
|
|
93
|
-
Allows a user to just call arm.set(ArmDemand.ARM)
|
|
107
|
+
Allows a user to just call arm.set(ArmDemand.ARM).
|
|
108
|
+
"""
|
|
94
109
|
|
|
95
110
|
TIMEOUT: float = 3
|
|
96
111
|
|
|
@@ -215,7 +230,7 @@ class LogicGateConfigurer(StandardReadable):
|
|
|
215
230
|
"""Uses the specified `LogicGateConfiguration` to configure a gate on the Zebra.
|
|
216
231
|
|
|
217
232
|
Args:
|
|
218
|
-
type (GateType): The type of gate e.g. AND/OR
|
|
233
|
+
type (GateType): The type of gate e.g. AND/OR.
|
|
219
234
|
gate_number (int): Which gate to configure.
|
|
220
235
|
config (LogicGateConfiguration): A configuration for the gate.
|
|
221
236
|
"""
|
|
@@ -253,8 +268,7 @@ class LogicGateConfiguration:
|
|
|
253
268
|
|
|
254
269
|
Args:
|
|
255
270
|
input_source (int): The source for the input (must be between 0 and 63).
|
|
256
|
-
invert (bool, optional): Whether the input should be inverted. Default
|
|
257
|
-
False.
|
|
271
|
+
invert (bool, optional): Whether the input should be inverted. Default False.
|
|
258
272
|
|
|
259
273
|
Returns:
|
|
260
274
|
LogicGateConfiguration: A description of the gate configuration.
|
|
@@ -5,11 +5,14 @@ from pydantic import BaseModel, Field, model_validator
|
|
|
5
5
|
|
|
6
6
|
class ZebraMappingValidations(BaseModel):
|
|
7
7
|
"""Raises an exception if field set to -1 is accessed, and validate against
|
|
8
|
-
multiple fields mapping to the same integer
|
|
8
|
+
multiple fields mapping to the same integer.
|
|
9
|
+
"""
|
|
9
10
|
|
|
10
11
|
def __getattribute__(self, name: str):
|
|
11
|
-
"""To protect against mismatch between the Zebra configuration that a plan
|
|
12
|
-
been instantiated, raise exception if a field
|
|
12
|
+
"""To protect against mismatch between the Zebra configuration that a plan
|
|
13
|
+
expects and the Zebra which has been instantiated, raise exception if a field
|
|
14
|
+
which has been set to -1 is accessed.
|
|
15
|
+
"""
|
|
13
16
|
value = object.__getattribute__(self, name)
|
|
14
17
|
if not name.startswith("__"):
|
|
15
18
|
if value == -1:
|
|
@@ -20,8 +23,7 @@ class ZebraMappingValidations(BaseModel):
|
|
|
20
23
|
|
|
21
24
|
@model_validator(mode="after")
|
|
22
25
|
def ensure_no_duplicate_connections(self):
|
|
23
|
-
"""Check that TTL outputs and sources are mapped to unique integers"""
|
|
24
|
-
|
|
26
|
+
"""Check that TTL outputs and sources are mapped to unique integers."""
|
|
25
27
|
integer_fields = {
|
|
26
28
|
key: value
|
|
27
29
|
for key, value in self.model_dump().items()
|
|
@@ -40,7 +42,9 @@ class ZebraMappingValidations(BaseModel):
|
|
|
40
42
|
|
|
41
43
|
class ZebraTTLOutputs(ZebraMappingValidations):
|
|
42
44
|
"""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
|
|
45
|
+
None if that hardware is not connected. A value of -1 means this hardware is not
|
|
46
|
+
connected.
|
|
47
|
+
"""
|
|
44
48
|
|
|
45
49
|
TTL_EIGER: int = Field(default=-1, ge=-1, le=4)
|
|
46
50
|
TTL_PILATUS: int = Field(default=-1, ge=-1, le=4)
|
|
@@ -49,10 +53,11 @@ class ZebraTTLOutputs(ZebraMappingValidations):
|
|
|
49
53
|
TTL_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
50
54
|
TTL_XSPRESS3: int = Field(default=-1, ge=-1, le=4)
|
|
51
55
|
TTL_PANDA: int = Field(default=-1, ge=-1, le=4)
|
|
56
|
+
TTL_JUNGFRAU: int = Field(default=-1, ge=-1, le=4)
|
|
52
57
|
|
|
53
58
|
|
|
54
59
|
class ZebraSources(ZebraMappingValidations):
|
|
55
|
-
"""Maps internal Zebra signal source to their integer PV value"""
|
|
60
|
+
"""Maps internal Zebra signal source to their integer PV value."""
|
|
56
61
|
|
|
57
62
|
DISCONNECT: int = Field(default=0, ge=0, le=63)
|
|
58
63
|
IN1_TTL: int = Field(default=1, ge=0, le=63)
|
|
@@ -26,7 +26,8 @@ class ZebraShutter(StandardReadable, Movable[ZebraShutterState]):
|
|
|
26
26
|
automatic control. A soft input (aliased to control_mode) will switch between
|
|
27
27
|
which of these AND gates to use. For the manual gate the shutter is then controlled
|
|
28
28
|
by a different soft input (aliased to manual_position_setpoint). Both these AND
|
|
29
|
-
gates then feed into an OR gate, which then feeds to the shutter.
|
|
29
|
+
gates then feed into an OR gate, which then feeds to the shutter.
|
|
30
|
+
"""
|
|
30
31
|
|
|
31
32
|
def __init__(self, prefix: str, name: str = ""):
|
|
32
33
|
self._manual_position_setpoint = epics_signal_w(
|
|
@@ -22,14 +22,14 @@ def _get_zocalo_connection(environment):
|
|
|
22
22
|
|
|
23
23
|
@dataclass
|
|
24
24
|
class ZocaloStartInfo:
|
|
25
|
-
"""
|
|
26
|
-
ispyb_dcid (int): The ID of the data collection in ISPyB
|
|
27
|
-
filename (str): The name of the file that the detector will store into dev/shm
|
|
28
|
-
start_frame_index (int): The index of the first image of this collection within
|
|
29
|
-
|
|
30
|
-
number_of_frames (int): The number of frames in this collection
|
|
31
|
-
message_index (int): Which trigger this is in the detector collection e.g. 0 for
|
|
32
|
-
|
|
25
|
+
"""Attributes:
|
|
26
|
+
ispyb_dcid (int): The ID of the data collection in ISPyB.
|
|
27
|
+
filename (str): The name of the file that the detector will store into dev/shm.
|
|
28
|
+
start_frame_index (int): The index of the first image of this collection within
|
|
29
|
+
the file written by the detector.
|
|
30
|
+
number_of_frames (int): The number of frames in this collection.
|
|
31
|
+
message_index (int): Which trigger this is in the detector collection e.g. 0 for
|
|
32
|
+
the first collection after a single arm, 1 for the next...
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
35
|
ispyb_dcid: int
|
|
@@ -56,7 +56,8 @@ class ZocaloTrigger:
|
|
|
56
56
|
into a plan, use the ZocaloResults ophyd device.
|
|
57
57
|
|
|
58
58
|
see https://diamondlightsource.github.io/dodal/main/how-to/zocalo.html for
|
|
59
|
-
more information about zocalo.
|
|
59
|
+
more information about zocalo.
|
|
60
|
+
"""
|
|
60
61
|
|
|
61
62
|
def __init__(self, environment: str = ZOCALO_ENV):
|
|
62
63
|
self.zocalo_environment: str = environment
|
|
@@ -83,10 +84,10 @@ class ZocaloTrigger:
|
|
|
83
84
|
start_data: ZocaloStartInfo,
|
|
84
85
|
):
|
|
85
86
|
"""Tells the data analysis pipeline we have started a run.
|
|
86
|
-
Assumes that appropriate data has already been put into ISPyB
|
|
87
|
+
Assumes that appropriate data has already been put into ISPyB.
|
|
87
88
|
|
|
88
89
|
Args:
|
|
89
|
-
start_data (ZocaloStartInfo): Data about the collection to send to zocalo
|
|
90
|
+
start_data (ZocaloStartInfo): Data about the collection to send to zocalo.
|
|
90
91
|
"""
|
|
91
92
|
LOGGER.info(f"Starting Zocalo job {start_data}")
|
|
92
93
|
data = dataclasses.asdict(start_data)
|
|
@@ -95,12 +96,11 @@ class ZocaloTrigger:
|
|
|
95
96
|
|
|
96
97
|
def run_end(self, data_collection_id: int):
|
|
97
98
|
"""Tells the data analysis pipeline we have finished a run.
|
|
98
|
-
Assumes that appropriate data has already been put into ISPyB
|
|
99
|
+
Assumes that appropriate data has already been put into ISPyB.
|
|
99
100
|
|
|
100
101
|
Args:
|
|
101
102
|
data_collection_id (int): The ID of the data collection representing the
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
gridscan in ISPyB.
|
|
104
104
|
"""
|
|
105
105
|
LOGGER.info(f"Ending Zocalo job with ispyb id {data_collection_id}")
|
|
106
106
|
self._send_to_zocalo(
|