or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

area-detectors.mdcore-framework.mdepics-integration.mdflyers-continuous-scanning.mdindex.mdmotors-positioners.mdsimulation-testing.mdspecialized-devices.md

index.mddocs/

0

# Ophyd

1

2

Ophyd is a comprehensive Python library that provides a high-level hardware abstraction layer for experiment orchestration and data acquisition systems, with particular emphasis on EPICS (Experimental Physics and Industrial Control System) control systems. It enables scientists and engineers to interact with diverse hardware devices through a unified interface featuring standardized methods like `trigger()`, `read()`, and `set()`, while abstracting away control system specifics.

3

4

## Package Information

5

6

- **Package Name**: ophyd

7

- **Language**: Python

8

- **Installation**: `pip install ophyd`

9

- **Documentation**: https://blueskyproject.io/ophyd

10

- **Version**: 1.11.0

11

12

## Core Imports

13

14

```python

15

import ophyd

16

```

17

18

Common imports for device creation and control:

19

20

```python

21

from ophyd import Device, Component, EpicsSignal, EpicsMotor

22

from ophyd import Signal, SignalRO, DerivedSignal, EpicsSignalNoValidation

23

from ophyd import ALL_COMPONENTS, Kind

24

from ophyd import setup_ophyd, set_handler

25

from ophyd.status import StatusBase, wait

26

```

27

28

For area detector functionality:

29

30

```python

31

from ophyd.areadetector import AreaDetector, SimDetector

32

from ophyd.areadetector.plugins import HDF5Plugin, ImagePlugin

33

```

34

35

## Basic Usage

36

37

```python

38

from ophyd import Device, Component, EpicsSignal, EpicsMotor

39

from ophyd.status import wait

40

41

# Define a custom device using Components

42

class MyDevice(Device):

43

temperature = Component(EpicsSignal, 'TEMP:PV')

44

pressure = Component(EpicsSignal, 'PRES:PV')

45

46

# Create device instance

47

device = MyDevice('MY:DEVICE:', name='my_device')

48

49

# Connect to hardware

50

device.wait_for_connection()

51

52

# Read all device values

53

reading = device.read()

54

print(reading)

55

56

# Use a positioner (motor)

57

motor = EpicsMotor('XF:28IDC:MOTOR1', name='motor1')

58

motor.wait_for_connection()

59

60

# Move motor and wait for completion

61

status = motor.set(10.0) # Move to position 10.0

62

wait(status) # Wait for move to complete

63

64

# Read motor position

65

current_pos = motor.position

66

print(f"Current position: {current_pos}")

67

```

68

69

## Architecture

70

71

Ophyd's design is built around several key concepts:

72

73

- **Device**: High-level objects that group related hardware components and provide coordinated operations

74

- **Signal**: Individual readable/writable values representing hardware channels or computed values

75

- **Component**: Building blocks that define the structure of devices and their relationships

76

- **Status**: Objects that track the progress of asynchronous operations like moves or acquisitions

77

- **Control Layer**: Abstraction over EPICS backends (pyepics, caproto, dummy) for different deployment needs

78

79

This architecture enables the creation of reusable, composable device definitions that can be shared across facilities and experiments while maintaining compatibility with the broader Bluesky ecosystem for automated data collection.

80

81

## Capabilities

82

83

### Core Framework

84

85

The foundational classes and interfaces that form the backbone of ophyd's device abstraction system, including device composition, signal management, and status tracking.

86

87

```python { .api }

88

class Device:

89

def __init__(self, prefix='', *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): ...

90

def read(self): ...

91

def describe(self): ...

92

def configure(self, d): ...

93

def read_configuration(self): ...

94

def describe_configuration(self): ...

95

def trigger(self): ...

96

def stage(self): ...

97

def unstage(self): ...

98

99

class Signal:

100

def __init__(self, *, name, value=0, timestamp=None, parent=None, kind='normal', tolerance=None, rtolerance=None, **kwargs): ...

101

def get(self, **kwargs): ...

102

def put(self, value, **kwargs): ...

103

def set(self, value, **kwargs): ...

104

def read(self): ...

105

def describe(self): ...

106

107

class Component:

108

def __init__(self, cls, suffix='', *, lazy=False, trigger_value=None, add_prefix=None, doc=None, kind='normal', **kwargs): ...

109

110

class StatusBase:

111

def __init__(self, *, timeout=None, settle_time=None): ...

112

@property

113

def done(self): ...

114

@property

115

def success(self): ...

116

def wait(self, timeout=None): ...

117

118

def wait(status, timeout=None, poll_period=0.05): ...

119

```

120

121

[Core Framework](./core-framework.md)

122

123

### EPICS Integration

124

125

Hardware control through EPICS process variables, providing the primary interface to laboratory instruments and control systems in scientific facilities.

126

127

```python { .api }

128

class EpicsSignal(Signal):

129

def __init__(self, read_pv, write_pv=None, *, pv_kw=None, put_complete=False, string=False, limits=False, auto_monitor=None, name=None, **kwargs): ...

130

131

class EpicsSignalRO(Signal):

132

def __init__(self, read_pv, *, pv_kw=None, string=False, limits=False, auto_monitor=None, name=None, **kwargs): ...

133

134

def set_cl(control_layer=None, *, pv_telemetry=False): ...

135

def get_cl(): ...

136

```

137

138

[EPICS Integration](./epics-integration.md)

139

140

### Motors and Positioners

141

142

Positioning devices including EPICS motors, software positioners, and pseudo positioners for coordinate transformations and multi-axis control.

143

144

```python { .api }

145

class EpicsMotor(Device):

146

def __init__(self, prefix='', *, name, settle_time=0.0, timeout=None, **kwargs): ...

147

def move(self, position, **kwargs): ...

148

def home(self, direction, **kwargs): ...

149

def stop(self, **kwargs): ...

150

@property

151

def position(self): ...

152

153

class PseudoPositioner(Device):

154

def __init__(self, prefix='', *, configuration_attrs=None, read_attrs=None, **kwargs): ...

155

def forward(self, pseudo_pos): ...

156

def inverse(self, real_pos): ...

157

158

class SoftPositioner(Device):

159

def __init__(self, *, name=None, **kwargs): ...

160

def move(self, position, **kwargs): ...

161

```

162

163

[Motors and Positioners](./motors-positioners.md)

164

165

### Area Detectors

166

167

Comprehensive support for 2D area detectors including cameras, plugins for data processing, file I/O, and triggering strategies for coordinated data acquisition.

168

169

```python { .api }

170

class AreaDetector(Device):

171

def __init__(self, prefix, *, name, **kwargs): ...

172

def stage(self): ...

173

def unstage(self): ...

174

def trigger(self): ...

175

176

class DetectorBase(Device):

177

def __init__(self, prefix, *, read_attrs=None, configuration_attrs=None, **kwargs): ...

178

179

# Camera classes for specific detector types

180

class SimDetectorCam(CamBase): ...

181

class AndorCam(CamBase): ...

182

class PerkinElmerCam(CamBase): ...

183

184

# Plugin classes for data processing

185

class HDF5Plugin(FilePlugin): ...

186

class TIFFPlugin(FilePlugin): ...

187

class ImagePlugin(PluginBase): ...

188

class StatsPlugin(PluginBase): ...

189

```

190

191

[Area Detectors](./area-detectors.md)

192

193

### Specialized Devices

194

195

Pre-built device classes for common laboratory instruments including scalers, multi-channel analyzers, and electrometers.

196

197

```python { .api }

198

class EpicsScaler(Device):

199

def __init__(self, prefix, *, name, **kwargs): ...

200

def stage(self): ...

201

def trigger(self): ...

202

203

class EpicsMCA(Device):

204

def __init__(self, prefix, *, name, **kwargs): ...

205

def erase(self): ...

206

def start(self): ...

207

def stop(self): ...

208

209

class QuadEM(Device):

210

def __init__(self, prefix, *, name, **kwargs): ...

211

def stage(self): ...

212

def trigger(self): ...

213

```

214

215

[Specialized Devices](./specialized-devices.md)

216

217

### Simulation and Testing

218

219

Mock devices and signals for testing, development, and offline work without requiring actual hardware connections.

220

221

```python { .api }

222

class SynSignal(Signal):

223

def __init__(self, *, name, func=None, **kwargs): ...

224

225

class SynAxis(Device):

226

def __init__(self, *, name, **kwargs): ...

227

def move(self, position, **kwargs): ...

228

229

class SynGauss(Device):

230

def __init__(self, name, motor, motor_field, center, Imax, sigma=1, noise='poisson', noise_multiplier=1, random_state=None, **kwargs): ...

231

232

class FakeEpicsSignal(Signal):

233

def __init__(self, read_pv, write_pv=None, **kwargs): ...

234

```

235

236

[Simulation and Testing](./simulation-testing.md)

237

238

### Flyers and Continuous Scanning

239

240

Interfaces for continuous scanning and fly scanning where data is collected while motors are in motion.

241

242

```python { .api }

243

class FlyerInterface:

244

def kickoff(self): ...

245

def complete(self): ...

246

def collect(self): ...

247

def describe_collect(self): ...

248

249

class MonitorFlyerMixin:

250

def kickoff(self): ...

251

def complete(self): ...

252

def collect(self): ...

253

```

254

255

[Flyers and Continuous Scanning](./flyers-continuous-scanning.md)

256

257

### Units and Conversions

258

259

Support for unit-aware signals and unit conversions.

260

261

```python { .api }

262

class UnitConversionDerivedSignal(DerivedSignal):

263

def __init__(self, derived_from, original_units, derived_units, **kwargs): ...

264

```

265

266

### Callbacks and Event Publishing

267

268

Event publishing for integration with data acquisition systems.

269

270

```python { .api }

271

class UidPublish:

272

def __init__(self, RE, stream_name='primary'): ...

273

274

class LastUidPublish:

275

def __init__(self, RE): ...

276

```

277

278

## Utility Functions

279

280

Device management and configuration utilities for connection handling, logging, and instance management.

281

282

```python { .api }

283

# Connection management

284

def wait_for_lazy_connection(): ...

285

def do_not_wait_for_lazy_connection(): ...

286

287

# Instance management

288

def register_instances_in_weakset(device_class): ...

289

def register_instances_keyed_on_name(device_class): ...

290

def select_version(name, version): ...

291

292

# Setup and configuration

293

def setup_ophyd(logger=None): ...

294

def set_handler(handler=None): ...

295

296

# Component utilities

297

def kind_context(kind): ...

298

ALL_COMPONENTS: frozenset # Set of all component classes

299

```

300

301

## Error Handling

302

303

Ophyd defines several exception types for different error conditions:

304

305

```python { .api }

306

class OpException(Exception): ...

307

class ReadOnlyError(OpException): ...

308

class LimitError(OpException): ...

309

class DisconnectedError(OpException): ...

310

class StatusTimeoutError(Exception): ...

311

class WaitTimeoutError(Exception): ...

312

```

313

314

Common error handling patterns:

315

316

```python

317

from ophyd.utils.errors import DisconnectedError, StatusTimeoutError

318

319

try:

320

status = device.set(new_value)

321

wait(status, timeout=10.0)

322

except DisconnectedError:

323

print("Device is not connected")

324

except StatusTimeoutError:

325

print("Operation timed out")

326

```

327

328

## Types

329

330

```python { .api }

331

from enum import IntFlag

332

333

class Kind(IntFlag):

334

"""Flags for indicating the kind of reading."""

335

omitted = 0b000

336

normal = 0b001

337

config = 0b010

338

hinted = 0b101

339

340

class Staged(Enum):

341

"""Enum for device staging states."""

342

no = 'no'

343

yes = 'yes'

344

partially = 'partially'

345

346

# Type aliases

347

Reading = Dict[str, Dict[str, Any]] # {'signal_name': {'value': val, 'timestamp': ts}}

348

Configuration = Dict[str, Dict[str, Any]] # Same structure as Reading

349

Description = Dict[str, Dict[str, Any]] # {'signal_name': {'dtype': 'number', 'shape': []}}

350

```