Asynchronous Acquisition

This section encompasses “fly scans,” “monitoring,” and in general handling data acquisition that is occurring at different rates.

Note

If you are here because you just want to “move two motors at once” or something in that category, you’re in luck: you don’t need anything as complex as what we present in this section. Read about multidimensional plans in the section on Plans.

In short, “flying” is for acquisition at high rates and “monitoring” is for acquisition at an irregular or slow rate. Monitoring does not guarantee that all readings will be captured; i.e. monitoring is lossy. It is susceptible to network glitches. But flying, by contract, is not lossy if correctly implementated.

Flying means: “Let the hardware take control, cache data externally, and then transfer all the data to the RunEngine at the end.” This is essential when the data acquisition rates are faster than the RunEngine or Python can go.

Note

As a point of reference, the RunEngine processes message at a rate of about 35k/s (not including any time added by whatever the message does).

In [3]: %timeit RE(Msg('null') for j in range(1000))
10 loops, best of 3: 26.8 ms per loop

Monitoring a means acquiring readings whenever a new reading is available, at a device’s natural update rate. For example, we might monitor background condition (e.g., beam current) on the side while executing the primary logic of a plan. The documents are generated in real time — not all at the end, like flying — so if the update rate is too high, monitoring can slow down the execution of the plan. As mentioned above, monitoring is also lossy: if network traffic is high, some readings may be missed.

Flying

In bluesky’s view, there are three steps to “flying” a device during a scan.

  1. Kickoff: Begin accumulating data. A ‘kickoff’ command completes once acquisition has successfully started.

  2. Complete: This step tells the device, “I am ready whenever you are ready.” If the device is just collecting until it is told to stop, it will report that it is ready immediately. If the device is executing some predetermined trajectory, it will finish before reporting ready.

  3. Collect: Finally, the data accumulated by the device is transferred to the RunEngine and processed like any other data.

To “fly” one or more “flyable” devices during a plan, bluesky provides a preprocessor <preprocessors>. It is available as a wrapper, fly_during_wrapper()

from ophyd.sim import det, flyer1, flyer2  # simulated hardware
from bluesky.plans import count
from bluesky.preprocessors import fly_during_wrapper

RE(fly_during_wrapper(count([det], num=5), [flyer1, flyer2]))

and as a decorator, fly_during_decorator().

from ophyd.sim import det, flyer1, flyer2  # simulated hardware
from bluesky.plans import count
from bluesky.preprocessors import fly_during_wrapper

# Define a new plan for future use.
fly_and_count = fly_during_decorator([flyer1, flyer2])(count)

RE(fly_and_count([det]))

Alternatively, if you are using Supplemental Data, simply append to or extend its list of flyers to kick off during every run:

from ophyd.sim import flyer1, flyer2

# Assume sd is an instance of the SupplementalData set up as
# descripted in the documentation linked above.
sd.flyers.extend([flyer1, flyer2])

They will be included with all plans until removed.

Monitoring

To monitor some device during a plan, bluesky provides a preprocessor <preprocessors>. It is available as a wrapper, monitor_during_wrapper()

from ophyd.sim import det, det1
from bluesky.plans import count
from bluesky.preprocessors import monitor_during_wrapper

# Record any updates from det1 while 'counting' det 5 times.
RE(monitor_during_wrapper(count([det], num=5), [det1]))

and as a decorator, monitor_during_decorator().

from ophyd.sim import det, det1
from bluesky.plans import count
from bluesky.preprocessors import monitor_during_wrapper

# Define a new plan for future use.
monitor_and_count = monitor_during_decorator([det1])(count)

RE(monitor_and_count([det]))

Alternatively, if you are using Supplemental Data, simply append to or extend its list of signals to monitor:

from ophyd.sim import det1

# Assume sd is an instance of the SupplementalData set up as
# descripted in the documentation linked above.
sd.monitors.append(det1)

They will be included with all plans until removed.