In this notebook you will:
BONUS Material Located after our objectives. It is in the form of Q & A.
Recommend Prerequisites:
#pip install -U --pre databroker[all]
Hosted by Andi
Run the next cells to make the ipython kernel match the previous session
%run -i gm_user/user_profile.py
%run -i gm_user/user_startup.py
%run -i gm_user/user_startup_night.py
md_info()
temperature.readback.get()
First, open the file gm_user/user_startup_night.py and view it side by side with this notebook.
It's pretty clear that we should run RE(one_temperature())
and this is a good first "real" test of our functions.
RE(one_temperature())
But we can test how to put this together with our planned overnight script:
RE(one_temperature())
But what if we want to try to automate some processing or take better advantage of data access tools like databroker
or its replacement tiled
?
Let's look at line 22 in gm_user/user_startup_night.py.
Not the new agurment utilized in count()
.
md={'purpose':'analyze'}
md
key names (purpose
) are not enforced/checkeddb[-1].start
Let's test how to put this together with our planned overnight script:
check_limits( bpp.pchain(one_temperature(), my_experiment([41, 42])) )
NOW edit the cell below to pass the pchained plans to the RE.
( bpp.pchain(one_temperature(), my_experiment([41, 42])) )
Is the tempeature being recorded?
We know that it is not. The next tutorial deals with data access. However, two simple verifications utilize the start and stop documents.
db[-1].start
db[-1].stop
temperature
to the primary
datastream¶RE(count([noisy_det, temperature], 5) )
### Add temperature to the primary datastream
RE(count([noisy_det, ], 5) )
SupplenmentalData
(sd
)sd
sd.baseline =[temperature]
sd.baseline
RE(count([noisy_det], 5) )
BestEffortCallbacks
(bec
) is used to control some of the bluesky interface features
# OPTIONAL, explore bec by uncommenting the line directly below
# dir(bec)
bec.disable_baseline()
RE(count([noisy_det], 5) )
db[-1].table('baseline')
Hosted by Josh
Some mistakes are difficult to understand immediately. Let's have a look at a couple common ones and how troubleshoot.
sd.baseline
¶sd.baseline.append([motor1, motor2])
RE(count([noisy_det], 2) )
sd.baseline
sd.baseline =[temperature]
sd.baseline.extend([motor1, motor2])
Try again after entering your solution above
RE(count([noisy_det], 2) )
RE(scan(dets, motor, -5, 5, 3))
my_dets
dets = my_dets
dets is my_dets
RE(scan(dets, motor, -5, 5, 3))
RE(scan([dets], motor, -5, 5, 11))
dets
And this is also a trap if you use another common DAQ
ascan motor start stop steps time
RE(scan([det], motor, -5, 5, 3))
RE(scan(det, motor, -5, 5, 3))
RE(scan( motor, -5, 5, 3))
RE(scan(my_dets, motor, -5, 5, 3))
Counting time is handled per detector which makes asynchronous collection possible (more flexibility).
RE(scan( motor, -5, 5, 3, 1))
RE(scan(my_dets, motor, -5, 5, 3))
Counting time is handled per detector which makes asynchronous collection possible (more flexibility).
RE(scan(my_dets, motor, -5, 5, 3, 1))
Self-guided Tour
Q1 What other pre-assembled plans are avaialbe with blueksy "out-of-the-box" installation? How do I make a 2D scan?
A1 Check the docs:
Q2 Why is the scan so noisy when I know the detector has a low noise level?
A2 Realy motors are not perfect and electrical ground loops are difficult to remove. Try:
motor.setpoint
Q3 Why is summarize_plan(rel_scan([det], motor, -1, 1, 21))
incorrect
A3 bluesky.simulators
use the current live position of all motors. Currently, relative scans generate the motor trajectory as the scan proceeds in the RE. For best results, you can fake relative scans:
my_motor_pos = motor.setpoint.get()
yield from scan([det], motor, my_motor_pos-1, my_motor_pos+1, 21)
Q4 What if I want to control .get()
like the rest of bluesky's plan generators inside my custom plan? NoteL .get()
emmits a query to the network inside summarize_plan()
.
A4 Use bps.rd()
my_variable = yield from bps.rd(top_level_device.device_child_to_return_single_value)
Q5 How do perform a line scan on multiple motors (or through reciprocal space) on multiple "motors"?
A5 Using
scan?
it is possible to see that you can scan N motors. Below N=2.
RE(scan([det], motor, -5, 5, motor1, -5, 5, 3))
Not that only the first motor is plotted in the LivePlot.
Q6 What about a theta-2theta scan?
A6 Alter the scan arguments
twotheta = motor
theta = motor1
RE(scan([det], twotheta, -5, 5, theta, -5/2, 5/2, 3))
Not that only the first motor is plotted in the LivePlot.
Q7 How do I control what detectors and motors are plotted and included in the table?
A7 Bluesky hints. Each signal has a "kind". The options are:
print(f'{temperature.setpoint.kind=}')
print(f'{temperature.readback.kind=}')
temperature.setpoint.kind='hinted'
print(f'\n{temperature.setpoint.kind=}')
Q8 Bluesky doesn't have device I want to record or control. What is the fastest way to get going?
A8 ophyd EpicsSignal or EpicsSignalRO (ReadOnly) may be set up in 1 line. As long as you do not need bluesky to check many aspects of how the signal is used to ensure performance, then this should be a decent quick fix.
from ophyd.signal import EpicsSignal
my_signal = EpicsSignal('sting_representing_EPICS_PV', name="my_signal")
In terms of EPICS or pyepics, the usage would be:
pyepics.caget('sting_representing_EPICS_PV')
Q9 How do I make a 2D mesh-like scan for imaging?
A9 There are a few different pre-assembled plans. Check the docs for the full list.
RE(grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
True))
Last argument is for "snaking" (True or False).
grid_scan??
bec.disable_table()
RE(grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
True))
Q10 Are there additional inspection/simulation plans for 2D imaging scans?
A10 Yes.
from ophyd.sim import motor, motor1, det
from bluesky.simulators import summarize_plan, check_limits, plot_raster_path
from bluesky.plans import *
plan = grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
True)
plot_raster_path(plan, 'motor', 'motor1', probe_size=.1)
# from ophyd.sim import motor, motor1, det
# from bluesky.simulators import summarize_plan, check_limits, plot_raster_path
# from bluesky.plans import *
plan = grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
True)
plot_raster_path(plan, 'motor', 'motor1', probe_size=.1)
Remember, plans are generators so the below will fail.
plan = grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
False)
plot_raster_path(plan, 'motor', 'motor1', probe_size=.1)
def see_diff_with_relative():
yield from mv(motor, -1, motor1, -1)
yield from rel_grid_scan([det], motor, -1, 1, 9,
motor1, -1, 1, 9,
True)
bec.disable_table()
RE(see_diff_with_relative())