Skip to content

Commit 885b30d

Browse files
committed
f
1 parent 9aeb074 commit 885b30d

10 files changed

Lines changed: 474 additions & 445 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
related:
3+
- title: ScanArgument
4+
url: learn/scans/scanargument.md
5+
- title: GUI Config
6+
url: learn/scans/gui-config.md
7+
- title: Learn by Example
8+
url: learn/scans/learn-by-example.md
9+
---
10+
11+
# Argument Bundles
12+
13+
This page explains how scans can describe repeated positional input bundles when a normal fixed
14+
Python signature is not enough.
15+
16+
## The Scan Signature
17+
18+
In the current scan implementation, a scan definition is described largely by its `__init__`
19+
signature plus a few class attributes.
20+
21+
The scan server serializes that signature and publishes it to clients. The client then uses it to:
22+
23+
- expose the scan under `scans.<name>`
24+
- attach a live Python signature in IPython
25+
- validate kwargs and bundled positional inputs
26+
- resolve device-name strings to device objects when the annotations require that
27+
28+
This means the signature is no longer only local Python documentation. It is part of the runtime API
29+
contract between the scan server, the client, and GUIs.
30+
31+
## `arg_input` and `arg_bundle_size`
32+
33+
!!! tip
34+
`arg_input` and `arg_bundle_size` are special cases for scans with an undefined number of
35+
input arguments. Most scans developed in plugins do not need them.
36+
37+
If the number of input arguments is not fixed, the usual Python-style fixed signature is not enough.
38+
39+
For example, a line scan can work with any number of motors in parallel, so the scan cannot rely on
40+
one fixed positional argument layout in the way an ordinary Python function usually would.
41+
42+
In those cases, scans with repeated positional bundles declare those bundles explicitly.
43+
44+
For a line scan, that can look like this:
45+
46+
```py
47+
arg_input = {
48+
"device": DeviceBase,
49+
"start": float,
50+
"stop": float,
51+
}
52+
arg_bundle_size = {"bundle": 3, "min": 1, "max": None}
53+
```
54+
55+
`arg_bundle_size` then tells BEC how many positional values belong to one bundle and how many
56+
bundles are allowed.
57+
58+
This is what lets BEC validate a call such as:
59+
60+
```py
61+
scans.line_scan(dev.samx, -1, 1, dev.samy, -2, 2, steps=5, relative=False)
62+
```
63+
64+
without treating those positional arguments as an unstructured `*args` blob.
65+
66+
Rich input metadata for individual parameters is covered separately on
67+
[ScanArgument](scanargument.md).
68+
69+
## Reloading The Scan Server
70+
71+
If you add a new scan or change an existing scan class, the scan server must reload that Python code
72+
before the changes become available.
73+
74+
In practice, that means you should restart or reload the scan server after editing scan
75+
implementations. Otherwise the running server will continue using the old version of the scan.
76+
77+
## Next Step
78+
79+
After argument bundles, continue with [GUI Config](gui-config.md) to see how scans group inputs for
80+
graphical clients.
81+
82+
## What To Remember
83+
84+
!!! info "What to remember"
85+
- The serialized scan signature is part of the runtime API between the scan server, clients, and GUIs.
86+
- `arg_input` and `arg_bundle_size` define repeated positional bundles such as move targets or line-scan ranges.
87+
- `ScanArgument` covers rich metadata for individual inputs, while argument bundles describe repeated positional structure.
88+
- After changing scan code, the scan server must be reloaded or restarted.

docs/learn/scans/gui-config.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
related:
3+
- title: ScanArgument
4+
url: learn/scans/scanargument.md
5+
- title: Argument Bundles
6+
url: learn/scans/argument-bundles.md
7+
- title: Learn by Example
8+
url: learn/scans/learn-by-example.md
9+
---
10+
11+
# GUI Config
12+
13+
This page explains how scans can group their inputs for graphical clients through `gui_config`.
14+
15+
## What `gui_config` Does
16+
17+
`gui_config` describes how scan inputs should be grouped in graphical interfaces.
18+
19+
For example, a scan can group inputs under headings such as:
20+
21+
- `Device`
22+
- `Movement Parameters`
23+
- `Acquisition Parameters`
24+
25+
This does not change how the scan runs. It helps GUIs present scan inputs in a clear structure
26+
instead of showing one flat list of parameters.
27+
28+
## A Typical Example
29+
30+
```py
31+
gui_config = {
32+
"Device 1": ["motor1", "start_motor1", "stop_motor1"],
33+
"Device 2": ["motor2", "start_motor2", "stop_motor2"],
34+
"Movement Parameters": ["step", "relative"],
35+
"Acquisition Parameters": [
36+
"exp_time",
37+
"frames_per_trigger",
38+
"settling_time",
39+
"readout_time",
40+
],
41+
}
42+
```
43+
44+
In this example, the scan definition is still the same Python class and the same Python signature.
45+
`gui_config` only changes how that information is grouped and presented in graphical clients.
46+
47+
## How It Fits With Scan Signatures
48+
49+
`gui_config` does not replace the scan signature or `ScanArgument` metadata.
50+
51+
Instead, these pieces work together:
52+
53+
- the signature defines which inputs exist
54+
- `ScanArgument` enriches individual inputs with labels, units, bounds, and descriptions
55+
- `gui_config` groups those inputs into a clearer layout for GUIs
56+
57+
This is why `gui_config` is best thought of as presentation metadata rather than execution logic.
58+
59+
## Reloading The Scan Server
60+
61+
If you add a new scan or change an existing scan class, the scan server must reload that Python code
62+
before the changes become available.
63+
64+
In practice, that means you should restart or reload the scan server after editing scan
65+
implementations. Otherwise the running server will continue using the old version of the scan.
66+
67+
## Next Step
68+
69+
If you want to see `gui_config` and related scan-definition details in a richer real scan, read the
70+
[worked example: hexagonal scan](hexagonal-scan-example.md).
71+
72+
## What To Remember
73+
74+
!!! info "What to remember"
75+
- `gui_config` groups scan inputs for graphical clients.
76+
- It changes presentation, not scan execution.
77+
- `gui_config` works alongside the scan signature and `ScanArgument` metadata.
78+
- After changing scan code, the scan server must be reloaded or restarted.

docs/learn/scans/learn-by-example.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ related:
1212
url: learn/scans/scan-info.md
1313
- title: ScanArgument
1414
url: learn/scans/scanargument.md
15-
- title: Scan Definition Info
16-
url: learn/scans/scan-definition-info.md
15+
- title: GUI Config
16+
url: learn/scans/gui-config.md
1717
---
1818

1919
# Learn by Example

docs/learn/scans/motions.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
related:
3+
- title: Scan Lifecycle
4+
url: learn/scans/lifecycle.md
5+
- title: Scan Components
6+
url: learn/scans/scan-components.md
7+
- title: Argument Bundles
8+
url: learn/scans/argument-bundles.md
9+
---
10+
11+
# Motions
12+
13+
In BEC, a scan does not have to acquire detector data.
14+
15+
A coordinated motion can also be treated as a scan if it uses the same lifecycle, reporting model,
16+
and request interface as other scans. That is why commands such as `mv` and `umv` are implemented
17+
with the same scan framework even though their main job is to reposition motors.
18+
19+
This allows motion-only commands to benefit from the scan infrastructure:
20+
21+
- it can reuse the same argument handling and validation
22+
- it can publish status in the same general format
23+
- it can use the same actions and components helpers
24+
- it can fit naturally into the same client and server model as other scan-like operations
25+
26+
## Marking A Motion-Only Command
27+
28+
There are two flags that a scan can set to indicate that it is not a data-taking scan:
29+
- `is_scan=False` indicates that the operation is not a scan, so it should be kept separate from ordinary scan entries in user interfaces.
30+
- `scan_type=None` indicates that the operation is neither hardware-triggered nor software-triggered, so it should not be confused with acquisition scans.
31+
32+
## `move` and `updated_move`
33+
34+
Both `move` and `updated_move` are motion commands implemented through the scan interface.
35+
36+
They accept repeated motor/target bundles, support relative motion, and run through the same hook
37+
structure as other scans.
38+
39+
They are exposed as `scans.mv` and `scans.umv` or through the high-level-interface as
40+
41+
- `umv` for `scans.umv(..., relative=False)`
42+
- `umvr` for `scans.umv(..., relative=True)`
43+
- `mv` for `scans.mv(..., relative=False)`
44+
- `mvr` for `scans.mv(..., relative=True)`
45+
46+
## The Shared Lifecycle
47+
48+
Even though this command is motion-only, it still defines the same lifecycle hooks:
49+
50+
- `prepare_scan`
51+
- `open_scan`
52+
- `stage`
53+
- `pre_scan`
54+
- `scan_core`
55+
- `post_scan`
56+
- `unstage`
57+
- `close_scan`
58+
- `on_exception`
59+
60+
In motion-only scans, most lifecycle hooks are kept empty or very simple. In particular, `scan_core` is the main place where the motion logic lives.
61+
62+
## What To Remember
63+
64+
!!! info "What to remember"
65+
- In BEC, a scan does not have to acquire data to use the scan framework.
66+
- Coordinated motions such as `move` and `updated_move` can use the same lifecycle and reporting model as scans.
67+
- Motion-only commands can still reuse argument bundles, actions, components, and scan status reporting.
68+
- To mark a motion-only command, set `is_scan=False` and `scan_type=None` in the scan class.
69+
- Lifecycle hooks must be defined, but they can be kept simple or empty if they are not needed.

0 commit comments

Comments
 (0)