CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-ophyd

Bluesky hardware abstraction library with EPICS control system integration for scientific instrument automation.

Pending
Overview
Eval results
Files

area-detectors.mddocs/

Area Detectors

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.

Capabilities

Base Area Detector Classes

Foundation classes that provide the core area detector functionality.

class DetectorBase(Device):
    """
    Base class for all area detectors.
    
    Parameters:
    - prefix (str): EPICS PV prefix for detector
    - name (str): Detector name
    - read_attrs (list): Attributes to include in read()
    - configuration_attrs (list): Configuration attributes
    """
    def __init__(self, prefix, *, read_attrs=None, configuration_attrs=None, **kwargs): ...
    
    def stage(self):
        """
        Stage detector for data acquisition.
        
        Returns:
        list: Staged components
        """
    
    def unstage(self):
        """
        Unstage detector after acquisition.
        
        Returns:
        list: Unstaged components
        """
    
    def trigger(self):
        """
        Trigger detector acquisition.
        
        Returns:
        StatusBase: Trigger completion status
        """

class AreaDetector(DetectorBase):
    """
    Generic area detector with camera and plugin support.
    
    Provides a complete area detector system with camera control
    and plugin chain for data processing and file writing.
    """
    def __init__(self, prefix, *, name, **kwargs): ...
    
    # Core components (automatically created)
    cam = Component(AreaDetectorCam, 'cam1:')
    image = Component(ImagePlugin, 'image1:')
    
    def stage(self):
        """Stage detector and plugins for acquisition."""
    
    def unstage(self):
        """Unstage detector and clean up."""

class SimDetector(DetectorBase):
    """
    Simulated area detector for testing and development.
    
    Provides all the functionality of a real detector but generates
    synthetic data instead of requiring hardware.
    """
    def __init__(self, prefix, *, name, **kwargs): ...

class ADBase(Device):
    """
    Base class providing core area detector functionality.
    
    Contains common PVs and methods used by all area detector components.
    """
    def __init__(self, prefix='', **kwargs): ...

Camera Classes

Camera interfaces for different detector hardware types.

class CamBase(ADBase):
    """
    Base camera class with common camera functionality.
    
    Provides standard camera controls like acquire, trigger mode,
    image size, and exposure time.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # Standard camera controls
    acquire = Component(EpicsSignal, 'Acquire', trigger_value=1)
    acquire_time = Component(EpicsSignal, 'AcquireTime')
    acquire_period = Component(EpicsSignal, 'AcquirePeriod')
    
    # Image size and binning
    size_x = Component(EpicsSignal, 'SizeX')
    size_y = Component(EpicsSignal, 'SizeY')
    bin_x = Component(EpicsSignal, 'BinX')
    bin_y = Component(EpicsSignal, 'BinY')
    
    # Trigger controls
    trigger_mode = Component(EpicsSignal, 'TriggerMode')
    image_mode = Component(EpicsSignal, 'ImageMode')
    num_images = Component(EpicsSignal, 'NumImages')

class AreaDetectorCam(CamBase):
    """Generic area detector camera."""
    def __init__(self, prefix, **kwargs): ...

class SimDetectorCam(CamBase):
    """Simulated detector camera with synthetic image generation."""
    def __init__(self, prefix, **kwargs): ...
    
    # Simulation-specific controls
    sim_mode = Component(EpicsSignal, 'SimMode')
    gain_x = Component(EpicsSignal, 'GainX')
    gain_y = Component(EpicsSignal, 'GainY')

# Specific detector camera classes (30+ types available)
class AndorCam(CamBase):
    """Andor camera interface."""
    def __init__(self, prefix, **kwargs): ...

class PerkinElmerCam(CamBase):
    """PerkinElmer detector camera."""
    def __init__(self, prefix, **kwargs): ...

class PointGreyCam(CamBase):
    """Point Grey camera interface."""
    def __init__(self, prefix, **kwargs): ...

class AdscCam(CamBase):
    """ADSC detector camera."""
    def __init__(self, prefix, **kwargs): ...

class PilatusDetectorCam(CamBase):
    """Pilatus detector camera."""
    def __init__(self, prefix, **kwargs): ...

Plugin System

Plugins provide data processing, visualization, and file I/O capabilities.

class PluginBase(ADBase):
    """
    Base class for all area detector plugins.
    
    Plugins process data from cameras or other plugins in a pipeline.
    
    Parameters:
    - suffix (str): Plugin PV suffix (e.g., 'image1:', 'HDF1:')
    """
    def __init__(self, prefix, **kwargs): ...
    
    # Plugin control
    enable = Component(EpicsSignal, 'EnableCallbacks')
    nd_array_port = Component(EpicsSignal, 'NDArrayPort', string=True)
    
    def enable_on_stage(self):
        """Enable plugin when parent detector is staged."""
    
    def disable_on_unstage(self):
        """Disable plugin when parent detector is unstaged."""

class ImagePlugin(PluginBase):
    """
    Image display plugin for live viewing.
    
    Provides image data for display systems and live feedback.
    """
    def __init__(self, prefix, **kwargs): ...

class StatsPlugin(PluginBase):
    """
    Statistics plugin for image analysis.
    
    Calculates min, max, mean, sigma, and other statistics
    on image data in real-time.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # Statistics outputs
    min_value = Component(EpicsSignalRO, 'MinValue_RBV')
    max_value = Component(EpicsSignalRO, 'MaxValue_RBV') 
    mean_value = Component(EpicsSignalRO, 'MeanValue_RBV')
    sigma_value = Component(EpicsSignalRO, 'SigmaValue_RBV')
    total = Component(EpicsSignalRO, 'Total_RBV')

class ROIPlugin(PluginBase):
    """
    Region of Interest plugin for extracting image sub-regions.
    
    Defines rectangular regions for analysis and processing.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # ROI definition
    min_x = Component(EpicsSignal, 'MinX')
    min_y = Component(EpicsSignal, 'MinY')
    size_x = Component(EpicsSignal, 'SizeX')
    size_y = Component(EpicsSignal, 'SizeY')

class TransformPlugin(PluginBase):
    """
    Transform plugin for image rotation, mirroring, and scaling.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # Transform controls
    transform_type = Component(EpicsSignal, 'Type')
    origin_location = Component(EpicsSignal, 'Origin')

File Plugins

Plugins for saving detector data to various file formats.

class FilePlugin(PluginBase):
    """
    Base class for file writing plugins.
    
    Provides common file writing functionality including
    path management, file naming, and write control.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # File path and naming
    file_path = Component(EpicsSignal, 'FilePath', string=True)
    file_name = Component(EpicsSignal, 'FileName', string=True)
    file_template = Component(EpicsSignal, 'FileTemplate', string=True)
    file_number = Component(EpicsSignal, 'FileNumber')
    
    # File writing control
    capture = Component(EpicsSignal, 'Capture')
    num_capture = Component(EpicsSignal, 'NumCapture')
    
    def stage(self):
        """Configure file plugin for acquisition."""
    
    def unstage(self):
        """Clean up after acquisition."""

class HDF5Plugin(FilePlugin):
    """
    HDF5 file writing plugin.
    
    Saves detector data in HDF5 format with comprehensive metadata
    and support for compression and chunking.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # HDF5-specific controls
    compression = Component(EpicsSignal, 'Compression')
    store_attr = Component(EpicsSignal, 'StoreAttr')
    store_perform = Component(EpicsSignal, 'StorePerform')

class TIFFPlugin(FilePlugin):
    """
    TIFF file writing plugin.
    
    Saves individual images as TIFF files with standard formatting.
    """
    def __init__(self, prefix, **kwargs): ...

class NetCDFPlugin(FilePlugin):
    """
    NetCDF file writing plugin for scientific data formats.
    """
    def __init__(self, prefix, **kwargs): ...

class JPEGPlugin(FilePlugin):
    """
    JPEG file writing plugin for compressed images.
    """
    def __init__(self, prefix, **kwargs): ...
    
    # JPEG-specific controls
    quality = Component(EpicsSignal, 'Quality')

Trigger Mixins

Classes that define different triggering strategies for coordinated data acquisition.

class TriggerBase:
    """
    Base trigger interface for area detectors.
    
    Defines the trigger protocol that detectors must implement
    for integration with data acquisition systems.
    """
    def trigger(self):
        """
        Trigger detector acquisition.
        
        Returns:
        StatusBase: Status tracking trigger completion
        """
        raise NotImplementedError()

class SingleTrigger(TriggerBase):
    """
    Single frame trigger strategy.
    
    Configures detector for single image acquisition per trigger.
    """
    def trigger(self):
        """Trigger single frame acquisition."""
        # Set single image mode
        # Start acquisition
        # Return status
    
    def stage(self):
        """Configure for single trigger mode."""

class MultiTrigger(TriggerBase):
    """
    Multiple frame trigger strategy.
    
    Configures detector for multiple image acquisition per trigger.
    """
    def __init__(self, num_images=1, **kwargs):
        self.num_images = num_images
        super().__init__(**kwargs)
    
    def trigger(self):
        """Trigger multi-frame acquisition."""
    
    def stage(self):
        """Configure for multi-trigger mode."""

class ContinuousAcquisitionTrigger(TriggerBase):
    """
    Continuous acquisition trigger for streaming data.
    
    Starts continuous acquisition and manages data collection
    over specified time periods.
    """
    def trigger(self):
        """Start continuous acquisition."""
    
    def stage(self):
        """Configure for continuous mode."""

FileStore Integration

Mixins for integrating with data management systems and event-based data access.

class FileStoreBase:
    """
    Base class for FileStore integration.
    
    Provides integration with document-based data systems
    for tracking detector data files and metadata.
    """
    def generate_datum(self, key, timestamp, uid):
        """
        Generate datum document for data file.
        
        Parameters:
        - key (str): Data key identifier
        - timestamp (float): Data timestamp
        - uid (str): Unique identifier
        
        Returns:
        str: Datum ID for referencing data
        """

class FileStoreHDF5(FileStoreBase):
    """
    FileStore integration for HDF5 files.
    
    Manages HDF5 file metadata and provides data access
    through the document model.
    """
    def __init__(self, *args, **kwargs): ...

class FileStoreTIFF(FileStoreBase):
    """
    FileStore integration for TIFF files.
    """
    def __init__(self, *args, **kwargs): ...

Usage Examples

Basic Area Detector Usage

from ophyd.areadetector import AreaDetector, SingleTrigger

# Create detector with single trigger capability
class MyDetector(SingleTrigger, AreaDetector):
    pass

detector = MyDetector('XF:28IDC:DET:', name='detector')
detector.wait_for_connection()

# Configure camera
detector.cam.acquire_time.put(0.1)  # 100ms exposure
detector.cam.image_mode.put('Single')

# Stage detector for acquisition  
detector.stage()

# Trigger acquisition
status = detector.trigger()
wait(status)

# Read image data
reading = detector.read()

# Unstage when done
detector.unstage()

Setting Up File Saving

from ophyd.areadetector import AreaDetector, HDF5Plugin, TIFFPlugin

detector = AreaDetector('XF:28IDC:DET:', name='detector')
detector.wait_for_connection()

# Configure HDF5 plugin
hdf5 = detector.hdf5
hdf5.file_path.put('/data/detector/')
hdf5.file_name.put('scan')
hdf5.file_template.put('%s%s_%04d.h5')
hdf5.enable.put(1)

# Configure for 10 images
hdf5.num_capture.put(10)
detector.cam.num_images.put(10)
detector.cam.image_mode.put('Multiple')

# Start acquisition
detector.stage()
hdf5.capture.put(1)  # Start file writing

status = detector.trigger()
wait(status)  # Wait for all 10 images

detector.unstage()
print(f"Data saved to: {hdf5.full_file_name.get()}")

Using Statistics Plugin

detector = AreaDetector('XF:28IDC:DET:', name='detector')
detector.wait_for_connection()

# Enable statistics plugin
stats = detector.stats1
stats.enable.put(1)

# Configure region of interest for stats
stats.min_x.put(100)
stats.min_y.put(100) 
stats.size_x.put(200)
stats.size_y.put(200)

# Take image and get statistics
detector.stage()
status = detector.trigger()
wait(status)

# Read statistics
print(f"Mean intensity: {stats.mean_value.get()}")
print(f"Max intensity: {stats.max_value.get()}")
print(f"Total counts: {stats.total.get()}")

detector.unstage()

Multi-Trigger Acquisition

from ophyd.areadetector import AreaDetector, MultiTrigger

class MultiImageDetector(MultiTrigger, AreaDetector):
    def __init__(self, *args, num_images=5, **kwargs):
        super().__init__(*args, num_images=num_images, **kwargs)

detector = MultiImageDetector('XF:28IDC:DET:', name='detector', num_images=10)
detector.wait_for_connection()

# Configure exposure
detector.cam.acquire_time.put(0.05)  # 50ms per image

# Stage for multi-image acquisition
detector.stage()

# Trigger acquisition of 10 images
status = detector.trigger()
wait(status)  # Wait for all 10 images

detector.unstage()

Custom Detector with Plugins

from ophyd import Component
from ophyd.areadetector import (AreaDetector, HDF5Plugin, TIFFPlugin, 
                                StatsPlugin, ROIPlugin, ImagePlugin)

class MyAdvancedDetector(AreaDetector):
    """Custom detector with specific plugin configuration."""
    
    # File plugins
    hdf5 = Component(HDF5Plugin, 'HDF1:')
    tiff = Component(TIFFPlugin, 'TIFF1:')
    
    # Analysis plugins
    stats1 = Component(StatsPlugin, 'Stats1:')
    stats2 = Component(StatsPlugin, 'Stats2:')
    roi1 = Component(ROIPlugin, 'ROI1:')
    roi2 = Component(ROIPlugin, 'ROI2:')
    
    # Display
    image1 = Component(ImagePlugin, 'image1:')

detector = MyAdvancedDetector('XF:28IDC:DET:', name='detector')
detector.wait_for_connection()

# Configure multiple ROIs
detector.roi1.min_x.put(0)
detector.roi1.min_y.put(0)
detector.roi1.size_x.put(512)
detector.roi1.size_y.put(512)

detector.roi2.min_x.put(200)
detector.roi2.min_y.put(200)
detector.roi2.size_x.put(100)
detector.roi2.size_y.put(100)

# Connect stats plugins to ROIs
detector.stats1.nd_array_port.put('ROI1')
detector.stats2.nd_array_port.put('ROI2')

# Enable all plugins
for plugin in [detector.roi1, detector.roi2, detector.stats1, detector.stats2]:
    plugin.enable.put(1)

Simulation Detector

from ophyd.areadetector import SimDetector, SingleTrigger

class MySimDetector(SingleTrigger, SimDetector):
    pass

sim_detector = MySimDetector('XF:28IDC:SIM:', name='sim_detector')
sim_detector.wait_for_connection()

# Configure simulation parameters
sim_detector.cam.sim_mode.put(1)  # Linear ramp
sim_detector.cam.acquire_time.put(0.1)

# Take simulated image
sim_detector.stage()
status = sim_detector.trigger()
wait(status)

# The detector generates synthetic data
reading = sim_detector.read()
sim_detector.unstage()

Install with Tessl CLI

npx tessl i tessl/pypi-ophyd

docs

area-detectors.md

core-framework.md

epics-integration.md

flyers-continuous-scanning.md

index.md

motors-positioners.md

simulation-testing.md

specialized-devices.md

tile.json