Important

You can run this notebook in a live session Binder or view it on nbviewer or GitHub.

Supplemental Data

In this notebook you will:

  • Run some simulated experiments including supplemental baseline readings and an asynchronously monitored signal.

  • Access the saved data.

Configuration

Below, we will connect to EPICS IOC(s) controlling simulated hardware in lieu of actual motors, detectors. 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.

[1]:
!supervisorctl -c supervisor/supervisord.conf status
decay                            RUNNING   pid 4977, uptime 0:04:29
mini_beamline                    RUNNING   pid 4978, uptime 0:04:29
random_walk                      RUNNING   pid 4979, uptime 0:04:29
random_walk_horiz                RUNNING   pid 4980, uptime 0:04:29
random_walk_vert                 RUNNING   pid 4981, uptime 0:04:29
simple                           RUNNING   pid 4982, uptime 0:04:29
thermo_sim                       RUNNING   pid 4983, uptime 0:04:29
trigger_with_pc                  RUNNING   pid 4984, uptime 0:04:29
[2]:
%run scripts/beamline_configuration.py
/home/travis/virtualenv/python3.7.1/lib/python3.7/site-packages/pims/image_reader.py:26: RuntimeWarning: PIMS image_reader.py could not find scikit-image. Falling back to matplotlib's imread(), which uses floats instead of integers. This may break your scripts.
(To ignore this warning, include the line "warnings.simplefilter("ignore", RuntimeWarning)" in your script.)
  warnings.warn(RuntimeWarning(ski_preferred))
[3]:
sd
[3]:
SupplementalData(baseline=[], monitors=[], flyers=[])

Baseline Readings

Now, at the beginning and end of every run, record the positions of these motors.

[4]:
sd.baseline = [mtr_spotx, mtr_spoty]
[5]:
# run a similar scan as other exercises
plt.figure('ph_det vs motor_ph')
RE(scan([ph], motor_ph, -1, 1, 5))


Transient Scan ID: 28     Time: 2020-07-15 20:29:37
Persistent Unique Scan ID: '4c30512b-b926-415b-a69c-0decfd60b61c'
New stream: 'baseline'
Start-of-run baseline readings:
+--------------------------------+--------------------------------+
|                    motor_spotx | 1.0                            |
|                    motor_spoty | 0.0                            |
+--------------------------------+--------------------------------+
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |   motor_ph |     ph_det |
+-----------+------------+------------+------------+
|         1 | 20:29:37.2 |     -1.000 |      94961 |
|         2 | 20:29:37.3 |     -0.500 |      97233 |
|         3 | 20:29:37.3 |      0.000 |      98578 |
|         4 | 20:29:37.3 |      0.500 |      98123 |
|         5 | 20:29:37.3 |      1.000 |      96288 |
+-----------+------------+------------+------------+
generator scan ['4c30512b'] (scan num: 28)
End-of-run baseline readings:
+--------------------------------+--------------------------------+
|                    motor_spotx | 1.0                            |
|                    motor_spoty | 0.0                            |
+--------------------------------+--------------------------------+



[5]:
('4c30512b-b926-415b-a69c-0decfd60b61c',)

Notice

New stream: 'baseline'

as well as the boxes of readings. How can we access that data later? It doesn’t show up in the table!

[6]:
# Let's show the plot again so you can refer back to it when looking at the tables.
plt.gcf()
[6]:
_images/Supplemental_Data_8_0.png
[7]:
db[-1].table()
[7]:
time ph_det motor_ph
seq_num
1 2020-07-15 20:29:37.272127390 94961.0 -1.0
2 2020-07-15 20:29:37.304666519 97233.0 -0.5
3 2020-07-15 20:29:37.344527006 98578.0 0.0
4 2020-07-15 20:29:37.358096838 98123.0 0.5
5 2020-07-15 20:29:37.367267370 96288.0 1.0
[8]:
db[-1].table('primary')  # the default
[8]:
time ph_det motor_ph
seq_num
1 2020-07-15 20:29:37.272127390 94961.0 -1.0
2 2020-07-15 20:29:37.304666519 97233.0 -0.5
3 2020-07-15 20:29:37.344527006 98578.0 0.0
4 2020-07-15 20:29:37.358096838 98123.0 0.5
5 2020-07-15 20:29:37.367267370 96288.0 1.0
[9]:
db[-1].table('baseline')
[9]:
time motor_spotx motor_spoty
seq_num
1 2020-07-15 20:29:37.078415632 1.0 0.0
2 2020-07-15 20:29:37.373380661 1.0 0.0

If the table gets too wide, it’s handy to know how to take the transpose of a DataFrame.

[10]:
db[-1].table('baseline').T
[10]:
seq_num 1 2
time 2020-07-15 20:29:37.078415632 2020-07-15 20:29:37.373380661
motor_spotx 1 1
motor_spoty 0 0

Asynchronous Monitoring

[11]:
sd.monitors = [I]
[12]:
RE(scan([ph], motor_ph, -1, 1, 10))


Transient Scan ID: 29     Time: 2020-07-15 20:29:37
Persistent Unique Scan ID: 'b6a73cd4-81eb-4a45-a0fd-78f4b6778561'
New stream: 'baseline'
Start-of-run baseline readings:
+--------------------------------+--------------------------------+
|                    motor_spotx | 1.0                            |
|                    motor_spoty | 0.0                            |
+--------------------------------+--------------------------------+
New stream: 'I_monitor'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |   motor_ph |     ph_det |
+-----------+------------+------------+------------+
|         1 | 20:29:38.2 |     -1.000 |     102051 |
|         2 | 20:29:38.2 |     -0.778 |     103339 |
|         3 | 20:29:38.2 |     -0.556 |     104215 |
|         4 | 20:29:38.2 |     -0.333 |     103826 |
|         5 | 20:29:38.2 |     -0.111 |     104682 |
|         6 | 20:29:38.2 |      0.111 |     104348 |
|         7 | 20:29:38.2 |      0.333 |     103826 |
|         8 | 20:29:38.2 |      0.556 |     103751 |
|         9 | 20:29:38.2 |      0.778 |     103441 |
|        10 | 20:29:38.2 |      1.000 |     102886 |
+-----------+------------+------------+------------+
generator scan ['b6a73cd4'] (scan num: 29)
End-of-run baseline readings:
+--------------------------------+--------------------------------+
|                    motor_spotx | 1.0                            |
|                    motor_spoty | 0.0                            |
+--------------------------------+--------------------------------+



[12]:
('b6a73cd4-81eb-4a45-a0fd-78f4b6778561',)

Notice

New stream: 'I_monitor'

and a new figure. But the Best-Effort Callback doesn’t show us the numbers from monitor readings. (There’s just not enough room.)

[13]:
h = db[-1]
h.table('I_monitor')
[13]:
time I
seq_num
1 2020-07-15 20:29:38.043104172 517.707383
2 2020-07-15 20:29:38.090347767 520.261166
3 2020-07-15 20:29:38.194128990 522.308894

What streams do we have? Another good Header method to know:

[14]:
h.stream_names
[14]:
['primary', 'I_monitor', 'baseline']

Exercises

  1. Add mtr_slit to the list of things to be recorded as baseline readings.

[ ]:

[15]:
%load solutions/add_baseline_device.py
  1. Remove mtr_slit from the list of things to be recorded as baseline readings.

[ ]:

[16]:
%load solutions/remove_baseline_device.py
  1. Empty the list of things to be monitored.

[ ]:

[17]:
%load solutions/clear_supplemental_monitors.py