In this notebook you will:
count
and scan
.Recommend Prerequisites:
Below, we will connect to EPICS IOC(s) controlling simulated hardware in lieu of actual motors and detectors. An EPICS IOC is control system software that allows communication with a wide variety of hardware using a common interface. The IOCs should already be running in the background. Run this command to verify that they are running: it should produce output with RUNNING on each line. In the event of a problem, edit this command to replace status
with restart all
and run again.
%matplotlib widget
!supervisorctl -c supervisor/supervisord.conf status
%run scripts/beamline_configuration.py
# aliases for convenience/readability
motor = motor_ph
det = ph
Check that we can communicate with the hardware. If this doesn't raise an error, it worked.
det.wait_for_connection()
In the example below, the Bluesky run engine is the interpreter of experiment plans and count
is an experiment plan used here to acquire one reading from a point detector.
from bluesky.plans import count
RE(count([det]))
The return value is a list of the run IDs that uniquely identify this data set. The "scan num" is easier to remember but is not good for long-term reference because it may not be unique.
Let's looks at the documentation for count
to see what our other options are.
help(count) # or, equiavently, type count? or ?count
# Creating a figure explicitly in advance helps with the
# top-to-bottom flow of this notebook, but it is not necessary.
# If this is omitted, bluesky will cause a figure to appear
# during the RE(...) execution below.
plt.figure('ph_det vs time')
# five consecutive readings
RE(count([det], num=5))
plt.gcf() # Display a snapshot of the current state of the figure.
plt.gcf().canvas # To avoid needing to scroll up, display the interactive canvas again here.
# five sequential readings separated by a 1-second delay
RE(count([det], num=5, delay=1))
plt.gcf() # Display a snapshot of the current state of the figure.
Scan motor
from -10 to 10, stopping at 15 equally-spaced points along the way and reading det
.
# Creating a figure explicitly in advance helps with the
# top-to-bottom flow of this notebook, but it is not necessary.
# If this is omitted, bluesky will cause a figure to appear
# during the RE(...) execution below.
plt.figure('ph_det vs motor_ph')
RE(scan([det], motor, -10, 10, 15))
plt.gcf() # Display a snapshot of the current state of the figure.
Bluesky includes utilities to inspecting plans before they are run. You can imagine various reasons you might want to do this. Example:
from bluesky.simulators import summarize_plan
summarize_plan(scan([det], motor, -1, 1, 3))
Define a custom "plan", using the Python syntax yield from
to dispatch out to built-in plans.
plt.gcf().canvas # To avoid needing to scroll up, display the interactive canvas again here.
# The plan_stubs module contains smaller plans.
# They can be used alone or as buildling blocks for larger plans.
from bluesky.plan_stubs import mv
def sweep_exposure_time(times):
"Multiple scans: one per exposure time setting."
for t in times:
yield from mv(det.exp, t)
yield from scan([det], motor, -10, 10, 5)
RE(sweep_exposure_time([0.01, 0.1, 1]))
plt.gcf() # Display a snapshot of the current state of the figure.
Q1: Above we ran a count
with multiple readings separated by a fixed delay. The delay
parameter also accepts a list of values. Try a count
with a variable delay.
# Try your solution here. Fill in the blank:
# RE(count(____)))
Execute the following cell to reveal a solution:
%load solutions/count_variable_delay.py
Q2: Write a custom plan that scans the same region twice, first with coarse steps and then with fine steps.
# Try your solution here. Fill in the blank:
# def coarse_and_fine(detectors, motor, start, stop):
# yield from scan(___)
# yield from scan(___)
#
# RE(coarse_and_fine([det], motor, -10, 10))
%load solutions/scan_coarse_and_fine.py
Q3. All of the usages of scan we have seen so far scan from negative to positive. Scan from positive to negative.
# Try your solution here.
%load solutions/scan_positive_to_negative.py
Q4: The scan
plan samples equally-spaced points. To sample arbitrary points, you can use list_scan
. Import it from the same module that we imported scan
from, then use list_scan?
to view its documentation and figure out how to use it. Scan the positions [1, 1, 2, 3, 5, 8]
.
# Try your solution here.
%load solutions/scan_fibonacci.py
Q5: What's wrong with this? (What does it do?)
# Broken example
def sweep_exposure_time(times):
"Multiple scans: one per exposure time setting."
for t in times:
mv(det.exp, t)
scan([det], motor, -10, 10, 15)
%load solutions/broken_sweep_exposure_time_explanation.txt