ophyd-async 0.2.0__py3-none-any.whl → 0.3a2__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/__init__.py +1 -4
- ophyd_async/_version.py +2 -2
- ophyd_async/core/__init__.py +16 -10
- ophyd_async/core/_providers.py +38 -5
- ophyd_async/core/async_status.py +3 -3
- ophyd_async/core/detector.py +211 -62
- ophyd_async/core/device.py +45 -38
- ophyd_async/core/device_save_loader.py +96 -23
- ophyd_async/core/flyer.py +30 -244
- ophyd_async/core/signal.py +47 -21
- ophyd_async/core/signal_backend.py +7 -4
- ophyd_async/core/sim_signal_backend.py +30 -18
- ophyd_async/core/standard_readable.py +4 -2
- ophyd_async/core/utils.py +93 -30
- ophyd_async/epics/_backend/_aioca.py +30 -36
- ophyd_async/epics/_backend/_p4p.py +75 -41
- ophyd_async/epics/_backend/common.py +25 -0
- ophyd_async/epics/areadetector/__init__.py +4 -0
- ophyd_async/epics/areadetector/aravis.py +69 -0
- ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +1 -1
- ophyd_async/epics/areadetector/controllers/aravis_controller.py +73 -0
- ophyd_async/epics/areadetector/controllers/pilatus_controller.py +37 -25
- ophyd_async/epics/areadetector/drivers/aravis_driver.py +154 -0
- ophyd_async/epics/areadetector/drivers/pilatus_driver.py +4 -4
- ophyd_async/epics/areadetector/pilatus.py +50 -0
- ophyd_async/epics/areadetector/writers/_hdffile.py +21 -7
- ophyd_async/epics/areadetector/writers/hdf_writer.py +26 -15
- ophyd_async/epics/demo/__init__.py +33 -3
- ophyd_async/epics/motion/motor.py +20 -14
- ophyd_async/epics/pvi/__init__.py +3 -0
- ophyd_async/epics/pvi/pvi.py +318 -0
- ophyd_async/epics/signal/__init__.py +0 -2
- ophyd_async/epics/signal/signal.py +26 -9
- ophyd_async/panda/__init__.py +19 -5
- ophyd_async/panda/_common_blocks.py +49 -0
- ophyd_async/panda/_hdf_panda.py +48 -0
- ophyd_async/panda/_panda_controller.py +37 -0
- ophyd_async/panda/_trigger.py +39 -0
- ophyd_async/panda/_utils.py +15 -0
- ophyd_async/panda/writers/__init__.py +3 -0
- ophyd_async/panda/writers/_hdf_writer.py +220 -0
- ophyd_async/panda/writers/_panda_hdf_file.py +58 -0
- ophyd_async/planstubs/__init__.py +5 -0
- ophyd_async/planstubs/prepare_trigger_and_dets.py +57 -0
- ophyd_async/protocols.py +73 -0
- ophyd_async/sim/__init__.py +11 -0
- ophyd_async/sim/demo/__init__.py +3 -0
- ophyd_async/sim/demo/sim_motor.py +116 -0
- ophyd_async/sim/pattern_generator.py +318 -0
- ophyd_async/sim/sim_pattern_detector_control.py +55 -0
- ophyd_async/sim/sim_pattern_detector_writer.py +34 -0
- ophyd_async/sim/sim_pattern_generator.py +37 -0
- {ophyd_async-0.2.0.dist-info → ophyd_async-0.3a2.dist-info}/METADATA +20 -76
- ophyd_async-0.3a2.dist-info/RECORD +76 -0
- {ophyd_async-0.2.0.dist-info → ophyd_async-0.3a2.dist-info}/WHEEL +1 -1
- ophyd_async/epics/signal/pvi_get.py +0 -22
- ophyd_async/panda/panda.py +0 -294
- ophyd_async-0.2.0.dist-info/RECORD +0 -53
- /ophyd_async/panda/{table.py → _table.py} +0 -0
- {ophyd_async-0.2.0.dist-info → ophyd_async-0.3a2.dist-info}/LICENSE +0 -0
- {ophyd_async-0.2.0.dist-info → ophyd_async-0.3a2.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.2.0.dist-info → ophyd_async-0.3a2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import (
|
|
4
|
+
Any,
|
|
5
|
+
AsyncGenerator,
|
|
6
|
+
AsyncIterator,
|
|
7
|
+
Dict,
|
|
8
|
+
Iterator,
|
|
9
|
+
List,
|
|
10
|
+
Optional,
|
|
11
|
+
Sequence,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
import h5py
|
|
15
|
+
import numpy as np
|
|
16
|
+
from bluesky.protocols import Descriptor, StreamAsset
|
|
17
|
+
from event_model import (
|
|
18
|
+
ComposeStreamResource,
|
|
19
|
+
ComposeStreamResourceBundle,
|
|
20
|
+
StreamDatum,
|
|
21
|
+
StreamRange,
|
|
22
|
+
StreamResource,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from ophyd_async.core import DirectoryInfo, DirectoryProvider
|
|
26
|
+
from ophyd_async.core.signal import SignalR, observe_value
|
|
27
|
+
from ophyd_async.core.sim_signal_backend import SimSignalBackend
|
|
28
|
+
from ophyd_async.core.utils import DEFAULT_TIMEOUT
|
|
29
|
+
|
|
30
|
+
# raw data path
|
|
31
|
+
DATA_PATH = "/entry/data/data"
|
|
32
|
+
|
|
33
|
+
# pixel sum path
|
|
34
|
+
SUM_PATH = "/entry/sum"
|
|
35
|
+
|
|
36
|
+
MAX_UINT8_VALUE = np.iinfo(np.uint8).max
|
|
37
|
+
|
|
38
|
+
SLICE_NAME = "AD_HDF5_SWMR_SLICE"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class DatasetConfig:
|
|
43
|
+
name: str
|
|
44
|
+
shape: Sequence[int]
|
|
45
|
+
maxshape: tuple[Any, ...] = (None,)
|
|
46
|
+
path: Optional[str] = None
|
|
47
|
+
multiplier: Optional[int] = 1
|
|
48
|
+
dtype: Optional[Any] = None
|
|
49
|
+
fillvalue: Optional[int] = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_full_file_description(
|
|
53
|
+
datasets: List[DatasetConfig], outer_shape: tuple[int, ...]
|
|
54
|
+
):
|
|
55
|
+
full_file_description: Dict[str, Descriptor] = {}
|
|
56
|
+
for d in datasets:
|
|
57
|
+
source = f"soft://{d.name}"
|
|
58
|
+
shape = outer_shape + tuple(d.shape)
|
|
59
|
+
dtype = "number" if d.shape == [1] else "array"
|
|
60
|
+
descriptor = Descriptor(
|
|
61
|
+
source=source, shape=shape, dtype=dtype, external="STREAM:"
|
|
62
|
+
)
|
|
63
|
+
key = d.name.replace("/", "_")
|
|
64
|
+
full_file_description[key] = descriptor
|
|
65
|
+
return full_file_description
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def generate_gaussian_blob(height: int, width: int) -> np.ndarray:
|
|
69
|
+
"""Make a Gaussian Blob with float values in range 0..1"""
|
|
70
|
+
x, y = np.meshgrid(np.linspace(-1, 1, width), np.linspace(-1, 1, height))
|
|
71
|
+
d = np.sqrt(x * x + y * y)
|
|
72
|
+
blob = np.exp(-(d**2))
|
|
73
|
+
return blob
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def generate_interesting_pattern(x: float, y: float) -> float:
|
|
77
|
+
"""This function is interesting in x and y in range -10..10, returning
|
|
78
|
+
a float value in range 0..1
|
|
79
|
+
"""
|
|
80
|
+
z = 0.5 + (np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)) / 2
|
|
81
|
+
return z
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class HdfStreamProvider:
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
directory_info: DirectoryInfo,
|
|
88
|
+
full_file_name: Path,
|
|
89
|
+
datasets: List[DatasetConfig],
|
|
90
|
+
) -> None:
|
|
91
|
+
self._last_emitted = 0
|
|
92
|
+
self._bundles: List[ComposeStreamResourceBundle] = self._compose_bundles(
|
|
93
|
+
directory_info, full_file_name, datasets
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def _compose_bundles(
|
|
97
|
+
self,
|
|
98
|
+
directory_info: DirectoryInfo,
|
|
99
|
+
full_file_name: Path,
|
|
100
|
+
datasets: List[DatasetConfig],
|
|
101
|
+
) -> List[StreamAsset]:
|
|
102
|
+
path = str(full_file_name.relative_to(directory_info.root))
|
|
103
|
+
root = str(directory_info.root)
|
|
104
|
+
bundler_composer = ComposeStreamResource()
|
|
105
|
+
|
|
106
|
+
bundles: List[ComposeStreamResourceBundle] = []
|
|
107
|
+
|
|
108
|
+
bundles = [
|
|
109
|
+
bundler_composer(
|
|
110
|
+
spec=SLICE_NAME,
|
|
111
|
+
root=root,
|
|
112
|
+
resource_path=path,
|
|
113
|
+
data_key=d.name.replace("/", "_"),
|
|
114
|
+
resource_kwargs={
|
|
115
|
+
"path": d.path,
|
|
116
|
+
"multiplier": d.multiplier,
|
|
117
|
+
"timestamps": "/entry/instrument/NDAttributes/NDArrayTimeStamp",
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
for d in datasets
|
|
121
|
+
]
|
|
122
|
+
return bundles
|
|
123
|
+
|
|
124
|
+
def stream_resources(self) -> Iterator[StreamResource]:
|
|
125
|
+
for bundle in self._bundles:
|
|
126
|
+
yield bundle.stream_resource_doc
|
|
127
|
+
|
|
128
|
+
def stream_data(self, indices_written: int) -> Iterator[StreamDatum]:
|
|
129
|
+
# Indices are relative to resource
|
|
130
|
+
if indices_written > self._last_emitted:
|
|
131
|
+
updated_stream_range = StreamRange(
|
|
132
|
+
start=self._last_emitted,
|
|
133
|
+
stop=indices_written,
|
|
134
|
+
)
|
|
135
|
+
self._last_emitted = indices_written
|
|
136
|
+
for bundle in self._bundles:
|
|
137
|
+
yield bundle.compose_stream_datum(indices=updated_stream_range)
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
def close(self) -> None:
|
|
141
|
+
for bundle in self._bundles:
|
|
142
|
+
bundle.close()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class PatternGenerator:
|
|
146
|
+
def __init__(
|
|
147
|
+
self,
|
|
148
|
+
saturation_exposure_time: float = 1,
|
|
149
|
+
detector_width: int = 320,
|
|
150
|
+
detector_height: int = 240,
|
|
151
|
+
) -> None:
|
|
152
|
+
self.saturation_exposure_time = saturation_exposure_time
|
|
153
|
+
self.exposure = saturation_exposure_time
|
|
154
|
+
self.x = 0.0
|
|
155
|
+
self.y = 0.0
|
|
156
|
+
self.height = detector_height
|
|
157
|
+
self.width = detector_width
|
|
158
|
+
self.written_images_counter: int = 0
|
|
159
|
+
|
|
160
|
+
# it automatically initializes to 0
|
|
161
|
+
self.signal_backend = SimSignalBackend(int)
|
|
162
|
+
self.sim_signal = SignalR(self.signal_backend)
|
|
163
|
+
blob = np.array(
|
|
164
|
+
generate_gaussian_blob(width=detector_width, height=detector_height)
|
|
165
|
+
* MAX_UINT8_VALUE
|
|
166
|
+
)
|
|
167
|
+
self.STARTING_BLOB = blob
|
|
168
|
+
self._hdf_stream_provider: Optional[HdfStreamProvider] = None
|
|
169
|
+
self._handle_for_h5_file: Optional[h5py.File] = None
|
|
170
|
+
self.target_path: Optional[Path] = None
|
|
171
|
+
|
|
172
|
+
async def write_image_to_file(self) -> None:
|
|
173
|
+
assert self._handle_for_h5_file, "no file has been opened!"
|
|
174
|
+
# prepare - resize the fixed hdf5 data structure
|
|
175
|
+
# so that the new image can be written
|
|
176
|
+
new_layer = self.written_images_counter + 1
|
|
177
|
+
target_dimensions = (new_layer, self.height, self.width)
|
|
178
|
+
|
|
179
|
+
# generate the simulated data
|
|
180
|
+
intensity: float = generate_interesting_pattern(self.x, self.y)
|
|
181
|
+
detector_data: np.uint8 = np.uint8(
|
|
182
|
+
self.STARTING_BLOB
|
|
183
|
+
* intensity
|
|
184
|
+
* self.exposure
|
|
185
|
+
/ self.saturation_exposure_time
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
self._handle_for_h5_file[DATA_PATH].resize(target_dimensions)
|
|
189
|
+
|
|
190
|
+
print(f"writing image {new_layer}")
|
|
191
|
+
assert self._handle_for_h5_file, "no file has been opened!"
|
|
192
|
+
self._handle_for_h5_file[DATA_PATH].resize(target_dimensions)
|
|
193
|
+
|
|
194
|
+
self._handle_for_h5_file[SUM_PATH].resize((new_layer,))
|
|
195
|
+
|
|
196
|
+
# write data to disc (intermediate step)
|
|
197
|
+
self._handle_for_h5_file[DATA_PATH][self.written_images_counter] = detector_data
|
|
198
|
+
self._handle_for_h5_file[SUM_PATH][self.written_images_counter] = np.sum(
|
|
199
|
+
detector_data
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# save metadata - so that it's discoverable
|
|
203
|
+
self._handle_for_h5_file[DATA_PATH].flush()
|
|
204
|
+
self._handle_for_h5_file[SUM_PATH].flush()
|
|
205
|
+
|
|
206
|
+
# counter increment is last
|
|
207
|
+
# as only at this point the new data is visible from the outside
|
|
208
|
+
self.written_images_counter += 1
|
|
209
|
+
await self.signal_backend.put(self.written_images_counter)
|
|
210
|
+
|
|
211
|
+
def set_exposure(self, value: float) -> None:
|
|
212
|
+
self.exposure = value
|
|
213
|
+
|
|
214
|
+
def set_x(self, value: float) -> None:
|
|
215
|
+
self.x = value
|
|
216
|
+
|
|
217
|
+
def set_y(self, value: float) -> None:
|
|
218
|
+
self.y = value
|
|
219
|
+
|
|
220
|
+
async def open_file(
|
|
221
|
+
self, directory: DirectoryProvider, multiplier: int = 1
|
|
222
|
+
) -> Dict[str, Descriptor]:
|
|
223
|
+
await self.sim_signal.connect()
|
|
224
|
+
|
|
225
|
+
self.target_path = self._get_new_path(directory)
|
|
226
|
+
|
|
227
|
+
self._handle_for_h5_file = h5py.File(self.target_path, "w", libver="latest")
|
|
228
|
+
|
|
229
|
+
assert self._handle_for_h5_file, "not loaded the file right"
|
|
230
|
+
|
|
231
|
+
datasets = self._get_datasets()
|
|
232
|
+
for d in datasets:
|
|
233
|
+
self._handle_for_h5_file.create_dataset(
|
|
234
|
+
name=d.name,
|
|
235
|
+
shape=d.shape,
|
|
236
|
+
dtype=d.dtype,
|
|
237
|
+
maxshape=d.maxshape,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# once datasets written, can switch the model to single writer multiple reader
|
|
241
|
+
self._handle_for_h5_file.swmr_mode = True
|
|
242
|
+
|
|
243
|
+
outer_shape = (multiplier,) if multiplier > 1 else ()
|
|
244
|
+
full_file_description = get_full_file_description(datasets, outer_shape)
|
|
245
|
+
|
|
246
|
+
# cache state to self
|
|
247
|
+
self._datasets = datasets
|
|
248
|
+
self.multiplier = multiplier
|
|
249
|
+
self._directory_provider = directory
|
|
250
|
+
return full_file_description
|
|
251
|
+
|
|
252
|
+
def _get_new_path(self, directory: DirectoryProvider) -> Path:
|
|
253
|
+
info = directory()
|
|
254
|
+
filename = f"{info.prefix}pattern{info.suffix}.h5"
|
|
255
|
+
new_path: Path = info.root / info.resource_dir / filename
|
|
256
|
+
return new_path
|
|
257
|
+
|
|
258
|
+
def _get_datasets(self) -> List[DatasetConfig]:
|
|
259
|
+
raw_dataset = DatasetConfig(
|
|
260
|
+
# name=data_name,
|
|
261
|
+
name=DATA_PATH,
|
|
262
|
+
dtype=np.uint8,
|
|
263
|
+
shape=(1, self.height, self.width),
|
|
264
|
+
maxshape=(None, self.height, self.width),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
sum_dataset = DatasetConfig(
|
|
268
|
+
name=SUM_PATH,
|
|
269
|
+
dtype=np.float64,
|
|
270
|
+
shape=(1,),
|
|
271
|
+
maxshape=(None,),
|
|
272
|
+
fillvalue=-1,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
datasets: List[DatasetConfig] = [raw_dataset, sum_dataset]
|
|
276
|
+
return datasets
|
|
277
|
+
|
|
278
|
+
async def collect_stream_docs(
|
|
279
|
+
self, indices_written: int
|
|
280
|
+
) -> AsyncIterator[StreamAsset]:
|
|
281
|
+
"""
|
|
282
|
+
stream resource says "here is a dataset",
|
|
283
|
+
stream datum says "here are N frames in that stream resource",
|
|
284
|
+
you get one stream resource and many stream datums per scan
|
|
285
|
+
"""
|
|
286
|
+
if self._handle_for_h5_file:
|
|
287
|
+
self._handle_for_h5_file.flush()
|
|
288
|
+
# when already something was written to the file
|
|
289
|
+
if indices_written:
|
|
290
|
+
# if no frames arrived yet, there's no file to speak of
|
|
291
|
+
# cannot get the full filename the HDF writer will write
|
|
292
|
+
# until the first frame comes in
|
|
293
|
+
if not self._hdf_stream_provider:
|
|
294
|
+
assert self.target_path, "open file has not been called"
|
|
295
|
+
datasets = self._get_datasets()
|
|
296
|
+
self._datasets = datasets
|
|
297
|
+
self._hdf_stream_provider = HdfStreamProvider(
|
|
298
|
+
self._directory_provider(),
|
|
299
|
+
self.target_path,
|
|
300
|
+
self._datasets,
|
|
301
|
+
)
|
|
302
|
+
for doc in self._hdf_stream_provider.stream_resources():
|
|
303
|
+
yield "stream_resource", doc
|
|
304
|
+
if self._hdf_stream_provider:
|
|
305
|
+
for doc in self._hdf_stream_provider.stream_data(indices_written):
|
|
306
|
+
yield "stream_datum", doc
|
|
307
|
+
|
|
308
|
+
def close(self) -> None:
|
|
309
|
+
if self._handle_for_h5_file:
|
|
310
|
+
self._handle_for_h5_file.close()
|
|
311
|
+
print("file closed")
|
|
312
|
+
self._handle_for_h5_file = None
|
|
313
|
+
|
|
314
|
+
async def observe_indices_written(
|
|
315
|
+
self, timeout=DEFAULT_TIMEOUT
|
|
316
|
+
) -> AsyncGenerator[int, None]:
|
|
317
|
+
async for num_captured in observe_value(self.sim_signal, timeout=timeout):
|
|
318
|
+
yield num_captured // self.multiplier
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from ophyd_async.core import DirectoryProvider
|
|
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
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SimPatternDetectorControl(DetectorControl):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
pattern_generator: PatternGenerator,
|
|
14
|
+
directory_provider: DirectoryProvider,
|
|
15
|
+
exposure: float = 0.1,
|
|
16
|
+
) -> None:
|
|
17
|
+
self.pattern_generator: PatternGenerator = pattern_generator
|
|
18
|
+
self.pattern_generator.set_exposure(exposure)
|
|
19
|
+
self.directory_provider: DirectoryProvider = directory_provider
|
|
20
|
+
self.task: Optional[asyncio.Task] = None
|
|
21
|
+
super().__init__()
|
|
22
|
+
|
|
23
|
+
async def arm(
|
|
24
|
+
self,
|
|
25
|
+
num: int,
|
|
26
|
+
trigger: DetectorTrigger = DetectorTrigger.internal,
|
|
27
|
+
exposure: Optional[float] = 0.01,
|
|
28
|
+
) -> AsyncStatus:
|
|
29
|
+
assert exposure is not None
|
|
30
|
+
period: float = exposure + self.get_deadtime(exposure)
|
|
31
|
+
task = asyncio.create_task(
|
|
32
|
+
self._coroutine_for_image_writing(exposure, period, num)
|
|
33
|
+
)
|
|
34
|
+
self.task = task
|
|
35
|
+
return AsyncStatus(task)
|
|
36
|
+
|
|
37
|
+
async def disarm(self):
|
|
38
|
+
if self.task:
|
|
39
|
+
self.task.cancel()
|
|
40
|
+
try:
|
|
41
|
+
await self.task
|
|
42
|
+
except asyncio.CancelledError:
|
|
43
|
+
pass
|
|
44
|
+
self.task = None
|
|
45
|
+
|
|
46
|
+
def get_deadtime(self, exposure: float) -> float:
|
|
47
|
+
return 0.001
|
|
48
|
+
|
|
49
|
+
async def _coroutine_for_image_writing(
|
|
50
|
+
self, exposure: float, period: float, frames_number: int
|
|
51
|
+
):
|
|
52
|
+
for _ in range(frames_number):
|
|
53
|
+
self.pattern_generator.set_exposure(exposure)
|
|
54
|
+
await asyncio.sleep(period)
|
|
55
|
+
await self.pattern_generator.write_image_to_file()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import AsyncGenerator, AsyncIterator, Dict
|
|
2
|
+
|
|
3
|
+
from bluesky.protocols import Descriptor
|
|
4
|
+
|
|
5
|
+
from ophyd_async.core import DirectoryProvider
|
|
6
|
+
from ophyd_async.core.detector import DetectorWriter
|
|
7
|
+
from ophyd_async.sim.pattern_generator import PatternGenerator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SimPatternDetectorWriter(DetectorWriter):
|
|
11
|
+
pattern_generator: PatternGenerator
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self, pattern_generator: PatternGenerator, directoryProvider: DirectoryProvider
|
|
15
|
+
) -> None:
|
|
16
|
+
self.pattern_generator = pattern_generator
|
|
17
|
+
self.directory_provider = directoryProvider
|
|
18
|
+
|
|
19
|
+
async def open(self, multiplier: int = 1) -> Dict[str, Descriptor]:
|
|
20
|
+
return await self.pattern_generator.open_file(
|
|
21
|
+
self.directory_provider, multiplier
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
async def close(self) -> None:
|
|
25
|
+
self.pattern_generator.close()
|
|
26
|
+
|
|
27
|
+
def collect_stream_docs(self, indices_written: int) -> AsyncIterator:
|
|
28
|
+
return self.pattern_generator.collect_stream_docs(indices_written)
|
|
29
|
+
|
|
30
|
+
def observe_indices_written(self, timeout=...) -> AsyncGenerator[int, None]:
|
|
31
|
+
return self.pattern_generator.observe_indices_written()
|
|
32
|
+
|
|
33
|
+
async def get_indices_written(self) -> int:
|
|
34
|
+
return self.pattern_generator.written_images_counter
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Sequence
|
|
3
|
+
|
|
4
|
+
from ophyd_async.core import DirectoryProvider, StaticDirectoryProvider
|
|
5
|
+
from ophyd_async.core.detector import StandardDetector
|
|
6
|
+
from ophyd_async.core.signal import SignalR
|
|
7
|
+
from ophyd_async.sim.pattern_generator import PatternGenerator
|
|
8
|
+
|
|
9
|
+
from .sim_pattern_detector_control import SimPatternDetectorControl
|
|
10
|
+
from .sim_pattern_detector_writer import SimPatternDetectorWriter
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SimPatternDetector(StandardDetector):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
path: Path,
|
|
17
|
+
config_sigs: Sequence[SignalR] = [],
|
|
18
|
+
name: str = "sim_pattern_detector",
|
|
19
|
+
writer_timeout: float = 1,
|
|
20
|
+
) -> None:
|
|
21
|
+
self.directory_provider: DirectoryProvider = StaticDirectoryProvider(path)
|
|
22
|
+
self.pattern_generator = PatternGenerator()
|
|
23
|
+
writer = SimPatternDetectorWriter(
|
|
24
|
+
pattern_generator=self.pattern_generator,
|
|
25
|
+
directoryProvider=self.directory_provider,
|
|
26
|
+
)
|
|
27
|
+
controller = SimPatternDetectorControl(
|
|
28
|
+
pattern_generator=self.pattern_generator,
|
|
29
|
+
directory_provider=self.directory_provider,
|
|
30
|
+
)
|
|
31
|
+
super().__init__(
|
|
32
|
+
controller=controller,
|
|
33
|
+
writer=writer,
|
|
34
|
+
config_sigs=config_sigs,
|
|
35
|
+
name=name,
|
|
36
|
+
writer_timeout=writer_timeout,
|
|
37
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3a2
|
|
4
4
|
Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
|
|
5
5
|
Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -35,21 +35,19 @@ License: BSD 3-Clause License
|
|
|
35
35
|
Project-URL: GitHub, https://github.com/bluesky/ophyd-async
|
|
36
36
|
Classifier: Development Status :: 3 - Alpha
|
|
37
37
|
Classifier: License :: OSI Approved :: BSD License
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
39
38
|
Classifier: Programming Language :: Python :: 3.10
|
|
40
39
|
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
-
Requires-Python: >=3.
|
|
42
|
-
Description-Content-Type: text/
|
|
40
|
+
Requires-Python: >=3.10
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
43
42
|
License-File: LICENSE
|
|
44
43
|
Requires-Dist: networkx >=2.0
|
|
45
44
|
Requires-Dist: numpy
|
|
46
45
|
Requires-Dist: packaging
|
|
47
46
|
Requires-Dist: pint
|
|
48
|
-
Requires-Dist: bluesky
|
|
49
|
-
Requires-Dist: event-model
|
|
47
|
+
Requires-Dist: bluesky >=1.13.0a3
|
|
48
|
+
Requires-Dist: event-model <1.21.0
|
|
50
49
|
Requires-Dist: p4p
|
|
51
50
|
Requires-Dist: pyyaml
|
|
52
|
-
Requires-Dist: typing-extensions ; python_version < "3.8"
|
|
53
51
|
Provides-Extra: ca
|
|
54
52
|
Requires-Dist: aioca >=1.6 ; extra == 'ca'
|
|
55
53
|
Provides-Extra: dev
|
|
@@ -64,7 +62,6 @@ Requires-Dist: inflection ; extra == 'dev'
|
|
|
64
62
|
Requires-Dist: ipython ; extra == 'dev'
|
|
65
63
|
Requires-Dist: ipywidgets ; extra == 'dev'
|
|
66
64
|
Requires-Dist: matplotlib ; extra == 'dev'
|
|
67
|
-
Requires-Dist: mypy ; extra == 'dev'
|
|
68
65
|
Requires-Dist: myst-parser ; extra == 'dev'
|
|
69
66
|
Requires-Dist: numpydoc ; extra == 'dev'
|
|
70
67
|
Requires-Dist: ophyd ; extra == 'dev'
|
|
@@ -73,13 +70,14 @@ Requires-Dist: pipdeptree ; extra == 'dev'
|
|
|
73
70
|
Requires-Dist: pre-commit ; extra == 'dev'
|
|
74
71
|
Requires-Dist: pydata-sphinx-theme >=0.12 ; extra == 'dev'
|
|
75
72
|
Requires-Dist: pyepics >=3.4.2 ; extra == 'dev'
|
|
76
|
-
Requires-Dist: pyside6 ; extra == 'dev'
|
|
73
|
+
Requires-Dist: pyside6 ==6.6.2 ; extra == 'dev'
|
|
77
74
|
Requires-Dist: pytest ; extra == 'dev'
|
|
78
75
|
Requires-Dist: pytest-asyncio ; extra == 'dev'
|
|
79
76
|
Requires-Dist: pytest-cov ; extra == 'dev'
|
|
80
77
|
Requires-Dist: pytest-faulthandler ; extra == 'dev'
|
|
81
78
|
Requires-Dist: pytest-rerunfailures ; extra == 'dev'
|
|
82
79
|
Requires-Dist: pytest-timeout ; extra == 'dev'
|
|
80
|
+
Requires-Dist: ruff ; extra == 'dev'
|
|
83
81
|
Requires-Dist: sphinx-autobuild ; extra == 'dev'
|
|
84
82
|
Requires-Dist: sphinx-copybutton ; extra == 'dev'
|
|
85
83
|
Requires-Dist: sphinx-design ; extra == 'dev'
|
|
@@ -89,75 +87,21 @@ Requires-Dist: types-pyyaml ; extra == 'dev'
|
|
|
89
87
|
Provides-Extra: pva
|
|
90
88
|
Requires-Dist: p4p ; extra == 'pva'
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
[](https://github.com/bluesky/ophyd-async/actions/workflows/ci.yml)
|
|
91
|
+
[](https://codecov.io/gh/bluesky/ophyd-async)
|
|
92
|
+
[](https://pypi.org/project/ophyd-async)
|
|
93
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
# ophyd_async
|
|
96
96
|
|
|
97
|
-
Asynchronous
|
|
97
|
+
Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
Documentation
|
|
103
|
-
|
|
99
|
+
| Source | <https://github.com/bluesky/ophyd-async> |
|
|
100
|
+
| :-----------: | :-----------------------------------------------: |
|
|
101
|
+
| PyPI | `pip install ophyd-async` |
|
|
102
|
+
| Documentation | <https://bluesky.github.io/ophyd-async> |
|
|
103
|
+
| Releases | <https://github.com/bluesky/ophyd-async/releases> |
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
be used as an abstraction layer that enables experiment orchestration and data
|
|
107
|
-
acquisition code to operate above the specifics of particular devices and control
|
|
108
|
-
systems.
|
|
105
|
+
<!-- README only content. Anything below this line won't be included in index.md -->
|
|
109
106
|
|
|
110
|
-
|
|
111
|
-
experiment orchestration and data acquisition. However, these libraries are
|
|
112
|
-
able to be used in a stand-alone fashion. For an example of how a facility defines
|
|
113
|
-
and uses ophyd-async devices, see `dls-dodal`_, which is currently using a
|
|
114
|
-
mixture of ophyd and ophyd-async devices.
|
|
115
|
-
|
|
116
|
-
While `EPICS`_ is the most common control system layer that ophyd-async can
|
|
117
|
-
interface with, other control systems like `Tango`_ are used by some facilities
|
|
118
|
-
also. In addition to the abstractions provided by ophyd, ophyd-async allows:
|
|
119
|
-
|
|
120
|
-
* Asynchronous signal access, opening the possibility for hardware-triggered
|
|
121
|
-
scanning (also known as fly-scanning)
|
|
122
|
-
* Simpler instantiation of devices (groupings of signals) with less reliance
|
|
123
|
-
upon complex class hierarchies
|
|
124
|
-
|
|
125
|
-
NOTE: ophyd-async is included on a provisional basis until the v1.0 release.
|
|
126
|
-
|
|
127
|
-
See the tutorials for usage examples.
|
|
128
|
-
|
|
129
|
-
.. |code_ci| image:: https://github.com/bluesky/ophyd-async/actions/workflows/code.yml/badge.svg?branch=main
|
|
130
|
-
:target: https://github.com/bluesky/ophyd-async/actions/workflows/code.yml
|
|
131
|
-
:alt: Code CI
|
|
132
|
-
|
|
133
|
-
.. |docs_ci| image:: https://github.com/bluesky/ophyd-async/actions/workflows/docs.yml/badge.svg?branch=main
|
|
134
|
-
:target: https://github.com/bluesky/ophyd-async/actions/workflows/docs.yml
|
|
135
|
-
:alt: Docs CI
|
|
136
|
-
|
|
137
|
-
.. |coverage| image:: https://codecov.io/gh/bluesky/ophyd-async/branch/master/graph/badge.svg
|
|
138
|
-
:target: https://codecov.io/gh/bluesky/ophyd-async
|
|
139
|
-
:alt: Test Coverage
|
|
140
|
-
|
|
141
|
-
.. |pypi_version| image:: https://img.shields.io/pypi/v/ophyd-async.svg
|
|
142
|
-
:target: https://pypi.org/project/ophyd-async
|
|
143
|
-
:alt: Latest PyPI version
|
|
144
|
-
|
|
145
|
-
.. |license| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
|
|
146
|
-
:target: https://opensource.org/licenses/BSD-3-Clause
|
|
147
|
-
:alt: BSD 3-Clause License
|
|
148
|
-
|
|
149
|
-
.. _Bluesky Run Engine: http://blueskyproject.io/bluesky
|
|
150
|
-
|
|
151
|
-
.. _Ophyd: http://blueskyproject.io/ophyd
|
|
152
|
-
|
|
153
|
-
.. _dls-dodal: https://github.com/DiamondLightSource/dodal
|
|
154
|
-
|
|
155
|
-
.. _EPICS: http://www.aps.anl.gov/epics/
|
|
156
|
-
|
|
157
|
-
.. _Tango: https://www.tango-controls.org/
|
|
158
|
-
|
|
159
|
-
..
|
|
160
|
-
Anything below this line is used when viewing README.rst and will be replaced
|
|
161
|
-
when included in index.rst
|
|
162
|
-
|
|
163
|
-
See https://blueskyproject.io/ophyd-async for more detailed documentation.
|
|
107
|
+
See https://bluesky.github.io/ophyd-async for more detailed documentation.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
ophyd_async/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
|
|
2
|
+
ophyd_async/__main__.py,sha256=G-Zcv_G9zK7Nhx6o5L5w-wyhMxdl_WgyMELu8IMFqAE,328
|
|
3
|
+
ophyd_async/_version.py,sha256=qiI6_8XDVi-QTRXglHkCWQmocyDKhwu0_7zIjyy3JmQ,408
|
|
4
|
+
ophyd_async/protocols.py,sha256=8kQms6exvlMRqK0DESv4LyhhweUf7bskUj0ODWBLra8,2283
|
|
5
|
+
ophyd_async/core/__init__.py,sha256=pzR-cIfjKTOoL8BFkvhwwflMIYzCOpeXU1xkppC1V7c,2252
|
|
6
|
+
ophyd_async/core/_providers.py,sha256=LrlTMPHKXWOPVkpAOw-pqBq0kip-c3C9ZZPoFfiaV4M,2212
|
|
7
|
+
ophyd_async/core/async_status.py,sha256=-sfIf7VhwAP25kSVwKZjAIYOTROpfnh2jgkDw5_afSU,2801
|
|
8
|
+
ophyd_async/core/detector.py,sha256=bc_9rXDaRiD2tciSZtP57h64r8wOCG4ZcWnmnJORRlI,11220
|
|
9
|
+
ophyd_async/core/device.py,sha256=Bm8u1wEN6PuJgCgis_msVRvfrO1_RumxAIMPag8k-cI,5813
|
|
10
|
+
ophyd_async/core/device_save_loader.py,sha256=RXA3dPUPihAR2ZGDStlGiA-TAsr_xqL0snsCjMsMnfA,9138
|
|
11
|
+
ophyd_async/core/flyer.py,sha256=rTAcFIyfGJwzwP-oI-V6nPNQiZazKDHn278wC9-sZgQ,2305
|
|
12
|
+
ophyd_async/core/signal.py,sha256=ZNHP9yh81l3kOpyQvnXuASVBlU8SJiKEQczKvJXXCxI,12549
|
|
13
|
+
ophyd_async/core/signal_backend.py,sha256=z0bwzM9IYp-hOZGlxy0u8JHfMGlULP17p14l2eVuk6A,1528
|
|
14
|
+
ophyd_async/core/sim_signal_backend.py,sha256=HK6-_jAvH3Uc8ijnVgLtjl1SsGWyiEH7ptkyUQPv_E4,6071
|
|
15
|
+
ophyd_async/core/standard_readable.py,sha256=ZoArn8sk31Kz389_CDe_Z70L9L6qjT5uVqYi5ywj2oM,2614
|
|
16
|
+
ophyd_async/core/utils.py,sha256=AVF5e42CVG_GaLoHJSI82iC4KAO60fb9fEJMISHBCNM,5043
|
|
17
|
+
ophyd_async/epics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
ophyd_async/epics/_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
ophyd_async/epics/_backend/_aioca.py,sha256=TZiV5r7CvEbM40t3TrTG4mVJBZGI_NDIaQlhfUHm0us,8789
|
|
20
|
+
ophyd_async/epics/_backend/_p4p.py,sha256=NtGncTdiou9HPt0fLPhPjRDcvUsUJ_6em9bhcQew-C8,12061
|
|
21
|
+
ophyd_async/epics/_backend/common.py,sha256=o0heeQEM7aP-QYCicwOEtNHs5c5OD6raR-5cTs9yRX0,840
|
|
22
|
+
ophyd_async/epics/areadetector/__init__.py,sha256=T5coX2Osb59uzQFlpHykp_spV-SBRQZYWdAIpDDsYQc,442
|
|
23
|
+
ophyd_async/epics/areadetector/aravis.py,sha256=cCugTlUs0b7mtzKTyxtWCRXO27tYA7zycPVPMhgkMyU,2335
|
|
24
|
+
ophyd_async/epics/areadetector/pilatus.py,sha256=gEJVUphr5gj8TwSYcc07ZakWk9tRIKKZRnPva5LZVBE,1537
|
|
25
|
+
ophyd_async/epics/areadetector/single_trigger_det.py,sha256=q5mG-OUVagIjvXLb28lsrGj4eUSoH2pNW2rT4rQR8fA,1206
|
|
26
|
+
ophyd_async/epics/areadetector/utils.py,sha256=dez54oElIkGMnhSM9qghToUB1opSqjdWTV2vhHCgRMA,3133
|
|
27
|
+
ophyd_async/epics/areadetector/controllers/__init__.py,sha256=UG2-M5d2ykp2T8isQJCbAsGZF1aH0BtC_OPlzzPTjnA,149
|
|
28
|
+
ophyd_async/epics/areadetector/controllers/ad_sim_controller.py,sha256=mthZ6WxajMEgUKptq3bnkIctbLhjzTagV66i1auB8cg,1587
|
|
29
|
+
ophyd_async/epics/areadetector/controllers/aravis_controller.py,sha256=vRiSexnFzijG8eEwowMAFIe730xFNMmgjjbXQVi4zrc,2394
|
|
30
|
+
ophyd_async/epics/areadetector/controllers/pilatus_controller.py,sha256=cd1CKkaXlwkpQ0I1VL7nN0U8R4VweTsa08WhvHYI4nY,2243
|
|
31
|
+
ophyd_async/epics/areadetector/drivers/__init__.py,sha256=AOpIEYfoBhG9Nc4-SId99v4PpyEh4_RBXfNaqiXlwUI,315
|
|
32
|
+
ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=ikfyNcZwJa5ah52DckjrBzkMMT_eDY1smM4XWfb6A6E,3689
|
|
33
|
+
ophyd_async/epics/areadetector/drivers/aravis_driver.py,sha256=Z96xXKfGJbLYehyy0wmP3mCW5lVRmdypmX-9U8cYbD8,5607
|
|
34
|
+
ophyd_async/epics/areadetector/drivers/pilatus_driver.py,sha256=fc3vNHqop9oLg-fvaU-diQNEV5U1qzA9vX2T8Hwy_E8,478
|
|
35
|
+
ophyd_async/epics/areadetector/writers/__init__.py,sha256=tpPcrYd1hs8WS7C0gmCnR2EBwjE5RzCljI7WwZ2V_LM,191
|
|
36
|
+
ophyd_async/epics/areadetector/writers/_hdfdataset.py,sha256=E0C9VgsPyY35h7k0mvcIhjsIVNavApLxizqNWlM388w,167
|
|
37
|
+
ophyd_async/epics/areadetector/writers/_hdffile.py,sha256=YtUgOKX53m0TaFEGBW671qXqNuuEKxEyLV5Ein1fjvo,1799
|
|
38
|
+
ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=oons06X8OAw3fh3IggvvQazjIgWpZAQ9jo_PBdtYewM,5259
|
|
39
|
+
ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=rutCstILCGGwhP5pH_2lWM2QUcZ88-uxx5dTZIJUMWQ,1562
|
|
40
|
+
ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=l0yBBEazviyFsWJv_4_sfGn_YM_Iyd0_SlMdAmUlXDU,871
|
|
41
|
+
ophyd_async/epics/demo/__init__.py,sha256=XSoP6xZVuQtxcDe6ZBIUy76iEgOywJgR4Z-ASEyyc90,6237
|
|
42
|
+
ophyd_async/epics/demo/demo_ad_sim_detector.py,sha256=06y65yvaqXvL2rDocjYyLz9kTVzuwV-LeuPhEfExdOA,944
|
|
43
|
+
ophyd_async/epics/demo/mover.db,sha256=RFz0rxZue689Wh1sWTZwWeFMUrH04ttPq2u5xJH_Fp4,998
|
|
44
|
+
ophyd_async/epics/demo/sensor.db,sha256=AVtiydrdtwAz2EFurO2Ult9SSRtre3r0akOBbL98LT0,554
|
|
45
|
+
ophyd_async/epics/motion/__init__.py,sha256=tnmVRIwKa9PdN_xonJdAUD04UpEceh-hoD7XI62yDB0,46
|
|
46
|
+
ophyd_async/epics/motion/motor.py,sha256=PBnkPuoCU1u1HD8IGEOM9GF2d1kwd0Hi7V9tr2rahZY,3786
|
|
47
|
+
ophyd_async/epics/pvi/__init__.py,sha256=TbOQNY4enQWgtr1T7x129vpo2p7FIFlr8cyZqqv5Lk4,158
|
|
48
|
+
ophyd_async/epics/pvi/pvi.py,sha256=hpn7GeO0xk_-UDoy42LIsi0adER9IZO3HPP2iu6Nmu4,11320
|
|
49
|
+
ophyd_async/epics/signal/__init__.py,sha256=wb93RTqvSbGKVFQj8OHykbVLGLmwKHU72oi5xYu2UaY,188
|
|
50
|
+
ophyd_async/epics/signal/_epics_transport.py,sha256=DEIL0iYUAWssysVEgWGu1fHSM1l-ATV2kjUgPtDN9LY,858
|
|
51
|
+
ophyd_async/epics/signal/signal.py,sha256=J3Kush7lK0lGj9dZG6qfNPFGNDsv4s-Ggv__1O9qaqA,3165
|
|
52
|
+
ophyd_async/panda/__init__.py,sha256=ZaD1nRgGKAGFGdpP1WWF-FnX3wcGuYqqq0QRZbaSBYQ,692
|
|
53
|
+
ophyd_async/panda/_common_blocks.py,sha256=n0PPc1rar43oDSIA-yNubTc8fR5YCW1tyjQU58whsg0,1038
|
|
54
|
+
ophyd_async/panda/_hdf_panda.py,sha256=zZxIdNIXHwjlZA-HTezQNfcCh98P2Pst6Pcld92rPLM,1414
|
|
55
|
+
ophyd_async/panda/_panda_controller.py,sha256=dIqcjmaIHVrki8UXSoDx46kk6I2Lhpe2o3sXNg5f-RQ,1238
|
|
56
|
+
ophyd_async/panda/_table.py,sha256=dLoRP4zYNOkD_s0Vkp2wVYAwkjVG8nNdf8-FaXOTfPo,5655
|
|
57
|
+
ophyd_async/panda/_trigger.py,sha256=tBH8uq_4o1ASG9yofVxq3tjf5v8LPzniDTRL4yjramI,1195
|
|
58
|
+
ophyd_async/panda/_utils.py,sha256=VHW5kPVISyEkmse_qQcyisBkkEwMO6GG2Ago-CH1AFA,487
|
|
59
|
+
ophyd_async/panda/writers/__init__.py,sha256=xy7BguVQG4HNIDBfKPjMj0KQo1tptC9LbCpEuMcVGaM,70
|
|
60
|
+
ophyd_async/panda/writers/_hdf_writer.py,sha256=tmIMWKQhURZu3PnmJyEn0xd94CWijpErXo_oJTSfefA,7626
|
|
61
|
+
ophyd_async/panda/writers/_panda_hdf_file.py,sha256=42iHaTax4JjOBpNC7d4nkNL9SM14OTnFPTIcXv2jg-4,1759
|
|
62
|
+
ophyd_async/planstubs/__init__.py,sha256=G9B80_d87lnOThUsGbAYPqzMw9xDelq2TbS7dkB692o,188
|
|
63
|
+
ophyd_async/planstubs/prepare_trigger_and_dets.py,sha256=0c4XDAxVkSanyDKtaMda0VgPEbk2jM0geVzAx707DhI,1772
|
|
64
|
+
ophyd_async/sim/__init__.py,sha256=ScjH1g7FMo5yPACfJRZE6xGBWCHU4bKDzNQk1tqObnA,366
|
|
65
|
+
ophyd_async/sim/pattern_generator.py,sha256=R9iC4ofkcM6KI1cLFDdgyggBccXrGmb5_MNIIlPVgQc,10646
|
|
66
|
+
ophyd_async/sim/sim_pattern_detector_control.py,sha256=Ypz8IuRYAY2J243IhVbNyGr_Z-XtpJZ1qxma6NR3TgM,1838
|
|
67
|
+
ophyd_async/sim/sim_pattern_detector_writer.py,sha256=X7AUYKL19Z0CLAI_wzQvJMo5CUYlebT_7-q7CgZ9FsA,1243
|
|
68
|
+
ophyd_async/sim/sim_pattern_generator.py,sha256=w5oc5QaFpAxzM0S5irvcOqsyASgN0rZQRzMjbZ5r8cE,1326
|
|
69
|
+
ophyd_async/sim/demo/__init__.py,sha256=9mxKpslrL89cfSj4g3og8Br3O--pMj3hhWZS-Xu6kyA,56
|
|
70
|
+
ophyd_async/sim/demo/sim_motor.py,sha256=Nt8mD_RY4pl80wQOQ3g0KIfNep4_9teJh4ioYgIsLj8,4036
|
|
71
|
+
ophyd_async-0.3a2.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
|
|
72
|
+
ophyd_async-0.3a2.dist-info/METADATA,sha256=_ZQVR2K-Bjx7gL7Z6kmlFbOjeEGG8ttArDfMshOri9g,5249
|
|
73
|
+
ophyd_async-0.3a2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
74
|
+
ophyd_async-0.3a2.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
|
|
75
|
+
ophyd_async-0.3a2.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
|
|
76
|
+
ophyd_async-0.3a2.dist-info/RECORD,,
|