Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/dodal/beamlines/b07.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
LensMode,
)
from dodal.devices.beamlines.b07_shared import PsuMode
from dodal.devices.electron_analyser.base import EnergySource
from dodal.devices.electron_analyser.specs import SpecsDetector
from dodal.devices.hutch_shutter import (
EXP_SHUTTER_2_INFIX,
Expand Down Expand Up @@ -48,20 +47,15 @@ def pgm() -> PlaneGratingMonochromator:
)


@devices.factory()
def energy_source(pgm: PlaneGratingMonochromator) -> EnergySource:
return EnergySource(pgm.energy.user_readback)


# CAM:IMAGE will fail to connect outside the beamline network,
# see https://github.com/DiamondLightSource/dodal/issues/1852
@devices.factory()
def analyser(energy_source: EnergySource) -> SpecsDetector[LensMode, PsuMode]:
def analyser(pgm: PlaneGratingMonochromator) -> SpecsDetector[LensMode, PsuMode]:
return SpecsDetector[LensMode, PsuMode](
prefix=f"{B_PREFIX.beamline_prefix}-EA-DET-01:CAM:",
lens_mode_type=LensMode,
psu_mode_type=PsuMode,
energy_source=energy_source,
energy_source=pgm.energy.user_readback,
)


Expand Down
10 changes: 2 additions & 8 deletions src/dodal/beamlines/b07_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
LensMode,
)
from dodal.devices.beamlines.b07_shared import PsuMode
from dodal.devices.electron_analyser.base import EnergySource
from dodal.devices.electron_analyser.specs import SpecsDetector
from dodal.devices.hutch_shutter import HutchShutter
from dodal.devices.motors import XYZAzimuthPolarStage
Expand Down Expand Up @@ -42,20 +41,15 @@ def ccmc() -> ChannelCutMonochromator:
return ChannelCutMonochromator(prefix=f"{C_PREFIX.beamline_prefix}-OP-CCM-01:")


@devices.factory()
def energy_source(pgm: PlaneGratingMonochromator) -> EnergySource:
return EnergySource(pgm.energy.user_readback)


# CAM:IMAGE will fail to connect outside the beamline network,
# see https://github.com/DiamondLightSource/dodal/issues/1852
@devices.factory()
def analyser(energy_source: EnergySource) -> SpecsDetector[LensMode, PsuMode]:
def analyser(pgm: PlaneGratingMonochromator) -> SpecsDetector[LensMode, PsuMode]:
return SpecsDetector[LensMode, PsuMode](
prefix=f"{C_PREFIX.beamline_prefix}-EA-DET-01:CAM:",
lens_mode_type=LensMode,
psu_mode_type=PsuMode,
energy_source=energy_source,
energy_source=pgm.energy.user_readback,
)


Expand Down
8 changes: 5 additions & 3 deletions src/dodal/beamlines/i05.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from dodal.devices.beamlines.i05 import I05Goniometer
from dodal.devices.beamlines.i05_shared import LensMode, M4M5Mirror, PassEnergy
from dodal.devices.common_mirror import XYZSwitchingMirror
from dodal.devices.electron_analyser.mbs import MbsAnalyserDriverIO
from dodal.devices.electron_analyser.mbs import MbsDetector
from dodal.devices.hutch_shutter import HutchShutter
from dodal.devices.pgm import PlaneGratingMonochromator
from dodal.devices.temperture_controller import Lakeshore336
from dodal.log import set_beamline as set_log_beamline
from dodal.utils import BeamlinePrefix, get_beamline_name
Expand Down Expand Up @@ -50,9 +51,10 @@ def sa() -> I05Goniometer:


@devices.factory
def analyser_driver() -> MbsAnalyserDriverIO:
return MbsAnalyserDriverIO[LensMode, PassEnergy](
def analyser(pgm: PlaneGratingMonochromator) -> MbsDetector[LensMode, PassEnergy]:
return MbsDetector[LensMode, PassEnergy](
prefix=f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:",
lens_mode_type=LensMode,
pass_energy_type=PassEnergy,
energy_source=pgm.energy.user_readback,
)
8 changes: 5 additions & 3 deletions src/dodal/beamlines/i05_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from dodal.devices.beamlines.i05_1 import XYZAzimuthPolarDefocusStage
from dodal.devices.beamlines.i05_shared import LensMode, Mj7j8Mirror, PassEnergy
from dodal.devices.common_mirror import XYZPiezoSwitchingMirror
from dodal.devices.electron_analyser.mbs import MbsAnalyserDriverIO
from dodal.devices.electron_analyser.mbs import MbsDetector
from dodal.devices.hutch_shutter import HutchShutter
from dodal.devices.pgm import PlaneGratingMonochromator
from dodal.log import set_beamline as set_log_beamline
from dodal.utils import BeamlinePrefix, get_beamline_name

Expand Down Expand Up @@ -39,9 +40,10 @@ def sm() -> XYZAzimuthPolarDefocusStage:


@devices.factory
def analyser_driver() -> MbsAnalyserDriverIO[LensMode, PassEnergy]:
return MbsAnalyserDriverIO[LensMode, PassEnergy](
def analyser(pgm: PlaneGratingMonochromator) -> MbsDetector[LensMode, PassEnergy]:
return MbsDetector[LensMode, PassEnergy](
prefix=f"{PREFIX.beamline_prefix}-EA-DET-04:CAM:",
lens_mode_type=LensMode,
pass_energy_type=PassEnergy,
energy_source=pgm.energy.user_readback,
)
2 changes: 1 addition & 1 deletion src/dodal/beamlines/i09.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def ew4000(
lens_mode_type=LensMode,
psu_mode_type=PsuMode,
pass_energy_type=PassEnergy,
energy_source=dual_energy_source,
energy_source=dual_energy_source.energy,
shutter=dual_fast_shutter,
source_selector=source_selector,
)
Expand Down
12 changes: 4 additions & 8 deletions src/dodal/beamlines/i09_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from dodal.device_manager import DeviceManager
from dodal.devices.beamlines.i09_1 import LensMode, PsuMode
from dodal.devices.common_dcm import DoubleCrystalMonochromatorWithDSpacing
from dodal.devices.electron_analyser.base import EnergySource
from dodal.devices.electron_analyser.specs import SpecsDetector
from dodal.devices.motors import XYZAzimuthTiltPolarStage
from dodal.devices.synchrotron import Synchrotron
Expand All @@ -25,20 +24,17 @@ def synchrotron() -> Synchrotron:
return Synchrotron()


@devices.factory()
def energy_source(dcm: DoubleCrystalMonochromatorWithDSpacing) -> EnergySource:
return EnergySource(dcm.energy_in_eV)


# CAM:IMAGE will fail to connect outside the beamline network,
# see https://github.com/DiamondLightSource/dodal/issues/1852
@devices.factory()
def analyser(energy_source: EnergySource) -> SpecsDetector[LensMode, PsuMode]:
def analyser(
dcm: DoubleCrystalMonochromatorWithDSpacing,
) -> SpecsDetector[LensMode, PsuMode]:
return SpecsDetector[LensMode, PsuMode](
prefix=f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:",
lens_mode_type=LensMode,
psu_mode_type=PsuMode,
energy_source=energy_source,
energy_source=dcm.energy_in_eV,
)


Expand Down
2 changes: 1 addition & 1 deletion src/dodal/beamlines/p60.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ def r4000(
lens_mode_type=LensMode,
psu_mode_type=PsuMode,
pass_energy_type=PassEnergy,
energy_source=energy_source,
energy_source=energy_source.energy,
)
4 changes: 1 addition & 3 deletions src/dodal/devices/electron_analyser/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
TLensMode,
)
from .base_util import to_binding_energy, to_kinetic_energy
from .energy_sources import AbstractEnergySource, DualEnergySource, EnergySource
from .energy_sources import DualEnergySource

__all__ = [
"ElectronAnalyserDetector",
Expand All @@ -35,7 +35,5 @@
"TLensMode",
"to_binding_energy",
"to_kinetic_energy",
"AbstractEnergySource",
"DualEnergySource",
"EnergySource",
]
14 changes: 9 additions & 5 deletions src/dodal/devices/electron_analyser/base/base_detector.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from collections.abc import Sequence
from typing import Generic

import numpy as np
Expand All @@ -8,6 +9,7 @@
AsyncStatus,
DetectorArmLogic,
DetectorTriggerLogic,
SignalR,
StandardDetector,
derived_signal_r,
)
Expand Down Expand Up @@ -63,19 +65,21 @@ def __init__(
arm_logic: DetectorArmLogic,
trigger_logic: DetectorTriggerLogic,
region_logic: RegionLogic,
config_sigs: Sequence[SignalR] = (),
name: str = "",
):
self._region_logic = region_logic
# ToDo - Add data logic
self.add_detector_logics(arm_logic, trigger_logic)

self.binding_energy_axis = derived_signal_r(
self._calculate_binding_energy_axis,
"eV",
energy_axis=region_logic.driver.energy_axis,
excitation_energy=region_logic.energy_source.energy,
excitation_energy=region_logic.energy_source,
energy_mode=region_logic.driver.energy_mode,
)
self._region_logic = region_logic
# ToDo - Add data logic
self.add_detector_logics(arm_logic, trigger_logic)
self.add_config_signals(self.binding_energy_axis)
self.add_config_signals(self.binding_energy_axis, *config_sigs)

self.sequence = SequenceHolder()
super().__init__(name)
Expand Down
5 changes: 2 additions & 3 deletions src/dodal/devices/electron_analyser/base/detector_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
TAbstractAnalyserDriverIO,
)
from dodal.devices.electron_analyser.base.base_region import BaseRegion
from dodal.devices.electron_analyser.base.energy_sources import AbstractEnergySource
from dodal.devices.fast_shutter import GenericFastShutter
from dodal.devices.selectable_source import SourceSelector

Expand Down Expand Up @@ -76,7 +75,7 @@ class RegionLogic:
def __init__(
self,
driver: AbstractAnalyserDriverIO,
energy_source: AbstractEnergySource,
energy_source: SignalR[float],
source_selector: SourceSelector | None = None,
):
self.driver = driver
Expand All @@ -88,6 +87,6 @@ async def setup_with_region(self, region: BaseRegion) -> None:
if self.source_selector is not None:
await self.source_selector.set(region.excitation_energy_source)

excitation_energy = await self.energy_source.energy.get_value()
excitation_energy = await self.energy_source.get_value()
epics_region = region.prepare_for_epics(excitation_energy)
await self.driver.set(epics_region)
64 changes: 15 additions & 49 deletions src/dodal/devices/electron_analyser/base/energy_sources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from abc import abstractmethod

from ophyd_async.core import (
Reference,
SignalR,
Expand All @@ -13,46 +11,15 @@
from dodal.devices.selectable_source import SelectedSource, get_obj_from_selected_source


class AbstractEnergySource(StandardReadable):
"""Abstract device that wraps an energy source signal and provides common interface
via a energy signal.
"""

@property
@abstractmethod
def energy(self) -> SignalR[float]:
"""Signal to provide the excitation energy value in eV."""


class EnergySource(AbstractEnergySource):
"""Wraps a signal that relates to energy and provides common interface via energy
signal. It provides the name of the wrapped signal as a child signal in the
read_configuration via wrapped_device_name and adds the signal as a readable.
"""

def __init__(self, source: SignalR[float], name: str = "") -> None:
self.add_readables([source])
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.wrapped_device_name, _ = soft_signal_r_and_setter(
str, initial_value=source.name
)
self._source_ref = Reference(source)
super().__init__(name)

@property
def energy(self) -> SignalR[float]:
return self._source_ref()


def get_float_from_selected_source(
selected: SelectedSource, s1: float, s2: float
) -> float:
"""Wrapper function to provide type hints for derived signal."""
return get_obj_from_selected_source(selected, s1, s2)


class DualEnergySource(AbstractEnergySource):
"""Holds two EnergySource devices and provides a signal to read energy depending on
class DualEnergySource(StandardReadable):
"""Provides a signal to read energy depending on
which source is selected. The energy is the one that corrosponds to the
selected_source signal. For example, selected_source is source1 if selected_source
is at SelectedSource.SOURCE1 and vise versa for source2 and
Expand All @@ -73,21 +40,20 @@ def __init__(
name: str = "",
):
self.selected_source_ref = Reference(selected_source)
self.source1_ref = Reference(source1)
self.source2_ref = Reference(source2)
with self.add_children_as_readables():
self.source1 = EnergySource(source1)
self.source2 = EnergySource(source2)
self.energy = derived_signal_r(
get_float_from_selected_source,
"eV",
selected=selected_source,
s1=source1,
s2=source2,
)

self._selected_energy = derived_signal_r(
get_float_from_selected_source,
"eV",
selected=self.selected_source_ref(),
s1=self.source1.energy,
s2=self.source2.energy,
)
self.add_readables([selected_source])
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.source1, _ = soft_signal_r_and_setter(str, initial_value=source1.name)
self.source2, _ = soft_signal_r_and_setter(str, initial_value=source2.name)
self.add_readables([selected_source, source1, source2])

super().__init__(name)

@property
def energy(self) -> SignalR[float]:
return self._selected_energy
9 changes: 8 additions & 1 deletion src/dodal/devices/electron_analyser/mbs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from .mbs_detector import MbsDetector
from .mbs_driver_io import MbsAnalyserDriverIO
from .mbs_enums import AcquisitionMode
from .mbs_region import MbsRegion, MbsSequence

__all__ = ["MbsAnalyserDriverIO", "AcquisitionMode", "MbsRegion", "MbsSequence"]
__all__ = [
"MbsDetector",
"MbsAnalyserDriverIO",
"AcquisitionMode",
"MbsRegion",
"MbsSequence",
]
Loading
Loading