-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add i18 beamline definition - WITH device_factory #722
Changes from 92 commits
0baece2
c902167
4fb6a76
7311a8e
9c52087
d902185
d774413
ed4f4c8
52d6ffe
42f1618
ba01d19
80ac2e8
2aa1255
378b978
d2a5c14
a01e7f5
e97bbae
1792482
1502f89
5b760eb
a712008
b0583a8
52f7b71
ccd69e5
0f53ba6
68c0a7a
a8a020b
314edda
9d522ca
9376dd1
67b43cd
f5f0618
b808dd1
9f2369e
6526c61
01de971
70df1eb
78fdc27
5224b96
61007bd
e8c8bcd
e039885
d94415f
5972984
ebb5175
1068b44
9201e5b
b916855
216728c
1ba4df5
cdaaf25
7d2ddd3
c19a147
9faa28e
eb13245
02a94dd
fd7adc2
6616168
2dccb09
f9bf3e5
3f4cbf2
18515b6
f1e03f9
87c9c73
b79b76d
11b08e3
f743462
e753e40
17fa5d3
7c651cc
e3a2e0e
3b3fc28
5536626
568828d
8e42ad9
8e17e2f
c239359
1e7f4a2
5fe2ca2
fe7ff5e
a3f8b1a
b5fef2d
05f2f50
5b8fec4
3f2a7c3
7d66522
cfc9f78
5a87cee
f111987
5fbf51e
10b54a7
8171e96
de2d3c6
5f4220e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
from pathlib import Path | ||
|
||
from ophyd_async.fastcs.panda import HDFPanda | ||
|
||
from dodal.common.beamlines.beamline_utils import ( | ||
device_factory, | ||
get_path_provider, | ||
set_path_provider, | ||
) | ||
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline | ||
from dodal.common.crystal_metadata import CrystalMetadata | ||
from dodal.common.visit import ( | ||
LocalDirectoryServiceClient, | ||
StaticVisitPathProvider, | ||
) | ||
from dodal.devices.i18.diode import Diode | ||
from dodal.devices.i18.KBMirror import KBMirror | ||
from dodal.devices.i18.table import Table | ||
from dodal.devices.i18.thor_labs_stage import ThorLabsStage | ||
from dodal.devices.i22.dcm import DoubleCrystalMonochromator | ||
from dodal.devices.slits import Slits | ||
from dodal.devices.synchrotron import Synchrotron | ||
from dodal.devices.tetramm import TetrammDetector | ||
from dodal.devices.undulator import Undulator | ||
from dodal.log import set_beamline as set_log_beamline | ||
from dodal.utils import BeamlinePrefix, get_beamline_name | ||
|
||
BL = get_beamline_name("i18") | ||
PREFIX = BeamlinePrefix(BL) | ||
set_log_beamline(BL) | ||
set_utils_beamline(BL) | ||
|
||
|
||
# Currently we must hard-code the visit, determining the visit at runtime requires | ||
# infrastructure that is still WIP. | ||
# Communication with GDA is also WIP so for now we determine an arbitrary scan number | ||
# locally and write the commissioning directory. The scan number is not guaranteed to | ||
# be unique and the data is at risk - this configuration is for testing only. | ||
set_path_provider( | ||
StaticVisitPathProvider( | ||
BL, | ||
Path("/dls/i18/data/2024/cm37264-2/bluesky"), | ||
client=LocalDirectoryServiceClient(), | ||
) | ||
) | ||
|
||
|
||
@device_factory() | ||
def synchrotron() -> Synchrotron: | ||
return Synchrotron() | ||
|
||
|
||
@device_factory() | ||
def undulator() -> Undulator: | ||
return Undulator(f"{PREFIX.insertion_prefix}-MO-SERVC-01:") | ||
|
||
|
||
@device_factory() | ||
def dcm() -> DoubleCrystalMonochromator: | ||
crystal_1_metadata = CrystalMetadata( | ||
usage="Bragg", | ||
type="silicon", | ||
reflection=(1, 1, 1), | ||
d_spacing=(3.13475, "nm"), | ||
) | ||
|
||
crystal_2_metadata = CrystalMetadata( | ||
usage="Bragg", | ||
type="silicon", | ||
reflection=(1, 1, 1), | ||
d_spacing=(3.13475, "nm"), | ||
) | ||
|
||
return DoubleCrystalMonochromator( | ||
prefix=f"{PREFIX.beamline_prefix}-MO-DCM-01:", | ||
temperature_prefix=f"{PREFIX.beamline_prefix}-DI-DCM-01:", | ||
crystal_1_metadata=crystal_1_metadata, | ||
crystal_2_metadata=crystal_2_metadata, | ||
) | ||
|
||
|
||
@device_factory() | ||
def slits_1() -> Slits: | ||
return Slits( | ||
f"{PREFIX.beamline_prefix}-AL-SLITS-01:", | ||
x_centre="X:CENTER", | ||
y_centre="Y:CENTER", | ||
) | ||
|
||
|
||
# PandA IOC needs to be updated to support PVI | ||
@device_factory(skip=True) | ||
def panda1() -> HDFPanda: | ||
return HDFPanda( | ||
f"{PREFIX.beamline_prefix}-MO-PANDA-01:", | ||
path_provider=get_path_provider(), | ||
) | ||
|
||
|
||
@device_factory() | ||
def i0() -> TetrammDetector: | ||
return TetrammDetector( | ||
f"{PREFIX.beamline_prefix}-DI-XBPM-02:", | ||
path_provider=get_path_provider(), | ||
type="Cividec Diamond XBPM", | ||
) | ||
|
||
|
||
@device_factory() | ||
def it() -> TetrammDetector: | ||
return TetrammDetector( | ||
f"{PREFIX.beamline_prefix}-DI-XBPM-01:", | ||
path_provider=get_path_provider(), | ||
) | ||
|
||
|
||
@device_factory(skip=True) | ||
# VFM uses different IOC than HFM https://github.com/DiamondLightSource/dodal/issues/1009 | ||
def vfm() -> KBMirror: | ||
return KBMirror(f"{PREFIX.beamline_prefix}-OP-VFM-01:") | ||
|
||
|
||
@device_factory() | ||
def hfm() -> KBMirror: | ||
return KBMirror(f"{PREFIX.beamline_prefix}-OP-HFM-01:") | ||
|
||
|
||
@device_factory() | ||
def d7diode() -> Diode: | ||
return Diode(f"{PREFIX.beamline_prefix}-DI-PHDGN-07:") | ||
|
||
|
||
@device_factory() | ||
def main_table() -> Table: | ||
return Table(f"{PREFIX.beamline_prefix}-MO-TABLE-01:") | ||
|
||
|
||
@device_factory() | ||
def thor_labs_stage() -> ThorLabsStage: | ||
return ThorLabsStage(f"{PREFIX.beamline_prefix}-MO-TABLE-02:") |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,31 @@ | ||||
from bluesky.protocols import Movable | ||||
from ophyd_async.core import AsyncStatus, StandardReadable | ||||
from ophyd_async.epics.core import epics_signal_rw | ||||
from pydantic import BaseModel | ||||
|
||||
|
||||
class XYPosition(BaseModel): | ||||
x: float | ||||
y: float | ||||
|
||||
|
||||
class KBMirror(StandardReadable, Movable): | ||||
def __init__( | ||||
self, | ||||
prefix: str, | ||||
name: str = "", | ||||
): | ||||
self._prefix = prefix | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: not used anywhere There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to have it for reference for checking the object status though |
||||
with self.add_children_as_readables(): | ||||
self.x = epics_signal_rw(float, prefix + "X") | ||||
self.y = epics_signal_rw(float, prefix + "Y") | ||||
self.bend1 = epics_signal_rw(float, prefix + "BEND1") | ||||
self.bend2 = epics_signal_rw(float, prefix + "BEND2") | ||||
self.curve = epics_signal_rw(float, prefix + "CURVE") | ||||
self.ellip = epics_signal_rw(float, prefix + "ELLIP") | ||||
super().__init__(name=name) | ||||
|
||||
@AsyncStatus.wrap | ||||
async def set(self, value: XYPosition): | ||||
self.x.set(value.x) | ||||
self.y.set(value.y) |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,17 @@ | ||||
from ophyd_async.core import ( | ||||
StandardReadable, | ||||
) | ||||
from ophyd_async.epics.core import epics_signal_r | ||||
|
||||
|
||||
class Diode(StandardReadable): | ||||
def __init__( | ||||
self, | ||||
prefix: str, | ||||
name: str = "", | ||||
): | ||||
self._prefix = prefix | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit |
||||
with self.add_children_as_readables(): | ||||
self.signal = epics_signal_r(float, prefix + "B:DIODE:I") | ||||
|
||||
super().__init__(name=name) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from ophyd_async.core import ( | ||
AsyncStatus, | ||
StandardReadable, | ||
) | ||
from ophyd_async.epics.motor import Motor | ||
from pydantic import BaseModel | ||
|
||
|
||
class TablePosition(BaseModel): | ||
x: float | ||
y: float | ||
z: float | None = None | ||
theta: float | None = None | ||
stan-dot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
class Table(StandardReadable): | ||
def __init__(self, prefix: str, name: str = "") -> None: | ||
with self.add_children_as_readables(): | ||
self.x = Motor(prefix + "X") | ||
self.y = Motor(prefix + "Y") | ||
self.z = Motor(prefix + "Z") | ||
self.theta = Motor(prefix + "THETA") | ||
super().__init__(name=name) | ||
|
||
@AsyncStatus.wrap | ||
async def set(self, value: TablePosition): | ||
self.x.set(value.x) | ||
self.y.set(value.y) | ||
if value.z: | ||
self.z.set(value.z) | ||
if value.theta: | ||
self.theta.set(value.theta) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from ophyd_async.core import ( | ||
AsyncStatus, | ||
StandardReadable, | ||
) | ||
from ophyd_async.epics.motor import Motor | ||
from pydantic import BaseModel | ||
|
||
|
||
class XYPosition(BaseModel): | ||
x: float | ||
y: float | ||
|
||
|
||
class ThorLabsStage(StandardReadable): | ||
def __init__(self, prefix: str, name: str = "") -> None: | ||
with self.add_children_as_readables(): | ||
self.x = Motor(prefix + "X") | ||
self.y = Motor(prefix + "Y") | ||
super().__init__(name=name) | ||
|
||
@AsyncStatus.wrap | ||
async def set(self, value: XYPosition): | ||
self.x.set(value.x) | ||
self.y.set(value.y) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from unittest.mock import ANY | ||
|
||
import pytest | ||
from ophyd_async.core import DeviceCollector | ||
from ophyd_async.testing import set_mock_value | ||
|
||
from dodal.devices.i18.KBMirror import KBMirror, XYPosition | ||
|
||
|
||
@pytest.fixture | ||
async def kbmirror() -> KBMirror: | ||
"""Fixture to set up a mock KBMirror device using DeviceCollector.""" | ||
async with DeviceCollector(mock=True): | ||
kbmirror = KBMirror(prefix="MIRROR:") | ||
return kbmirror | ||
|
||
|
||
async def test_setting_xy_position_kbmirror(kbmirror: KBMirror): | ||
""" | ||
Test setting x and y positions on the KBMirror using the ophyd_async mock tools. | ||
""" | ||
# Mock the initial values of the x and y signals | ||
set_mock_value(kbmirror.x, 0.0) | ||
set_mock_value(kbmirror.y, 0.0) | ||
|
||
# Create a position object | ||
position = XYPosition(x=1.23, y=4.56) | ||
|
||
# Call set to update the position | ||
await kbmirror.set(position) | ||
|
||
reading = await kbmirror.read() | ||
expected_reading = { | ||
"kbmirror-y": { | ||
"value": 4.56, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"kbmirror-bend1": { | ||
"value": 0.0, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"kbmirror-ellip": { | ||
"value": 0.0, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"kbmirror-x": { | ||
"value": 1.23, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"kbmirror-bend2": { | ||
"value": 0.0, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"kbmirror-curve": { | ||
"value": 0.0, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
} | ||
|
||
assert reading == expected_reading |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from unittest.mock import ANY | ||
|
||
import pytest | ||
from ophyd_async.core import DeviceCollector | ||
from ophyd_async.testing import set_mock_value | ||
|
||
from dodal.devices.i18.table import Table, TablePosition | ||
|
||
|
||
@pytest.fixture | ||
async def table() -> Table: | ||
"""Fixture to set up a mock Table device using DeviceCollector.""" | ||
async with DeviceCollector(mock=True): | ||
table = Table(prefix="MIRROR:") | ||
return table | ||
|
||
|
||
async def test_setting_xy_position_table(table: Table): | ||
""" | ||
Test setting x and y positions on the Table using the ophyd_async mock tools. | ||
""" | ||
set_mock_value(table.x.user_readback, 1.23) | ||
set_mock_value(table.y.user_readback, 4.56) | ||
|
||
# Create a position object | ||
position = TablePosition(x=1.23, y=4.56, z=0.0, theta=0.0) | ||
|
||
# Call set to update the position | ||
await table.set(position) | ||
|
||
reading = await table.read() | ||
expected_reading = { | ||
"table-y": { | ||
"value": 4.56, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"table-x": { | ||
"value": 1.23, | ||
"timestamp": ANY, | ||
"alarm_severity": 0, | ||
}, | ||
"table-theta": { | ||
"alarm_severity": 0, | ||
"timestamp": ANY, | ||
"value": 0.0, | ||
}, | ||
"table-z": {"alarm_severity": 0, "timestamp": ANY, "value": 0.0}, | ||
} | ||
|
||
assert reading == expected_reading |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import pytest | ||
from ophyd_async.core import DeviceCollector | ||
|
||
from dodal.devices.i18.thor_labs_stage import ThorLabsStage, XYPosition | ||
|
||
|
||
@pytest.fixture | ||
async def fake_thor_labs_stage(): | ||
async with DeviceCollector(mock=True): | ||
fake_thor_labs_stage = ThorLabsStage("", "thor_labs_stage") | ||
|
||
return fake_thor_labs_stage | ||
|
||
|
||
async def test_setting(fake_thor_labs_stage: ThorLabsStage): | ||
pos = XYPosition(x=5, y=5) | ||
await fake_thor_labs_stage.set(pos) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these crystals correct or copied from i22?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can double check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sent an email about this