Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
f209651
Create Superconducting magnet device for i06-1
oliwenmandiamond Jun 30, 2026
b3f9037
correct pvs
oliwenmandiamond Jun 30, 2026
e004d75
Update to user own coordinate device
oliwenmandiamond Jun 30, 2026
a4812df
Complete implementation
oliwenmandiamond Jul 1, 2026
56a754d
Add to do comments
oliwenmandiamond Jul 1, 2026
d4f3dc7
Add SuperconductingMagnetController
oliwenmandiamond Jul 6, 2026
310be3b
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 6, 2026
71b1cc0
Add RampMagnetController
oliwenmandiamond Jul 7, 2026
ac72244
Move ramp controllers to own file
oliwenmandiamond Jul 7, 2026
770d400
Add read methods for spherical coordinates
oliwenmandiamond Jul 8, 2026
706c39c
Rename to ramp controllers to MagnetAxisRampRateController
oliwenmandiamond Jul 8, 2026
3487313
Add ramp_controller tests
oliwenmandiamond Jul 8, 2026
1deca95
Add tests for superconducting_magnet
oliwenmandiamond Jul 9, 2026
bc877e9
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 9, 2026
0f3829c
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 9, 2026
712ca91
Add individual spherical axis tests
oliwenmandiamond Jul 9, 2026
c2dc441
Merge branch 'add_i06_magnets' of ssh://github.com/DiamondLightSource…
oliwenmandiamond Jul 9, 2026
7da935c
Increased timeout to 600 seconds, no longer a signal
oliwenmandiamond Jul 9, 2026
27389fb
Add order of set test
oliwenmandiamond Jul 9, 2026
c45047f
Add missing code coverage
oliwenmandiamond Jul 9, 2026
de9bc5c
Andd Flyable and Prepare methods and tests
oliwenmandiamond Jul 10, 2026
1c359d5
Add doc strings to classes
oliwenmandiamond Jul 10, 2026
e526270
Refactor magnets to have moment strategies, add better mock behaviour
oliwenmandiamond Jul 14, 2026
7a55ad1
Remove commented out code
oliwenmandiamond Jul 14, 2026
917718d
Fix test
oliwenmandiamond Jul 14, 2026
7bb955b
Update doc strings and add logging
oliwenmandiamond Jul 14, 2026
d0282c6
Remove unneeded comment
oliwenmandiamond Jul 14, 2026
55446eb
Add better mocking behaviour
oliwenmandiamond Jul 15, 2026
424d5a3
Update SuperConductingMagnet to SuperConductingMagnetController
oliwenmandiamond Jul 15, 2026
c12f482
Add test for no movement strategy
oliwenmandiamond Jul 15, 2026
d11a7ee
Improve typing
oliwenmandiamond Jul 15, 2026
665095f
Add check_value logic for the ramp controllers
oliwenmandiamond Jul 15, 2026
f8b281e
Rename lakeshore devices to use cooling/heating
oliwenmandiamond Jul 15, 2026
928f0ad
Add missing code coverage
oliwenmandiamond Jul 15, 2026
7317776
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 15, 2026
4ba4f12
Update to ophyd-async v0.20
oliwenmandiamond Jul 17, 2026
7ccbc28
Update naming issue
oliwenmandiamond Jul 17, 2026
8f040e2
Update remaining tests that are not bluesky verb errors
oliwenmandiamond Jul 17, 2026
d5c165f
Fix apple2 mock_config:_client errors
oliwenmandiamond Jul 17, 2026
572edb6
update comment
oliwenmandiamond Jul 17, 2026
ab0dbcf
Remove unneeded connects
oliwenmandiamond Jul 17, 2026
83d0d5b
Fix fasteiger test
oliwenmandiamond Jul 17, 2026
e82b298
Merge branch 'main' into update_to_ophyd_async_0_20
oliwenmandiamond Jul 17, 2026
8bb0094
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 22, 2026
bdbeec8
Update to use 0.21 and use env variable
oliwenmandiamond Jul 22, 2026
377f5d4
Fix ConfigClient issue
oliwenmandiamond Jul 22, 2026
58674a5
Merge branch 'main' into update_to_ophyd_async_0_20
oliwenmandiamond Jul 22, 2026
b011acc
Bump ophyd-async pin to >=0.20.1 and fix set_mock_attr test failures
claude Jul 22, 2026
dba111c
Remove temporary OPHYD_ASYNC_ALLOW_RESERVED_ATTRS mask
claude Jul 22, 2026
7fc58a4
Fix pyright regression from set_mock_attr changes
claude Jul 22, 2026
a87e8b7
Update src/dodal/devices/beamlines/i06_1/magnets/movement.py
oliwenmandiamond Jul 23, 2026
efcae4f
Apply suggestion from @Relm-Arrowny
oliwenmandiamond Jul 23, 2026
3e01616
Apply suggestion from @Relm-Arrowny
oliwenmandiamond Jul 23, 2026
e0fd0b1
Update spelling mistakes and typos
oliwenmandiamond Jul 23, 2026
7521776
Merge branch 'add_i06_magnets' of ssh://github.com/DiamondLightSource…
oliwenmandiamond Jul 23, 2026
2981ca4
Add axis limit
oliwenmandiamond Jul 23, 2026
d508686
Fix tests
oliwenmandiamond Jul 23, 2026
ce9f2c6
Add check to block external parallel moves
oliwenmandiamond Jul 23, 2026
7ba2746
Add test for blocking parallel moves done externally
oliwenmandiamond Jul 23, 2026
6b05be4
Update test to check we can still move after
oliwenmandiamond Jul 23, 2026
d0a0022
Add check_within_limits method for movements
oliwenmandiamond Jul 24, 2026
f1de08a
Add better doc string for total_position
oliwenmandiamond Jul 24, 2026
79ed9a8
Add missing test coverage
oliwenmandiamond Jul 24, 2026
b52e33f
Standardise error messages
oliwenmandiamond Jul 24, 2026
ded7246
Rename MagnetModes to MagnetMode
oliwenmandiamond Jul 27, 2026
1a28425
Add tests for enums
oliwenmandiamond Jul 27, 2026
6e3cbcb
Update to us axis mode for MagnetAxis
oliwenmandiamond Jul 27, 2026
f629c58
Increase test coverage
oliwenmandiamond Jul 28, 2026
931bef9
Improve spherical coordinates
oliwenmandiamond Jul 28, 2026
fcdfc08
Add test for new spherical movement request
oliwenmandiamond Jul 28, 2026
018e974
Create coordinates
oliwenmandiamond Jul 28, 2026
ffea025
Update to use epics_triggerable_command
oliwenmandiamond Jul 28, 2026
da5ac51
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 28, 2026
2f89975
Merge branch 'main' into update_to_ophyd_async_0_20
oliwenmandiamond Jul 29, 2026
6b424b6
Merge branch 'update_to_ophyd_async_0_20' of ssh://github.com/Diamond…
oliwenmandiamond Jul 29, 2026
70175a5
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 29, 2026
d3bc8b3
Merge branch 'update_to_ophyd_async_0_20' into add_i06_magnets
oliwenmandiamond Jul 29, 2026
8d2ce05
Merge branch 'main' into add_i06_magnets
oliwenmandiamond Jul 29, 2026
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
22 changes: 20 additions & 2 deletions src/dodal/beamlines/i06_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
from dodal.device_manager import DeviceManager
from dodal.devices.beamlines.i06_1 import DiffractionDichroism
from dodal.devices.beamlines.i06_1.magnets import (
MagnetThreeAxesRampRateController,
SuperConductingMagnetController,
)
from dodal.devices.motors import XYThetaStage
from dodal.devices.temperture_controller import Lakeshore336
from dodal.log import set_beamline as set_log_beamline
Expand All @@ -17,12 +21,12 @@


@devices.factory()
def diff_cooling_temperature_controller() -> Lakeshore336:
def ls336_cooling() -> Lakeshore336:
return Lakeshore336(prefix=f"{PREFIX.beamline_prefix}-EA-TCTRL-02:")


@devices.factory()
def diff_heating_temperature_controller() -> Lakeshore336:
def ls336_heating() -> Lakeshore336:
return Lakeshore336(prefix=f"{PREFIX.beamline_prefix}-EA-TCTRL-03:")


Expand All @@ -34,3 +38,17 @@ def xabs() -> XYThetaStage:
@devices.factory()
def dd() -> DiffractionDichroism:
return DiffractionDichroism(f"{PREFIX.beamline_prefix}-EA-DDIFF-01:")


@devices.factory()
def mag_ramp_rate() -> MagnetThreeAxesRampRateController:
return MagnetThreeAxesRampRateController(f"{PREFIX.beamline_prefix}-EA-SMC")


@devices.factory()
def scmc(
mag_ramp_rate: MagnetThreeAxesRampRateController,
) -> SuperConductingMagnetController:
return SuperConductingMagnetController(
f"{PREFIX.beamline_prefix}-EA-MAG-01:", mag_ramp_rate
)
35 changes: 35 additions & 0 deletions src/dodal/devices/beamlines/i06_1/magnets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from .coordinates import (
MagnetPosition,
MagnetRequest,
MagnetSphericalPosition,
MagnetSphericalRequest,
)
from .movement import MagnetPositionError
from .ramp_controller import (
MagnetAxisRampRateController,
MagnetThreeAxesRampRateController,
)
from .superconducting_magnet import (
FlyMagnetInfo,
MagnetAxis,
MagnetLimitStatus,
MagnetMode,
MagnetRampStatus,
SuperConductingMagnetController,
)

__all__ = [
"MagnetPosition",
"MagnetSphericalPosition",
"MagnetSphericalRequest",
"MagnetRequest",
"MagnetPositionError",
"MagnetAxisRampRateController",
"MagnetThreeAxesRampRateController",
"FlyMagnetInfo",
"MagnetAxis",
"MagnetLimitStatus",
"MagnetMode",
"MagnetRampStatus",
"SuperConductingMagnetController",
]
93 changes: 93 additions & 0 deletions src/dodal/devices/beamlines/i06_1/magnets/coordinates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import math
from dataclasses import dataclass


@dataclass(kw_only=True)
class MagnetPosition:
x: float
y: float
z: float

@staticmethod
def calc_theta(x: float, z: float) -> float:
theta = math.degrees(math.atan2(-x, z))
return theta % 360

@staticmethod
def calc_rho(x: float, y: float, z: float) -> float:
return math.hypot(x, y, z)

@staticmethod
def calc_phi(x: float, y: float, z: float) -> float:
return math.degrees(math.atan2(math.hypot(x, z), y))

def to_spherical(self) -> "MagnetSphericalPosition":
return MagnetSphericalPosition(
rho=self.calc_rho(self.x, self.y, self.z),
theta=self.calc_theta(self.x, self.z),
phi=self.calc_phi(self.x, self.y, self.z),
)

@property
def field_magnitude(self) -> float:
return math.hypot(self.x, self.y, self.z)

def to_request_pos(self) -> "MagnetRequest":
return MagnetRequest(x=self.x, y=self.y, z=self.z)


@dataclass(kw_only=True)
class MagnetSphericalPosition:
rho: float
theta: float # degrees
phi: float # degrees

def to_cartesian(self) -> MagnetPosition:
theta = math.radians(self.theta)
phi = math.radians(self.phi)
return MagnetPosition(
x=-self.rho * math.sin(phi) * math.sin(theta),
y=self.rho * math.cos(phi),
z=self.rho * math.sin(phi) * math.cos(theta),
)

def to_request_pos(self) -> "MagnetSphericalRequest":
return MagnetSphericalRequest(rho=self.rho, theta=self.theta, phi=self.phi)


@dataclass(frozen=True, kw_only=True)
class MagnetRequest:
x: float | None = None
y: float | None = None
z: float | None = None

def __post_init__(self):
if self.x is None and self.y is None and self.z is None:
raise ValueError("At least one of x, y, or z must be specified.")

def resolve_pos(self, current: MagnetPosition) -> MagnetPosition:
"""Resolve unspecified coordinates using the current position."""
return MagnetPosition(
x=current.x if self.x is None else self.x,
y=current.y if self.y is None else self.y,
z=current.z if self.z is None else self.z,
)


@dataclass(frozen=True, kw_only=True)
class MagnetSphericalRequest:
rho: float | None = None
theta: float | None = None
phi: float | None = None

def __post_init__(self):
if self.rho is None and self.theta is None and self.phi is None:
raise ValueError("At least one of rho, theta, or phi must be specified.")

def resolve_pos(self, current: MagnetSphericalPosition) -> MagnetSphericalPosition:
"""Resolve unspecified coordinates using the current position."""
return MagnetSphericalPosition(
rho=current.rho if self.rho is None else self.rho,
theta=current.theta if self.theta is None else self.theta,
phi=current.phi if self.phi is None else self.phi,
)
34 changes: 34 additions & 0 deletions src/dodal/devices/beamlines/i06_1/magnets/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from ophyd_async.core import StrictEnum


class MagnetMode(StrictEnum):
UNIAXIAL_X = "UNIAXIAL_X"
UNIAXIAL_Y = "UNIAXIAL_Y"
UNIAXIAL_Z = "UNIAXIAL_Z"
SPHERICAL = "SPHERICAL"
PLANAR_XZ = "PLANAR_XZ"
QUADRANT_XY = "QUADRANT_XY"
CUBIC = "CUBIC"
UNDEFINED = "UNDEFINED"

@property
def axis_alias(self) -> str:
match self:
case MagnetMode.UNIAXIAL_X:
return "x"
case MagnetMode.UNIAXIAL_Y:
return "y"
case MagnetMode.UNIAXIAL_Z:
return "z"
case _:
raise ValueError(f"{self} is not a valid uniaxial.")


class MagnetRampStatus(StrictEnum):
RAMP_MADE = "RAMP MADE"
RAMPING = "RAMPING"


class MagnetLimitStatus(StrictEnum):
OK = "OK"
VIOLATION = "VIOLATION"
Loading
Loading