0
# Area Detectors
1
2
Comprehensive support for 2D area detectors including cameras, plugins for data processing, file I/O, and triggering strategies for coordinated data acquisition. Area detectors form a modular system where cameras capture images and plugins process, display, and save data.
3
4
## Capabilities
5
6
### Base Area Detector Classes
7
8
Foundation classes that provide the core area detector functionality.
9
10
```python { .api }
11
class DetectorBase(Device):
12
"""
13
Base class for all area detectors.
14
15
Parameters:
16
- prefix (str): EPICS PV prefix for detector
17
- name (str): Detector name
18
- read_attrs (list): Attributes to include in read()
19
- configuration_attrs (list): Configuration attributes
20
"""
21
def __init__(self, prefix, *, read_attrs=None, configuration_attrs=None, **kwargs): ...
22
23
def stage(self):
24
"""
25
Stage detector for data acquisition.
26
27
Returns:
28
list: Staged components
29
"""
30
31
def unstage(self):
32
"""
33
Unstage detector after acquisition.
34
35
Returns:
36
list: Unstaged components
37
"""
38
39
def trigger(self):
40
"""
41
Trigger detector acquisition.
42
43
Returns:
44
StatusBase: Trigger completion status
45
"""
46
47
class AreaDetector(DetectorBase):
48
"""
49
Generic area detector with camera and plugin support.
50
51
Provides a complete area detector system with camera control
52
and plugin chain for data processing and file writing.
53
"""
54
def __init__(self, prefix, *, name, **kwargs): ...
55
56
# Core components (automatically created)
57
cam = Component(AreaDetectorCam, 'cam1:')
58
image = Component(ImagePlugin, 'image1:')
59
60
def stage(self):
61
"""Stage detector and plugins for acquisition."""
62
63
def unstage(self):
64
"""Unstage detector and clean up."""
65
66
class SimDetector(DetectorBase):
67
"""
68
Simulated area detector for testing and development.
69
70
Provides all the functionality of a real detector but generates
71
synthetic data instead of requiring hardware.
72
"""
73
def __init__(self, prefix, *, name, **kwargs): ...
74
75
class ADBase(Device):
76
"""
77
Base class providing core area detector functionality.
78
79
Contains common PVs and methods used by all area detector components.
80
"""
81
def __init__(self, prefix='', **kwargs): ...
82
```
83
84
### Camera Classes
85
86
Camera interfaces for different detector hardware types.
87
88
```python { .api }
89
class CamBase(ADBase):
90
"""
91
Base camera class with common camera functionality.
92
93
Provides standard camera controls like acquire, trigger mode,
94
image size, and exposure time.
95
"""
96
def __init__(self, prefix, **kwargs): ...
97
98
# Standard camera controls
99
acquire = Component(EpicsSignal, 'Acquire', trigger_value=1)
100
acquire_time = Component(EpicsSignal, 'AcquireTime')
101
acquire_period = Component(EpicsSignal, 'AcquirePeriod')
102
103
# Image size and binning
104
size_x = Component(EpicsSignal, 'SizeX')
105
size_y = Component(EpicsSignal, 'SizeY')
106
bin_x = Component(EpicsSignal, 'BinX')
107
bin_y = Component(EpicsSignal, 'BinY')
108
109
# Trigger controls
110
trigger_mode = Component(EpicsSignal, 'TriggerMode')
111
image_mode = Component(EpicsSignal, 'ImageMode')
112
num_images = Component(EpicsSignal, 'NumImages')
113
114
class AreaDetectorCam(CamBase):
115
"""Generic area detector camera."""
116
def __init__(self, prefix, **kwargs): ...
117
118
class SimDetectorCam(CamBase):
119
"""Simulated detector camera with synthetic image generation."""
120
def __init__(self, prefix, **kwargs): ...
121
122
# Simulation-specific controls
123
sim_mode = Component(EpicsSignal, 'SimMode')
124
gain_x = Component(EpicsSignal, 'GainX')
125
gain_y = Component(EpicsSignal, 'GainY')
126
127
# Specific detector camera classes (30+ types available)
128
class AndorCam(CamBase):
129
"""Andor camera interface."""
130
def __init__(self, prefix, **kwargs): ...
131
132
class PerkinElmerCam(CamBase):
133
"""PerkinElmer detector camera."""
134
def __init__(self, prefix, **kwargs): ...
135
136
class PointGreyCam(CamBase):
137
"""Point Grey camera interface."""
138
def __init__(self, prefix, **kwargs): ...
139
140
class AdscCam(CamBase):
141
"""ADSC detector camera."""
142
def __init__(self, prefix, **kwargs): ...
143
144
class PilatusDetectorCam(CamBase):
145
"""Pilatus detector camera."""
146
def __init__(self, prefix, **kwargs): ...
147
```
148
149
### Plugin System
150
151
Plugins provide data processing, visualization, and file I/O capabilities.
152
153
```python { .api }
154
class PluginBase(ADBase):
155
"""
156
Base class for all area detector plugins.
157
158
Plugins process data from cameras or other plugins in a pipeline.
159
160
Parameters:
161
- suffix (str): Plugin PV suffix (e.g., 'image1:', 'HDF1:')
162
"""
163
def __init__(self, prefix, **kwargs): ...
164
165
# Plugin control
166
enable = Component(EpicsSignal, 'EnableCallbacks')
167
nd_array_port = Component(EpicsSignal, 'NDArrayPort', string=True)
168
169
def enable_on_stage(self):
170
"""Enable plugin when parent detector is staged."""
171
172
def disable_on_unstage(self):
173
"""Disable plugin when parent detector is unstaged."""
174
175
class ImagePlugin(PluginBase):
176
"""
177
Image display plugin for live viewing.
178
179
Provides image data for display systems and live feedback.
180
"""
181
def __init__(self, prefix, **kwargs): ...
182
183
class StatsPlugin(PluginBase):
184
"""
185
Statistics plugin for image analysis.
186
187
Calculates min, max, mean, sigma, and other statistics
188
on image data in real-time.
189
"""
190
def __init__(self, prefix, **kwargs): ...
191
192
# Statistics outputs
193
min_value = Component(EpicsSignalRO, 'MinValue_RBV')
194
max_value = Component(EpicsSignalRO, 'MaxValue_RBV')
195
mean_value = Component(EpicsSignalRO, 'MeanValue_RBV')
196
sigma_value = Component(EpicsSignalRO, 'SigmaValue_RBV')
197
total = Component(EpicsSignalRO, 'Total_RBV')
198
199
class ROIPlugin(PluginBase):
200
"""
201
Region of Interest plugin for extracting image sub-regions.
202
203
Defines rectangular regions for analysis and processing.
204
"""
205
def __init__(self, prefix, **kwargs): ...
206
207
# ROI definition
208
min_x = Component(EpicsSignal, 'MinX')
209
min_y = Component(EpicsSignal, 'MinY')
210
size_x = Component(EpicsSignal, 'SizeX')
211
size_y = Component(EpicsSignal, 'SizeY')
212
213
class TransformPlugin(PluginBase):
214
"""
215
Transform plugin for image rotation, mirroring, and scaling.
216
"""
217
def __init__(self, prefix, **kwargs): ...
218
219
# Transform controls
220
transform_type = Component(EpicsSignal, 'Type')
221
origin_location = Component(EpicsSignal, 'Origin')
222
```
223
224
### File Plugins
225
226
Plugins for saving detector data to various file formats.
227
228
```python { .api }
229
class FilePlugin(PluginBase):
230
"""
231
Base class for file writing plugins.
232
233
Provides common file writing functionality including
234
path management, file naming, and write control.
235
"""
236
def __init__(self, prefix, **kwargs): ...
237
238
# File path and naming
239
file_path = Component(EpicsSignal, 'FilePath', string=True)
240
file_name = Component(EpicsSignal, 'FileName', string=True)
241
file_template = Component(EpicsSignal, 'FileTemplate', string=True)
242
file_number = Component(EpicsSignal, 'FileNumber')
243
244
# File writing control
245
capture = Component(EpicsSignal, 'Capture')
246
num_capture = Component(EpicsSignal, 'NumCapture')
247
248
def stage(self):
249
"""Configure file plugin for acquisition."""
250
251
def unstage(self):
252
"""Clean up after acquisition."""
253
254
class HDF5Plugin(FilePlugin):
255
"""
256
HDF5 file writing plugin.
257
258
Saves detector data in HDF5 format with comprehensive metadata
259
and support for compression and chunking.
260
"""
261
def __init__(self, prefix, **kwargs): ...
262
263
# HDF5-specific controls
264
compression = Component(EpicsSignal, 'Compression')
265
store_attr = Component(EpicsSignal, 'StoreAttr')
266
store_perform = Component(EpicsSignal, 'StorePerform')
267
268
class TIFFPlugin(FilePlugin):
269
"""
270
TIFF file writing plugin.
271
272
Saves individual images as TIFF files with standard formatting.
273
"""
274
def __init__(self, prefix, **kwargs): ...
275
276
class NetCDFPlugin(FilePlugin):
277
"""
278
NetCDF file writing plugin for scientific data formats.
279
"""
280
def __init__(self, prefix, **kwargs): ...
281
282
class JPEGPlugin(FilePlugin):
283
"""
284
JPEG file writing plugin for compressed images.
285
"""
286
def __init__(self, prefix, **kwargs): ...
287
288
# JPEG-specific controls
289
quality = Component(EpicsSignal, 'Quality')
290
```
291
292
### Trigger Mixins
293
294
Classes that define different triggering strategies for coordinated data acquisition.
295
296
```python { .api }
297
class TriggerBase:
298
"""
299
Base trigger interface for area detectors.
300
301
Defines the trigger protocol that detectors must implement
302
for integration with data acquisition systems.
303
"""
304
def trigger(self):
305
"""
306
Trigger detector acquisition.
307
308
Returns:
309
StatusBase: Status tracking trigger completion
310
"""
311
raise NotImplementedError()
312
313
class SingleTrigger(TriggerBase):
314
"""
315
Single frame trigger strategy.
316
317
Configures detector for single image acquisition per trigger.
318
"""
319
def trigger(self):
320
"""Trigger single frame acquisition."""
321
# Set single image mode
322
# Start acquisition
323
# Return status
324
325
def stage(self):
326
"""Configure for single trigger mode."""
327
328
class MultiTrigger(TriggerBase):
329
"""
330
Multiple frame trigger strategy.
331
332
Configures detector for multiple image acquisition per trigger.
333
"""
334
def __init__(self, num_images=1, **kwargs):
335
self.num_images = num_images
336
super().__init__(**kwargs)
337
338
def trigger(self):
339
"""Trigger multi-frame acquisition."""
340
341
def stage(self):
342
"""Configure for multi-trigger mode."""
343
344
class ContinuousAcquisitionTrigger(TriggerBase):
345
"""
346
Continuous acquisition trigger for streaming data.
347
348
Starts continuous acquisition and manages data collection
349
over specified time periods.
350
"""
351
def trigger(self):
352
"""Start continuous acquisition."""
353
354
def stage(self):
355
"""Configure for continuous mode."""
356
```
357
358
### FileStore Integration
359
360
Mixins for integrating with data management systems and event-based data access.
361
362
```python { .api }
363
class FileStoreBase:
364
"""
365
Base class for FileStore integration.
366
367
Provides integration with document-based data systems
368
for tracking detector data files and metadata.
369
"""
370
def generate_datum(self, key, timestamp, uid):
371
"""
372
Generate datum document for data file.
373
374
Parameters:
375
- key (str): Data key identifier
376
- timestamp (float): Data timestamp
377
- uid (str): Unique identifier
378
379
Returns:
380
str: Datum ID for referencing data
381
"""
382
383
class FileStoreHDF5(FileStoreBase):
384
"""
385
FileStore integration for HDF5 files.
386
387
Manages HDF5 file metadata and provides data access
388
through the document model.
389
"""
390
def __init__(self, *args, **kwargs): ...
391
392
class FileStoreTIFF(FileStoreBase):
393
"""
394
FileStore integration for TIFF files.
395
"""
396
def __init__(self, *args, **kwargs): ...
397
```
398
399
## Usage Examples
400
401
### Basic Area Detector Usage
402
403
```python
404
from ophyd.areadetector import AreaDetector, SingleTrigger
405
406
# Create detector with single trigger capability
407
class MyDetector(SingleTrigger, AreaDetector):
408
pass
409
410
detector = MyDetector('XF:28IDC:DET:', name='detector')
411
detector.wait_for_connection()
412
413
# Configure camera
414
detector.cam.acquire_time.put(0.1) # 100ms exposure
415
detector.cam.image_mode.put('Single')
416
417
# Stage detector for acquisition
418
detector.stage()
419
420
# Trigger acquisition
421
status = detector.trigger()
422
wait(status)
423
424
# Read image data
425
reading = detector.read()
426
427
# Unstage when done
428
detector.unstage()
429
```
430
431
### Setting Up File Saving
432
433
```python
434
from ophyd.areadetector import AreaDetector, HDF5Plugin, TIFFPlugin
435
436
detector = AreaDetector('XF:28IDC:DET:', name='detector')
437
detector.wait_for_connection()
438
439
# Configure HDF5 plugin
440
hdf5 = detector.hdf5
441
hdf5.file_path.put('/data/detector/')
442
hdf5.file_name.put('scan')
443
hdf5.file_template.put('%s%s_%04d.h5')
444
hdf5.enable.put(1)
445
446
# Configure for 10 images
447
hdf5.num_capture.put(10)
448
detector.cam.num_images.put(10)
449
detector.cam.image_mode.put('Multiple')
450
451
# Start acquisition
452
detector.stage()
453
hdf5.capture.put(1) # Start file writing
454
455
status = detector.trigger()
456
wait(status) # Wait for all 10 images
457
458
detector.unstage()
459
print(f"Data saved to: {hdf5.full_file_name.get()}")
460
```
461
462
### Using Statistics Plugin
463
464
```python
465
detector = AreaDetector('XF:28IDC:DET:', name='detector')
466
detector.wait_for_connection()
467
468
# Enable statistics plugin
469
stats = detector.stats1
470
stats.enable.put(1)
471
472
# Configure region of interest for stats
473
stats.min_x.put(100)
474
stats.min_y.put(100)
475
stats.size_x.put(200)
476
stats.size_y.put(200)
477
478
# Take image and get statistics
479
detector.stage()
480
status = detector.trigger()
481
wait(status)
482
483
# Read statistics
484
print(f"Mean intensity: {stats.mean_value.get()}")
485
print(f"Max intensity: {stats.max_value.get()}")
486
print(f"Total counts: {stats.total.get()}")
487
488
detector.unstage()
489
```
490
491
### Multi-Trigger Acquisition
492
493
```python
494
from ophyd.areadetector import AreaDetector, MultiTrigger
495
496
class MultiImageDetector(MultiTrigger, AreaDetector):
497
def __init__(self, *args, num_images=5, **kwargs):
498
super().__init__(*args, num_images=num_images, **kwargs)
499
500
detector = MultiImageDetector('XF:28IDC:DET:', name='detector', num_images=10)
501
detector.wait_for_connection()
502
503
# Configure exposure
504
detector.cam.acquire_time.put(0.05) # 50ms per image
505
506
# Stage for multi-image acquisition
507
detector.stage()
508
509
# Trigger acquisition of 10 images
510
status = detector.trigger()
511
wait(status) # Wait for all 10 images
512
513
detector.unstage()
514
```
515
516
### Custom Detector with Plugins
517
518
```python
519
from ophyd import Component
520
from ophyd.areadetector import (AreaDetector, HDF5Plugin, TIFFPlugin,
521
StatsPlugin, ROIPlugin, ImagePlugin)
522
523
class MyAdvancedDetector(AreaDetector):
524
"""Custom detector with specific plugin configuration."""
525
526
# File plugins
527
hdf5 = Component(HDF5Plugin, 'HDF1:')
528
tiff = Component(TIFFPlugin, 'TIFF1:')
529
530
# Analysis plugins
531
stats1 = Component(StatsPlugin, 'Stats1:')
532
stats2 = Component(StatsPlugin, 'Stats2:')
533
roi1 = Component(ROIPlugin, 'ROI1:')
534
roi2 = Component(ROIPlugin, 'ROI2:')
535
536
# Display
537
image1 = Component(ImagePlugin, 'image1:')
538
539
detector = MyAdvancedDetector('XF:28IDC:DET:', name='detector')
540
detector.wait_for_connection()
541
542
# Configure multiple ROIs
543
detector.roi1.min_x.put(0)
544
detector.roi1.min_y.put(0)
545
detector.roi1.size_x.put(512)
546
detector.roi1.size_y.put(512)
547
548
detector.roi2.min_x.put(200)
549
detector.roi2.min_y.put(200)
550
detector.roi2.size_x.put(100)
551
detector.roi2.size_y.put(100)
552
553
# Connect stats plugins to ROIs
554
detector.stats1.nd_array_port.put('ROI1')
555
detector.stats2.nd_array_port.put('ROI2')
556
557
# Enable all plugins
558
for plugin in [detector.roi1, detector.roi2, detector.stats1, detector.stats2]:
559
plugin.enable.put(1)
560
```
561
562
### Simulation Detector
563
564
```python
565
from ophyd.areadetector import SimDetector, SingleTrigger
566
567
class MySimDetector(SingleTrigger, SimDetector):
568
pass
569
570
sim_detector = MySimDetector('XF:28IDC:SIM:', name='sim_detector')
571
sim_detector.wait_for_connection()
572
573
# Configure simulation parameters
574
sim_detector.cam.sim_mode.put(1) # Linear ramp
575
sim_detector.cam.acquire_time.put(0.1)
576
577
# Take simulated image
578
sim_detector.stage()
579
status = sim_detector.trigger()
580
wait(status)
581
582
# The detector generates synthetic data
583
reading = sim_detector.read()
584
sim_detector.unstage()
585
```