dls-dodal 1.45.0__py3-none-any.whl → 1.47.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/METADATA +2 -2
  2. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/RECORD +76 -64
  3. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/__init__.py +0 -1
  6. dodal/beamlines/b07.py +2 -6
  7. dodal/beamlines/b07_1.py +1 -3
  8. dodal/beamlines/i03.py +16 -19
  9. dodal/beamlines/i04.py +49 -17
  10. dodal/beamlines/i09.py +1 -3
  11. dodal/beamlines/i09_1.py +1 -3
  12. dodal/beamlines/i18.py +7 -4
  13. dodal/beamlines/i22.py +3 -3
  14. dodal/beamlines/i23.py +75 -4
  15. dodal/beamlines/p38.py +4 -4
  16. dodal/beamlines/p60.py +2 -6
  17. dodal/beamlines/p99.py +48 -4
  18. dodal/common/beamlines/beamline_parameters.py +1 -2
  19. dodal/common/beamlines/beamline_utils.py +5 -0
  20. dodal/common/data_util.py +4 -0
  21. dodal/devices/aperturescatterguard.py +47 -47
  22. dodal/devices/common_dcm.py +77 -0
  23. dodal/devices/current_amplifiers/struck_scaler_counter.py +1 -1
  24. dodal/devices/diamond_filter.py +5 -17
  25. dodal/devices/eiger.py +1 -1
  26. dodal/devices/electron_analyser/__init__.py +8 -0
  27. dodal/devices/electron_analyser/abstract/__init__.py +28 -0
  28. dodal/devices/electron_analyser/abstract/base_detector.py +210 -0
  29. dodal/devices/electron_analyser/abstract/base_driver_io.py +121 -0
  30. dodal/devices/electron_analyser/{abstract_region.py → abstract/base_region.py} +2 -9
  31. dodal/devices/electron_analyser/specs/__init__.py +11 -0
  32. dodal/devices/electron_analyser/specs/detector.py +29 -0
  33. dodal/devices/electron_analyser/specs/driver_io.py +64 -0
  34. dodal/devices/electron_analyser/{specs_region.py → specs/region.py} +1 -1
  35. dodal/devices/electron_analyser/types.py +6 -0
  36. dodal/devices/electron_analyser/util.py +13 -0
  37. dodal/devices/electron_analyser/vgscienta/__init__.py +12 -0
  38. dodal/devices/electron_analyser/vgscienta/detector.py +36 -0
  39. dodal/devices/electron_analyser/vgscienta/driver_io.py +39 -0
  40. dodal/devices/electron_analyser/{vgscienta_region.py → vgscienta/region.py} +1 -1
  41. dodal/devices/fast_grid_scan.py +7 -9
  42. dodal/devices/i03/__init__.py +3 -0
  43. dodal/devices/{dcm.py → i03/dcm.py} +8 -12
  44. dodal/devices/{undulator_dcm.py → i03/undulator_dcm.py} +6 -4
  45. dodal/devices/i04/__init__.py +3 -0
  46. dodal/devices/i04/constants.py +9 -0
  47. dodal/devices/i04/murko_results.py +195 -0
  48. dodal/devices/i10/diagnostics.py +9 -61
  49. dodal/devices/i13_1/merlin.py +3 -4
  50. dodal/devices/i13_1/merlin_controller.py +1 -1
  51. dodal/devices/i22/dcm.py +10 -12
  52. dodal/devices/i24/dcm.py +8 -17
  53. dodal/devices/i24/focus_mirrors.py +9 -13
  54. dodal/devices/i24/pilatus_metadata.py +9 -9
  55. dodal/devices/i24/pmac.py +19 -14
  56. dodal/devices/{i03 → mx_phase1}/beamstop.py +6 -12
  57. dodal/devices/oav/oav_calculations.py +2 -2
  58. dodal/devices/oav/oav_detector.py +32 -22
  59. dodal/devices/oav/utils.py +2 -2
  60. dodal/devices/p99/andor2_point.py +41 -0
  61. dodal/devices/positioner.py +49 -0
  62. dodal/devices/tetramm.py +8 -6
  63. dodal/devices/turbo_slit.py +2 -2
  64. dodal/devices/util/adjuster_plans.py +1 -1
  65. dodal/devices/zebra/zebra.py +4 -0
  66. dodal/devices/zebra/zebra_constants_mapping.py +1 -1
  67. dodal/devices/zocalo/__init__.py +0 -3
  68. dodal/devices/zocalo/zocalo_results.py +6 -32
  69. dodal/log.py +14 -14
  70. dodal/plan_stubs/data_session.py +10 -1
  71. dodal/plan_stubs/electron_analyser/__init__.py +3 -0
  72. dodal/plan_stubs/electron_analyser/{configure_controller.py → configure_driver.py} +30 -18
  73. dodal/plans/verify_undulator_gap.py +2 -2
  74. dodal/common/signal_utils.py +0 -88
  75. dodal/devices/electron_analyser/abstract_analyser_io.py +0 -47
  76. dodal/devices/electron_analyser/specs_analyser_io.py +0 -19
  77. dodal/devices/electron_analyser/vgscienta_analyser_io.py +0 -26
  78. dodal/devices/logging_ophyd_device.py +0 -17
  79. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/entry_points.txt +0 -0
  80. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/licenses/LICENSE +0 -0
  81. {dls_dodal-1.45.0.dist-info → dls_dodal-1.47.0.dist-info}/top_level.txt +0 -0
@@ -1,37 +1,44 @@
1
1
  from bluesky import plan_stubs as bps
2
+ from bluesky.utils import MsgGenerator, plan
3
+ from ophyd_async.epics.adcore import ADImageMode
2
4
 
3
- from dodal.devices.electron_analyser.abstract_analyser_io import (
5
+ from dodal.common.types import MsgGenerator
6
+ from dodal.devices.electron_analyser.abstract import (
4
7
  AbstractAnalyserDriverIO,
5
- )
6
- from dodal.devices.electron_analyser.abstract_region import (
7
8
  AbstractBaseRegion,
8
9
  )
9
- from dodal.devices.electron_analyser.specs_analyser_io import (
10
- SpecsAnalyserDriverIO,
11
- )
12
- from dodal.devices.electron_analyser.specs_region import SpecsRegion
13
- from dodal.devices.electron_analyser.vgscienta_analyser_io import (
10
+ from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsRegion
11
+ from dodal.devices.electron_analyser.util import to_kinetic_energy
12
+ from dodal.devices.electron_analyser.vgscienta import (
14
13
  VGScientaAnalyserDriverIO,
15
- )
16
- from dodal.devices.electron_analyser.vgscienta_region import (
17
14
  VGScientaRegion,
18
15
  )
19
16
  from dodal.log import LOGGER
20
17
 
21
18
 
19
+ @plan
22
20
  def configure_analyser(
23
21
  analyser: AbstractAnalyserDriverIO,
24
22
  region: AbstractBaseRegion,
25
23
  excitation_energy: float,
26
- ):
24
+ ) -> MsgGenerator:
27
25
  LOGGER.info(f'Configuring analyser with region "{region.name}"')
28
- low_energy = region.to_kinetic_energy(region.low_energy, excitation_energy)
29
- high_energy = region.to_kinetic_energy(region.high_energy, excitation_energy)
26
+
27
+ low_energy = to_kinetic_energy(
28
+ region.low_energy, region.energy_mode, excitation_energy
29
+ )
30
+ high_energy = to_kinetic_energy(
31
+ region.high_energy, region.energy_mode, excitation_energy
32
+ )
30
33
  pass_energy_type = analyser.pass_energy_type
31
34
  pass_energy = pass_energy_type(region.pass_energy)
35
+
32
36
  # Set detector settings, wait for them all to have completed
33
37
  # fmt: off
34
38
  yield from bps.mv(
39
+ analyser.region_name, region.name,
40
+ analyser.energy_mode, region.energy_mode,
41
+ analyser.excitation_energy, excitation_energy,
35
42
  analyser.low_energy, low_energy,
36
43
  analyser.high_energy, high_energy,
37
44
  analyser.slices, region.slices,
@@ -43,13 +50,14 @@ def configure_analyser(
43
50
  # fmt: on
44
51
 
45
52
 
53
+ @plan
46
54
  def configure_specs(
47
55
  analyser: SpecsAnalyserDriverIO, region: SpecsRegion, excitation_energy: float
48
- ):
56
+ ) -> MsgGenerator:
49
57
  yield from configure_analyser(analyser, region, excitation_energy)
50
58
  # fmt: off
51
59
  yield from bps.mv(
52
- analyser.values, region.values,
60
+ analyser.snapshot_values, region.values,
53
61
  analyser.psu_mode, region.psu_mode,
54
62
  )
55
63
  # fmt: on
@@ -60,11 +68,14 @@ def configure_specs(
60
68
  yield from bps.mv(analyser.energy_step, region.energy_step)
61
69
 
62
70
 
71
+ @plan
63
72
  def configure_vgscienta(
64
73
  analyser: VGScientaAnalyserDriverIO, region: VGScientaRegion, excitation_energy
65
- ):
74
+ ) -> MsgGenerator:
66
75
  yield from configure_analyser(analyser, region, excitation_energy)
67
- centre_energy = region.to_kinetic_energy(region.fix_energy, excitation_energy)
76
+ centre_energy = to_kinetic_energy(
77
+ region.fix_energy, region.energy_mode, excitation_energy
78
+ )
68
79
 
69
80
  # fmt: off
70
81
  yield from bps.mv(
@@ -75,6 +86,7 @@ def configure_vgscienta(
75
86
  analyser.x_channel_size, region.x_channel_size(),
76
87
  analyser.y_channel_size, region.y_channel_size(),
77
88
  analyser.detector_mode, region.detector_mode,
78
- analyser.image_mode, "Single",
89
+ analyser.excitation_energy_source, region.excitation_energy_source,
90
+ analyser.image_mode, ADImageMode.SINGLE,
79
91
  )
80
92
  # fmt: on
@@ -2,14 +2,14 @@ from typing import Protocol, runtime_checkable
2
2
 
3
3
  from bluesky import plan_stubs as bps
4
4
 
5
- from dodal.devices.dcm import DCM
5
+ from dodal.devices.common_dcm import BaseDCM
6
6
  from dodal.devices.undulator import Undulator
7
7
 
8
8
 
9
9
  @runtime_checkable
10
10
  class CheckUndulatorDevices(Protocol):
11
11
  undulator: Undulator
12
- dcm: DCM
12
+ dcm: BaseDCM
13
13
 
14
14
 
15
15
  def verify_undulator_gap(devices: CheckUndulatorDevices):
@@ -1,88 +0,0 @@
1
- from collections.abc import Callable, Coroutine
2
- from typing import Any
3
-
4
- from bluesky.protocols import Reading
5
- from ophyd_async.core import SignalDatatypeT, SignalR, SignalRW, SoftSignalBackend
6
-
7
- SetHardwareType = Callable[[SignalDatatypeT], Coroutine[Any, Any, None]]
8
-
9
-
10
- class HardwareBackedSoftSignalBackend(SoftSignalBackend[SignalDatatypeT]):
11
- def __init__(
12
- self,
13
- get_from_hardware_func: Callable[[], Coroutine[Any, Any, SignalDatatypeT]],
14
- set_to_hardware_func: SetHardwareType | None = None,
15
- *args,
16
- **kwargs,
17
- ) -> None:
18
- self.get_from_hardware_func = get_from_hardware_func
19
- self.set_to_hardware_func = set_to_hardware_func
20
- super().__init__(*args, **kwargs)
21
-
22
- async def _update_value(self):
23
- new_value = await self.get_from_hardware_func()
24
- self.set_value(new_value)
25
-
26
- async def get_reading(self) -> Reading:
27
- await self._update_value()
28
- return await super().get_reading()
29
-
30
- async def get_value(self) -> SignalDatatypeT:
31
- await self._update_value()
32
- return await super().get_value()
33
-
34
- async def put(self, value: SignalDatatypeT | None, wait: bool) -> None:
35
- if self.set_to_hardware_func:
36
- write_value = self.initial_value if value is None else value
37
- await self.set_to_hardware_func(write_value)
38
-
39
-
40
- def create_rw_hardware_backed_soft_signal(
41
- datatype: type[SignalDatatypeT],
42
- get_from_hardware_func: Callable[[], Coroutine[Any, Any, SignalDatatypeT]],
43
- set_to_hardware_func: SetHardwareType,
44
- units: str | None = None,
45
- precision: int | None = None,
46
- ):
47
- """Creates a soft signal that, when read will call the function passed into
48
- `get_from_hardware_func` and return this. When set it will call `set_to_hardware_func`
49
- and send something to the hardware.
50
-
51
- This will allow you to make soft signals derived from arbitrary hardware signals.
52
- However, calling subscribe on this signal does not give you a sensible value. See https://github.com/bluesky/ophyd-async/issues/525
53
- for a more full solution.
54
- """
55
- return SignalRW(
56
- backend=HardwareBackedSoftSignalBackend(
57
- get_from_hardware_func,
58
- set_to_hardware_func,
59
- datatype,
60
- units=units,
61
- precision=precision,
62
- )
63
- )
64
-
65
-
66
- def create_r_hardware_backed_soft_signal(
67
- datatype: type[SignalDatatypeT],
68
- get_from_hardware_func: Callable[[], Coroutine[Any, Any, SignalDatatypeT]],
69
- units: str | None = None,
70
- precision: int | None = None,
71
- ):
72
- """Creates a soft signal that, when read will call the function passed into
73
- `get_from_hardware_func` and return this.
74
-
75
- This will allow you to make soft signals derived from arbitrary hardware signals.
76
- However, calling subscribe on this signal does not give you a sensible value and
77
- the signal is currently read only. See https://github.com/bluesky/ophyd-async/issues/525
78
- for a more full solution.
79
- """
80
- return SignalR(
81
- backend=HardwareBackedSoftSignalBackend(
82
- get_from_hardware_func,
83
- None,
84
- datatype,
85
- units=units,
86
- precision=precision,
87
- )
88
- )
@@ -1,47 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import TypeVar
3
-
4
- from ophyd_async.core import StandardReadable
5
- from ophyd_async.epics.core import epics_signal_rw
6
-
7
- from dodal.devices.electron_analyser.abstract_region import EnergyMode
8
-
9
-
10
- class AbstractAnalyserDriverIO(ABC, StandardReadable):
11
- """
12
- Generic device to configure electron analyser with new region settings.
13
- Electron analysers should inherit from this class for further specialisation.
14
- """
15
-
16
- def __init__(self, prefix: str, name: str = "") -> None:
17
- with self.add_children_as_readables():
18
- self.low_energy = epics_signal_rw(float, prefix + "LOW_ENERGY")
19
- self.high_energy = epics_signal_rw(float, prefix + "HIGH_ENERGY")
20
- self.slices = epics_signal_rw(int, prefix + "SLICES")
21
- self.lens_mode = epics_signal_rw(str, prefix + "LENS_MODE")
22
- self.pass_energy = epics_signal_rw(
23
- self.pass_energy_type, prefix + "PASS_ENERGY"
24
- )
25
- self.energy_step = epics_signal_rw(float, prefix + "STEP_SIZE")
26
- self.iterations = epics_signal_rw(int, prefix + "NumExposures")
27
- self.acquisition_mode = epics_signal_rw(str, prefix + "ACQ_MODE")
28
-
29
- super().__init__(name)
30
-
31
- def to_kinetic_energy(
32
- self, value: float, excitation_energy: float, mode: EnergyMode
33
- ) -> float:
34
- return excitation_energy - value if mode == EnergyMode.BINDING else value
35
-
36
- @property
37
- @abstractmethod
38
- def pass_energy_type(self) -> type:
39
- """
40
- Return the type the pass_energy should be. Each one is unfortunately different
41
- for the underlying analyser software and cannot be changed on epics side.
42
- """
43
-
44
-
45
- TAbstractAnalyserDriverIO = TypeVar(
46
- "TAbstractAnalyserDriverIO", bound=AbstractAnalyserDriverIO
47
- )
@@ -1,19 +0,0 @@
1
- from ophyd_async.epics.core import epics_signal_rw
2
-
3
- from dodal.devices.electron_analyser.abstract_analyser_io import (
4
- AbstractAnalyserDriverIO,
5
- )
6
-
7
-
8
- class SpecsAnalyserDriverIO(AbstractAnalyserDriverIO):
9
- def __init__(self, prefix: str, name: str = "") -> None:
10
- with self.add_children_as_readables():
11
- self.psu_mode = epics_signal_rw(str, prefix + "SCAN_RANGE")
12
- self.values = epics_signal_rw(int, prefix + "VALUES")
13
- self.centre_energy = epics_signal_rw(float, prefix + "KINETIC_ENERGY")
14
-
15
- super().__init__(prefix, name)
16
-
17
- @property
18
- def pass_energy_type(self) -> type:
19
- return float
@@ -1,26 +0,0 @@
1
- from ophyd_async.epics.core import epics_signal_rw
2
-
3
- from dodal.devices.electron_analyser.abstract_analyser_io import (
4
- AbstractAnalyserDriverIO,
5
- )
6
- from dodal.devices.electron_analyser.vgscienta_region import (
7
- DetectorMode,
8
- )
9
-
10
-
11
- class VGScientaAnalyserDriverIO(AbstractAnalyserDriverIO):
12
- def __init__(self, prefix: str, name: str = "") -> None:
13
- with self.add_children_as_readables():
14
- self.centre_energy = epics_signal_rw(float, prefix + "CENTRE_ENERGY")
15
- self.first_x_channel = epics_signal_rw(int, prefix + "MinX")
16
- self.first_y_channel = epics_signal_rw(int, prefix + "MinY")
17
- self.x_channel_size = epics_signal_rw(int, prefix + "SizeX")
18
- self.y_channel_size = epics_signal_rw(int, prefix + "SizeY")
19
- self.detector_mode = epics_signal_rw(DetectorMode, prefix + "DETECTOR_MODE")
20
- self.image_mode = epics_signal_rw(str, prefix + "ImageMode")
21
-
22
- super().__init__(prefix, name)
23
-
24
- @property
25
- def pass_energy_type(self) -> type:
26
- return str
@@ -1,17 +0,0 @@
1
- from ophyd import Device
2
- from ophyd.log import logger as ophyd_logger
3
-
4
-
5
- class InfoLoggingDevice(Device):
6
- def wait_for_connection(self, all_signals=False, timeout=2.0):
7
- class_name = self.__class__.__name__
8
- ophyd_logger.info(
9
- f"{class_name} waiting for connection, {'not' if all_signals else ''} waiting for all signals, timeout = {timeout}s.",
10
- )
11
- try:
12
- super().wait_for_connection(all_signals, timeout)
13
- except TimeoutError as e:
14
- ophyd_logger.error(f"{class_name} failed to connect.", exc_info=True)
15
- raise e
16
- else:
17
- ophyd_logger.info(f"{class_name} connected.")