Devices#

Ophyd-style Devices for the APS.

Also consult the Index under the Ophyd heading for links to the Devices, Exceptions, Mixins, Signals, and other support items described here.

Categories#

See these categories:

APS General Support#

ApsCycleDM(*args, **kwargs)

Get the APS cycle name from the APS Data Management system or a local file.

ApsMachineParametersDevice(*args, **kwargs)

Common operational parameters of the APS of general interest.

ApsPssShutter(*args, **kwargs)

APS PSS shutter

ApsPssShutterWithStatus(*args, **kwargs)

APS PSS shutter with separate status PV

SimulatedApsPssShutterWithStatus(*args, **kwargs)

Simulated APS PSS shutter

Area Detector Support#

AD_EpicsFileNameHDF5Plugin(*args, **kwargs)

Alternative to HDF5Plugin: EPICS area detector PV sets file name.

AD_EpicsFileNameJPEGPlugin(*args, **kwargs)

Alternative to JPEGPlugin: EPICS area detector PV sets file name.

AD_EpicsFileNameTIFFPlugin(*args, **kwargs)

Alternative to TIFFPlugin: EPICS area detector PV sets file name.

AD_EpicsFileNameMixin(*args, **kwargs)

Custom class to define image file name from EPICS.

AD_EpicsHdf5FileName(*args, **kwargs)

Custom class to define HDF5 image file name from EPICS PVs.

AD_EpicsHDF5IterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsHdf5FileName and AD_EpicsFileNameHDF5Plugin

AD_EpicsJPEGFileName(*args, **kwargs)

Custom class to define JPEG image file name from EPICS PVs.

AD_EpicsJPEGIterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsJPEGFileName and AD_EpicsFileNameJPEGPlugin

AD_EpicsTIFFFileName(*args, **kwargs)

Custom class to define TIFF image file name from EPICS PVs.

AD_EpicsTIFFIterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsTIFFFileName and AD_EpicsFileNameTIFFPlugin

AD_setup_FrameType(prefix[, scheme])

configure so frames are identified & handled by type (dark, white, or image)

CamMixin_V34(*args, **kwargs)

Update cam support to AD release 3.1.1.

CamMixin_V3_1_1(*args, **kwargs)

Update cam support to AD release 3.1.1.

SingleTrigger_V34(*args, **kwargs)

Variation of ophyd's SingleTrigger mixin supporting AcquireBusy.

AD_full_file_name_local(plugin)

Return AD plugin's Last filename using local filesystem path.

AD_plugin_primed(plugin)

Has area detector pushed an NDarray to the file writer plugin? True or False

AD_prime_plugin2(plugin)

Prime this area detector's file writer plugin.

ensure_AD_plugin_primed(plugin[, allow])

Ensure the AD file writing plugin is primed (warmed up), if allowed.

Detector & Scaler Support#

Struck3820(*args, **kwargs)

Struck/SIS 3820 Multi-Channel Scaler (as used by USAXS)

MeasCompCtr(*args, **kwargs)

Measurement Computing USB CTR08 high-speed counter/timer.

MeasCompCtrMcs(*args, **kwargs)

Measurement Computing USB CTR08 Multi-Channel Scaler Controls.

use_EPICS_scaler_channels(scaler)

configure scaler for only the channels with names assigned in EPICS

SynPseudoVoigt(*args, **kwargs)

Evaluate a point on a pseudo-Voigt based on the value of a motor.

Tip

The Measurement Computing USB-CTR08 EPICS support provides a compatible EPICS scaler record.

Fly Scan Support#

ScalerMotorFlyer() support withdrawn pending issue #763.

Motors, Positioners, Axes, …#

AxisTunerException

Exception during execution of AxisTunerBase subclass

AxisTunerMixin(*args, **kwargs)

Mixin class to provide tuning capabilities for an axis

EpicsDescriptionMixin(*args, **kwargs)

add a record's description field to a Device, such as EpicsMotor

EpicsMotorDialMixin(*args, **kwargs)

add motor record's dial coordinate fields to Device

EpicsMotorEnableMixin(*args, **kwargs)

mixin providing access to motor enable/disable

EpicsMotorLimitsMixin(*args, **kwargs)

add motor record HLM & LLM fields & compatibility get_lim() and set_lim()

EpicsMotorRawMixin(*args, **kwargs)

add motor record's raw coordinate fields to Device

EpicsMotorResolutionMixin(*args, **kwargs)

Add motor record's resolution fields to motor.

EpicsMotorServoMixin(*args, **kwargs)

add motor record's servo loop controls to Device

PVPositionerSoftDone(*args, **kwargs)

PVPositioner that computes done as a soft signal.

PVPositionerSoftDoneWithStop(*args, **kwargs)

PVPositionerSoftDone with stop() and inposition.

EpicsMotorShutter(*args, **kwargs)

Shutter, implemented with an EPICS motor moved between two positions

EpicsOnOffShutter(*args, **kwargs)

Shutter using a single EPICS PV moved between two positions

SimulatedSwaitControllerPositioner(*args, ...)

Simulated process controller as positioner with EPICS swait record.

SimulatedTransformControllerPositioner(...)

Simulated process controller as positioner with EPICS transform record.

Shutters#

ApsPssShutter(*args, **kwargs)

APS PSS shutter

ApsPssShutterWithStatus(*args, **kwargs)

APS PSS shutter with separate status PV

EpicsMotorShutter(*args, **kwargs)

Shutter, implemented with an EPICS motor moved between two positions

EpicsOnOffShutter(*args, **kwargs)

Shutter using a single EPICS PV moved between two positions

OneSignalShutter(*args, **kwargs)

Shutter Device using one Signal for open and close.

ShutterBase(*args, **kwargs)

Base class for all shutter Devices.

SimulatedApsPssShutterWithStatus(*args, **kwargs)

Simulated APS PSS shutter

Slits#

HHLSlits(*args, **kwargs)

High Heat Load Slit.

XiaSlit2D(*args, **kwargs)

EPICS synApps optics xia_slit.db 2D support: inb out bot top ...

Optics2Slit1D(*args, **kwargs)

EPICS synApps optics 2slit.db 1D support: xn, xp, size, center, sync

Optics2Slit2D_HV(*args, **kwargs)

EPICS synApps optics 2slit.db 2D support: h.xn, h.xp, v.xn, v.xp

Optics2Slit2D_InbOutBotTop(*args, **kwargs)

EPICS synApps optics 2slit.db 2D support: inb, out, bot, top

SlitGeometry(width, height, x, y)

Slit size and center as a named tuple

synApps Support#

See separate synApps section.

Temperature Support#

Controllers#

Eurotherm2216e(*args, **kwargs)

Eurotherm 2216e Temperature Controller

LakeShore336Device(*args, **kwargs)

LakeShore 336 temperature controller.

LakeShore340Device(*args, **kwargs)

LakeShore 340 temperature controller

Linkam_CI94_Device(*args, **kwargs)

Linkam model CI94 temperature controller

Linkam_T96_Device(*args, **kwargs)

Linkam model T96 temperature controller

PTC10AioChannel(*args, **kwargs)

SRS PTC10 AIO module

PTC10RtdChannel(*args, **kwargs)

SRS PTC10 RTD module channel

PTC10TcChannel(*args, **kwargs)

SRS PTC10 Tc (thermocouple) module channel

PTC10PositionerMixin(*args, **kwargs)

Mixin so SRS PTC10 can be used as a (temperature) positioner.

SimulatedSwaitControllerPositioner(*args, ...)

Simulated process controller as positioner with EPICS swait record.

SimulatedTransformControllerPositioner(...)

Simulated process controller as positioner with EPICS transform record.

Readers#

MeasCompTc32(*args, **kwargs)

Measurement Computing TC-32 32-channel Thermocouple reader.

Other Support#

ApsBssUserInfoDevice(*args, **kwargs)

Provide current experiment info from the APS BSS.

DM_WorkflowConnector(*args, **kwargs)

Support for the APS Data Management tools.

Pf4FilterSingle(*args, **kwargs)

XIA PF4 Filter: one set of 4 filters (A).

Pf4FilterDual(*args, **kwargs)

XIA PF4 Filter: two sets of 4 filters (A, B).

Pf4FilterTriple(*args, **kwargs)

XIA PF4 Filter: three sets of 4 filters (A, B, C).

Pf4FilterBank(*args, **kwargs)

A single module of XIA PF4 filters (4-blades).

Pf4FilterCommon(*args, **kwargs)

XIA PF4 filters - common support.

DualPf4FilterBox(*args, **kwargs)

LEGACY (use Pf4FilterDual now): Dual (Al, Ti) Xia PF4 filter boxes

EpicsDescriptionMixin(*args, **kwargs)

add a record's description field to a Device, such as EpicsMotor

dict_device_factory([data])

Create a DictionaryDevice class using the supplied dictionary.

make_dict_device(obj[, name])

Make recordable DictionaryDevice instance from dictionary.

EpicsScanIdSignal(*args, **kwargs)

Use an EPICS PV as the source of the RunEngine's scan_id.

MeasCompCtr(*args, **kwargs)

Measurement Computing USB CTR08 high-speed counter/timer.

KohzuSeqCtl_Monochromator(*args, **kwargs)

synApps Kohzu double-crystal monochromator sequence control program

SimulatedSwaitControllerPositioner(*args, ...)

Simulated process controller as positioner with EPICS swait record.

SimulatedTransformControllerPositioner(...)

Simulated process controller as positioner with EPICS transform record.

SRS570_PreAmplifier(*args, **kwargs)

Ophyd support for Stanford Research Systems 570 preamplifier from synApps.

Struck3820(*args, **kwargs)

Struck/SIS 3820 Multi-Channel Scaler (as used by USAXS)

DG645Delay(*args, **kwargs)

An SRS DG-645 digial delay/pulse generator.

LabJackBase(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

LabJackT4(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

LabJackT7(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

LabJackT7Pro(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

LabJackT8(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

Internal Routines#

ApsOperatorMessagesDevice(*args, **kwargs)

General messages from the APS main control room.

TrackingSignal(*args, **kwargs)

Non-EPICS signal for use when coordinating Device actions.

DeviceMixinBase(*args, **kwargs)

Base class for apstools Device mixin classes

All Submodules#

APS User Proposal and ESAF Information#

ApsBssUserInfoDevice(*args, **kwargs)

Provide current experiment info from the APS BSS.

class apstools.devices.aps_bss_user.ApsBssUserInfoDevice(*args: Any, **kwargs: Any)[source]#

Bases: Device

Provide current experiment info from the APS BSS.

BSS: Beamtime Scheduling System

EXAMPLE:

bss_user_info = ApsBssUserInfoDevice(
                    "9id_bss:",
                    name="bss_user_info")
sd.baseline.append(bss_user_info)

NOTE: There is info provided by the APS proposal & ESAF systems.

Connect with APS Data Management workflows.

Example:

import bluesky
from apstools.devices import DM_WorkflowConnector

RE = bluesky.RunEngine()

dm_workflow = DM_WorkflowConnector(name="dm_workflow", labels=["DM"])
RE(
    dm_workflow.run_as_plan(
        workflow="example-01",
        filePath="/home/beams/S1IDTEST/.bashrc"
    )
)

Note

DM_WorkflowConnector() requires APS Data Management package (aps-dm-api >=5)

DM_WorkflowConnector(*args, **kwargs)

Support for the APS Data Management tools.

class apstools.devices.aps_data_management.DM_WorkflowConnector(*args: Any, **kwargs: Any)[source]#

Bases: Device

Support for the APS Data Management tools.

The DM workflow dictionary of arguments (workflow_args) needs special attention. Python’s dict structure is not compatible with MongoDB. In turn, ophyd does not support it. A custom plan can choose how to use the `workflow_args` dictionary:

  • use with DM workflow, as planned

  • add workflow_args to the start metadata

  • write as run stream:

    from apstools.devices import make_dict_device
    from apstools.plans import write_stream
    
    yield from write_stream(
        [make_dict_device(workflow_args, name="kwargs")],
        "workflow_args"
    )
    

api

Local copy of DM Processing API object.

idle

Is DM Processing idle?

processing_jobs

The list of DM processsing jobs.

report_processing_stages([truncate])

Print a table about each stage of the workflow process.

report_status([t_offset])

Status report.

run_as_plan([workflow, wait, timeout])

Run the DM workflow as a bluesky plan.

start_workflow([workflow, timeout])

Kickoff a DM workflow with optional reporting timeout.

workflows

Return the list of workflows.

put_if_different(signal, value)

Put ophyd signal only if new value is different.

_update_processing_data()

(internal) Called periodically (while process runs) to update self.job.

_update_processing_data()[source]#

(internal) Called periodically (while process runs) to update self.job.

Also updates certain ophyd signals.

property api#

Local copy of DM Processing API object.

getJob()[source]#

Get the current processing job object.

property idle#

Is DM Processing idle?

property processing_jobs#

The list of DM processsing jobs.

put_if_different(signal, value)[source]#

Put ophyd signal only if new value is different.

report_processing_stages(truncate=40)[source]#

Print a table about each stage of the workflow process.

report_status(t_offset=None)[source]#

Status report.

run_as_plan(workflow: str = '', wait: bool = True, timeout: int = 180, **kwargs)[source]#

Run the DM workflow as a bluesky plan.

start_workflow(workflow='', timeout=180, **kwargs)[source]#

Kickoff a DM workflow with optional reporting timeout.

The reporting process will continue until the workflow ends or the timeout period is exceeded. It does not affect the actual workflow.

property workflows#

Return the list of workflows.

Area Detector Support#

AD_EpicsFileNameHDF5Plugin(*args, **kwargs)

Alternative to HDF5Plugin: EPICS area detector PV sets file name.

AD_EpicsFileNameJPEGPlugin(*args, **kwargs)

Alternative to JPEGPlugin: EPICS area detector PV sets file name.

AD_EpicsFileNameMixin(*args, **kwargs)

Custom class to define image file name from EPICS.

AD_EpicsFileNameTIFFPlugin(*args, **kwargs)

Alternative to TIFFPlugin: EPICS area detector PV sets file name.

AD_EpicsHdf5FileName(*args, **kwargs)

Custom class to define HDF5 image file name from EPICS PVs.

AD_EpicsHDF5IterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsHdf5FileName and AD_EpicsFileNameHDF5Plugin

AD_EpicsJPEGFileName(*args, **kwargs)

Custom class to define JPEG image file name from EPICS PVs.

AD_EpicsJPEGIterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsJPEGFileName and AD_EpicsFileNameJPEGPlugin

AD_EpicsTIFFFileName(*args, **kwargs)

Custom class to define TIFF image file name from EPICS PVs.

AD_EpicsTIFFIterativeWriter(*args, **kwargs)

intermediate class between AD_EpicsTIFFFileName and AD_EpicsFileNameTIFFPlugin

AD_full_file_name_local(plugin)

Return AD plugin's Last filename using local filesystem path.

AD_plugin_primed(plugin)

Has area detector pushed an NDarray to the file writer plugin? True or False

AD_prime_plugin(detector, plugin)

Prime this area detector's file writer plugin.

AD_prime_plugin2(plugin)

Prime this area detector's file writer plugin.

AD_setup_FrameType(prefix[, scheme])

configure so frames are identified & handled by type (dark, white, or image)

CamMixin_V3_1_1(*args, **kwargs)

Update cam support to AD release 3.1.1.

CamMixin_V34(*args, **kwargs)

Update cam support to AD release 3.1.1.

SingleTrigger_V34(*args, **kwargs)

Variation of ophyd's SingleTrigger mixin supporting AcquireBusy.

ensure_AD_plugin_primed(plugin[, allow])

Ensure the AD file writing plugin is primed (warmed up), if allowed.

class apstools.devices.area_detector_support.AD_EpicsFileNameHDF5Plugin(*args: Any, **kwargs: Any)[source]#

Bases: HDF5Plugin_V34, AD_EpicsHDF5IterativeWriter

Alternative to HDF5Plugin: EPICS area detector PV sets file name.

Caution

Caveat emptor applies here. You assume expertise!

Uses AD_EpicsHdf5FileName.

EXAMPLE:

from apstools.devices import CamMixin_V34
from apstools.devices import SingleTrigger_V34
from apstools.devices.area_detector_support import AD_EpicsFileNameHDF5Plugin
from ophyd import EpicsSignalWithRBV
from ophyd.areadetector import ADComponent
from ophyd.areadetector import DetectorBase
from ophyd.areadetector.plugins import ImagePlugin_V34 as ImagePlugin
from ophyd.areadetector.plugins import PvaPlugin_V34 as PvaPlugin
from ophyd.areadetector import SimDetectorCam
import datetime
import pathlib


IOC = "ad:"
IMAGE_DIR = "adsimdet/%Y/%m/%d"
AD_IOC_MOUNT_PATH = pathlib.Path("/tmp")
BLUESKY_MOUNT_PATH = pathlib.Path("/tmp/docker_ioc/iocad/tmp")

# MUST end with a `/`, pathlib will NOT provide it
WRITE_PATH_TEMPLATE = f"{AD_IOC_MOUNT_PATH / IMAGE_DIR}/"
READ_PATH_TEMPLATE = f"{BLUESKY_MOUNT_PATH / IMAGE_DIR}/"

class SimDetectorCam_V34(CamMixin_V34, SimDetectorCam):
    '''Revise SimDetectorCam for ADCore revisions.'''

class SimDetector_V34(SingleTrigger_V34, DetectorBase):
    '''ADSimDetector'''

    cam = ADComponent(SimDetectorCam_V34, "cam1:")
    image = ADComponent(ImagePlugin, "image1:")
    hdf1 = ADComponent(
        AD_EpicsFileNameHDF5Plugin,
        "HDF1:",
        write_path_template=WRITE_PATH_TEMPLATE,
        read_path_template=READ_PATH_TEMPLATE,
    )
    pva = ADComponent(PvaPlugin, "Pva1:")

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsFileNameJPEGPlugin(*args: Any, **kwargs: Any)[source]#

Bases: JPEGPlugin_V34, AD_EpicsJPEGIterativeWriter

Alternative to JPEGPlugin: EPICS area detector PV sets file name.

Caution

Caveat emptor applies here. You assume expertise!

Uses AD_EpicsJpegFileName.

EXAMPLE:

from apstools.devices import CamMixin_V34
from apstools.devices import SingleTrigger_V34
from apstools.devices.area_detector_support import AD_EpicsFileNameJPEGPlugin
from ophyd import EpicsSignalWithRBV
from ophyd.areadetector import ADComponent
from ophyd.areadetector import DetectorBase
from ophyd.areadetector.plugins import ImagePlugin_V34 as ImagePlugin
from ophyd.areadetector.plugins import PvaPlugin_V34 as PvaPlugin
from ophyd.areadetector import SimDetectorCam
import datetime
import pathlib


IOC = "ad:"
IMAGE_DIR = "adsimdet/%Y/%m/%d"
AD_IOC_MOUNT_PATH = pathlib.Path("/tmp")
BLUESKY_MOUNT_PATH = pathlib.Path("/tmp/docker_ioc/iocad/tmp")

# MUST end with a `/`, pathlib will NOT provide it
WRITE_PATH_TEMPLATE = f"{AD_IOC_MOUNT_PATH / IMAGE_DIR}/"
READ_PATH_TEMPLATE = f"{BLUESKY_MOUNT_PATH / IMAGE_DIR}/"


class SimDetectorCam_V34(CamMixin_V34, SimDetectorCam):
    '''Revise SimDetectorCam for ADCore revisions.'''


class SimDetector_V34(SingleTrigger_V34, DetectorBase):
    '''ADSimDetector'''

    cam = ADComponent(SimDetectorCam_V34, "cam1:")
    image = ADComponent(ImagePlugin, "image1:")
    jpeg1 = ADComponent(
        AD_EpicsFileNameHDF5Plugin,
        "JPEG1:",
        write_path_template=WRITE_PATH_TEMPLATE,
        read_path_template=READ_PATH_TEMPLATE,
    )
    pva = ADComponent(PvaPlugin, "Pva1:")

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsFileNameMixin(*args: Any, **kwargs: Any)[source]#

Bases: FileStorePluginBase

Custom class to define image file name from EPICS.

Used as part of AD_EpicsFileNameHDF5Plugin.

Caution

Caveat emptor applies here. You assume expertise!

Replace standard ophyd file naming algorithm (where file names are defined as UUID strings, virtually guaranteeing that no existing images files will ever be overwritten).

Caller is responsible for setting values of these Components:

  • array_counter

  • auto_increment

  • auto_save

  • compression (only HDF)

  • create_directory

  • file_name

  • file_number

  • file_path

  • file_template

  • num_capture

make_filename()

overrides default behavior: Get info from EPICS file writer plugin.

get_frames_per_point()

overrides default behavior

stage()

Overrides default behavior of parent class.

To allow users to control the file name, we override the make_filename() method here and we need to override some intervening classes.

To allow users to control the file number, we override the stage() method here and triple-comment out that line, and bring in sections from the methods we are replacing here.

It is allowed to set the file_template="%s%s.h5" so the file name does not include the file number.

The image file name is set in FileStoreBase.make_filename() from ophyd.areadetector.filestore_mixins. This is called (during device staging) from FileStoreBase.stage()

_remove_caller_stage_sigs()[source]#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()[source]#

overrides default behavior

make_filename()[source]#

overrides default behavior: Get info from EPICS file writer plugin.

stage()[source]#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsFileNameTIFFPlugin(*args: Any, **kwargs: Any)[source]#

Bases: TIFFPlugin_V34, AD_EpicsTIFFIterativeWriter

Alternative to TIFFPlugin: EPICS area detector PV sets file name.

Caution

Caveat emptor applies here. You assume expertise!

Uses AD_EpicsTIFFFileName.

EXAMPLE:

from apstools.devices import CamMixin_V34
from apstools.devices import SingleTrigger_V34
from apstools.devices.area_detector_support import AD_EpicsFileNameTIFFPlugin
from ophyd import EpicsSignalWithRBV
from ophyd.areadetector import ADComponent
from ophyd.areadetector import DetectorBase
from ophyd.areadetector.plugins import ImagePlugin_V34 as ImagePlugin
from ophyd.areadetector.plugins import PvaPlugin_V34 as PvaPlugin
from ophyd.areadetector import SimDetectorCam
import datetime
import pathlib


IOC = "ad:"
IMAGE_DIR = "adsimdet/%Y/%m/%d"
AD_IOC_MOUNT_PATH = pathlib.Path("/tmp")
BLUESKY_MOUNT_PATH = pathlib.Path("/tmp/docker_ioc/iocad/tmp")

# MUST end with a `/`, pathlib will NOT provide it
WRITE_PATH_TEMPLATE = f"{AD_IOC_MOUNT_PATH / IMAGE_DIR}/"
READ_PATH_TEMPLATE = f"{BLUESKY_MOUNT_PATH / IMAGE_DIR}/"


class SimDetectorCam_V34(CamMixin_V34, SimDetectorCam):
    '''Revise SimDetectorCam for ADCore revisions.'''


class SimDetector_V34(SingleTrigger_V34, DetectorBase):
    '''ADSimDetector'''

    cam = ADComponent(SimDetectorCam_V34, "cam1:")
    image = ADComponent(ImagePlugin, "image1:")
    tiff1 = ADComponent(
        AD_EpicsFileNameTIFFPlugin,
        "TIFF1:",
        write_path_template=WRITE_PATH_TEMPLATE,
        read_path_template=READ_PATH_TEMPLATE,
    )
    pva = ADComponent(PvaPlugin, "Pva1:")

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsHDF5IterativeWriter(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsHdf5FileName, FileStoreIterativeWrite

intermediate class between AD_EpicsHdf5FileName and AD_EpicsFileNameHDF5Plugin

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsHdf5FileName(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsFileNameMixin

Custom class to define HDF5 image file name from EPICS PVs.

Used as part of AD_EpicsFileNameHDF5Plugin.

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsJPEGFileName(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsFileNameMixin

Custom class to define JPEG image file name from EPICS PVs.

Used as part of AD_EpicsFileNameJPEGPlugin.

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsJPEGIterativeWriter(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsJPEGFileName, FileStoreIterativeWrite

intermediate class between AD_EpicsJPEGFileName and AD_EpicsFileNameJPEGPlugin

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsTIFFFileName(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsFileNameMixin

Custom class to define TIFF image file name from EPICS PVs.

Used as part of AD_EpicsFileNameTIFFPlugin.

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

class apstools.devices.area_detector_support.AD_EpicsTIFFIterativeWriter(*args: Any, **kwargs: Any)[source]#

Bases: AD_EpicsTIFFFileName, FileStoreIterativeWrite

intermediate class between AD_EpicsTIFFFileName and AD_EpicsFileNameTIFFPlugin

(new in apstools release 1.6.2)

_remove_caller_stage_sigs()#

Caller is responsible for setting these stage_sigs.

get_frames_per_point()#

overrides default behavior

make_filename()#

overrides default behavior: Get info from EPICS file writer plugin.

stage()#

Overrides default behavior of parent class.

Parent class items overridden here:

  • Sets file_name based on a UUID.

  • Sets file_path from write_path_template.

  • Sets file_number to 0.

Set EPICS items before device is staged, then copy EPICS naming template (and other items) to ophyd after staging.

apstools.devices.area_detector_support.AD_full_file_name_local(plugin)[source]#

Return AD plugin’s Last filename using local filesystem path.

Get the full name, in terms of the bluesky filesystem, for the image file recently-acquired by the area detector plugin.

Return the name as a pathlib object.

PARAMETERS

plugin obj :

Instance of ophyd area detector file writing plugin.

(new in apstools release 1.6.2)

apstools.devices.area_detector_support.AD_plugin_primed(plugin)[source]#

Has area detector pushed an NDarray to the file writer plugin? True or False

PARAMETERS

plugin

obj : area detector plugin to be primed (such as detector.hdf1)

EXAMPLE:

AD_plugin_primed(detector.hdf1)

Works around an observed issue: #598 NSLS-II/ophyd#598

If detector IOC has just been started and has not yet taken an image with the file writer plugin, then a TimeoutError will occur as the file writer plugin “Capture” is set to 1 (Start). In such case, first acquire at least one image with the file writer plugin enabled.

Also issue in apstools (needs a robust method to detect if primed): BCDA-APS/apstools#464

Since Area Detector release 2.1 (2014-10-14).

The prime process is not needed if you select the LazyOpen feature with Stream mode for the file plugin. LazyOpen defers file creation until the first frame arrives in the plugin. This removes the need to initialize the plugin with a dummy frame before starting capture.

apstools.devices.area_detector_support.AD_prime_plugin(detector, plugin)[source]#

Prime this area detector’s file writer plugin.

PARAMETERS

detector

obj : area detector (such as detector)

plugin

obj : area detector plugin to be primed (such as detector.hdf1)

EXAMPLE:

AD_prime_plugin(detector, detector.hdf1)
apstools.devices.area_detector_support.AD_prime_plugin2(plugin)[source]#

Prime this area detector’s file writer plugin.

Collect and push an NDarray to the file writer plugin. Works with all file writer plugins.

Based on ophyd.areadetector.plugins.HDF5Plugin.warmup().

PARAMETERS

plugin

obj : area detector plugin to be primed (such as detector.hdf1)

EXAMPLE:

AD_prime_plugin2(detector.hdf1)
apstools.devices.area_detector_support.AD_setup_FrameType(prefix, scheme='NeXus')[source]#

configure so frames are identified & handled by type (dark, white, or image)

PARAMETERS

prefix

str : EPICS PV prefix of area detector, such as 13SIM1:

scheme

str : any key in the AD_FrameType_schemes dictionary

This routine prepares the EPICS Area Detector to identify frames by image type for handling by clients, such as the HDF5 file writing plugin. With the HDF5 plugin, the FrameType PV is added to the NDattributes and then used in the layout file to direct the acquired frame to the chosen dataset. The FrameType PV value provides the HDF5 address to be used.

To use a different scheme than the defaults, add a new key to the AD_FrameType_schemes dictionary, defining storage values for the fields of the EPICS mbbo record that you will be using.

see: https://nbviewer.org/github/BCDA-APS/bluesky_training/blob/main/images_darks_flats.ipynb

EXAMPLE:

AD_setup_FrameType("2bmbPG3:", scheme="DataExchange")
  • Call this function before creating the ophyd area detector object

  • use lower-level PyEpics interface

class apstools.devices.area_detector_support.CamMixin_V34(*args: Any, **kwargs: Any)[source]#

Bases: CamMixin_V3_1_1

Update cam support to AD release 3.1.1.

(new in release 1.6.3)

class apstools.devices.area_detector_support.CamMixin_V3_1_1(*args: Any, **kwargs: Any)[source]#

Bases: CamBase

Update cam support to AD release 3.1.1.

(new in release 1.6.3)

class apstools.devices.area_detector_support.SingleTrigger_V34(*args: Any, **kwargs: Any)[source]#

Bases: SingleTrigger

Variation of ophyd’s SingleTrigger mixin supporting AcquireBusy.

(new in release 1.6.3)

stage()[source]#

Prepare device settings before data acquisition.

unstage()[source]#

Restore device settings after data acquisition.

apstools.devices.area_detector_support.ensure_AD_plugin_primed(plugin, allow=False)[source]#

Ensure the AD file writing plugin is primed (warmed up), if allowed.

This function primes the plugin only if it is deemed necessary (for the use by ophyd).

PARAMETERS

plugin

obj : area detector plugin to be primed (such as detector.hdf1)

allow

bool : (default: False) Should the detector be primed? This keyword argument might be provided by a local configuration setting, controlled externally, such as from configuration file or other ophyd Signal.

EXAMPLE:

from apstools.devices import ensure_AD_plugin_primed
ensure_AD_plugin_primed(det.hdf1, True)

# or from a boolean python object

from local_configuration_settings import ok_to_prime
ensure_AD_plugin_primed(det.hdf1, allow=ok_to_prime)

An area detector file writing plugin is primed (as considered by ophyd) if the plugin’s image array parameters (size, number of bits, & color mode) match those configured in the cam. This agreement is required by the bluesky RunEngine (via area_detector_handlers) to generate a descriptor document for any ensuing image events.

Use with these area detector file writing plugins (maybe others):

  • HDF5Plugin

  • JPEGPlugin

  • NetCDFPlugin

  • TIFFPlugin

Even with lazy_open=1, ophyd (via area_detector_handlers) checks if the area detector file writing plugin has been primed.

(new in apstools release 1.6.16)

APS cycles#

ApsCycleDM(*args, **kwargs)

Get the APS cycle name from the APS Data Management system or a local file.

class apstools.devices.aps_cycle.ApsCycleDM(*args: Any, **kwargs: Any)[source]#

Bases: SynSignalRO

Get the APS cycle name from the APS Data Management system or a local file.

This signal is read-only.

class apstools.devices.aps_cycle._ApsCycleDB[source]#

Bases: object

Python representation of the APS run cycle schedule table.

_read_cycle_data()[source]#

Read the list of APS run cycles from a local file.

The file is formatted in YAML after reformatting content received from the APS Data Management package (aps-dm-api). The YAML format is easily updated and human-readable.

_write_cycle_data()[source]#

Write the list of APS run cycles to a local file.

The file is formatted exactly as received from the APS Data Management package (aps-dm-api). This allows automatic updates as needed.

To update the LOCAL_FILE, run this code (on a workstation at the APS):

from apstools._devices.aps_cycle import cycle_db
cycle_db._write_cycle_data()
get_cycle_name(ts=None)[source]#

Get the name of the current APS run cycle.

By default, the name of the current run cycle (based on the current timestamp) will be returned.

PARAMETERS

ts float:

Absolute time stamp (such as from time.time()). Default: current time stamp.

RETURNS

Returns cycle name (str) or None if timestamp is not in data table.

APS Machine Parameters#

APS machine parameters

ApsMachineParametersDevice(*args, **kwargs)

Common operational parameters of the APS of general interest.

ApsOperatorMessagesDevice(*args, **kwargs)

General messages from the APS main control room.

class apstools.devices.aps_machine.ApsMachineParametersDevice(*args: Any, **kwargs: Any)[source]#

Bases: Device

Common operational parameters of the APS of general interest.

EXAMPLE:

import apstools.devices as APS_devices
APS = APS_devices.ApsMachineParametersDevice(name="APS")
aps_current = APS.current

# make sure these values are logged at start and stop of every scan
sd.baseline.append(APS)
# record storage ring current as secondary stream during scans
# name: aps_current_monitor
# db[-1].table("aps_current_monitor")
sd.monitors.append(aps_current)

The sd.baseline and sd.monitors usage relies on this global setup:

from bluesky import SupplementalData
sd = SupplementalData()
RE.preprocessors.append(sd)

inUserOperations

determine if APS is in User Operations mode (boolean)

aps_cycle#

alias of ApsCycleDM

property inUserOperations#

determine if APS is in User Operations mode (boolean)

Use this property to configure ophyd Devices for direct or simulated hardware. See issue #49 (BCDA-APS/apstools#49) for details.

EXAMPLE:

APS = apstools.devices.ApsMachineParametersDevice(name="APS")

if APS.inUserOperations:
    suspend_APS_current = bluesky.suspenders.SuspendFloor(APS.current, 2, resume_thresh=10)
    RE.install_suspender(suspend_APS_current)
else:
    # use pseudo shutter controls and no current suspenders
    pass
operator_messages#

alias of ApsOperatorMessagesDevice

class apstools.devices.aps_machine.ApsOperatorMessagesDevice(*args: Any, **kwargs: Any)[source]#

Bases: Device

General messages from the APS main control room.

APS undulator#

ApsUndulator(*args, **kwargs)

APS Undulator

ApsUndulatorDual(*args, **kwargs)

APS Undulator with upstream and downstream controls

class apstools.devices.aps_undulator.ApsUndulator(*args: Any, **kwargs: Any)[source]#

Bases: Device

APS Undulator

EXAMPLE:

undulator = ApsUndulator("ID09ds:", name="undulator")
tracking#

alias of TrackingSignal

class apstools.devices.aps_undulator.ApsUndulatorDual(*args: Any, **kwargs: Any)[source]#

Bases: Device

APS Undulator with upstream and downstream controls

EXAMPLE:

undulator = ApsUndulatorDual("ID09", name="undulator")

note:: the trailing : in the PV prefix should be omitted

downstream#

alias of ApsUndulator

upstream#

alias of ApsUndulator

Axis Tuner#

AxisTunerException

Exception during execution of AxisTunerBase subclass

AxisTunerMixin(*args, **kwargs)

Mixin class to provide tuning capabilities for an axis

exception apstools.devices.axis_tuner.AxisTunerException[source]#

Bases: ValueError

Exception during execution of AxisTunerBase subclass

add_note()#

Exception.add_note(note) – add a note to the exception

with_traceback()#

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class apstools.devices.axis_tuner.AxisTunerMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

Mixin class to provide tuning capabilities for an axis

See the TuneAxis() example in this jupyter notebook: BCDA-APS/apstools

HOOK METHODS

There are two hook methods (pre_tune_method(), and post_tune_method()) for callers to add additional plan parts, such as opening or closing shutters, setting detector parameters, or other actions.

Each hook method must accept a single argument: an axis object such as EpicsMotor or SynAxis, such as:

def my_pre_tune_hook(axis):
    yield from bps.mv(shutter, "open")
def my_post_tune_hook(axis):
    yield from bps.mv(shutter, "close")

class TunableSynAxis(AxisTunerMixin, SynAxis): pass

myaxis = TunableSynAxis(name="myaxis")
mydet = SynGauss('mydet', myaxis, 'myaxis', center=0.21, Imax=0.98e5, sigma=0.127)
myaxis.tuner = TuneAxis([mydet], myaxis)
myaxis.pre_tune_method = my_pre_tune_hook
myaxis.post_tune_method = my_post_tune_hook

def tune_myaxis():
    yield from myaxis.tune(md={"plan_name": "tune_myaxis"})

RE(tune_myaxis())
_default_post_tune_method()[source]#

called after tune()

_default_pre_tune_method()[source]#

called before tune()

Ophyd definitions for digital delay and pulse generators.

class apstools.devices.delay.DG645Delay(*args: Any, **kwargs: Any)[source]#

Bases: Device

An SRS DG-645 digial delay/pulse generator.

This device has four delayed outputs: AB, CD, EF, GH.

Configuration of the output parameters (e.g. amplitude, polarity) is done using components output_AB, etc. The individual delays for the start and end of the output pulse are configured using individual channels channel_A etc.

There is also a T0 output which is the reference pulses used for the remaining delayed outputs.

autoip_state#

alias of EpicsSignalWithIO

bare_socket_state#

alias of EpicsSignalWithIO

burst_count#

alias of EpicsSignalWithIO

burst_delay#

alias of EpicsSignalWithIO

burst_mode#

alias of EpicsSignalWithIO

burst_period#

alias of EpicsSignalWithIO

channel_A#

alias of DG645Channel

channel_B#

alias of DG645Channel

channel_C#

alias of DG645Channel

channel_D#

alias of DG645Channel

channel_E#

alias of DG645Channel

channel_F#

alias of DG645Channel

channel_G#

alias of DG645Channel

channel_H#

alias of DG645Channel

dhcp_state#

alias of EpicsSignalWithIO

gateway#

alias of EpicsSignalWithIO

gpib_address#

alias of EpicsSignalWithIO

gpib_state#

alias of EpicsSignalWithIO

ip_address#

alias of EpicsSignalWithIO

lan_state#

alias of EpicsSignalWithIO

network_mask#

alias of EpicsSignalWithIO

output_AB#

alias of DG645DelayOutput

output_CD#

alias of DG645DelayOutput

output_EF#

alias of DG645DelayOutput

output_GH#

alias of DG645DelayOutput

output_T0#

alias of DG645Output

serial_baud#

alias of EpicsSignalWithIO

serial_state#

alias of EpicsSignalWithIO

static_ip_state#

alias of EpicsSignalWithIO

telnet_state#

alias of EpicsSignalWithIO

trigger_advanced_mode#

alias of EpicsSignalWithIO

trigger_holdoff#

alias of EpicsSignalWithIO

trigger_inhibit#

alias of EpicsSignalWithIO

trigger_level#

alias of EpicsSignalWithIO

trigger_prescale#

alias of EpicsSignalWithIO

trigger_rate#

alias of EpicsSignalWithIO

trigger_source#

alias of EpicsSignalWithIO

vxi11_state#

alias of EpicsSignalWithIO

Mixin to add EPICS .DESC field#

EpicsDescriptionMixin(*args, **kwargs)

add a record's description field to a Device, such as EpicsMotor

class apstools.devices.description_mixin.EpicsDescriptionMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

add a record’s description field to a Device, such as EpicsMotor

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsDescriptionMixin

class MyEpicsMotor(EpicsDescriptionMixin, EpicsMotor): pass

m1 = MyEpicsMotor('xxx:m1', name='m1')
print(m1.desc.get())

more ideas:

class TunableSynAxis(AxisTunerMixin, SynAxis):
    '''synthetic axis that can be tuned'''

class TunableEpicsMotor(AxisTunerMixin, EpicsMotor):
    '''EpicsMotor that can be tuned'''

class EpicsMotorWithDescription(EpicsDescriptionMixin, EpicsMotor):
    '''EpicsMotor with description field'''

class EpicsMotorWithMore(
    EpicsDescriptionMixin,
    EpicsMotorLimitsMixin,
    EpicsMotorDialMixin,
    EpicsMotorRawMixin,
    EpicsMotor
):
    '''
    EpicsMotor with more fields

    * description (``desc``)
    * soft motor limits (``soft_limit_hi``, ``soft_limit_lo``)
    * dial coordinates (``dial``)
    * raw coordinates (``raw``)
    '''

DictionaryDevice#

Create an ophyd Device defined by a dictionary so that a simple dictionary can be recorded in a bluesky data stream.

dict_device_factory([data])

Create a DictionaryDevice class using the supplied dictionary.

make_dict_device(obj[, name])

Make recordable DictionaryDevice instance from dictionary.

apstools.devices.dict_device_support.dict_device_factory(data={})[source]#

Create a DictionaryDevice class using the supplied dictionary.

apstools.devices.dict_device_support.make_dict_device(obj, name='ddev')[source]#

Make recordable DictionaryDevice instance from dictionary.

New in release 1.6.4.

class apstools.devices.epics_scan_id_signal.EpicsScanIdSignal(*args: Any, **kwargs: Any)[source]#

Bases: EpicsSignal

Use an EPICS PV as the source of the RunEngine’s scan_id.

Uses a writable EPICS integer PV (such as longout record).

EXAMPLE:

scan_id = EpicsScanIdDevice("ioc:scan_id:longout", name="scan_id")
# ...
RE = bluesky.RunEngine({}, scan_id_source=scan_id.cb_scan_id_source)

(new in release 1.6.3)

cb_scan_id_source(*args, **kwargs)[source]#

Callback function for RunEngine. Returns next scan_id to be used.

  • Get current scan_id from PV.

  • Apply lower limit of zero.

  • Increment.

  • Set PV with new value.

  • Return new value.

Eurotherm 2216e Temperature Controller#

The 2216e is a temperature controller from Eurotherm.

Eurotherm2216e(*args, **kwargs)

Eurotherm 2216e Temperature Controller

According to their website, the Eurotherm 2216e Temperature Controller [1] is obsolete. Please see [its] replacement EPC3016 [2] in our EPC3000 Series. [3]

New in apstools 1.6.0.

class apstools.devices.eurotherm_2216e.Eurotherm2216e(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

Eurotherm 2216e Temperature Controller

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_sensor(*args, **kwargs)[source]#

units: Convert dC from sensor to C

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.hhl_slits.HHLSlits(*args: Any, **kwargs: Any)[source]#

Bases: Device

High Heat Load Slit.

There are no independent parts to move, so each axis only has center and size.

Based on the 25-ID-A whitebeam slits.

The motor parameters listed below specify which motor records control which axis. The last piece of the PV prefix will be removed, and the motor number added on. For example, if the prefix is “255ida:slits:US:”, and the pitch motor is “255ida:slits:m3”, then pitch_motor should be “m3”.

Parameters#

prefix:

EPICS prefix required to communicate with HHL Slit IOC, ex: “25ida:slits:US:”

pitch_motor:

The motor record suffix controlling the real pitch motor, ex “m3”

yaw_motor:

The motor record suffix controlling the real yaw motor, ex “m4”

horizontal_motor:

The motor record suffix controlling the real horizontal motor, ex: “m1”

diagonal_motor:

The motor record suffix controlling the real diagonal motor, ex: “m2”

class SlitAxis(*args: Any, **kwargs: Any)[source]#

Bases: Device

h#

alias of SlitAxis

v#

alias of SlitAxis

Kohzu double-crystal monochromator#

KohzuSeqCtl_Monochromator(*args, **kwargs)

synApps Kohzu double-crystal monochromator sequence control program

class apstools.devices.kohzu_monochromator.KohzuSeqCtl_Monochromator(*args: Any, **kwargs: Any)[source]#

Bases: Device

synApps Kohzu double-crystal monochromator sequence control program

calibrate_energy(value)[source]#

Calibrate the monochromator energy.

PARAMETERS

value: float

New energy for the current monochromator position.

energy#

alias of KohzuSoftPositioner

theta#

alias of KohzuSoftPositioner

wavelength#

alias of KohzuSoftPositioner

class apstools.devices.kohzu_monochromator.KohzuSoftPositioner(*args: Any, **kwargs: Any)[source]#

Bases: PVPositioner

_setup_move(position)[source]#

Move and do not wait until motion is complete (asynchronous).

cb_done(*args, **kwargs)[source]#

Called when parent’s done signal changes (EPICS CA monitor event).

cb_setpoint(*args, **kwargs)[source]#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force done=False. For any move, done must transition to != done_value, then back to done_value. Next update will refresh value from parent device.

property inposition#

Report (boolean) if positioner is done.

move(*args, **kwargs)[source]#

Reposition, with optional wait for completion.

LabJack Data Acquisition (DAQ)#

LabJackBase(*args, **kwargs)

A labjack T-series data acquisition unit (DAQ).

Ophyd definitions for Labjack T-series data acquisition devices.

Supported devices, all inherit from LabJackBase:

  • T4

  • T7

  • T7Pro

  • T8

These devices are based on EPICS LabJack module R3.0. The EPICS IOC database changed significantly from R2 to R3 when the module was rewritten to use the LJM library.

There are definitions for the entire LabJack device, as well as the various inputs/outputs available on the LabJack T-series. Individual inputs can be used as part of other devices. Assuming analog input 5 is connected to a gas flow meter:

from ophyd import Component as Cpt
from apstools.devices import labjack

class MyBeamline(Device):
    ...
    gas_flow = Cpt(labjack.AnalogInput, "LabJackT7_1:Ai5")
class apstools.devices.labjack.AnalogInput(*args: Any, **kwargs: Any)[source]#

Bases: Input

An analog input on a labjack device.

It is based on the synApps input record, but with LabJack specific signals added.

The .trigger() method will retrieve a fresh value using the .PROC field, though based on how EPICS support works, this is likely just the most recently polled value from the device. This can be useful if the .SCAN field is set to passive.

class apstools.devices.labjack.AnalogOutput(*args: Any, **kwargs: Any)[source]#

Bases: Output

An analog output on a labjack device.

class apstools.devices.labjack.DigitalIO(*args: Any, **kwargs: Any)[source]#

Bases: Device

A digital input/output channel on the labjack.

Because of the how the records are structured in EPICS, the prefix must not include the “Bi{N}” portion of the prefix. Instead, the prefix should be prefix for the whole labjack (e.g. LabJackT7_1:), and the channel number should be provided using the ch_num property. So for the digital I/O with its input available at PV LabJackT7_1:Bi3, use:

dio3 = DigitalIO("LabJackT7_1:", name="dio3", ch_num=3)

This will create signals for the input (Bi3), output (Bo3), and direction (Bd3) records.

input#

alias of Input

output#

alias of BinaryOutput

class apstools.devices.labjack.LabJackBase(*args: Any, **kwargs: Any)[source]#

Bases: Device

A labjack T-series data acquisition unit (DAQ).

To use the individual components separately, consider using the corresponding devices in the list below.

This device contains signals for the following:

The number of inputs and digital outputs depends on the specific LabJack T-series device being used. Therefore, the base device LabJackBase does not implement these I/O signals. Instead, consider using one of the subclasses, like LabJackT4.

The .trigger() method does not do much. To retrieve fresh values for analog inputs where .SCAN is passive, you will need to trigger the individual inputs themselves.

The waveform generator and waveform digitizer are included for convenience. Reading all the analog/digital inputs and outputs can be done by calling the .read() method. However, it is unlikely that the goal is also to trigger the digitizer and generator during this read. For this reason, the digitizer and generator have kind=”omitted”. To trigger the digitizer or generator, they can be used as separate devices:

lj = LabJackT4(...)

# Read a waveform from the digitizer
lj.waveform_digitizer.trigger().wait()
lj.waveform_digitizer.read()

# Same thing for the waveform generator
lj.waveform_generator.trigger().wait()
waveform_generator#

alias of WaveformGenerator

class apstools.devices.labjack.LabJackT4(*args: Any, **kwargs: Any)[source]#

Bases: LabJackBase

A labjack T-series data acquisition unit (DAQ).

To use the individual components separately, consider using the corresponding devices in the list below.

This device contains signals for the following:

The number of inputs and digital outputs depends on the specific LabJack T-series device being used. Therefore, the base device LabJackBase does not implement these I/O signals. Instead, consider using one of the subclasses, like LabJackT4.

The .trigger() method does not do much. To retrieve fresh values for analog inputs where .SCAN is passive, you will need to trigger the individual inputs themselves.

The waveform generator and waveform digitizer are included for convenience. Reading all the analog/digital inputs and outputs can be done by calling the .read() method. However, it is unlikely that the goal is also to trigger the digitizer and generator during this read. For this reason, the digitizer and generator have kind=”omitted”. To trigger the digitizer or generator, they can be used as separate devices:

lj = LabJackT4(...)

# Read a waveform from the digitizer
lj.waveform_digitizer.trigger().wait()
lj.waveform_digitizer.read()

# Same thing for the waveform generator
lj.waveform_generator.trigger().wait()
class WaveformDigitizer(*args: Any, **kwargs: Any)[source]#

Bases: WaveformDigitizer

waveform_digitizer#

alias of WaveformDigitizer

waveform_generator#

alias of WaveformGenerator

class apstools.devices.labjack.LabJackT7(*args: Any, **kwargs: Any)[source]#

Bases: LabJackBase

A labjack T-series data acquisition unit (DAQ).

To use the individual components separately, consider using the corresponding devices in the list below.

This device contains signals for the following:

The number of inputs and digital outputs depends on the specific LabJack T-series device being used. Therefore, the base device LabJackBase does not implement these I/O signals. Instead, consider using one of the subclasses, like LabJackT4.

The .trigger() method does not do much. To retrieve fresh values for analog inputs where .SCAN is passive, you will need to trigger the individual inputs themselves.

The waveform generator and waveform digitizer are included for convenience. Reading all the analog/digital inputs and outputs can be done by calling the .read() method. However, it is unlikely that the goal is also to trigger the digitizer and generator during this read. For this reason, the digitizer and generator have kind=”omitted”. To trigger the digitizer or generator, they can be used as separate devices:

lj = LabJackT4(...)

# Read a waveform from the digitizer
lj.waveform_digitizer.trigger().wait()
lj.waveform_digitizer.read()

# Same thing for the waveform generator
lj.waveform_generator.trigger().wait()
class WaveformDigitizer(*args: Any, **kwargs: Any)[source]#

Bases: WaveformDigitizer

waveform_digitizer#

alias of WaveformDigitizer

waveform_generator#

alias of WaveformGenerator

class apstools.devices.labjack.LabJackT7Pro(*args: Any, **kwargs: Any)[source]#

Bases: LabJackBase

A labjack T-series data acquisition unit (DAQ).

To use the individual components separately, consider using the corresponding devices in the list below.

This device contains signals for the following:

The number of inputs and digital outputs depends on the specific LabJack T-series device being used. Therefore, the base device LabJackBase does not implement these I/O signals. Instead, consider using one of the subclasses, like LabJackT4.

The .trigger() method does not do much. To retrieve fresh values for analog inputs where .SCAN is passive, you will need to trigger the individual inputs themselves.

The waveform generator and waveform digitizer are included for convenience. Reading all the analog/digital inputs and outputs can be done by calling the .read() method. However, it is unlikely that the goal is also to trigger the digitizer and generator during this read. For this reason, the digitizer and generator have kind=”omitted”. To trigger the digitizer or generator, they can be used as separate devices:

lj = LabJackT4(...)

# Read a waveform from the digitizer
lj.waveform_digitizer.trigger().wait()
lj.waveform_digitizer.read()

# Same thing for the waveform generator
lj.waveform_generator.trigger().wait()
class WaveformDigitizer(*args: Any, **kwargs: Any)[source]#

Bases: WaveformDigitizer

waveform_digitizer#

alias of WaveformDigitizer

waveform_generator#

alias of WaveformGenerator

class apstools.devices.labjack.LabJackT8(*args: Any, **kwargs: Any)[source]#

Bases: LabJackBase

A labjack T-series data acquisition unit (DAQ).

To use the individual components separately, consider using the corresponding devices in the list below.

This device contains signals for the following:

The number of inputs and digital outputs depends on the specific LabJack T-series device being used. Therefore, the base device LabJackBase does not implement these I/O signals. Instead, consider using one of the subclasses, like LabJackT4.

The .trigger() method does not do much. To retrieve fresh values for analog inputs where .SCAN is passive, you will need to trigger the individual inputs themselves.

The waveform generator and waveform digitizer are included for convenience. Reading all the analog/digital inputs and outputs can be done by calling the .read() method. However, it is unlikely that the goal is also to trigger the digitizer and generator during this read. For this reason, the digitizer and generator have kind=”omitted”. To trigger the digitizer or generator, they can be used as separate devices:

lj = LabJackT4(...)

# Read a waveform from the digitizer
lj.waveform_digitizer.trigger().wait()
lj.waveform_digitizer.read()

# Same thing for the waveform generator
lj.waveform_generator.trigger().wait()
class WaveformDigitizer(*args: Any, **kwargs: Any)[source]#

Bases: WaveformDigitizer

waveform_digitizer#

alias of WaveformDigitizer

waveform_generator#

alias of WaveformGenerator

class apstools.devices.labjack.WaveformDigitizer(*args: Any, **kwargs: Any)[source]#

Bases: Device

A feature of the Labjack devices that allows waveform capture.

By itself, this device does not include any actual data. It should be sub-classed for the individual T-series devices to use make_digitizer_waveforms() to produce waveform signals based on the number of inputs, using the ophyd DynamicDeviceComponent.

class T7Digitizer(WaveformDigitizer):
    waveforms = DCpt(make_digitizer_waveforms(14), kind="normal")
class apstools.devices.labjack.WaveformGenerator(*args: Any, **kwargs: Any)[source]#

Bases: Device

A feature of the Labjack devices that generates output waveforms.

apstools.devices.labjack.make_digitizer_waveforms(num_ais: int)[source]#

Create a dictionary with volt waveforms for the digitizer.

For use with an ophyd DynamicDeviceComponent.

Each analog input on the labjack could be included here, and probably should be unless there is a specific reason not to.

Parameters#

num_ais

How many analog inputs to include for this Labjack device.

Lakeshore temperature controllers#

LakeShore336Device(*args, **kwargs)

LakeShore 336 temperature controller.

LakeShore340Device(*args, **kwargs)

LakeShore 340 temperature controller

class apstools.devices.lakeshore_controllers.LS340_LoopBase(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

Base settings for both sample and control loops.

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
pause()[source]#

Change setpoint to current position.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.lakeshore_controllers.LS340_LoopControl(*args: Any, **kwargs: Any)[source]#

Bases: LS340_LoopBase

Control specific

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
pause()#

Change setpoint to current position.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.lakeshore_controllers.LS340_LoopSample(*args: Any, **kwargs: Any)[source]#

Bases: LS340_LoopBase

Sample specific

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
pause()#

Change setpoint to current position.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.lakeshore_controllers.LakeShore336Device(*args: Any, **kwargs: Any)[source]#

Bases: Device

LakeShore 336 temperature controller.

  • loop 1: temperature positioner AND heater, PID, & ramp controls

  • loop 2: temperature positioner AND heater, PID, & ramp controls

  • loop 3: temperature positioner

  • loop 4: temperature positioner

loop1#

alias of LakeShore336_LoopControl

loop2#

alias of LakeShore336_LoopControl

loop3#

alias of LakeShore336_LoopRO

loop4#

alias of LakeShore336_LoopRO

serial#

alias of AsynRecord

class apstools.devices.lakeshore_controllers.LakeShore336_LoopControl(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

LakeShore 336 temperature controller – with heater control.

The LakeShore 336 accepts up to two heaters.

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
pause()[source]#

Change setpoint to current position.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.lakeshore_controllers.LakeShore336_LoopRO(*args: Any, **kwargs: Any)[source]#

Bases: Device

LakeShore 336 temperature controller – Read-only loop (no heaters).

class apstools.devices.lakeshore_controllers.LakeShore340Device(*args: Any, **kwargs: Any)[source]#

Bases: Device

LakeShore 340 temperature controller

control#

alias of LS340_LoopControl

sample#

alias of LS340_LoopSample

serial#

alias of AsynRecord

Linkam temperature controllers#

Linkam_CI94_Device(*args, **kwargs)

Linkam model CI94 temperature controller

Linkam_T96_Device(*args, **kwargs)

Linkam model T96 temperature controller

class apstools.devices.linkam_controllers.Linkam_CI94_Device(*args: Any, **kwargs: Any)[source]#

Bases: Device

Linkam model CI94 temperature controller

EXAMPLE:

ci94 = Linkam_CI94_Device("IOC:ci94:", name="ci94")
temperature#

alias of PVPositionerSoftDoneWithStop

class apstools.devices.linkam_controllers.Linkam_T96_Device(*args: Any, **kwargs: Any)[source]#

Bases: Device

Linkam model T96 temperature controller

EXAMPLE:

tc1 = Linkam_T96("IOC:tc1:", name="tc1")
temperature#

alias of T96Temperature

class apstools.devices.linkam_controllers.T96Temperature(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

Measurement Computing TC-32 Thermocouple reader#

The TC-32 thermocouple module [4] is part of the EPICS measComp [5] module. The module documentation [6] shows a GUI screen with basic display of the 32 thermocouple channels and the various digital (binary) I/O bits.

new in apstools release 1.6.14

Public class(es)

MeasCompTc32(*args, **kwargs)

Measurement Computing TC-32 32-channel Thermocouple reader.

Internal class(es)

_MC_TC32_BaseClass(*args, **kwargs)

Base class for I/O interface classes below.

Tc32BinaryInput(*args, **kwargs)

Binary input channel of a MeasComp TC-32 device.

Tc32BinaryOutput(*args, **kwargs)

Binary output channel of a MeasComp TC-32 device.

Tc32ThermocoupleChannel(*args, **kwargs)

Thermocouple channel of a MeasComp TC-32 device.

_channels(dev_class, channel_list)

Create the channels for the I/O interface.

class apstools.devices.measComp_tc32_support.MeasCompTc32(*args: Any, **kwargs: Any)[source]#

Bases: Device

Measurement Computing TC-32 32-channel Thermocouple reader.

class apstools.devices.measComp_tc32_support.Tc32BinaryInput(*args: Any, **kwargs: Any)[source]#

Bases: _MC_TC32_BaseClass

Binary input channel of a MeasComp TC-32 device.

  • EPICS support: measComp/Db/measCompBinaryIn.template

  • Users will not need to call this class directly.

class apstools.devices.measComp_tc32_support.Tc32BinaryOutput(*args: Any, **kwargs: Any)[source]#

Bases: _MC_TC32_BaseClass

Binary output channel of a MeasComp TC-32 device.

  • EPICS support: measComp/Db/measCompBinaryOut.template

  • Users will not need to call this class directly.

class apstools.devices.measComp_tc32_support.Tc32ThermocoupleChannel(*args: Any, **kwargs: Any)[source]#

Bases: _MC_TC32_BaseClass

Thermocouple channel of a MeasComp TC-32 device.

  • EPICS support: measComp/Db/measCompTemperatureIn.template

  • Users will not need to call this class directly.

class apstools.devices.measComp_tc32_support._MC_TC32_BaseClass(*args: Any, **kwargs: Any)[source]#

Bases: Device

Base class for I/O interface classes below.

Enables a common apstools.devices.measComp_tc32_support._channels() function to work for all the interfaces.

Users will not need to call this class directly.

apstools.devices.measComp_tc32_support._channels(dev_class, channel_list)[source]#

Create the channels for the I/O interface.

Measurement Computing USB-CTR 8-Channel Scaler#

Measurement Computing CTR High-Speed Counter/Timer Device

https://www.farnell.com/datasheets/3795358.pdf

There is more to this device than just the 8-channel scaler. Underlying support: epics-modules/measComp

The EPICS support provides for an optional scaler, compatible with the EPICS scaler record.

new in apstools release 1.6.18

Public class(es)

MeasCompCtr(*args, **kwargs)

Measurement Computing USB CTR08 high-speed counter/timer.

MeasCompCtrMcs(*args, **kwargs)

Measurement Computing USB CTR08 Multi-Channel Scaler Controls.

Internal class(es)

MeasCompCtrDeviceCounterChannel(*args, **kwargs)

Measurement Computing USB CTR08 Pulse Counter channel.

MeasCompCtrDevicePulseGenChannel(*args, **kwargs)

Measurement Computing USB CTR08 Pulse Generator channel.

class apstools.devices.measComp_usb_ctr_support.MeasCompCtr(*args: Any, **kwargs: Any)[source]#

Bases: Device

Measurement Computing USB CTR08 high-speed counter/timer.

counter_1#

alias of MeasCompCtrDeviceCounterChannel

counter_2#

alias of MeasCompCtrDeviceCounterChannel

counter_3#

alias of MeasCompCtrDeviceCounterChannel

counter_4#

alias of MeasCompCtrDeviceCounterChannel

counter_5#

alias of MeasCompCtrDeviceCounterChannel

counter_6#

alias of MeasCompCtrDeviceCounterChannel

counter_7#

alias of MeasCompCtrDeviceCounterChannel

counter_8#

alias of MeasCompCtrDeviceCounterChannel

pulse_gen_1#

alias of MeasCompCtrDevicePulseGenChannel

pulse_gen_2#

alias of MeasCompCtrDevicePulseGenChannel

pulse_gen_3#

alias of MeasCompCtrDevicePulseGenChannel

pulse_gen_4#

alias of MeasCompCtrDevicePulseGenChannel

class apstools.devices.measComp_usb_ctr_support.MeasCompCtrDeviceCounterChannel(*args: Any, **kwargs: Any)[source]#

Bases: Device

Measurement Computing USB CTR08 Pulse Counter channel.

class apstools.devices.measComp_usb_ctr_support.MeasCompCtrDevicePulseGenChannel(*args: Any, **kwargs: Any)[source]#

Bases: Device

Measurement Computing USB CTR08 Pulse Generator channel.

class apstools.devices.measComp_usb_ctr_support.MeasCompCtrMcs(*args: Any, **kwargs: Any)[source]#

Bases: Device

Measurement Computing USB CTR08 Multi-Channel Scaler Controls.

Base class for Device Mixins#

DeviceMixinBase(*args, **kwargs)

Base class for apstools Device mixin classes

class apstools.devices.mixin_base.DeviceMixinBase(*args: Any, **kwargs: Any)[source]#

Bases: Device

Base class for apstools Device mixin classes

Mixin classes for Motor Devices#

EpicsMotorDialMixin(*args, **kwargs)

add motor record's dial coordinate fields to Device

EpicsMotorEnableMixin(*args, **kwargs)

mixin providing access to motor enable/disable

EpicsMotorLimitsMixin(*args, **kwargs)

add motor record HLM & LLM fields & compatibility get_lim() and set_lim()

EpicsMotorRawMixin(*args, **kwargs)

add motor record's raw coordinate fields to Device

EpicsMotorResolutionMixin(*args, **kwargs)

Add motor record's resolution fields to motor.

EpicsMotorServoMixin(*args, **kwargs)

add motor record's servo loop controls to Device

class apstools.devices.motor_mixins.EpicsMotorDialMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

add motor record’s dial coordinate fields to Device

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorDialMixin

class myEpicsMotor(EpicsMotorDialMixin, EpicsMotor): pass
m1 = myEpicsMotor('xxx:m1', name='m1')
print(m1.dial.read())
class apstools.devices.motor_mixins.EpicsMotorEnableMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

mixin providing access to motor enable/disable

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorEnableMixin

class MyEpicsMotor(EpicsMotorEnableMixin, EpicsMotor): ...

m1 = MyEpicsMotor('xxx:m1', name='m1')
print(m1.enabled)

In a bluesky plan:

yield from bps.mv(m1.enable_disable, m1.MOTOR_DISABLE)
# ... other activities
yield from bps.mv(m1.enable_disable, m1.MOTOR_ENABLE)
disable_motor()[source]#

BLOCKING call to disable motor axis

enable_motor()[source]#

BLOCKING call to enable motor axis

class apstools.devices.motor_mixins.EpicsMotorLimitsMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

add motor record HLM & LLM fields & compatibility get_lim() and set_lim()

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorLimitsMixin

class myEpicsMotor(EpicsMotorLimitsMixin, EpicsMotor): pass
m1 = myEpicsMotor('xxx:m1', name='m1')
lo = m1.get_lim(-1)
hi = m1.get_lim(1)
m1.set_lim(-25, -5)
print(m1.get_lim(-1), m1.get_lim(1))
m1.set_lim(lo, hi)
get_lim(flag)[source]#

Returns the user limit of motor

  • flag > 0: returns high limit

  • flag < 0: returns low limit

  • flag == 0: returns None

Similar with SPEC command

set_lim(low, high)[source]#

Sets the low and high limits of motor

  • No action taken if motor is moving.

  • Low limit is set to lesser of (low, high)

  • High limit is set to greater of (low, high)

Similar with SPEC command

class apstools.devices.motor_mixins.EpicsMotorRawMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

add motor record’s raw coordinate fields to Device

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorRawMixin

class myEpicsMotor(EpicsMotorRawMixin, EpicsMotor): pass
m1 = myEpicsMotor('xxx:m1', name='m1')
print(m1.raw.read())
class apstools.devices.motor_mixins.EpicsMotorResolutionMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

Add motor record’s resolution fields to motor.

Usually, a facility will not provide such high-level access to calibration parameters since these are associated with fixed parameters of hardware. For simulators, it is convenient to provide access so that default settings (typically low-resolution) from the IOC can be changed as part of the device setup in bluesky.

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorResolutionMixin

class myEpicsMotor(EpicsMotorResolutionMixin, EpicsMotor): pass
m1 = myEpicsMotor('xxx:m1', name='m1')
print(f"resolution={m1.resolution.read()}")
print(f"steps_per_rev={m1.steps_per_rev.read()}")
print(f"units_per_rev={m1.units_per_rev.read()}")
class apstools.devices.motor_mixins.EpicsMotorServoMixin(*args: Any, **kwargs: Any)[source]#

Bases: DeviceMixinBase

add motor record’s servo loop controls to Device

EXAMPLE:

from ophyd import EpicsMotor
from apstools.devices import EpicsMotorServoMixin

class myEpicsMotor(EpicsMotorServoMixin, EpicsMotor): pass
m1 = myEpicsMotor('xxx:m1', name='m1')
print(m1.servo.read())

PVPositioner that computes done as a soft signal.

PVPositionerSoftDone(*args, **kwargs)

PVPositioner that computes done as a soft signal.

PVPositionerSoftDoneWithStop(*args, **kwargs)

PVPositionerSoftDone with stop() and inposition.

class apstools.devices.positioner_soft_done.PVPositionerSoftDone(*args: Any, **kwargs: Any)[source]#

Bases: PVPositioner

PVPositioner that computes done as a soft signal.

PARAMETERS

prefixstr, optional

The device prefix used for all sub-positioners. This is optional as it may be desirable to specify full PV names for PVPositioners.

readback_pvstr, optional

PV prefix of the readback signal. Disregarded if readback attribute is created.

setpoint_pvstr, optional

PV prefix of the setpoint signal. Disregarded if setpoint attribute is created.

tolerancefloat, optional

Motion tolerance. The motion is considered done when:

abs(readback-setpoint) <= tolerance

Defaults to 10^(-1*precision), where precision = setpoint.precision.

update_targetbool

True when this object update the target Component directly. Use False if the target Component will be updated externally, such as by the controller when target is an EpicsSignal. Defaults to True.

kwargs :

Passed to ophyd.PVPositioner

ATTRIBUTES

setpointSignal

The setpoint (request) signal

readbackSignal or None

The readback PV (e.g., encoder position PV)

actuateSignal or None

The actuation PV to set when movement is requested

actuate_valueany, optional

The actuation value, sent to the actuate signal when motion is requested

stop_signalSignal or None

The stop PV to set when motion should be stopped

stop_valueany, optional

The value sent to stop_signal when a stop is requested

targetSignal

The target value of a move request.

Override (in subclass) with EpicsSignal to connect with a PV.

In some controllers (such as temperature controllers), the setpoint may be changed incrementally towards this target value (such as a ramp or controlled trajectory). In such cases, the target will be final value while setpoint will be the current desired position.

Otherwise, both setpoint and target will be set to the same value.

(new in apstools 1.5.3)

_setup_move(position)[source]#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)[source]#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)[source]#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()[source]#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
class apstools.devices.positioner_soft_done.PVPositionerSoftDoneWithStop(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDone

PVPositionerSoftDone with stop() and inposition.

The stop() method sets the setpoint to the immediate readback value (only when inposition is True). This stops the positioner at the current position.

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
stop(*, success=False)[source]#

Hold the current readback when stop() is called and not inposition().

Generalized ophyd Device base class for preamplifiers.

PreamplifierBaseDevice(*args, **kwargs)

Generalized interface (base class) for preamplifiers.

class apstools.devices.preamp_base.PreamplifierBaseDevice(*args: Any, **kwargs: Any)[source]#

Bases: Device

Generalized interface (base class) for preamplifiers.

All subclasses of PreamplifierBaseDevice must define how to update the gain with the correct value from the amplifier. An example is SRS570_PreAmplifier.

See:

BCDA-APS/apstools#544

PTC10 Programmable Temperature Controller#

The PTC10 is a programmable temperature controller from SRS (Stanford Research Systems). The PTC10 is a modular system consisting of a base unit and provision for addition of add-on boards.

A single, complete ophyd.Device subclass will not describe all variations that could be installed. But the add-on boards each allow standardization. Each installation must build a custom class that matches their hardware configuration. The APS USAXS instrument has created a custom class based on the ophyd.PVPositioner to use their PTC10 as a temperature positioner.

PTC10AioChannel(*args, **kwargs)

SRS PTC10 AIO module

PTC10RtdChannel(*args, **kwargs)

SRS PTC10 RTD module channel

PTC10TcChannel(*args, **kwargs)

SRS PTC10 Tc (thermocouple) module channel

PTC10PositionerMixin(*args, **kwargs)

Mixin so SRS PTC10 can be used as a (temperature) positioner.

see:

https://www.thinksrs.com/products/ptc10.html

EXAMPLE:

from ophyd import PVPositioner

class MyPTC10(PTC10PositionerMixin, PVPositioner):
    readback = Component(EpicsSignalRO, "2A:temperature", kind="hinted")
    setpoint = Component(EpicsSignalWithRBV, "5A:setPoint", kind="hinted")

    rtd = Component(PTC10RtdChannel, "3A:")
    pid = Component(PTC10AioChannel, "5A:")

ptc10 = MyPTC10("IOC_PREFIX:ptc10:", name="ptc10")
ptc10.report_dmov_changes.put(True)  # a diagnostic
ptc10.tolerance.put(1.0)  # done when |readback-setpoint|<=tolerance

New in apstools 1.5.3.

class apstools.devices.ptc10_controller.PTC10AioChannel(*args: Any, **kwargs: Any)[source]#

Bases: Device

SRS PTC10 AIO module

class apstools.devices.ptc10_controller.PTC10PositionerMixin(*args: Any, **kwargs: Any)[source]#

Bases: Device

Mixin so SRS PTC10 can be used as a (temperature) positioner.

cb_readback(*args, **kwargs)

Called when readback changes (EPICS CA monitor event).

cb_setpoint(*args, **kwargs)

Called when setpoint changes (EPICS CA monitor event).

inposition

Report (boolean) if positioner is done.

stop(*[, success])

Hold the current readback when the stop() method is called and not done.

cb_readback(*args, **kwargs)[source]#

Called when readback changes (EPICS CA monitor event).

cb_setpoint(*args, **kwargs)[source]#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force done=False. For any move, done MUST change to != done_value, then change back to done_value (True). Without this response, a small move (within tolerance) will not return. Next update of readback will compute self.done.

property inposition#

Report (boolean) if positioner is done.

stop(*, success=False)[source]#

Hold the current readback when the stop() method is called and not done.

class apstools.devices.ptc10_controller.PTC10RtdChannel(*args: Any, **kwargs: Any)[source]#

Bases: Device

SRS PTC10 RTD module channel

class apstools.devices.ptc10_controller.PTC10TcChannel(*args: Any, **kwargs: Any)[source]#

Bases: Device

SRS PTC10 Tc (thermocouple) module channel

Scaler support#

use_EPICS_scaler_channels(scaler)

configure scaler for only the channels with names assigned in EPICS

apstools.devices.scaler_support.use_EPICS_scaler_channels(scaler)[source]#

configure scaler for only the channels with names assigned in EPICS

Note: For ScalerCH, use scaler.select_channels(None) instead of this code. (Applies only to ophyd.scaler.ScalerCH in releases after 2019-02-27.)

Shutters#

ApsPssShutter(*args, **kwargs)

APS PSS shutter

ApsPssShutterWithStatus(*args, **kwargs)

APS PSS shutter with separate status PV

EpicsMotorShutter(*args, **kwargs)

Shutter, implemented with an EPICS motor moved between two positions

EpicsOnOffShutter(*args, **kwargs)

Shutter using a single EPICS PV moved between two positions

OneSignalShutter(*args, **kwargs)

Shutter Device using one Signal for open and close.

ShutterBase(*args, **kwargs)

Base class for all shutter Devices.

SimulatedApsPssShutterWithStatus(*args, **kwargs)

Simulated APS PSS shutter

class apstools.devices.shutters.ApsPssShutter(*args: Any, **kwargs: Any)[source]#

Bases: ShutterBase

APS PSS shutter

  • APS PSS shutters have separate bit PVs for open and close

  • set either bit, the shutter moves, and the bit resets a short time later

  • no indication that the shutter has actually moved from the bits (see ApsPssShutterWithStatus() for alternative)

Since there is no direct indication that a shutter has moved, the state property will always return unknown and the isOpen and isClosed properties will always return False.

A consequence of the unknown state is that the shutter will always be commanded to move (and wait the delay_s time), even if it is already at that position. This device could keep track of the last commanded position, but that is not guaranteed to be true since the shutter could be moved from other software.

The default delay_s has been set at 1.2 s to allow for shutter motion. Change this as desired. Advise if this default should be changed.

PARAMETERS

prefix

str : EPICS PV prefix

name

str : (kwarg, required) object’s canonical name

close_pv

str : (kwarg, optional) Name of EPICS PV to close the shutter. If None, defaults to "{prefix}Close".

open_pv

str : (kwarg, optional) Name of EPICS PV to open the shutter. If None, defaults to "{prefix}Open".

EXAMPLE:

shutter_a = ApsPssShutter("2bma:A_shutter:", name="shutter")
shutter_a.wait_for_connection()

shutter_a.open()
shutter_a.close()

shutter_a.set("open")
shutter_a.set("close")

When using the shutter in a plan, be sure to use yield from, such as:

def in_a_plan(shutter):
    yield from abs_set(shutter, "open", wait=True)
    # do something
    yield from abs_set(shutter, "close", wait=True)

RE(in_a_plan(shutter_a))

The strings accepted by set() are defined in two lists: valid_open_values and valid_close_values. These lists are treated (internally to set()) as lower case strings.

Example, add “o” & “x” as aliases for “open” & “close”:

shutter_a.addOpenValue(“o”) shutter_a.addCloseValue(“x”) shutter_a.set(“o”) shutter_a.set(“x”)

addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close(timeout=10)[source]#

request the shutter to close (timeout is ignored)

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open(timeout=10)[source]#

request the shutter to open (timeout is ignored)

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

class apstools.devices.shutters.ApsPssShutterWithStatus(*args: Any, **kwargs: Any)[source]#

Bases: ApsPssShutter

APS PSS shutter with separate status PV

  • APS PSS shutters have separate bit PVs for open and close

  • set either bit, the shutter moves, and the bit resets a short time later

  • a separate status PV tells if the shutter is open or closed (see ApsPssShutter() for alternative)

PARAMETERS

prefix

str : EPICS PV prefix

state_pv

str : Name of EPICS PV that provides shutter’s current state.

name

str : (kwarg, required) object’s canonical name

EXAMPLE:

A_shutter = ApsPssShutterWithStatus(
    "2bma:A_shutter:",
    "PA:02BM:STA_A_FES_OPEN_PL",
    name="A_shutter")
B_shutter = ApsPssShutterWithStatus(
    "2bma:B_shutter:",
    "PA:02BM:STA_B_SBS_OPEN_PL",
    name="B_shutter")
A_shutter.wait_for_connection()
B_shutter.wait_for_connection()

A_shutter.open()
A_shutter.close()

or

A_shutter.set("open")
A_shutter.set("close")

When using the shutter in a plan, be sure to use yield from.

def in_a_plan(shutter):

yield from abs_set(shutter, “open”, wait=True) # do something yield from abs_set(shutter, “close”, wait=True)

RE(in_a_plan(A_shutter))

addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close(timeout=10)[source]#

request the shutter to close

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open(timeout=10)[source]#

request the shutter to open

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

wait_for_state(target, timeout=10, poll_s=0.01)[source]#

wait for the PSS state to reach a desired target

PARAMETERS

(kwarg, optional) Name of EPICS PV to close the shutter. If None, defaults to "{prefix}Close".

target

[str] : list of strings containing acceptable values

timeout

non-negative number : (kwarg, optional) Maximum amount of time (seconds) to wait for PSS state to reach target. If None, defaults to 10.

poll_s

non-negative number : (kwarg, optional) Time to wait (seconds) in first polling cycle. After first poll, this will be increased by _poll_factor_ up to a maximum time of _poll_s_max_. If None, defaults to 0.01.

class apstools.devices.shutters.EpicsMotorShutter(*args: Any, **kwargs: Any)[source]#

Bases: OneSignalShutter

Shutter, implemented with an EPICS motor moved between two positions

PARAMETERS

prefix

str : EPICS PV prefix

name

str : (kwarg, required) object’s canonical name

EXAMPLE:

tomo_shutter = EpicsMotorShutter("2bma:m23", name="tomo_shutter")
tomo_shutter.wait_for_connection()
tomo_shutter.close_value = 1.0      # default
tomo_shutter.open_value = 0.0       # default
tomo_shutter.tolerance = 0.01       # default
tomo_shutter.open()
tomo_shutter.close()

# or, when used in a plan
def planA():
    yield from abs_set(tomo_shutter, "open", group="O")
    yield from wait("O")
    yield from abs_set(tomo_shutter, "close", group="X")
    yield from wait("X")
def planA():
    yield from abs_set(tomo_shutter, "open", wait=True)
    yield from abs_set(tomo_shutter, "close", wait=True)
def planA():
    yield from mv(tomo_shutter, "open")
    yield from mv(tomo_shutter, "close")
addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close()[source]#

move motor to BEAM BLOCKED position, interactive use

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open()[source]#

move motor to BEAM NOT BLOCKED position, interactive use

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

class apstools.devices.shutters.EpicsOnOffShutter(*args: Any, **kwargs: Any)[source]#

Bases: OneSignalShutter

Shutter using a single EPICS PV moved between two positions

Use for a shutter controlled by a single PV which takes a value for the close command and a different value for the open command. The current position is determined by comparing the value of the control with the expected open and close values.

PARAMETERS

prefix

str : EPICS PV prefix

name

str : (kwarg, required) object’s canonical name

EXAMPLE:

bit_shutter = EpicsOnOffShutter("2bma:bit1", name="bit_shutter")
bit_shutter.wait_for_connection()
bit_shutter.close_value = 0      # default
bit_shutter.open_value = 1       # default
bit_shutter.open()
bit_shutter.close()

# or, when used in a plan
def planA():
    yield from mv(bit_shutter, "open")
    yield from mv(bit_shutter, "close")
addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close()#

BLOCKING: request shutter to close, called by set()

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open()#

BLOCKING: request shutter to open, called by set()

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

class apstools.devices.shutters.OneSignalShutter(*args: Any, **kwargs: Any)[source]#

Bases: ShutterBase

Shutter Device using one Signal for open and close.

PARAMETERS

signal

EpicsSignal or Signal : (override in subclass) The signal is the comunication to the hardware. In a subclass, the hardware may have more than one communication channel to use. See the ApsPssShutter as an example.

name

str : (kwarg, required) object’s canonical name

See ShutterBase for more parameters.

EXAMPLE

Create a simulated shutter:

shutter = OneSignalShutter(name=”shutter”)

open the shutter (interactively):

shutter.open()

Check the shutter is open:

In [144]: shutter.isOpen Out[144]: True

Use the shutter in a Bluesky plan. Set a post-move delay time of 1.0 seconds. Be sure to use yield from, such as:

def in_a_plan(shutter):
    shutter.delay_s = 1.0
    t0 = time.time()
    print("Shutter state: " + shutter.state, time.time()-t0)
    yield from bps.abs_set(shutter, "open", wait=True)    # wait for completion is optional
    print("Shutter state: " + shutter.state, time.time()-t0)
    yield from bps.mv(shutter, "open")    # do it again
    print("Shutter state: " + shutter.state, time.time()-t0)
    yield from bps.mv(shutter, "close")    # ALWAYS waits for completion
    print("Shutter state: " + shutter.state, time.time()-t0)

RE(in_a_plan(shutter))

which gives this output:

Shutter state: close 1.7642974853515625e-05 Shutter state: open 1.0032124519348145 Shutter state: open 1.0057861804962158 Shutter state: close 2.009695529937744

The strings accepted by set() are defined in two lists: valid_open_values and valid_close_values. These lists are treated (internally to set()) as lower case strings.

Example, add “o” & “x” as aliases for “open” & “close”:

shutter.addOpenValue(“o”) shutter.addCloseValue(“x”) shutter.set(“o”) shutter.set(“x”)

addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close()[source]#

BLOCKING: request shutter to close, called by set()

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open()[source]#

BLOCKING: request shutter to open, called by set()

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

class apstools.devices.shutters.ShutterBase(*args: Any, **kwargs: Any)[source]#

Bases: Device

Base class for all shutter Devices.

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

valid_open_values

[str] : A list of lower-case text values that are acceptable for use with the set() command to open the shutter.

valid_close_values

[str] : A list of lower-case text values that are acceptable for use with the set() command to close the shutter.

open_value

number : The actual value to send to open signal to open the shutter. (default = 1)

close_value

number : The actual value to send to close signal to close the shutter. (default = 0)

delay_s

float : time to wait (s) after move is complete, does not wait if shutter already in position (default = 0)

busy

Signal : (internal) tells if a move is in progress

unknown_state

str : (constant) Text reported by state when not open or closed. cannot move to this position (default = “unknown”)

name

str : (kwarg, required) object’s canonical name

addCloseValue(text)[source]#

a synonym to close the shutter, use with set()

addOpenValue(text)[source]#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close()[source]#

BLOCKING: request shutter to close, called by set().

Must implement in subclass of ShutterBase()

EXAMPLE:

if not self.isClosed:
    self.signal.put(self.close_value)
    if self.delay_s > 0:
        time.sleep(self.delay_s)    # blocking call OK here
inPosition(target)[source]#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)[source]#

ensure any given value is a lower-case string

open()[source]#

BLOCKING: request shutter to open, called by set().

Must implement in subclass of ShutterBase()

EXAMPLE:

if not self.isOpen:
    self.signal.put(self.open_value)
    if self.delay_s > 0:
        time.sleep(self.delay_s)    # blocking call OK here
set(value, **kwargs)[source]#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

returns open, close, or unknown

Must implement in subclass of ShutterBase()

EXAMPLE:

if self.signal.get() == self.open_value:
    result = self.valid_open_values[0]
elif self.signal.get() == self.close_value:
    result = self.valid_close_values[0]
else:
    result = self.unknown_state
return result
validTarget(target, should_raise=True)[source]#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

class apstools.devices.shutters.SimulatedApsPssShutterWithStatus(*args: Any, **kwargs: Any)[source]#

Bases: ApsPssShutterWithStatus

Simulated APS PSS shutter

PARAMETERS

prefix

str : EPICS PV prefix

name

str : (kwarg, required) object’s canonical name

EXAMPLE:

sim = SimulatedApsPssShutterWithStatus(name="sim")
addCloseValue(text)#

a synonym to close the shutter, use with set()

addOpenValue(text)#

a synonym to open the shutter, use with set()

property choices#

return list of acceptable choices for set()

close(timeout=10)#

request the shutter to close

inPosition(target)#

is the shutter at the target position?

property isClosed#

is the shutter closed?

property isOpen#

is the shutter open?

lowerCaseString(value)#

ensure any given value is a lower-case string

open(timeout=10)#

request the shutter to open

set(value, **kwargs)#

plan: request the shutter to open or close

PARAMETERS

value

str : any from self.choices (typically “open” or “close”)

kwargs

dict : ignored at this time

property state#

is shutter “open”, “close”, or “unknown”?

validTarget(target, should_raise=True)#

return whether (or not) target value is acceptable for self.set()

raise ValueError if not acceptable (default)

wait_for_state(target, timeout=10, poll_s=0.01)[source]#

wait for the PSS state to reach a desired target

PARAMETERS

target

[str] : list of strings containing acceptable values

timeout

non-negative number : Ignored in the simulation.

poll_s

non-negative number : Ignored in the simulation.

Simulate process controllers as positioners using EPICS records.

SimulatedSwaitControllerPositioner(*args, ...)

Simulated process controller as positioner with EPICS swait record.

SimulatedTransformControllerPositioner(...)

Simulated process controller as positioner with EPICS transform record.

class apstools.devices.simulated_controllers.SimulatedSwaitControllerPositioner(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

Simulated process controller as positioner with EPICS swait record.

The swait record completes the feedback loop, computing the next simulated controller reading.

Example with swait record:

controller = SimulatedSwaitControllerPositioner(
    "",
    name="controller",
    loop_pv="gp:userCalc1",
)
controller.wait_for_connection()
controller.setup(25)

setup(setpoint[, label, noise, period, ...])

Configure the swait record as a process controller.

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
loop#

alias of SwaitRecord

setup(setpoint, label='controller', noise=1, period='1 second', max_change=1, tolerance=1)[source]#

Configure the swait record as a process controller.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

class apstools.devices.simulated_controllers.SimulatedTransformControllerPositioner(*args: Any, **kwargs: Any)[source]#

Bases: PVPositionerSoftDoneWithStop

Simulated process controller as positioner with EPICS transform record.

The transform record completes the feedback loop, computing the next simulated controller reading and reporting if the readback is “in position”.

Example with transform record:

controller = SimulatedTransformControllerPositioner(
    "", name="controller", loop_pv="gp:userTran1",
)
controller.wait_for_connection()
controller.setup(25)

setup(setpoint[, label, noise, period, ...])

Configure the transform record as a process controller.

_setup_move(position)#

Move and do not wait until motion is complete (asynchronous)

cb_readback(*args, **kwargs)#

Called when readback changes (EPICS CA monitor event) or on-demand.

Responsible for determining _if_ the positioner is done moving. Since soft positioners have no such direct indication, computes if the positioner is in position (if a move is active).

cb_setpoint(*args, **kwargs)#

Called when setpoint changes (EPICS CA monitor event).

When the setpoint is changed, force`` done=False``. For any move, done must transition to != done_value, then back to done_value.

Without this response, a small move (within tolerance) will not return. The cb_readback() method will compute done.

Since other code will also call this method, check the keys in kwargs and do not react to the “wrong” signature.

cleanup()#

Clear subscriptions on exit.

property inposition#

Do readback and setpoint (both from cache) agree within tolerance?

Returns:

inposition = |readback - setpoint| <= tolerance
loop#

alias of TransformRecord

setup(setpoint, label='controller', noise=2, period='1 second', max_change=2, tolerance=1)[source]#

Configure the transform record as a process controller.

stop(*, success=False)#

Hold the current readback when stop() is called and not inposition().

Ophyd support for Stanford Research Systems 570 preamplifier from synApps

Public Structures

SRS570_PreAmplifier(*args, **kwargs)

Ophyd support for Stanford Research Systems 570 preamplifier from synApps.

This device connects with the SRS570 support from synApps. (epics-modules/ip)

The SRS570 synApps support is part of the ip module: https://htmlpreview.github.io/?https://raw.githubusercontent.com/epics-modules/ip/R3-6-1/documentation/swaitRecord.html

see:

epics-modules/ip

class apstools.devices.srs570_preamplifier.GainSignal(*args: Any, **kwargs: Any)[source]#

Bases: EpicsSignal

A signal where the settling time depends on the pre-amp gain.

Used to introduce a specific settle time when setting to account for the amp’s RC relaxation time when changing gain.

set(value, *, timeout=ophyd.signal.DEFAULT_WRITE_TIMEOUT, settle_time='auto')[source]#

Set the value of the Signal and return a Status object.

If put completion is used for this EpicsSignal, the status object will complete once EPICS reports the put has completed.

Otherwise the readback will be polled until equal to the set point (as in Signal.set)

Parameters#

valueany

The gain value.

timeoutfloat, optional

Maximum time to wait.

settle_time: float, optional

Delay after set() has completed to indicate completion to the caller. If "auto" (default), a reasonable settle time will be chosen based on the gain mode of the pre-amp.

Returns#

st : Status

See also

  • Signal.set

  • EpicsSignal.set

class apstools.devices.srs570_preamplifier.SRS570_PreAmplifier(*args: Any, **kwargs: Any)[source]#

Bases: PreamplifierBaseDevice

Ophyd support for Stanford Research Systems 570 preamplifier from synApps.

cb_gain(*args, **kwargs)[source]#

Called when sensitivity changes (EPICS CA monitor event).

property computed_gain#

Amplifier gain (A/V), as floating-point number.

gain_mode#

alias of GainSignal

sensitivity_unit#

alias of GainSignal

sensitivity_value#

alias of GainSignal

set_all#

alias of GainSignal

apstools.devices.srs570_preamplifier.calculate_settle_time(gain_value: int, gain_unit: int, gain_mode: str)[source]#

Determine the best settle time for a given combination of parameters.

Parameters can be strings of indexes.

Struck 3820#

Struck3820(*args, **kwargs)

Struck/SIS 3820 Multi-Channel Scaler (as used by USAXS)

class apstools.devices.struck3820.Struck3820(*args: Any, **kwargs: Any)[source]#

Bases: Device

Struck/SIS 3820 Multi-Channel Scaler (as used by USAXS)

Synthetic pseudo-Voigt function#

EXAMPLES:

Simple example of SynPseudoVoigt().#
1from apstools.devices import SynPseudoVoigt
2from ophyd.sim import motor
3det = SynPseudoVoigt('det', motor, 'motor',
4    center=0, eta=0.5, scale=1, sigma=1, bkg=0)
5
6# scan the "det" peak with the "motor" positioner
7# RE(bp.scan([det], motor, -2, 2, 41))
Example of SynPseudoVoigt() with randomized values.#
 1import numpy as np
 2from apstools.devices import SynPseudoVoigt
 3synthetic_pseudovoigt = SynPseudoVoigt(
 4    'synthetic_pseudovoigt', m1, 'm1',
 5    center=-1.5 + 0.5*np.random.uniform(),
 6    eta=0.2 + 0.5*np.random.uniform(),
 7    sigma=0.001 + 0.05*np.random.uniform(),
 8    scale=1e5,
 9    bkg=0.01*np.random.uniform())
10
11# scan the "synthetic_pseudovoigt" peak with the "m1" positioner
12# RE(bp.scan([synthetic_pseudovoigt], m1, -2, 0, 219))

SynPseudoVoigt(*args, **kwargs)

Evaluate a point on a pseudo-Voigt based on the value of a motor.

class apstools.devices.synth_pseudo_voigt.SynPseudoVoigt(*args: Any, **kwargs: Any)[source]#

Bases: SynSignal

Evaluate a point on a pseudo-Voigt based on the value of a motor.

Provides a signal to be measured. Acts like a detector.

See:

https://en.wikipedia.org/wiki/Voigt_profile

PARAMETERS

name str :

name of detector signal

motor positioner :

The independent coordinate

motor_field str :

name of motor

center float :

(optional) location of maximum value, default=0

eta float :

(optional) 0 <= eta < 1.0: Lorentzian fraction, default=0.5

scale float :

(optional) scale >= 1 : scale factor, default=1

sigma float :

(optional) sigma > 0 : width, default=1

bkg float :

(optional) bkg >= 0 : constant background, default=0

noise "poisson" or "uniform" or None :

Add noise to the result.

noise_multiplier float :

Only relevant for ‘uniform’ noise. Multiply the random amount of noise by ‘noise_multiplier’

randomize_parameters(scale=100000, bkg=0.01)[source]#

Set random parameters. -1 <= center < 1, 0.001 <= sigma < 0.051, 95k <= scale <= 105k

Tracking Signal for Device coordination#

TrackingSignal(*args, **kwargs)

Non-EPICS signal for use when coordinating Device actions.

class apstools.devices.tracking_signal.TrackingSignal(*args: Any, **kwargs: Any)[source]#

Bases: Signal

Non-EPICS signal for use when coordinating Device actions.

Signal to decide if undulator will be tracked while changing the monochromator energy.

check_value(value)[source]#

Check if the value is a boolean.

RAISES

ValueError

XIA PF4 Filters#

Pf4FilterSingle(*args, **kwargs)

XIA PF4 Filter: one set of 4 filters (A).

Pf4FilterDual(*args, **kwargs)

XIA PF4 Filter: two sets of 4 filters (A, B).

Pf4FilterTriple(*args, **kwargs)

XIA PF4 Filter: three sets of 4 filters (A, B, C).

Pf4FilterCommon(*args, **kwargs)

XIA PF4 filters - common support.

Pf4FilterBank(*args, **kwargs)

A single module of XIA PF4 filters (4-blades).

DualPf4FilterBox(*args, **kwargs)

LEGACY (use Pf4FilterDual now): Dual (Al, Ti) Xia PF4 filter boxes

class apstools.devices.xia_pf4.DualPf4FilterBox(*args: Any, **kwargs: Any)[source]#

Bases: Device

LEGACY (use Pf4FilterDual now): Dual (Al, Ti) Xia PF4 filter boxes

Support from synApps (using Al, Ti foils)

EXAMPLE:

pf4 = DualPf4FilterBox("2bmb:pf4:", name="pf4")
pf4_AlTi = DualPf4FilterBox("9idcRIO:pf4:", name="pf4_AlTi")
class apstools.devices.xia_pf4.Pf4FilterBank(*args: Any, **kwargs: Any)[source]#

Bases: Device

A single module of XIA PF4 filters (4-blades).

EXAMPLES:

pf4B = Pf4FilterBank("ioc:pf4:", name="pf4B", bank="B")

# -or-

class MyTriplePf4(Pf4FilterCommon):
    A = Component(Pf4FilterBank, "", bank="A")
    B = Component(Pf4FilterBank, "", bank="B")
    C = Component(Pf4FilterBank, "", bank="C")

pf4 = MyTriplePf4("ioc:pf4:", name="pf4")
See:

epics-modules/optics

class apstools.devices.xia_pf4.Pf4FilterCommon(*args: Any, **kwargs: Any)[source]#

Bases: Device

XIA PF4 filters - common support.

Use Pf4FilterCommon to build support for a configuration of PF4 filters (such as 3 or 4 filter banks).

EXAMPLE:

class MyTriplePf4(Pf4FilterCommon):
    A = Component(Pf4FilterBank, "", bank="A")
    B = Component(Pf4FilterBank, "", bank="B")
    C = Component(Pf4FilterBank, "", bank="C")

pf4 = MyTriplePf4("ioc:pf4:", name="pf4")
See:

epics-modules/optics

class apstools.devices.xia_pf4.Pf4FilterDual(*args: Any, **kwargs: Any)[source]#

Bases: Pf4FilterSingle

XIA PF4 Filter: two sets of 4 filters (A, B).

A#

alias of Pf4FilterBank

B#

alias of Pf4FilterBank

class apstools.devices.xia_pf4.Pf4FilterSingle(*args: Any, **kwargs: Any)[source]#

Bases: Pf4FilterCommon

XIA PF4 Filter: one set of 4 filters (A).

A#

alias of Pf4FilterBank

class apstools.devices.xia_pf4.Pf4FilterTriple(*args: Any, **kwargs: Any)[source]#

Bases: Pf4FilterDual

XIA PF4 Filter: three sets of 4 filters (A, B, C).

A#

alias of Pf4FilterBank

B#

alias of Pf4FilterBank

C#

alias of Pf4FilterBank

XIA Slit from EPICS synApps optics: xia_slit.db#

Coordinates (viewing from detector towards source):

    top
inb     out
    bot

Each blade [7] (in the XIA slit controller) travels in a _cylindrical_ coordinate system. Positive motion moves a blade outwards from the center with a backlash correction. No backlash correction is applied for negative motion (as the blades close). Size and center are computed by the underlying EPICS support.

hsize = inb + out vsize = top + bot

USAGE:

slit = XiaSlitController(“IOC:hsc1:”, name=”slit”) print(slit.geometry)

XiaSlit2D(*args, **kwargs)

EPICS synApps optics xia_slit.db 2D support: inb out bot top ...

class apstools.devices.xia_slit.XiaSlit2D(*args: Any, **kwargs: Any)[source]#

Bases: Device

EPICS synApps optics xia_slit.db 2D support: inb out bot top …

bot#

alias of PVPositionerSoftDone

property geometry#

Return the slit 2D size and center as a namedtuple.

hcenter#

alias of PVPositionerSoftDone

hsize#

alias of PVPositionerSoftDone

inb#

alias of PVPositionerSoftDone

out#

alias of PVPositionerSoftDone

top#

alias of PVPositionerSoftDone

vcenter#

alias of PVPositionerSoftDone

vsize#

alias of PVPositionerSoftDone