Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 0.10 docs #700

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
},
"remote.autoForwardPorts": false,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
}
Expand All @@ -38,7 +39,7 @@
},
"features": {
// add in eternal history and other bash features
"ghcr.io/diamondlightsource/devcontainer-features/bash-config:1.0.0": {}
"ghcr.io/diamondlightsource/devcontainer-features/bash-config:1": {}
},
// Create the config folder for the bash-config feature
"initializeCommand": "mkdir -p ${localEnv:HOME}/.config/bash-config",
Expand Down
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Contribute to the project
# How to contribute to the project

Contributions and issues are most welcome! All issues and pull requests are
handled through [GitHub](https://github.com/bluesky/ophyd-async/issues). Also, please check for any existing issues before
Expand Down
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ Asynchronous Bluesky hardware abstraction code, compatible with control systems
| Documentation | <https://bluesky.github.io/ophyd-async> |
| Releases | <https://github.com/bluesky/ophyd-async/releases> |

Ophyd-async is a Python library for asynchronously interfacing with hardware, intended to
be used as an abstraction layer that enables experiment orchestration and data acquisition code to operate above the specifics of particular devices and control
systems.
Ophyd-async is a Python library for asynchronously interfacing with hardware, intended to be used as an abstraction layer that enables experiment orchestration and data acquisition code to operate above the specifics of particular devices and control systems.

Both ophyd and ophyd-async are typically used with the [Bluesky Run Engine][] for experiment orchestration and data acquisition.
Both ophyd sync and ophyd-async are typically used with the [Bluesky Run Engine][] for experiment orchestration and data acquisition.

While [EPICS][] is the most common control system layer that ophyd-async can interface with, support for other control systems like [Tango][] will be supported in the future. The focus of ophyd-async is:
The main differences from ophyd sync are:

* Asynchronous signal access, opening the possibility for hardware-triggered scanning (also known as fly-scanning)
* Simpler instantiation of devices (groupings of signals) with less reliance upon complex class hierarchies
- Asynchronous Signal access, simplifying the parallel control of multiple Signals
- Support for [EPICS][] PVA and [Tango][] as well as the traditional EPICS CA
- Better library support for splitting the logic from the hardware interface to avoid complex class heirarchies

It was written with the aim of implementing flyscanning in a generic and extensible way with highly customizable devices like PandABox and the Delta Tau PMAC products. Using async code makes it possible to do the "put 3 PVs in parallel, then get from another PV" logic that is common in flyscanning without the performance and complexity overhead of multiple threads.

Devices from both ophyd sync and ophyd-async can be used in the same RunEngine and even in the same scan. This allows a per-device migration where devices are reimplemented in ophyd-async one by one.

[Bluesky Run Engine]: http://blueskyproject.io/bluesky
[EPICS]: http://www.aps.anl.gov/epics/
Expand Down
5 changes: 5 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* allow a wider screen so we can fit 88 chars of source code on it */
.bd-page-width {
max-width: 100rem;
/* default is 88rem */
}
5 changes: 0 additions & 5 deletions docs/_templates/custom-module-template.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
.. note::

Ophyd async is considered experimental until the v1.0 release and
may change API on minor release numbers before then

{{ ('``' + fullname + '``') | underline }}

{%- set filtered_members = [] %}
Expand Down
41 changes: 25 additions & 16 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
https://www.sphinx-doc.org/en/master/usage/configuration.html
"""

import os
import sys
from pathlib import Path
from subprocess import check_output
from typing import TypeVar

import requests

import ophyd_async

# -- General configuration ------------------------------------------------
sys.path.insert(0, os.path.abspath("../../src"))
# Override location of typevars just for sphinx
for k in ophyd_async.core.__all__:
v = getattr(ophyd_async.core, k)
if isinstance(v, TypeVar):
v.__module__ = "ophyd_async.core"

# General information about the project.
project = "ophyd-async"
copyright = "2014, Brookhaven National Lab"
Expand Down Expand Up @@ -61,7 +65,6 @@
"IPython.sphinxext.ipython_console_highlighting",
"matplotlib.sphinxext.plot_directive",
"myst_parser",
"numpydoc",
]

# So we can use the ::: syntax
Expand All @@ -72,23 +75,24 @@

# If true, Sphinx will warn about all references where the target cannot
# be found.
# nitpicky = True
nitpicky = True

# A list of (type, target) tuples (by default empty) that should be ignored when
# generating warnings in "nitpicky mode". Note that type should include the
# domain name if present. Example entries would be ('py:func', 'int') or
# ('envvar', 'LD_LIBRARY_PATH').
nitpick_ignore = [
# builtins
("py:class", "NoneType"),
("py:class", "'str'"),
("py:class", "'float'"),
("py:class", "'int'"),
("py:class", "'bool'"),
("py:class", "'object'"),
("py:class", "'id'"),
# typing
("py:class", "typing_extensions.Literal"),
("py:class", "ophyd_async.core._utils.T"),
# # builtins
# ("py:class", "NoneType"),
# ("py:class", "'str'"),
# ("py:class", "'float'"),
# ("py:class", "'int'"),
# ("py:class", "'bool'"),
# ("py:class", "'object'"),
# ("py:class", "'id'"),
# # typing
# ("py:class", "typing_extensions.Literal"),
]

# Order the members by the order they appear in the source code
Expand All @@ -98,7 +102,7 @@
autodoc_inherit_docstrings = False

# Add some more modules to the top level autosummary
ophyd_async.__all__ += ["sim", "epics", "tango", "fastcs", "plan_stubs"]
ophyd_async.__all__ += ["sim", "epics", "tango", "fastcs", "plan_stubs", "testing"]

# Document only what is in __all__
autosummary_ignore_module_all = False
Expand Down Expand Up @@ -137,6 +141,7 @@
"numpy": ("https://numpy.org/devdocs/", None),
"databroker": ("https://blueskyproject.io/databroker/", None),
"event-model": ("https://blueskyproject.io/event-model/main", None),
"pytest": ("https://docs.pytest.org/en/stable/", None),
}

# A dictionary of graphviz graph attributes for inheritance diagrams.
Expand Down Expand Up @@ -230,6 +235,10 @@
html_logo = "images/ophyd-async-logo.svg"
html_favicon = "images/ophyd-favicon.svg"

# Custom CSS
html_static_path = ["_static"]
html_css_files = ["custom.css"]

# If False and a module has the __all__ attribute set, autosummary documents
# every member listed in __all__ and no others. Default is True
autosummary_ignore_module_all = False
Expand Down
37 changes: 0 additions & 37 deletions docs/examples/epics_demo.py

This file was deleted.

2 changes: 1 addition & 1 deletion docs/examples/tango_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import bluesky.plans as bp
from bluesky import RunEngine

from ophyd_async.tango.sim import (
from ophyd_async.tango.demo import (
DemoCounter,
DemoMover,
TangoDetector,
Expand Down
36 changes: 36 additions & 0 deletions docs/explanations/declarative-vs-procedural.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Declarative vs Procedural Devices

Ophyd async has two styles of creating Devices, Declarative and Procedural. This article describes why there are two mechanisms for building Devices, and looks at the pros and cons of each style.

## Procedural style

The procedural style mirrors how you would create a traditional python class, you define an `__init__` method, add some class members, then call the superclass `__init__` method. In the case of ophyd async those class members are likely to be Signals and other Devices. For example, in the `ophyd_async.sim.SimMotor` we create its soft signal children in an `__init__` method:
```{literalinclude} ../../src/ophyd_async/sim/_motor.py
:start-after: class SimMotor
:end-before: def set_name
```
It is explicit and obvious, but verbose. It also allows you to embed arbitrary python logic in the creation of signals, so is required for making soft signals and DeviceVectors with contents based on an argument passed to `__init__`. It also allows you to use the [](#StandardReadable.add_children_as_readables) context manager which can save some typing.

## Declarative style

The declarative style mirrors how you would create a pydantic `BaseModel`. You create type hints to tell the base class what type of object you create, add annotations to tell it some parameters on how to create it, then the base class `__init__` will introspect and create them. For example, in the `ophyd_async.fastcs.panda.PulseBlock` we define the members we expect, and the baseclass will introspect the selected FastCS transport (EPICS IOC or Tango Device Server) and connect them, adding any extras that are published:
```{literalinclude} ../../src/ophyd_async/fastcs/panda/_block.py
:pyobject: PulseBlock
```
For a traditional EPICS IOC there is no such introspection mechanism, so we require a PV Suffix to be supplied via an [annotation](#typing.Annotated). For example, in `ophyd_async.epics.demo.DemoPointDetectorChannel` we describe the PV Suffix and whether the signal appears in `read()` or `read_configuration()` using [](#typing.Annotated):
```{literalinclude} ../../src/ophyd_async/epics/demo/_point_detector_channel.py
:pyobject: DemoPointDetectorChannel
```
It is compact and has the minimum amount of boilerplate, but is limited in its scope to what sorts of Signals and Devices the base class can create. It also requires the usage of a [](#StandardReadableFormat) for each Signal if using [](#StandardReadable) which may be more verbose than the procedural approach. It is best suited for introspectable FastCS and Tango devices, and repetitive EPICS Devices that are wrapped into larger Devices like areaDetectors.

## Grey area

There is quite a large segment of Devices that could be written both ways, for instance `ophyd_async.epics.demo.DemoMotor`. This could be written in either style with roughly the same legibility, so is a matter of taste:
```{literalinclude} ../../src/ophyd_async/epics/demo/_motor.py
:start-after: class DemoMotor
:end-before: def set_name
```

## Conclusion

Ophyd async supports both the declarative and procedural style, and is not prescriptive about which is used. In the end the decision is likely to come down to personal taste, and the style of the surrounding code.
67 changes: 67 additions & 0 deletions docs/explanations/design-goals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Design goals and differences with ophyd sync

Ophyd-async was designed to be a library for asynchronously interfacing with hardware. As such it fulfils the same role in the bluesky ecosystem as [ophyd sync](https://github.com/bluesky/ophyd): an abstraction layer that enables experiment orchestration and data acquisition code to operate above the specifics of particular devices and control systems. This document details the design goals and the differences with ophyd sync.

## Asynchronous Signal access

A fundamental part of ophyd-async is [](#asyncio). This allows lightweight and deterministic control of multiple signals, making it possible to do the "put 2 PVs in parallel, then get from another PV" logic that is common in flyscanning without the performance and complexity overhead of multiple threads.

For instance, the threaded version of the above looks something like this:
```python
def set_signal_thread(signal, value):
t = Thread(signal.set, value)
t.start()
return

def run():
t1 = set_signal_thread(signal1, value1)
t2 = set_signal_thread(signal2, value2)
t1.join()
t2.join()
value = signal3.get_value()
```
This gives the overhead of co-ordinating multiple OS threads, which requires events and locking for any more complicated example.

Compare to the asyncio version:
```python
async def run():
await asyncio.gather(
signal1.set(value1),
signal2.set(value2)
)
value = await signal3.get_value()
```
This runs in a single OS thread, but has predictable interrupt behavior, allowing for a much more readable linear flow.

```{seealso}
[](../how-to/interact-with-signals.md) for examples of the helpers that are easier to write with asyncio.
```

## Support for CA, PVA, Tango

As well as the tradition EPICS Channel Access, ophyd-async was written to allow other Control system protocols, like EPICS PV Access and Tango. An ophyd-async [](#Signal) contains no control system specific logic, but takes a [](#SignalBackend) that it uses whenever it needs to talk to the control system. Likewise at the [](#Device) level, a [](#DeviceConnector) allows control systems to fulfil the type hints of [declarative devices](./declarative-vs-procedural.md).

```{seealso}
[](./devices-signals-backends.md) for more information on how these fit together, and [](../tutorials/implementing-devices.md) for examples of Devices in different control systems.
```

## Clean Device Definition

For highly customizable devices like [PandABox](https://quantumdetectors.com/products/pandabox) there are often different pieces of logic that can talk to the same underlying hardware interface. The Devices in ophyd-async are structured so that the logic and interface can be split, and thus can be cleanly organized via composition rather than inheritance.

## Ease the implementation of flyscanning

One of the major drivers for ophyd-async was to ease the implementation of flyscanning. A library of flyscanning helpers is being developed to aid such strategies as:
- Definition of scan paths via [ScanSpec](https://github.com/dls-controls/scanspec)
- PVT Trajectory scanning in [Delta Tau motion controllers](https://github.com/dls-controls/pmac)
- Position compare and capture using a [PandABox](https://quantumdetectors.com/products/pandabox)

These strategies will be ported from DLS's previous flyscanning software [Malcolm](https://github.com/dls-controls/pymalcolm) and improved to take advantage of the flexibility of bluesky's plan definitions.

```{seealso}
The documents on flyscanning in the [bluesky cookbook](http://blueskyproject.io/bluesky-cookbook/glossary/flyscanning.html)
```

## Parity and interoperativity with ophyd sync

Devices from both ophyd sync and ophyd-async can be used in the same RunEngine and even in the same scan. This allows a per-device migration where devices are reimplemented in ophyd-async one by one. Eventually ophyd sync will gain feature parity with ophyd sync, supporting [the same set of devices as ophyd](https://blueskyproject.io/ophyd/user/reference/builtin-devices.html)
57 changes: 0 additions & 57 deletions docs/explanations/design-goals.rst

This file was deleted.

Loading
Loading