ophyd-async 0.4.0__py3-none-any.whl → 0.5.1__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.
- ophyd_async/_version.py +2 -2
- ophyd_async/core/__init__.py +86 -73
- ophyd_async/core/{detector.py → _detector.py} +42 -36
- ophyd_async/core/{device.py → _device.py} +1 -1
- ophyd_async/core/{device_save_loader.py → _device_save_loader.py} +3 -3
- ophyd_async/core/{flyer.py → _flyer.py} +6 -8
- ophyd_async/{epics/areadetector/writers/general_hdffile.py → core/_hdf_dataset.py} +4 -8
- ophyd_async/{log.py → core/_log.py} +11 -3
- ophyd_async/core/{mock_signal_backend.py → _mock_signal_backend.py} +3 -3
- ophyd_async/core/{mock_signal_utils.py → _mock_signal_utils.py} +7 -7
- ophyd_async/{protocols.py → core/_protocol.py} +1 -1
- ophyd_async/core/_providers.py +24 -37
- ophyd_async/core/{standard_readable.py → _readable.py} +6 -16
- ophyd_async/core/{signal.py → _signal.py} +79 -35
- ophyd_async/core/{signal_backend.py → _signal_backend.py} +4 -13
- ophyd_async/core/{soft_signal_backend.py → _soft_signal_backend.py} +3 -12
- ophyd_async/core/{async_status.py → _status.py} +3 -11
- ophyd_async/epics/adaravis/__init__.py +9 -0
- ophyd_async/epics/{areadetector/aravis.py → adaravis/_aravis.py} +9 -11
- ophyd_async/epics/{areadetector/controllers/aravis_controller.py → adaravis/_aravis_controller.py} +7 -10
- ophyd_async/epics/{areadetector/drivers/aravis_driver.py → adaravis/_aravis_io.py} +6 -3
- ophyd_async/epics/adcore/__init__.py +47 -0
- ophyd_async/epics/adcore/_core_io.py +138 -0
- ophyd_async/epics/{areadetector/drivers/ad_base.py → adcore/_core_logic.py} +16 -52
- ophyd_async/epics/{areadetector/writers/hdf_writer.py → adcore/_hdf_writer.py} +54 -29
- ophyd_async/epics/{areadetector/single_trigger_det.py → adcore/_single_trigger.py} +5 -6
- ophyd_async/epics/adcore/_utils.py +132 -0
- ophyd_async/epics/adkinetix/__init__.py +9 -0
- ophyd_async/epics/{areadetector/kinetix.py → adkinetix/_kinetix.py} +9 -11
- ophyd_async/epics/{areadetector/controllers/kinetix_controller.py → adkinetix/_kinetix_controller.py} +6 -9
- ophyd_async/epics/{areadetector/drivers/kinetix_driver.py → adkinetix/_kinetix_io.py} +9 -5
- ophyd_async/epics/adpilatus/__init__.py +11 -0
- ophyd_async/epics/{areadetector/pilatus.py → adpilatus/_pilatus.py} +10 -14
- ophyd_async/epics/{areadetector/controllers/pilatus_controller.py → adpilatus/_pilatus_controller.py} +15 -17
- ophyd_async/epics/{areadetector/drivers/pilatus_driver.py → adpilatus/_pilatus_io.py} +6 -4
- ophyd_async/epics/adsimdetector/__init__.py +7 -0
- ophyd_async/epics/{demo/demo_ad_sim_detector.py → adsimdetector/_sim.py} +10 -11
- ophyd_async/epics/{areadetector/controllers/ad_sim_controller.py → adsimdetector/_sim_controller.py} +8 -14
- ophyd_async/epics/advimba/__init__.py +9 -0
- ophyd_async/epics/{areadetector/vimba.py → advimba/_vimba.py} +9 -9
- ophyd_async/epics/{areadetector/controllers/vimba_controller.py → advimba/_vimba_controller.py} +9 -17
- ophyd_async/epics/{areadetector/drivers/vimba_driver.py → advimba/_vimba_io.py} +11 -8
- ophyd_async/epics/demo/__init__.py +9 -132
- ophyd_async/epics/demo/_mover.py +97 -0
- ophyd_async/epics/demo/_sensor.py +36 -0
- ophyd_async/epics/{motion/motor.py → motor.py} +28 -14
- ophyd_async/epics/pvi/__init__.py +2 -2
- ophyd_async/epics/pvi/{pvi.py → _pvi.py} +17 -14
- ophyd_async/epics/signal/__init__.py +7 -1
- ophyd_async/epics/{_backend → signal}/_aioca.py +15 -7
- ophyd_async/epics/{_backend/common.py → signal/_common.py} +2 -2
- ophyd_async/epics/signal/_epics_transport.py +3 -3
- ophyd_async/epics/{_backend → signal}/_p4p.py +18 -14
- ophyd_async/epics/signal/{signal.py → _signal.py} +10 -9
- ophyd_async/fastcs/odin/__init__.py +0 -0
- ophyd_async/{panda → fastcs/panda}/__init__.py +20 -15
- ophyd_async/{panda/_common_blocks.py → fastcs/panda/_block.py} +5 -3
- ophyd_async/{panda/_panda_controller.py → fastcs/panda/_control.py} +2 -1
- ophyd_async/{panda → fastcs/panda}/_hdf_panda.py +5 -10
- ophyd_async/{panda → fastcs/panda}/_trigger.py +3 -7
- ophyd_async/{panda/writers/_hdf_writer.py → fastcs/panda/_writer.py} +36 -28
- ophyd_async/plan_stubs/__init__.py +5 -2
- ophyd_async/plan_stubs/{ensure_connected.py → _ensure_connected.py} +1 -2
- ophyd_async/plan_stubs/{fly.py → _fly.py} +13 -9
- ophyd_async/plan_stubs/_nd_attributes.py +63 -0
- ophyd_async/sim/__init__.py +0 -11
- ophyd_async/sim/demo/__init__.py +18 -2
- ophyd_async/sim/demo/_pattern_detector/__init__.py +13 -0
- ophyd_async/sim/{sim_pattern_generator.py → demo/_pattern_detector/_pattern_detector.py} +8 -8
- ophyd_async/sim/{sim_pattern_detector_control.py → demo/_pattern_detector/_pattern_detector_controller.py} +9 -7
- ophyd_async/sim/{sim_pattern_detector_writer.py → demo/_pattern_detector/_pattern_detector_writer.py} +4 -4
- ophyd_async/sim/{pattern_generator.py → demo/_pattern_detector/_pattern_generator.py} +13 -11
- ophyd_async/sim/demo/{sim_motor.py → _sim_motor.py} +7 -5
- ophyd_async/sim/testing/__init__.py +0 -0
- ophyd_async/tango/__init__.py +0 -0
- {ophyd_async-0.4.0.dist-info → ophyd_async-0.5.1.dist-info}/METADATA +46 -44
- ophyd_async-0.5.1.dist-info/RECORD +90 -0
- {ophyd_async-0.4.0.dist-info → ophyd_async-0.5.1.dist-info}/WHEEL +1 -1
- ophyd_async/epics/areadetector/__init__.py +0 -23
- ophyd_async/epics/areadetector/controllers/__init__.py +0 -5
- ophyd_async/epics/areadetector/drivers/__init__.py +0 -23
- ophyd_async/epics/areadetector/utils.py +0 -104
- ophyd_async/epics/areadetector/writers/__init__.py +0 -5
- ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -43
- ophyd_async/epics/areadetector/writers/nd_plugin.py +0 -68
- ophyd_async/epics/motion/__init__.py +0 -3
- ophyd_async/panda/writers/__init__.py +0 -3
- ophyd_async-0.4.0.dist-info/RECORD +0 -84
- /ophyd_async/core/{utils.py → _utils.py} +0 -0
- /ophyd_async/{epics/_backend → fastcs}/__init__.py +0 -0
- /ophyd_async/{panda → fastcs/panda}/_table.py +0 -0
- /ophyd_async/{panda → fastcs/panda}/_utils.py +0 -0
- {ophyd_async-0.4.0.dist-info → ophyd_async-0.5.1.dist-info}/LICENSE +0 -0
- {ophyd_async-0.4.0.dist-info → ophyd_async-0.5.1.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.4.0.dist-info → ophyd_async-0.5.1.dist-info}/top_level.txt +0 -0
|
@@ -2,17 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Sequence
|
|
4
4
|
|
|
5
|
-
from ophyd_async.core import
|
|
6
|
-
DEFAULT_TIMEOUT,
|
|
7
|
-
PathProvider,
|
|
8
|
-
SignalR,
|
|
9
|
-
StandardDetector,
|
|
10
|
-
)
|
|
5
|
+
from ophyd_async.core import DEFAULT_TIMEOUT, PathProvider, SignalR, StandardDetector
|
|
11
6
|
from ophyd_async.epics.pvi import create_children_from_annotations, fill_pvi_entries
|
|
12
7
|
|
|
13
|
-
from .
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
8
|
+
from ._block import CommonPandaBlocks
|
|
9
|
+
from ._control import PandaPcapController
|
|
10
|
+
from ._writer import PandaHDFWriter
|
|
16
11
|
|
|
17
12
|
|
|
18
13
|
class HDFPanda(CommonPandaBlocks, StandardDetector):
|
|
@@ -31,7 +26,7 @@ class HDFPanda(CommonPandaBlocks, StandardDetector):
|
|
|
31
26
|
prefix=prefix,
|
|
32
27
|
path_provider=path_provider,
|
|
33
28
|
name_provider=lambda: name,
|
|
34
|
-
|
|
29
|
+
panda_data_block=self.data,
|
|
35
30
|
)
|
|
36
31
|
super().__init__(
|
|
37
32
|
controller=controller,
|
|
@@ -4,13 +4,9 @@ from typing import Optional
|
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
6
|
from ophyd_async.core import TriggerLogic, wait_for_value
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
SeqBlock,
|
|
11
|
-
SeqTable,
|
|
12
|
-
TimeUnits,
|
|
13
|
-
)
|
|
7
|
+
|
|
8
|
+
from ._block import PcompBlock, PcompDirectionOptions, SeqBlock, TimeUnits
|
|
9
|
+
from ._table import SeqTable
|
|
14
10
|
|
|
15
11
|
|
|
16
12
|
class SeqTableInfo(BaseModel):
|
|
@@ -8,14 +8,15 @@ from p4p.client.thread import Context
|
|
|
8
8
|
from ophyd_async.core import (
|
|
9
9
|
DEFAULT_TIMEOUT,
|
|
10
10
|
DetectorWriter,
|
|
11
|
+
HDFDataset,
|
|
12
|
+
HDFFile,
|
|
11
13
|
NameProvider,
|
|
12
14
|
PathProvider,
|
|
15
|
+
observe_value,
|
|
13
16
|
wait_for_value,
|
|
14
17
|
)
|
|
15
|
-
from ophyd_async.core.signal import observe_value
|
|
16
|
-
from ophyd_async.epics.areadetector.writers.general_hdffile import _HDFDataset, _HDFFile
|
|
17
18
|
|
|
18
|
-
from
|
|
19
|
+
from ._block import DataBlock
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class PandaHDFWriter(DetectorWriter):
|
|
@@ -26,14 +27,14 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
26
27
|
prefix: str,
|
|
27
28
|
path_provider: PathProvider,
|
|
28
29
|
name_provider: NameProvider,
|
|
29
|
-
|
|
30
|
+
panda_data_block: DataBlock,
|
|
30
31
|
) -> None:
|
|
31
|
-
self.
|
|
32
|
+
self.panda_data_block = panda_data_block
|
|
32
33
|
self._prefix = prefix
|
|
33
34
|
self._path_provider = path_provider
|
|
34
35
|
self._name_provider = name_provider
|
|
35
|
-
self._datasets: List[
|
|
36
|
-
self._file: Optional[
|
|
36
|
+
self._datasets: List[HDFDataset] = []
|
|
37
|
+
self._file: Optional[HDFFile] = None
|
|
37
38
|
self._multiplier = 1
|
|
38
39
|
|
|
39
40
|
# Triggered on PCAP arm
|
|
@@ -41,25 +42,33 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
41
42
|
"""Retrieve and get descriptor of all PandA signals marked for capture"""
|
|
42
43
|
|
|
43
44
|
# Ensure flushes are immediate
|
|
44
|
-
await self.
|
|
45
|
+
await self.panda_data_block.flush_period.set(0)
|
|
45
46
|
|
|
46
47
|
self._file = None
|
|
47
|
-
info = self._path_provider(device_name=self.
|
|
48
|
+
info = self._path_provider(device_name=self._name_provider())
|
|
49
|
+
|
|
50
|
+
# Set create dir depth first to guarantee that callback when setting
|
|
51
|
+
# directory path has correct value
|
|
52
|
+
await self.panda_data_block.create_directory.set(info.create_dir_depth)
|
|
53
|
+
|
|
48
54
|
# Set the initial values
|
|
49
55
|
await asyncio.gather(
|
|
50
|
-
self.
|
|
51
|
-
|
|
52
|
-
),
|
|
53
|
-
self.panda_device.data.hdf_file_name.set(
|
|
56
|
+
self.panda_data_block.hdf_directory.set(str(info.directory_path)),
|
|
57
|
+
self.panda_data_block.hdf_file_name.set(
|
|
54
58
|
f"{info.filename}.h5",
|
|
55
59
|
),
|
|
56
|
-
self.
|
|
57
|
-
# TODO: Set create_dir_depth once available
|
|
58
|
-
# https://github.com/bluesky/ophyd-async/issues/317
|
|
60
|
+
self.panda_data_block.num_capture.set(0),
|
|
59
61
|
)
|
|
60
62
|
|
|
63
|
+
# Make sure that directory exists or has been created.
|
|
64
|
+
if not await self.panda_data_block.directory_exists.get_value() == 1:
|
|
65
|
+
raise OSError(
|
|
66
|
+
f"Directory {info.directory_path} does not exist or "
|
|
67
|
+
"is not writable by the PandABlocks-ioc!"
|
|
68
|
+
)
|
|
69
|
+
|
|
61
70
|
# Wait for it to start, stashing the status that tells us when it finishes
|
|
62
|
-
await self.
|
|
71
|
+
await self.panda_data_block.capture.set(True)
|
|
63
72
|
if multiplier > 1:
|
|
64
73
|
raise ValueError(
|
|
65
74
|
"All PandA datasets should be scalar, multiplier should be 1"
|
|
@@ -75,7 +84,7 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
75
84
|
await self._update_datasets()
|
|
76
85
|
describe = {
|
|
77
86
|
ds.data_key: DataKey(
|
|
78
|
-
source=self.
|
|
87
|
+
source=self.panda_data_block.hdf_directory.source,
|
|
79
88
|
shape=ds.shape,
|
|
80
89
|
dtype="array" if ds.shape != [1] else "number",
|
|
81
90
|
dtype_numpy="<f8", # PandA data should always be written as Float64
|
|
@@ -91,9 +100,9 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
91
100
|
representation of datasets that the panda will write.
|
|
92
101
|
"""
|
|
93
102
|
|
|
94
|
-
capture_table = await self.
|
|
103
|
+
capture_table = await self.panda_data_block.datasets.get_value()
|
|
95
104
|
self._datasets = [
|
|
96
|
-
|
|
105
|
+
HDFDataset(dataset_name, "/" + dataset_name, [1], multiplier=1)
|
|
97
106
|
for dataset_name in capture_table["name"]
|
|
98
107
|
]
|
|
99
108
|
|
|
@@ -107,18 +116,18 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
107
116
|
|
|
108
117
|
matcher.__name__ = f"index_at_least_{index}"
|
|
109
118
|
await wait_for_value(
|
|
110
|
-
self.
|
|
119
|
+
self.panda_data_block.num_captured, matcher, timeout=timeout
|
|
111
120
|
)
|
|
112
121
|
|
|
113
122
|
async def get_indices_written(self) -> int:
|
|
114
|
-
return await self.
|
|
123
|
+
return await self.panda_data_block.num_captured.get_value()
|
|
115
124
|
|
|
116
125
|
async def observe_indices_written(
|
|
117
126
|
self, timeout=DEFAULT_TIMEOUT
|
|
118
127
|
) -> AsyncGenerator[int, None]:
|
|
119
128
|
"""Wait until a specific index is ready to be collected"""
|
|
120
129
|
async for num_captured in observe_value(
|
|
121
|
-
self.
|
|
130
|
+
self.panda_data_block.num_captured, timeout
|
|
122
131
|
):
|
|
123
132
|
yield num_captured // self._multiplier
|
|
124
133
|
|
|
@@ -128,10 +137,9 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
128
137
|
# TODO: fail if we get dropped frames
|
|
129
138
|
if indices_written:
|
|
130
139
|
if not self._file:
|
|
131
|
-
self._file =
|
|
132
|
-
self.
|
|
133
|
-
Path(await self.
|
|
134
|
-
/ Path(await self.panda_device.data.hdf_file_name.get_value()),
|
|
140
|
+
self._file = HDFFile(
|
|
141
|
+
Path(await self.panda_data_block.hdf_directory.get_value())
|
|
142
|
+
/ Path(await self.panda_data_block.hdf_file_name.get_value()),
|
|
135
143
|
self._datasets,
|
|
136
144
|
)
|
|
137
145
|
for doc in self._file.stream_resources():
|
|
@@ -141,6 +149,6 @@ class PandaHDFWriter(DetectorWriter):
|
|
|
141
149
|
|
|
142
150
|
# Could put this function as default for StandardDetector
|
|
143
151
|
async def close(self):
|
|
144
|
-
await self.
|
|
152
|
+
await self.panda_data_block.capture.set(
|
|
145
153
|
False, wait=True, timeout=DEFAULT_TIMEOUT
|
|
146
154
|
)
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from .
|
|
1
|
+
from ._ensure_connected import ensure_connected
|
|
2
|
+
from ._fly import (
|
|
3
3
|
fly_and_collect,
|
|
4
4
|
prepare_static_seq_table_flyer_and_detectors_with_same_trigger,
|
|
5
5
|
time_resolved_fly_and_collect_with_static_seq_table,
|
|
6
6
|
)
|
|
7
|
+
from ._nd_attributes import setup_ndattributes, setup_ndstats_sum
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
"fly_and_collect",
|
|
10
11
|
"prepare_static_seq_table_flyer_and_detectors_with_same_trigger",
|
|
11
12
|
"time_resolved_fly_and_collect_with_static_seq_table",
|
|
12
13
|
"ensure_connected",
|
|
14
|
+
"setup_ndattributes",
|
|
15
|
+
"setup_ndstats_sum",
|
|
13
16
|
]
|
|
@@ -3,10 +3,14 @@ from typing import List, Optional
|
|
|
3
3
|
import bluesky.plan_stubs as bps
|
|
4
4
|
from bluesky.utils import short_uid
|
|
5
5
|
|
|
6
|
-
from ophyd_async.core
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
from ophyd_async.core import (
|
|
7
|
+
DetectorTrigger,
|
|
8
|
+
StandardDetector,
|
|
9
|
+
StandardFlyer,
|
|
10
|
+
TriggerInfo,
|
|
11
|
+
in_micros,
|
|
12
|
+
)
|
|
13
|
+
from ophyd_async.fastcs.panda import (
|
|
10
14
|
PcompDirectionOptions,
|
|
11
15
|
PcompInfo,
|
|
12
16
|
SeqTable,
|
|
@@ -17,7 +21,7 @@ from ophyd_async.panda import (
|
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
def prepare_static_pcomp_flyer_and_detectors(
|
|
20
|
-
flyer:
|
|
24
|
+
flyer: StandardFlyer[PcompInfo],
|
|
21
25
|
detectors: List[StandardDetector],
|
|
22
26
|
pcomp_info: PcompInfo,
|
|
23
27
|
trigger_info: TriggerInfo,
|
|
@@ -36,7 +40,7 @@ def prepare_static_pcomp_flyer_and_detectors(
|
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
|
|
39
|
-
flyer:
|
|
43
|
+
flyer: StandardFlyer[SeqTableInfo],
|
|
40
44
|
detectors: List[StandardDetector],
|
|
41
45
|
number_of_frames: int,
|
|
42
46
|
exposure: float,
|
|
@@ -100,7 +104,7 @@ def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
|
|
|
100
104
|
|
|
101
105
|
def fly_and_collect(
|
|
102
106
|
stream_name: str,
|
|
103
|
-
flyer:
|
|
107
|
+
flyer: StandardFlyer[SeqTableInfo] | StandardFlyer[PcompInfo],
|
|
104
108
|
detectors: List[StandardDetector],
|
|
105
109
|
):
|
|
106
110
|
"""Kickoff, complete and collect with a flyer and multiple detectors.
|
|
@@ -140,7 +144,7 @@ def fly_and_collect(
|
|
|
140
144
|
|
|
141
145
|
def fly_and_collect_with_static_pcomp(
|
|
142
146
|
stream_name: str,
|
|
143
|
-
flyer:
|
|
147
|
+
flyer: StandardFlyer[PcompInfo],
|
|
144
148
|
detectors: List[StandardDetector],
|
|
145
149
|
number_of_pulses: int,
|
|
146
150
|
pulse_width: int,
|
|
@@ -166,7 +170,7 @@ def fly_and_collect_with_static_pcomp(
|
|
|
166
170
|
|
|
167
171
|
def time_resolved_fly_and_collect_with_static_seq_table(
|
|
168
172
|
stream_name: str,
|
|
169
|
-
flyer:
|
|
173
|
+
flyer: StandardFlyer[SeqTableInfo],
|
|
170
174
|
detectors: List[StandardDetector],
|
|
171
175
|
number_of_frames: int,
|
|
172
176
|
exposure: float,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from typing import Sequence
|
|
2
|
+
from xml.etree import cElementTree as ET
|
|
3
|
+
|
|
4
|
+
import bluesky.plan_stubs as bps
|
|
5
|
+
|
|
6
|
+
from ophyd_async.core._device import Device
|
|
7
|
+
from ophyd_async.epics.adcore._core_io import NDArrayBaseIO
|
|
8
|
+
from ophyd_async.epics.adcore._utils import (
|
|
9
|
+
NDAttributeDataType,
|
|
10
|
+
NDAttributeParam,
|
|
11
|
+
NDAttributePv,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def setup_ndattributes(
|
|
16
|
+
device: NDArrayBaseIO, ndattributes: Sequence[NDAttributePv | NDAttributeParam]
|
|
17
|
+
):
|
|
18
|
+
xml_text = ET.Element("Attributes")
|
|
19
|
+
|
|
20
|
+
for ndattribute in ndattributes:
|
|
21
|
+
if isinstance(ndattribute, NDAttributeParam):
|
|
22
|
+
ET.SubElement(
|
|
23
|
+
xml_text,
|
|
24
|
+
"Attribute",
|
|
25
|
+
name=ndattribute.name,
|
|
26
|
+
type="PARAM",
|
|
27
|
+
source=ndattribute.param,
|
|
28
|
+
addr=str(ndattribute.addr),
|
|
29
|
+
datatype=ndattribute.datatype.value,
|
|
30
|
+
description=ndattribute.description,
|
|
31
|
+
)
|
|
32
|
+
elif isinstance(ndattribute, NDAttributePv):
|
|
33
|
+
ET.SubElement(
|
|
34
|
+
xml_text,
|
|
35
|
+
"Attribute",
|
|
36
|
+
name=ndattribute.name,
|
|
37
|
+
type="EPICS_PV",
|
|
38
|
+
source=ndattribute.signal.source.split("ca://")[-1],
|
|
39
|
+
dbrtype=ndattribute.dbrtype.value,
|
|
40
|
+
description=ndattribute.description,
|
|
41
|
+
)
|
|
42
|
+
else:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"Invalid type for ndattributes: {type(ndattribute)}. "
|
|
45
|
+
"Expected NDAttributePv or NDAttributeParam."
|
|
46
|
+
)
|
|
47
|
+
yield from bps.mv(device.nd_attributes_file, xml_text)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def setup_ndstats_sum(detector: Device):
|
|
51
|
+
yield from (
|
|
52
|
+
setup_ndattributes(
|
|
53
|
+
detector.hdf,
|
|
54
|
+
[
|
|
55
|
+
NDAttributeParam(
|
|
56
|
+
name=f"{detector.name}-sum",
|
|
57
|
+
param="NDPluginStatsTotal",
|
|
58
|
+
datatype=NDAttributeDataType.DOUBLE,
|
|
59
|
+
description="Sum of the array",
|
|
60
|
+
)
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
)
|
ophyd_async/sim/__init__.py
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from .pattern_generator import PatternGenerator
|
|
2
|
-
from .sim_pattern_detector_control import SimPatternDetectorControl
|
|
3
|
-
from .sim_pattern_detector_writer import SimPatternDetectorWriter
|
|
4
|
-
from .sim_pattern_generator import SimPatternDetector
|
|
5
|
-
|
|
6
|
-
__all__ = [
|
|
7
|
-
"PatternGenerator",
|
|
8
|
-
"SimPatternDetectorControl",
|
|
9
|
-
"SimPatternDetectorWriter",
|
|
10
|
-
"SimPatternDetector",
|
|
11
|
-
]
|
ophyd_async/sim/demo/__init__.py
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from ._pattern_detector import (
|
|
2
|
+
DATA_PATH,
|
|
3
|
+
SUM_PATH,
|
|
4
|
+
PatternDetector,
|
|
5
|
+
PatternDetectorController,
|
|
6
|
+
PatternDetectorWriter,
|
|
7
|
+
PatternGenerator,
|
|
8
|
+
)
|
|
9
|
+
from ._sim_motor import SimMotor
|
|
2
10
|
|
|
3
|
-
__all__ = [
|
|
11
|
+
__all__ = [
|
|
12
|
+
"DATA_PATH",
|
|
13
|
+
"SUM_PATH",
|
|
14
|
+
"PatternGenerator",
|
|
15
|
+
"PatternDetector",
|
|
16
|
+
"PatternDetectorController",
|
|
17
|
+
"PatternDetectorWriter",
|
|
18
|
+
"SimMotor",
|
|
19
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from ._pattern_detector import PatternDetector
|
|
2
|
+
from ._pattern_detector_controller import PatternDetectorController
|
|
3
|
+
from ._pattern_detector_writer import PatternDetectorWriter
|
|
4
|
+
from ._pattern_generator import DATA_PATH, SUM_PATH, PatternGenerator
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"PatternDetector",
|
|
8
|
+
"PatternDetectorController",
|
|
9
|
+
"PatternDetectorWriter",
|
|
10
|
+
"DATA_PATH",
|
|
11
|
+
"SUM_PATH",
|
|
12
|
+
"PatternGenerator",
|
|
13
|
+
]
|
|
@@ -2,20 +2,20 @@ from pathlib import Path
|
|
|
2
2
|
from typing import Sequence
|
|
3
3
|
|
|
4
4
|
from ophyd_async.core import (
|
|
5
|
+
AsyncReadable,
|
|
5
6
|
FilenameProvider,
|
|
6
7
|
PathProvider,
|
|
8
|
+
StandardDetector,
|
|
7
9
|
StaticFilenameProvider,
|
|
8
10
|
StaticPathProvider,
|
|
9
11
|
)
|
|
10
|
-
from ophyd_async.core.detector import StandardDetector
|
|
11
|
-
from ophyd_async.protocols import AsyncReadable
|
|
12
|
-
from ophyd_async.sim.pattern_generator import PatternGenerator
|
|
13
12
|
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
13
|
+
from ._pattern_detector_controller import PatternDetectorController
|
|
14
|
+
from ._pattern_detector_writer import PatternDetectorWriter
|
|
15
|
+
from ._pattern_generator import PatternGenerator
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class PatternDetector(StandardDetector):
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
21
21
|
path: Path,
|
|
@@ -25,12 +25,12 @@ class SimPatternDetector(StandardDetector):
|
|
|
25
25
|
fp: FilenameProvider = StaticFilenameProvider(name)
|
|
26
26
|
self.path_provider: PathProvider = StaticPathProvider(fp, path)
|
|
27
27
|
self.pattern_generator = PatternGenerator()
|
|
28
|
-
writer =
|
|
28
|
+
writer = PatternDetectorWriter(
|
|
29
29
|
pattern_generator=self.pattern_generator,
|
|
30
30
|
path_provider=self.path_provider,
|
|
31
31
|
name_provider=lambda: self.name,
|
|
32
32
|
)
|
|
33
|
-
controller =
|
|
33
|
+
controller = PatternDetectorController(
|
|
34
34
|
pattern_generator=self.pattern_generator,
|
|
35
35
|
path_provider=self.path_provider,
|
|
36
36
|
)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from ophyd_async.core import PathProvider
|
|
5
|
-
from ophyd_async.core.async_status import AsyncStatus
|
|
6
|
-
from ophyd_async.core.detector import DetectorControl, DetectorTrigger
|
|
7
|
-
from ophyd_async.sim.pattern_generator import PatternGenerator
|
|
4
|
+
from ophyd_async.core import AsyncStatus, DetectorControl, DetectorTrigger, PathProvider
|
|
8
5
|
|
|
6
|
+
from ._pattern_generator import PatternGenerator
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
class PatternDetectorController(DetectorControl):
|
|
11
10
|
def __init__(
|
|
12
11
|
self,
|
|
13
12
|
pattern_generator: PatternGenerator,
|
|
@@ -15,6 +14,8 @@ class SimPatternDetectorControl(DetectorControl):
|
|
|
15
14
|
exposure: float = 0.1,
|
|
16
15
|
) -> None:
|
|
17
16
|
self.pattern_generator: PatternGenerator = pattern_generator
|
|
17
|
+
if exposure is None:
|
|
18
|
+
exposure = 0.1
|
|
18
19
|
self.pattern_generator.set_exposure(exposure)
|
|
19
20
|
self.path_provider: PathProvider = path_provider
|
|
20
21
|
self.task: Optional[asyncio.Task] = None
|
|
@@ -26,7 +27,8 @@ class SimPatternDetectorControl(DetectorControl):
|
|
|
26
27
|
trigger: DetectorTrigger = DetectorTrigger.internal,
|
|
27
28
|
exposure: Optional[float] = 0.01,
|
|
28
29
|
) -> AsyncStatus:
|
|
29
|
-
|
|
30
|
+
if exposure is None:
|
|
31
|
+
exposure = 0.1
|
|
30
32
|
period: float = exposure + self.get_deadtime(exposure)
|
|
31
33
|
task = asyncio.create_task(
|
|
32
34
|
self._coroutine_for_image_writing(exposure, period, num)
|
|
@@ -43,7 +45,7 @@ class SimPatternDetectorControl(DetectorControl):
|
|
|
43
45
|
pass
|
|
44
46
|
self.task = None
|
|
45
47
|
|
|
46
|
-
def get_deadtime(self, exposure: float) -> float:
|
|
48
|
+
def get_deadtime(self, exposure: float | None) -> float:
|
|
47
49
|
return 0.001
|
|
48
50
|
|
|
49
51
|
async def _coroutine_for_image_writing(
|
|
@@ -2,12 +2,12 @@ from typing import AsyncGenerator, AsyncIterator, Dict
|
|
|
2
2
|
|
|
3
3
|
from bluesky.protocols import DataKey
|
|
4
4
|
|
|
5
|
-
from ophyd_async.core import NameProvider, PathProvider
|
|
6
|
-
from ophyd_async.core.detector import DetectorWriter
|
|
7
|
-
from ophyd_async.sim.pattern_generator import PatternGenerator
|
|
5
|
+
from ophyd_async.core import DetectorWriter, NameProvider, PathProvider
|
|
8
6
|
|
|
7
|
+
from ._pattern_generator import PatternGenerator
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
class PatternDetectorWriter(DetectorWriter):
|
|
11
11
|
pattern_generator: PatternGenerator
|
|
12
12
|
|
|
13
13
|
def __init__(
|
|
@@ -5,10 +5,14 @@ import h5py
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from bluesky.protocols import DataKey, StreamAsset
|
|
7
7
|
|
|
8
|
-
from ophyd_async.core import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
from ophyd_async.core import (
|
|
9
|
+
DEFAULT_TIMEOUT,
|
|
10
|
+
HDFDataset,
|
|
11
|
+
HDFFile,
|
|
12
|
+
PathProvider,
|
|
13
|
+
observe_value,
|
|
14
|
+
soft_signal_r_and_setter,
|
|
15
|
+
)
|
|
12
16
|
|
|
13
17
|
# raw data path
|
|
14
18
|
DATA_PATH = "/entry/data/data"
|
|
@@ -56,7 +60,7 @@ class PatternGenerator:
|
|
|
56
60
|
generate_gaussian_blob(width=detector_width, height=detector_height)
|
|
57
61
|
* MAX_UINT8_VALUE
|
|
58
62
|
)
|
|
59
|
-
self._hdf_stream_provider: Optional[
|
|
63
|
+
self._hdf_stream_provider: Optional[HDFFile] = None
|
|
60
64
|
self._handle_for_h5_file: Optional[h5py.File] = None
|
|
61
65
|
self.target_path: Optional[Path] = None
|
|
62
66
|
|
|
@@ -135,13 +139,13 @@ class PatternGenerator:
|
|
|
135
139
|
# cache state to self
|
|
136
140
|
# Add the main data
|
|
137
141
|
self._datasets = [
|
|
138
|
-
|
|
142
|
+
HDFDataset(
|
|
139
143
|
data_key=name,
|
|
140
144
|
dataset=DATA_PATH,
|
|
141
145
|
shape=(self.height, self.width),
|
|
142
146
|
multiplier=multiplier,
|
|
143
147
|
),
|
|
144
|
-
|
|
148
|
+
HDFDataset(
|
|
145
149
|
f"{name}-sum",
|
|
146
150
|
dataset=SUM_PATH,
|
|
147
151
|
shape=(),
|
|
@@ -162,8 +166,7 @@ class PatternGenerator:
|
|
|
162
166
|
|
|
163
167
|
def _get_new_path(self, path_provider: PathProvider) -> Path:
|
|
164
168
|
info = path_provider(device_name="pattern")
|
|
165
|
-
|
|
166
|
-
new_path: Path = info.root / info.resource_dir / filename
|
|
169
|
+
new_path: Path = info.directory_path / info.filename
|
|
167
170
|
return new_path
|
|
168
171
|
|
|
169
172
|
async def collect_stream_docs(
|
|
@@ -183,8 +186,7 @@ class PatternGenerator:
|
|
|
183
186
|
# until the first frame comes in
|
|
184
187
|
if not self._hdf_stream_provider:
|
|
185
188
|
assert self.target_path, "open file has not been called"
|
|
186
|
-
self._hdf_stream_provider =
|
|
187
|
-
self._path_provider(),
|
|
189
|
+
self._hdf_stream_provider = HDFFile(
|
|
188
190
|
self.target_path,
|
|
189
191
|
self._datasets,
|
|
190
192
|
)
|
|
@@ -4,15 +4,17 @@ import time
|
|
|
4
4
|
|
|
5
5
|
from bluesky.protocols import Movable, Stoppable
|
|
6
6
|
|
|
7
|
-
from ophyd_async.core import
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
from ophyd_async.core import (
|
|
8
|
+
AsyncStatus,
|
|
9
|
+
ConfigSignal,
|
|
10
|
+
HintedSignal,
|
|
11
|
+
StandardReadable,
|
|
12
|
+
WatchableAsyncStatus,
|
|
13
|
+
WatcherUpdate,
|
|
10
14
|
observe_value,
|
|
11
15
|
soft_signal_r_and_setter,
|
|
12
16
|
soft_signal_rw,
|
|
13
17
|
)
|
|
14
|
-
from ophyd_async.core.standard_readable import ConfigSignal, HintedSignal
|
|
15
|
-
from ophyd_async.core.utils import WatcherUpdate
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class SimMotor(StandardReadable, Movable, Stoppable):
|
|
File without changes
|
|
File without changes
|