Scan Area Detector v. Motor#

Goals

  • Use EPICS motor(s):

    • ☒ Record current value (readback)

    • ☒ Record commanded value (setpoint)

  • Use EPICS area detector:

    • ☒ For each image

      • ☒ Write image to HDF5 file

      • ☒ Measure total counts in image

      • ☒ Measure maximum counts in image

      • ☒ Note the image’s “unique ID”

  • Step scan motor and collect n image frame(s) at each step:

    • ☒ Plan: count, just collect image(s)

    • ☒ Plan: scan with one motor

    • ☒ Plan: scan with two motors

    • ☒ Plan: grid_scan with two motors

  • Collect data in a SPEC data file.

Start the instrument package#

Our instrument package is in the bluesky subdirectory, so we add that to the search path before importing it.

[1]:
import pathlib, sys

sys.path.append(str(pathlib.Path().home() / "bluesky"))
from instrument.collection import *
/home/prjemian/bluesky/instrument/_iconfig.py
Activating auto-logging. Current session state plus future input saved.
Filename       : /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/docs/source/howto/.logs/ipython_console.log
Mode           : rotate
Output logging : True
Raw input log  : False
Timestamping   : True
State          : active
I Sat-13:18:30 - ############################################################ startup
I Sat-13:18:30 - logging started
I Sat-13:18:30 - logging level = 10
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/session_logs.py
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/collection.py
I Sat-13:18:30 - CONDA_PREFIX = /home/prjemian/.conda/envs/bluesky_2024_2
Exception reporting mode: Minimal
I Sat-13:18:30 - xmode exception level: 'Minimal'
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/mpl/notebook.py
I Sat-13:18:30 - #### Bluesky Framework ####
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/framework/check_python.py
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/framework/check_bluesky.py
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/framework/initialize.py
I Sat-13:18:30 - RunEngine metadata saved in directory: /home/prjemian/.config/Bluesky_RunEngine_md
I Sat-13:18:30 - using databroker catalog 'training'
I Sat-13:18:30 - using ophyd control layer: pyepics
I Sat-13:18:30 - Using EPICS PV gp:gp:int20 for scan_id
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/framework/metadata.py
I Sat-13:18:30 - #### Devices ####
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/devices/area_detector.py
I Sat-13:18:30 - /home/prjemian/bluesky/instrument/devices/calculation_records.py
I Sat-13:18:35 - /home/prjemian/bluesky/instrument/devices/fourc_diffractometer.py
I Sat-13:18:35 - /home/prjemian/bluesky/instrument/devices/ioc_stats.py
I Sat-13:18:35 - /home/prjemian/bluesky/instrument/devices/kohzu_monochromator.py
I Sat-13:18:35 - /home/prjemian/bluesky/instrument/devices/motors.py
I Sat-13:18:36 - /home/prjemian/bluesky/instrument/devices/noisy_detector.py
I Sat-13:18:36 - /home/prjemian/bluesky/instrument/devices/scaler.py
I Sat-13:18:37 - /home/prjemian/bluesky/instrument/devices/shutter_simulator.py
I Sat-13:18:37 - /home/prjemian/bluesky/instrument/devices/simulated_fourc.py
I Sat-13:18:37 - /home/prjemian/bluesky/instrument/devices/simulated_kappa.py
I Sat-13:18:37 - /home/prjemian/bluesky/instrument/devices/slits.py
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/devices/sixc_diffractometer.py
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/devices/temperature_signal.py
I Sat-13:18:38 - #### Callbacks ####
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/callbacks/spec_data_file_writer.py
I Sat-13:18:38 - #### Plans ####
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/plans/lup_plan.py
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/plans/peak_finder_example.py
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/utils/image_analysis.py
I Sat-13:18:38 - /home/prjemian/bluesky/instrument/plans/randomize_noisy_peak_plan.py
I Sat-13:18:38 - #### Utilities ####
I Sat-13:18:38 - writing to SPEC file: /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/docs/source/howto/20240615-131838.dat
I Sat-13:18:38 -    >>>>   Using default SPEC file name   <<<<
I Sat-13:18:38 -    file will be created when bluesky ends its next scan
I Sat-13:18:38 -    to change SPEC file, use command:   newSpecFile('title')
I Sat-13:18:38 - #### Startup is complete. ####
  • Create a custom area detector class with our own IOC prefix, add ROI and STATS plugins, and connect with local directories:

[2]:
from apstools.devices import SingleTrigger_V34
from ophyd.areadetector import ADComponent
from ophyd.areadetector import DetectorBase
from ophyd.areadetector.plugins import ImagePlugin_V34
from ophyd.areadetector.plugins import PvaPlugin_V34
from ophyd.areadetector.plugins import ROIPlugin_V34
from ophyd.areadetector.plugins import StatsPlugin_V34
import hdf5plugin  # needed to read LZ4-compressed image from HDF5 file

from instrument.devices.area_detector import MyHDF5Plugin
from instrument.devices.area_detector import SimDetectorCam_V34

# for my IOC, these parameters apply:
AD_IOC = "kad:"
FILE_BASE_IOC = "/tmp/"
FILE_BASE_BLUESKY = "/mnt/iockad/tmp/"

class SimDetector_V34(SingleTrigger_V34, DetectorBase):
    """
    ADSimDetector

    SingleTrigger:

    * stop any current acquisition
    * sets image_mode to 'Multiple'
    """

    cam = ADComponent(SimDetectorCam_V34, "cam1:")
    hdf1 = ADComponent(
        MyHDF5Plugin,
        "HDF1:",
        write_path_template=FILE_BASE_IOC,
        read_path_template=FILE_BASE_BLUESKY,
    )
    image = ADComponent(ImagePlugin_V34, "image1:")
    pva = ADComponent(PvaPlugin_V34, "Pva1:")
    roi1 = ADComponent(ROIPlugin_V34, "ROI1:")
    stats1 = ADComponent(StatsPlugin_V34, "Stats1:")

simdet = SimDetector_V34(AD_IOC, name="simdet")

Setup & connect with EPICS#

Search the ophyd object registry (oregistry) for the detector and motors. Verify that each is connected to EPICS.

[3]:
for nm in "simdet m1 m2".split():
    obj = oregistry.find(nm)
    print(f"{obj.connected=!r} {nm!r}")
obj.connected=True 'simdet'
obj.connected=True 'm1'
obj.connected=True 'm2'

Configure the area detector to:

  • Collect \(n\) image frame(s) for each press of the Acquire button.

  • Save image(s) to HDF5.

  • Record total counts in the image.

  • Record maximum counts in the image.

  • Record the unique ID of the image.

[4]:
def ad_setup(det):
    det.wait_for_connection(timeout=3)
    det.roi1.nd_array_port.put("SIM1")
    det.stats1.nd_array_port.put("ROI1")
    det.missing_plugins()

    det.cam.stage_sigs["num_images"] = 3

    det.hdf1.kind = "hinted"
    det.hdf1.create_directory.put(-5)
    det.hdf1.stage_sigs["compression"] = "LZ4"

    det.stats1.kind = "hinted"
    det.stats1.max_value.kind = "hinted"
    det.stats1.total.kind = "hinted"
    det.stats1.unique_id.kind = "hinted"

    det.cam.stage_sigs["wait_for_plugins"] = "Yes"
    det.hdf1.stage_sigs["blocking_callbacks"] = "No"
    det.image.stage_sigs["blocking_callbacks"] = "No"

ad_setup(simdet)

Diagnostics (optional)#

These steps are optional.

  • Show the data from area detector simdet. This is the data collected by the RE during a run..

[5]:
simdet.read()
[5]:
OrderedDict([('simdet_stats1_unique_id',
              {'value': 152858, 'timestamp': 1718408341.829117}),
             ('simdet_stats1_max_value',
              {'value': 164.0, 'timestamp': 1718408341.829133}),
             ('simdet_stats1_total',
              {'value': 11722735.0, 'timestamp': 1718408341.829158})])
  • Show how simdet is configured to collect \(n\) frames per point.

[6]:
print("Image frames per point:", simdet.cam.stage_sigs["num_images"])
Image frames per point: 3
  • Show the staging configuration for simdet.

[7]:
from pprint import pprint

pprint({"simdet": simdet.stage_sigs})
pprint({"simdet.cam": simdet.cam.stage_sigs})
pprint({"simdet.hdf1": simdet.hdf1.stage_sigs})
pprint({"simdet.roi1": simdet.roi1.stage_sigs})
pprint({"simdet.stats1": simdet.stats1.stage_sigs})
{'simdet': OrderedDict([('cam.acquire', 0), ('cam.image_mode', 1)])}
{'simdet.cam': OrderedDict([('num_images', 3), ('wait_for_plugins', 'Yes')])}
{'simdet.hdf1': OrderedDict([('enable', 1),
                             ('blocking_callbacks', 'No'),
                             ('parent.cam.array_callbacks', 1),
                             ('create_directory', -3),
                             ('auto_increment', 'Yes'),
                             ('array_counter', 0),
                             ('auto_save', 'Yes'),
                             ('num_capture', 0),
                             ('file_template', '%s%s_%6.6d.h5'),
                             ('file_write_mode', 'Stream'),
                             ('capture', 1),
                             ('compression', 'LZ4')])}
{'simdet.roi1': OrderedDict([('enable', 1),
                             ('blocking_callbacks', 'Yes'),
                             ('parent.cam.array_callbacks', 1)])}
{'simdet.stats1': OrderedDict([('enable', 1),
                               ('blocking_callbacks', 'Yes'),
                               ('parent.cam.array_callbacks', 1)])}
  • Show how the area detector ports are connected in a diagram.

[8]:
simdet.visualize_asyn_digraph()
../_images/howto__ad_v_motors_16_0.png

Read the Stats plugin signals#

  • The plan below reads the signals from simdet.stats1 multiple times. Since simdet itself is not included in the list of detectors, it will not be triggered (and thus will not produce new images). One can notice that the unique_id does not change. For clarity, the command is split into multiple lines.

[9]:
RE(
    bp.count(
        [
            simdet.stats1.unique_id,
            simdet.stats1.total,
            simdet.stats1.max_value
            ],
        num=5
        )
    )


Transient Scan ID: 92     Time: 2024-06-15 13:18:40
Persistent Unique Scan ID: 'ceaecdd7-e1af-411f-94f2-c14d5d3debab'
device=MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']), exception=Data keys (field names) from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']) collide with those from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']). The colliding keys are {'m2', 'm2_user_setpoint'}
New stream: 'label_start_motor'
New stream: 'primary'
+-----------+------------+-------------------------+---------------------+-------------------------+
|   seq_num |       time | simdet_stats1_unique_id | simdet_stats1_total | simdet_stats1_max_value |
+-----------+------------+-------------------------+---------------------+-------------------------+
|         1 | 13:18:41.1 |                  152858 |            11722735 |                     164 |
|         2 | 13:18:41.5 |                  152858 |            11722735 |                     164 |
|         3 | 13:18:41.9 |                  152858 |            11722735 |                     164 |
|         4 | 13:18:42.3 |                  152858 |            11722735 |                     164 |
|         5 | 13:18:42.6 |                  152858 |            11722735 |                     164 |
+-----------+------------+-------------------------+---------------------+-------------------------+
generator count ['ceaecdd7'] (scan num: 92)
[9]:
('ceaecdd7-e1af-411f-94f2-c14d5d3debab',)
../_images/howto__ad_v_motors_18_4.png
[10]:
# Assume our run is the most recent one in the catalog
run = cat[-1]
print(f"{run=!r}")

# Read the primary data from the most recent run
dataset = run.primary.read()
dataset
run=<BlueskyRun uid='ceaecdd7-e1af-411f-94f2-c14d5d3debab'>
/home/prjemian/.conda/envs/bluesky_2024_2/lib/python3.11/site-packages/databroker/intake_xarray_core/base.py:23: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  'dims': dict(self._ds.dims),
[10]:
<xarray.Dataset> Size: 160B
Dimensions:                  (time: 5)
Coordinates:
  * time                     (time) float64 40B 1.718e+09 ... 1.718e+09
Data variables:
    simdet_stats1_unique_id  (time) int64 40B 152858 152858 152858 152858 152858
    simdet_stats1_total      (time) float64 40B 1.172e+07 ... 1.172e+07
    simdet_stats1_max_value  (time) float64 40B 164.0 164.0 164.0 164.0 164.0

Take image(s) with the bp.count plan#

Collect 5 sets of images (3-frames each as configured above).

[11]:
uids = RE(bp.count([simdet], num=5))
print(f"uids=!r")


Transient Scan ID: 93     Time: 2024-06-15 13:18:44
Persistent Unique Scan ID: 'f39f2eb2-fc04-4696-ac26-245cd574f7c2'
device=MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']), exception=Data keys (field names) from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']) collide with those from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']). The colliding keys are {'m2', 'm2_user_setpoint'}
New stream: 'label_start_motor'
New stream: 'primary'
+-----------+------------+-------------------------+-------------------------+---------------------+
|   seq_num |       time | simdet_stats1_unique_id | simdet_stats1_max_value | simdet_stats1_total |
+-----------+------------+-------------------------+-------------------------+---------------------+
|         1 | 13:18:45.1 |                  152861 |                     164 |            11658834 |
|         2 | 13:18:45.5 |                  152864 |                     164 |            11710598 |
|         3 | 13:18:45.9 |                  152867 |                     163 |            11537287 |
|         4 | 13:18:46.3 |                  152870 |                     159 |            11360372 |
|         5 | 13:18:46.8 |                  152873 |                     166 |            11817560 |
+-----------+------------+-------------------------+-------------------------+---------------------+
generator count ['f39f2eb2'] (scan num: 93)
uids=!r
../_images/howto__ad_v_motors_21_3.png

Visualize the collected data#

Let’s examine the data from the most recent run in the catalog:

[12]:
# Get the dataset from the most recent run
dataset = cat[uids[-1]].primary.read()

#  Extract the image data
image_data = dataset["simdet_image"]

# Print the shape of the image data
print(f"{image_data.shape=!r}")

# Display the dataset
dataset
image_data.shape=(5, 3, 1024, 1024)
[12]:
<xarray.Dataset> Size: 16MB
Dimensions:                  (time: 5, dim_0: 3, dim_1: 1024, dim_2: 1024)
Coordinates:
  * time                     (time) float64 40B 1.718e+09 ... 1.718e+09
Dimensions without coordinates: dim_0, dim_1, dim_2
Data variables:
    simdet_image             (time, dim_0, dim_1, dim_2) uint8 16MB 10 9 ... 11
    simdet_stats1_unique_id  (time) int64 40B 152861 152864 152867 152870 152873
    simdet_stats1_max_value  (time) float64 40B 164.0 164.0 163.0 159.0 166.0
    simdet_stats1_total      (time) float64 40B 1.166e+07 ... 1.182e+07
  • Display the first image frame from the first point.

[13]:
image_data[0][0].plot.pcolormesh()  # Plot the first frame.
[13]:
<matplotlib.collections.QuadMesh at 0x7fddf7c27d50>
../_images/howto__ad_v_motors_25_1.png

About the HDF5 image file#

Information about the HDF5 file is saved as a resource document in the catalog. This command shows the content of that document.

[14]:
run = cat[uids[-1]]
resources = run.primary._resources
resources
[14]:
[Resource({'path_semantics': 'posix',
 'resource_kwargs': {'frame_per_point': 3},
 'resource_path': 'mnt/iockad/tmp/1245c370-4953-4ff3-8982_000000.h5',
 'root': '/',
 'run_start': 'f39f2eb2-fc04-4696-ac26-245cd574f7c2',
 'spec': 'AD_HDF5',
 'uid': '510c0d90-f922-41c2-a5ed-2b1013b82ab3'})]

Starting with this resources object (a Python list), this command reconstructs the image file name:

[15]:
resources[0]["root"] + resources[0]["resource_path"]
[15]:
'/mnt/iockad/tmp/1245c370-4953-4ff3-8982_000000.h5'

Show that this file is recognized on the file system available to Bluesky.

[16]:
from pathlib import Path

image_file = Path(resources[0]["root"] + resources[0]["resource_path"])
image_file.exists()
[16]:
True

The (1-D) bp.scan() plan with one motor#

Step scan a motor (m1); at each step:

  • Measure 3 images (as configured above during detector staging).

  • Record total counts.

  • Record maximum counts value.

In the interest of brevity here, further graphical data visualization will be turned off. Refer to the section above for the visualization steps. They are identical for each type of scan.

[17]:
bec.disable_plots()

Run the scan.

[18]:
uids = RE(bp.scan([simdet], m1, -1, 1, 5))
dataset = cat[uids[-1]].primary.read()
image_data = dataset["simdet_image"]
print(f"{image_data.shape=!r}")
dataset


Transient Scan ID: 94     Time: 2024-06-15 13:18:49
Persistent Unique Scan ID: '03dde617-eb69-4b66-abe5-8595de04051d'
device=MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']), exception=Data keys (field names) from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']) collide with those from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']). The colliding keys are {'m2', 'm2_user_setpoint'}
New stream: 'label_start_motor'
New stream: 'primary'
+-----------+------------+------------+-------------------------+-------------------------+---------------------+
|   seq_num |       time |         m1 | simdet_stats1_unique_id | simdet_stats1_max_value | simdet_stats1_total |
+-----------+------------+------------+-------------------------+-------------------------+---------------------+
|         1 | 13:18:52.0 |    -1.0000 |                  152876 |                     160 |            11445712 |
|         2 | 13:18:52.8 |    -0.5000 |                  152879 |                     163 |            11658331 |
|         3 | 13:18:53.6 |     0.0000 |                  152882 |                     162 |            11535839 |
|         4 | 13:18:54.4 |     0.5000 |                  152885 |                     165 |            11799101 |
|         5 | 13:18:55.2 |     1.0000 |                  152888 |                     166 |            11824045 |
+-----------+------------+------------+-------------------------+-------------------------+---------------------+
generator scan ['03dde617'] (scan num: 94)
image_data.shape=(5, 3, 1024, 1024)
[18]:
<xarray.Dataset> Size: 16MB
Dimensions:                  (time: 5, dim_0: 3, dim_1: 1024, dim_2: 1024)
Coordinates:
  * time                     (time) float64 40B 1.718e+09 ... 1.718e+09
Dimensions without coordinates: dim_0, dim_1, dim_2
Data variables:
    simdet_image             (time, dim_0, dim_1, dim_2) uint8 16MB 8 10 ... 9 6
    simdet_stats1_unique_id  (time) int64 40B 152876 152879 152882 152885 152888
    simdet_stats1_max_value  (time) float64 40B 160.0 163.0 162.0 165.0 166.0
    simdet_stats1_total      (time) float64 40B 1.145e+07 ... 1.182e+07
    m1                       (time) float64 40B -1.0 -0.5 0.0 0.5 1.0
    m1_user_setpoint         (time) float64 40B -1.0 -0.5 0.0 0.5 1.0

The (1-D) bp.scan() plan with two motors#

Step scan two motors together (m1 & m2) as in the previous section; at each step:

  • Measure 3 images (as configured above during detector staging).

  • Record total counts.

  • Record maximum counts value.

For clarity, the scan arguments are split into multiple lines.

[19]:
uids = RE(
    bp.scan(
        [simdet],
        m1, -1, 1,
        m2, 4, 1.5,
        5,
    )
)
print(f"uids=!r")

dataset = cat[uids[-1]].primary.read()
image_data = dataset["simdet_image"]
print(f"{image_data.shape=!r}")

dataset


Transient Scan ID: 95     Time: 2024-06-15 13:18:56
Persistent Unique Scan ID: 'b0fc4001-c2e2-468a-ac82-1ccb19ddbdb3'
device=MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']), exception=Data keys (field names) from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']) collide with those from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']). The colliding keys are {'m2', 'm2_user_setpoint'}
New stream: 'label_start_motor'
New stream: 'primary'
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
|   seq_num |       time |         m1 |         m2 | simdet_stats1_unique_id | simdet_stats1_max_value | simdet_stats1_total |
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
|         1 | 13:19:00.1 |    -1.0000 |     4.0000 |                  152891 |                     163 |            11659109 |
|         2 | 13:19:00.9 |    -0.5000 |     3.3750 |                  152894 |                     159 |            11355578 |
|         3 | 13:19:01.8 |     0.0000 |     2.7500 |                  152897 |                     164 |            11659418 |
|         4 | 13:19:02.7 |     0.5000 |     2.1250 |                  152900 |                     162 |            11536310 |
|         5 | 13:19:03.6 |     1.0000 |     1.5000 |                  152903 |                     163 |            11658922 |
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
generator scan ['b0fc4001'] (scan num: 95)
uids=!r
image_data.shape=(5, 3, 1024, 1024)
[19]:
<xarray.Dataset> Size: 16MB
Dimensions:                  (time: 5, dim_0: 3, dim_1: 1024, dim_2: 1024)
Coordinates:
  * time                     (time) float64 40B 1.718e+09 ... 1.718e+09
Dimensions without coordinates: dim_0, dim_1, dim_2
Data variables:
    simdet_image             (time, dim_0, dim_1, dim_2) uint8 16MB 8 6 ... 7 6
    simdet_stats1_unique_id  (time) int64 40B 152891 152894 152897 152900 152903
    simdet_stats1_max_value  (time) float64 40B 163.0 159.0 164.0 162.0 163.0
    simdet_stats1_total      (time) float64 40B 1.166e+07 ... 1.166e+07
    m1                       (time) float64 40B -1.0 -0.5 0.0 0.5 1.0
    m1_user_setpoint         (time) float64 40B -1.0 -0.5 0.0 0.5 1.0
    m2                       (time) float64 40B 4.0 3.375 2.75 2.125 1.5
    m2_user_setpoint         (time) float64 40B 4.0 3.375 2.75 2.125 1.5

Show the sequence of motor positions#

Both motors move at the same time. The same number of steps are taken by each motor. Below is a plot showing the readback values of each motor during a two-motor scan versus the data point number:

grid_scan motors v point number

The (2-D) bp.grid_scan() (mesh) plan#

Step scan two motors (m1 & m2) as in the previous section; at each step:

  • Measure 3 images (as configured aboveduring detector staging).

  • Record total counts.

  • Record maximum counts value.

For clarity, the grid_scan arguments are split into multiple lines.

[20]:
uids = RE(
    bp.grid_scan(
        [simdet],
        m1, -1, 1, 5,
        m2, -0.5, 0.5, 4,
        snake_axes=True,
    )
)
print(f"uids=!r")

dataset = cat[uids[-1]].primary.read()
image_data = dataset["simdet_image"]
print(f"{image_data.shape=!r}")

dataset


Transient Scan ID: 96     Time: 2024-06-15 13:19:04
Persistent Unique Scan ID: '5d5d851f-d953-4926-adb2-68e2cf658890'
device=MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']), exception=Data keys (field names) from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']) collide with those from MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu']). The colliding keys are {'m2', 'm2_user_setpoint'}
New stream: 'label_start_motor'
New stream: 'primary'
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
|   seq_num |       time |         m1 |         m2 | simdet_stats1_unique_id | simdet_stats1_max_value | simdet_stats1_total |
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
|         1 | 13:19:07.1 |    -1.0000 |    -0.5000 |                  152906 |                     164 |            11663011 |
|         2 | 13:19:07.6 |    -1.0000 |    -0.1667 |                  152909 |                     160 |            11445949 |
|         3 | 13:19:08.2 |    -1.0000 |     0.1667 |                  152912 |                     159 |            11355981 |
|         4 | 13:19:08.8 |    -1.0000 |     0.5000 |                  152915 |                     164 |            11677059 |
|         5 | 13:19:09.6 |    -0.5000 |     0.5000 |                  152918 |                     164 |            11708538 |
|         6 | 13:19:10.2 |    -0.5000 |     0.1667 |                  152921 |                     166 |            11846736 |
|         7 | 13:19:10.8 |    -0.5000 |    -0.1667 |                  152924 |                     164 |            11692952 |
|         8 | 13:19:11.4 |    -0.5000 |    -0.5000 |                  152927 |                     164 |            11693749 |
|         9 | 13:19:12.2 |     0.0000 |    -0.5000 |                  152930 |                     163 |            11657723 |
|        10 | 13:19:12.8 |     0.0000 |    -0.1667 |                  152933 |                     162 |            11536782 |
|        11 | 13:19:13.4 |     0.0000 |     0.1667 |                  152936 |                     164 |            11717110 |
|        12 | 13:19:14.0 |     0.0000 |     0.5000 |                  152939 |                     160 |            11411453 |
|        13 | 13:19:14.8 |     0.5000 |     0.5000 |                  152942 |                     161 |            11486128 |
|        14 | 13:19:15.4 |     0.5000 |     0.1667 |                  152945 |                     164 |            11702804 |
|        15 | 13:19:16.0 |     0.5000 |    -0.1667 |                  152948 |                     164 |            11728435 |
|        16 | 13:19:16.6 |     0.5000 |    -0.5000 |                  152951 |                     164 |            11695619 |
|        17 | 13:19:17.5 |     1.0000 |    -0.5000 |                  152954 |                     159 |            11388541 |
|        18 | 13:19:18.1 |     1.0000 |    -0.1667 |                  152957 |                     160 |            11455055 |
|        19 | 13:19:18.7 |     1.0000 |     0.1667 |                  152960 |                     160 |            11394404 |
|        20 | 13:19:19.2 |     1.0000 |     0.5000 |                  152963 |                     165 |            11773811 |
+-----------+------------+------------+------------+-------------------------+-------------------------+---------------------+
generator grid_scan ['5d5d851f'] (scan num: 96)
uids=!r
image_data.shape=(20, 3, 1024, 1024)
[20]:
<xarray.Dataset> Size: 63MB
Dimensions:                  (time: 20, dim_0: 3, dim_1: 1024, dim_2: 1024)
Coordinates:
  * time                     (time) float64 160B 1.718e+09 ... 1.718e+09
Dimensions without coordinates: dim_0, dim_1, dim_2
Data variables:
    simdet_image             (time, dim_0, dim_1, dim_2) uint8 63MB 8 14 ... 8 6
    simdet_stats1_unique_id  (time) int64 160B 152906 152909 ... 152960 152963
    simdet_stats1_max_value  (time) float64 160B 164.0 160.0 ... 160.0 165.0
    simdet_stats1_total      (time) float64 160B 1.166e+07 ... 1.177e+07
    m1                       (time) float64 160B -1.0 -1.0 -1.0 ... 1.0 1.0 1.0
    m1_user_setpoint         (time) float64 160B -1.0 -1.0 -1.0 ... 1.0 1.0 1.0
    m2                       (time) float64 160B -0.5 -0.1667 ... 0.1667 0.5
    m2_user_setpoint         (time) float64 160B -0.5 -0.1667 ... 0.1667 0.5

Show the sequence of motor positions#

Here is the sequence of how the motors are stepped during a grid_scan:

  • m1 is stepped through its range; at each step of m1:

    • At each step:

      • m2 is stepped through its range (m1 does not move).

        • With snake_axes=True, the m2 changes direction each time m1 is stepped.

        • At each step:

          • Measure 3 images (as configured aboveduring detector staging).

          • Record total counts.

          • Record maximum counts value.

The grid_scan with snake_axes=True progresses through the sequence of (m1, m2) combinations as would a snake.

The second motor of the grid_scan (m2) is snaked. It’s direction changes with each subsequent increment of the first motor (m1). Here’s a plot of readback value of each motor from a grid_scan plotted v. data point number:

grid_scan motors v time-of-day

SPEC data file#

All along, quietly in the background, the data has been saved both to a catalog and to a SPEC data file. The total counts, max counts, and unique ID from all scans can be plotted from the SPEC file using PyMCA or NeXpy.

The image content is not stored in the SPEC file, so images cannot be viewed from it. However, references to the images are saved as comments. See the comment lines that match a search for

resource {'spec': 'AD_HDF5'

Here is an example:

#C Thu Jun 13 11:36:38 2024.  resource {'spec': 'AD_HDF5', 'root': '/', 'resource_path': 'mnt/iockad/tmp/d94f633b-12a7-4ff0-92af_000000.h5', 'resource_kwargs': {'frame_per_point': 3}, 'path_semantics': 'posix', 'uid': '5328206b-dd13-49f8-b108-17e0d867d470', 'run_start': 'e8c24278-656f-4c79-b3eb-d522310f7649'}
[21]:
with open(specwriter.spec_filename) as f:
    print(f.read())
#F /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/docs/source/howto/20240615-131838.dat
#E 1718475518
#D Sat Jun 15 13:18:38 2024
#C Bluesky  user = prjemian  host = arf.jemian.org
#O0 dcm_m_theta  dcm_m_y  dcm_m_z  fourc_chi  fourc_omega  fourc_phi  fourc_tth  m1
#O1 m10  m11  m12  m13  m14  m15  m16  m2
#O2 m3  m4  m7  m8  m9  sixc_chi  sixc_delta  sixc_gamma
#O3 sixc_mu  sixc_omega  sixc_phi
#o0 dcm_m_theta  dcm_m_y  dcm_m_z  fourc_chi  fourc_omega  fourc_phi  fourc_tth  m1
#o1 m10  m11  m12  m13  m14  m15  m16  m2
#o2 m3  m4  m7  m8  m9  sixc_chi  sixc_delta  sixc_gamma
#o3 sixc_mu  sixc_omega  sixc_phi

#S 92  count(detectors=['simdet_stats1_unique_id', 'simdet_stats1_total', 'simdet_stats1_max_value'], num=5, delay=None)
#D Sat Jun 15 13:18:40 2024
#C Sat Jun 15 13:18:40 2024.  plan_type = generator
#C Sat Jun 15 13:18:40 2024.  uid = ceaecdd7-e1af-411f-94f2-c14d5d3debab
#MD uid = ceaecdd7-e1af-411f-94f2-c14d5d3debab
#MD beamline_id = Bluesky_training
#MD conda_prefix = /home/prjemian/.conda/envs/bluesky_2024_2
#MD databroker_catalog = training
#MD detectors = ['simdet_stats1_unique_id', 'simdet_stats1_total', 'simdet_stats1_max_value']
#MD iconfig = {'ADSIM_IOC_PREFIX': 'ad:', 'GP_IOC_PREFIX': 'gp:', 'DATABROKER_CATALOG': 'training', 'RUNENGINE_METADATA': {'beamline_id': 'Bluesky_training', 'instrument_name': 'BCDA EPICS Bluesky training', 'proposal_id': 'training', 'databroker_catalog': 'training'}, 'RUN_ENGINE_SCAN_ID_PV': 'gp:gp:int20', 'AD_IMAGE_DIR': 'adsimdet/%Y/%m/%d', 'AD_MOUNT_PATH': '/tmp', 'BLUESKY_MOUNT_PATH': '/tmp/docker_ioc/iocad/tmp', 'ALLOW_AREA_DETECTOR_WARMUP': True, 'ENABLE_AREA_DETECTOR_IMAGE_PLUGIN': True, 'ENABLE_CALCS': True, 'USE_PROGRESS_BAR': False, 'WRITE_NEXUS_DATA_FILES': False, 'NEXUS_WARN_MISSING_CONTENT': False, 'NEXUS_FILE_EXTENSION': 'h5', 'WRITE_SPEC_DATA_FILES': True, 'RUNENGINE_MD_PATH': '/home/prjemian/.config/Bluesky_RunEngine_md', 'LOGGING': {'NUMBER_OF_PREVIOUS_BACKUPS': 9}, 'PV_READ_TIMEOUT': 15, 'PV_WRITE_TIMEOUT': 15, 'PV_CONNECTION_TIMEOUT': 15, 'XMODE_DEBUG_LEVEL': 'Minimal', 'MINIMUM_PYTHON_VERSION': [3, 8], 'MINIMUM_BLUESKY_VERSION': [1, 10], 'MINIMUM_OPHYD_VERSION': [1, 7], 'MINIMUM_DATABROKER_VERSION': [1, 2], 'ICONFIG_VERSION': '1.0.1'}
#MD instrument_name = BCDA EPICS Bluesky training
#MD login_id = prjemian@arf.jemian.org
#MD num_intervals = 4
#MD num_points = 5
#MD pid = 154110
#MD proposal_id = training
#MD versions = {'apstools': '1.6.19', 'bluesky': '1.13.0a3', 'databroker': '1.2.5', 'epics': '3.5.2', 'h5py': '3.9.0', 'intake': '0.6.4', 'matplotlib': '3.8.4', 'numpy': '1.26.4', 'ophyd': '1.9.0', 'pyRestTable': '2020.0.8', 'spec2nexus': '2021.2.6'}
#P0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
#P1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5
#P2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
#P3 0.0 0.0 0.0
#N 5
#L Epoch_float  Epoch  simdet_stats1_unique_id  simdet_stats1_total  simdet_stats1_max_value
0.15399622917175293 0 152858 11722735.0 164.0
0.5764033794403076 1 152858 11722735.0 164.0
0.9582419395446777 1 152858 11722735.0 164.0
1.3527321815490723 1 152858 11722735.0 164.0
1.74350905418396 2 152858 11722735.0 164.0
#C Sat Jun 15 13:18:43 2024.  num_events_label_start_motor = 1
#C Sat Jun 15 13:18:43 2024.  num_events_primary = 5
#C Sat Jun 15 13:18:43 2024.  exit_status = success

#S 93  count(detectors=['simdet'], num=5, delay=None)
#D Sat Jun 15 13:18:44 2024
#C Sat Jun 15 13:18:44 2024.  plan_type = generator
#C Sat Jun 15 13:18:44 2024.  uid = f39f2eb2-fc04-4696-ac26-245cd574f7c2
#MD uid = f39f2eb2-fc04-4696-ac26-245cd574f7c2
#MD beamline_id = Bluesky_training
#MD conda_prefix = /home/prjemian/.conda/envs/bluesky_2024_2
#MD databroker_catalog = training
#MD detectors = ['simdet']
#MD iconfig = {'ADSIM_IOC_PREFIX': 'ad:', 'GP_IOC_PREFIX': 'gp:', 'DATABROKER_CATALOG': 'training', 'RUNENGINE_METADATA': {'beamline_id': 'Bluesky_training', 'instrument_name': 'BCDA EPICS Bluesky training', 'proposal_id': 'training', 'databroker_catalog': 'training'}, 'RUN_ENGINE_SCAN_ID_PV': 'gp:gp:int20', 'AD_IMAGE_DIR': 'adsimdet/%Y/%m/%d', 'AD_MOUNT_PATH': '/tmp', 'BLUESKY_MOUNT_PATH': '/tmp/docker_ioc/iocad/tmp', 'ALLOW_AREA_DETECTOR_WARMUP': True, 'ENABLE_AREA_DETECTOR_IMAGE_PLUGIN': True, 'ENABLE_CALCS': True, 'USE_PROGRESS_BAR': False, 'WRITE_NEXUS_DATA_FILES': False, 'NEXUS_WARN_MISSING_CONTENT': False, 'NEXUS_FILE_EXTENSION': 'h5', 'WRITE_SPEC_DATA_FILES': True, 'RUNENGINE_MD_PATH': '/home/prjemian/.config/Bluesky_RunEngine_md', 'LOGGING': {'NUMBER_OF_PREVIOUS_BACKUPS': 9}, 'PV_READ_TIMEOUT': 15, 'PV_WRITE_TIMEOUT': 15, 'PV_CONNECTION_TIMEOUT': 15, 'XMODE_DEBUG_LEVEL': 'Minimal', 'MINIMUM_PYTHON_VERSION': [3, 8], 'MINIMUM_BLUESKY_VERSION': [1, 10], 'MINIMUM_OPHYD_VERSION': [1, 7], 'MINIMUM_DATABROKER_VERSION': [1, 2], 'ICONFIG_VERSION': '1.0.1'}
#MD instrument_name = BCDA EPICS Bluesky training
#MD login_id = prjemian@arf.jemian.org
#MD num_intervals = 4
#MD num_points = 5
#MD pid = 154110
#MD proposal_id = training
#MD versions = {'apstools': '1.6.19', 'bluesky': '1.13.0a3', 'databroker': '1.2.5', 'epics': '3.5.2', 'h5py': '3.9.0', 'intake': '0.6.4', 'matplotlib': '3.8.4', 'numpy': '1.26.4', 'ophyd': '1.9.0', 'pyRestTable': '2020.0.8', 'spec2nexus': '2021.2.6'}
#P0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
#P1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5
#P2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
#P3 0.0 0.0 0.0
#N 7
#L Epoch_float  Epoch  simdet_image  simdet_stats1_unique_id  simdet_stats1_max_value  simdet_stats1_total  simdet
0.2595047950744629 0 0 152861 164.0 11658834.0 0
#U 0 simdet_image 510c0d90-f922-41c2-a5ed-2b1013b82ab3/0
0.6947643756866455 1 1 152864 164.0 11710598.0 0
#U 1 simdet_image 510c0d90-f922-41c2-a5ed-2b1013b82ab3/1
1.1037673950195312 1 2 152867 163.0 11537287.0 0
#U 2 simdet_image 510c0d90-f922-41c2-a5ed-2b1013b82ab3/2
1.5303704738616943 2 3 152870 159.0 11360372.0 0
#U 3 simdet_image 510c0d90-f922-41c2-a5ed-2b1013b82ab3/3
1.9436140060424805 2 4 152873 166.0 11817560.0 0
#U 4 simdet_image 510c0d90-f922-41c2-a5ed-2b1013b82ab3/4
#C Sat Jun 15 13:18:45 2024.  resource {'spec': 'AD_HDF5', 'root': '/', 'resource_path': 'mnt/iockad/tmp/1245c370-4953-4ff3-8982_000000.h5', 'resource_kwargs': {'frame_per_point': 3}, 'path_semantics': 'posix', 'uid': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'run_start': 'f39f2eb2-fc04-4696-ac26-245cd574f7c2'}
#C Sat Jun 15 13:18:45 2024.  datum {'resource': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'datum_id': '510c0d90-f922-41c2-a5ed-2b1013b82ab3/0', 'datum_kwargs': {'point_number': 0}}
#C Sat Jun 15 13:18:45 2024.  datum {'resource': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'datum_id': '510c0d90-f922-41c2-a5ed-2b1013b82ab3/1', 'datum_kwargs': {'point_number': 1}}
#C Sat Jun 15 13:18:45 2024.  datum {'resource': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'datum_id': '510c0d90-f922-41c2-a5ed-2b1013b82ab3/2', 'datum_kwargs': {'point_number': 2}}
#C Sat Jun 15 13:18:46 2024.  datum {'resource': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'datum_id': '510c0d90-f922-41c2-a5ed-2b1013b82ab3/3', 'datum_kwargs': {'point_number': 3}}
#C Sat Jun 15 13:18:46 2024.  datum {'resource': '510c0d90-f922-41c2-a5ed-2b1013b82ab3', 'datum_id': '510c0d90-f922-41c2-a5ed-2b1013b82ab3/4', 'datum_kwargs': {'point_number': 4}}
#C Sat Jun 15 13:18:47 2024.  num_events_label_start_motor = 1
#C Sat Jun 15 13:18:47 2024.  num_events_primary = 5
#C Sat Jun 15 13:18:47 2024.  exit_status = success

#S 94  scan(detectors=['simdet'], num=5, args='['m1', -1, 1]', per_step='None')
#D Sat Jun 15 13:18:49 2024
#C Sat Jun 15 13:18:49 2024.  plan_type = generator
#C Sat Jun 15 13:18:49 2024.  uid = 03dde617-eb69-4b66-abe5-8595de04051d
#MD uid = 03dde617-eb69-4b66-abe5-8595de04051d
#MD beamline_id = Bluesky_training
#MD conda_prefix = /home/prjemian/.conda/envs/bluesky_2024_2
#MD databroker_catalog = training
#MD detectors = ['simdet']
#MD iconfig = {'ADSIM_IOC_PREFIX': 'ad:', 'GP_IOC_PREFIX': 'gp:', 'DATABROKER_CATALOG': 'training', 'RUNENGINE_METADATA': {'beamline_id': 'Bluesky_training', 'instrument_name': 'BCDA EPICS Bluesky training', 'proposal_id': 'training', 'databroker_catalog': 'training'}, 'RUN_ENGINE_SCAN_ID_PV': 'gp:gp:int20', 'AD_IMAGE_DIR': 'adsimdet/%Y/%m/%d', 'AD_MOUNT_PATH': '/tmp', 'BLUESKY_MOUNT_PATH': '/tmp/docker_ioc/iocad/tmp', 'ALLOW_AREA_DETECTOR_WARMUP': True, 'ENABLE_AREA_DETECTOR_IMAGE_PLUGIN': True, 'ENABLE_CALCS': True, 'USE_PROGRESS_BAR': False, 'WRITE_NEXUS_DATA_FILES': False, 'NEXUS_WARN_MISSING_CONTENT': False, 'NEXUS_FILE_EXTENSION': 'h5', 'WRITE_SPEC_DATA_FILES': True, 'RUNENGINE_MD_PATH': '/home/prjemian/.config/Bluesky_RunEngine_md', 'LOGGING': {'NUMBER_OF_PREVIOUS_BACKUPS': 9}, 'PV_READ_TIMEOUT': 15, 'PV_WRITE_TIMEOUT': 15, 'PV_CONNECTION_TIMEOUT': 15, 'XMODE_DEBUG_LEVEL': 'Minimal', 'MINIMUM_PYTHON_VERSION': [3, 8], 'MINIMUM_BLUESKY_VERSION': [1, 10], 'MINIMUM_OPHYD_VERSION': [1, 7], 'MINIMUM_DATABROKER_VERSION': [1, 2], 'ICONFIG_VERSION': '1.0.1'}
#MD instrument_name = BCDA EPICS Bluesky training
#MD login_id = prjemian@arf.jemian.org
#MD motors = ('m1',)
#MD num_intervals = 4
#MD num_points = 5
#MD pid = 154110
#MD plan_pattern = inner_product
#MD plan_pattern_args = {'num': 5, 'args': ["MyEpicsMotor(prefix='gp:m1', name='m1', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu'])", -1, 1]}
#MD plan_pattern_module = bluesky.plan_patterns
#MD proposal_id = training
#MD versions = {'apstools': '1.6.19', 'bluesky': '1.13.0a3', 'databroker': '1.2.5', 'epics': '3.5.2', 'h5py': '3.9.0', 'intake': '0.6.4', 'matplotlib': '3.8.4', 'numpy': '1.26.4', 'ophyd': '1.9.0', 'pyRestTable': '2020.0.8', 'spec2nexus': '2021.2.6'}
#P0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
#P1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5
#P2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
#P3 0.0 0.0 0.0
#N 9
#L m1  Epoch_float  Epoch  simdet_image  simdet_stats1_unique_id  simdet_stats1_max_value  simdet_stats1_total  m1_user_setpoint  simdet
-1.0 2.4708797931671143 2 0 152876 160.0 11445712.0 -1.0 0
#U 0 simdet_image a833899a-286a-4eaf-94d8-8feaf24c9b52/0
-0.5 3.2200405597686768 3 1 152879 163.0 11658331.0 -0.5 0
#U 1 simdet_image a833899a-286a-4eaf-94d8-8feaf24c9b52/1
0.0 4.029770612716675 4 2 152882 162.0 11535839.0 0.0 0
#U 2 simdet_image a833899a-286a-4eaf-94d8-8feaf24c9b52/2
0.5 4.832399368286133 5 3 152885 165.0 11799101.0 0.5 0
#U 3 simdet_image a833899a-286a-4eaf-94d8-8feaf24c9b52/3
1.0 5.632269620895386 6 4 152888 166.0 11824045.0 1.0 0
#U 4 simdet_image a833899a-286a-4eaf-94d8-8feaf24c9b52/4
#C Sat Jun 15 13:18:52 2024.  resource {'spec': 'AD_HDF5', 'root': '/', 'resource_path': 'mnt/iockad/tmp/d2ada5a8-8b64-475f-9c2c_000000.h5', 'resource_kwargs': {'frame_per_point': 3}, 'path_semantics': 'posix', 'uid': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'run_start': '03dde617-eb69-4b66-abe5-8595de04051d'}
#C Sat Jun 15 13:18:52 2024.  datum {'resource': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'datum_id': 'a833899a-286a-4eaf-94d8-8feaf24c9b52/0', 'datum_kwargs': {'point_number': 0}}
#C Sat Jun 15 13:18:52 2024.  datum {'resource': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'datum_id': 'a833899a-286a-4eaf-94d8-8feaf24c9b52/1', 'datum_kwargs': {'point_number': 1}}
#C Sat Jun 15 13:18:53 2024.  datum {'resource': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'datum_id': 'a833899a-286a-4eaf-94d8-8feaf24c9b52/2', 'datum_kwargs': {'point_number': 2}}
#C Sat Jun 15 13:18:54 2024.  datum {'resource': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'datum_id': 'a833899a-286a-4eaf-94d8-8feaf24c9b52/3', 'datum_kwargs': {'point_number': 3}}
#C Sat Jun 15 13:18:55 2024.  datum {'resource': 'a833899a-286a-4eaf-94d8-8feaf24c9b52', 'datum_id': 'a833899a-286a-4eaf-94d8-8feaf24c9b52/4', 'datum_kwargs': {'point_number': 4}}
#C Sat Jun 15 13:18:55 2024.  num_events_label_start_motor = 1
#C Sat Jun 15 13:18:55 2024.  num_events_primary = 5
#C Sat Jun 15 13:18:55 2024.  exit_status = success

#S 95  scan(detectors=['simdet'], num=5, args='['m1', -1, 1, 'm2', 4, 1.5]', per_step='None')
#D Sat Jun 15 13:18:56 2024
#C Sat Jun 15 13:18:56 2024.  plan_type = generator
#C Sat Jun 15 13:18:56 2024.  uid = b0fc4001-c2e2-468a-ac82-1ccb19ddbdb3
#MD uid = b0fc4001-c2e2-468a-ac82-1ccb19ddbdb3
#MD beamline_id = Bluesky_training
#MD conda_prefix = /home/prjemian/.conda/envs/bluesky_2024_2
#MD databroker_catalog = training
#MD detectors = ['simdet']
#MD iconfig = {'ADSIM_IOC_PREFIX': 'ad:', 'GP_IOC_PREFIX': 'gp:', 'DATABROKER_CATALOG': 'training', 'RUNENGINE_METADATA': {'beamline_id': 'Bluesky_training', 'instrument_name': 'BCDA EPICS Bluesky training', 'proposal_id': 'training', 'databroker_catalog': 'training'}, 'RUN_ENGINE_SCAN_ID_PV': 'gp:gp:int20', 'AD_IMAGE_DIR': 'adsimdet/%Y/%m/%d', 'AD_MOUNT_PATH': '/tmp', 'BLUESKY_MOUNT_PATH': '/tmp/docker_ioc/iocad/tmp', 'ALLOW_AREA_DETECTOR_WARMUP': True, 'ENABLE_AREA_DETECTOR_IMAGE_PLUGIN': True, 'ENABLE_CALCS': True, 'USE_PROGRESS_BAR': False, 'WRITE_NEXUS_DATA_FILES': False, 'NEXUS_WARN_MISSING_CONTENT': False, 'NEXUS_FILE_EXTENSION': 'h5', 'WRITE_SPEC_DATA_FILES': True, 'RUNENGINE_MD_PATH': '/home/prjemian/.config/Bluesky_RunEngine_md', 'LOGGING': {'NUMBER_OF_PREVIOUS_BACKUPS': 9}, 'PV_READ_TIMEOUT': 15, 'PV_WRITE_TIMEOUT': 15, 'PV_CONNECTION_TIMEOUT': 15, 'XMODE_DEBUG_LEVEL': 'Minimal', 'MINIMUM_PYTHON_VERSION': [3, 8], 'MINIMUM_BLUESKY_VERSION': [1, 10], 'MINIMUM_OPHYD_VERSION': [1, 7], 'MINIMUM_DATABROKER_VERSION': [1, 2], 'ICONFIG_VERSION': '1.0.1'}
#MD instrument_name = BCDA EPICS Bluesky training
#MD login_id = prjemian@arf.jemian.org
#MD motors = ('m1', 'm2')
#MD num_intervals = 4
#MD num_points = 5
#MD pid = 154110
#MD plan_pattern = inner_product
#MD plan_pattern_args = {'num': 5, 'args': ["MyEpicsMotor(prefix='gp:m1', name='m1', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu'])", -1, 1, "MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu'])", 4, 1.5]}
#MD plan_pattern_module = bluesky.plan_patterns
#MD proposal_id = training
#MD versions = {'apstools': '1.6.19', 'bluesky': '1.13.0a3', 'databroker': '1.2.5', 'epics': '3.5.2', 'h5py': '3.9.0', 'intake': '0.6.4', 'matplotlib': '3.8.4', 'numpy': '1.26.4', 'ophyd': '1.9.0', 'pyRestTable': '2020.0.8', 'spec2nexus': '2021.2.6'}
#P0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
#P1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5
#P2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
#P3 0.0 0.0 0.0
#N 11
#L m1  m2  Epoch_float  Epoch  simdet_image  simdet_stats1_unique_id  simdet_stats1_max_value  simdet_stats1_total  m1_user_setpoint  m2_user_setpoint  simdet
-1.0 4.0 3.9975199699401855 4 0 152891 163.0 11659109.0 -1.0 4.0 0
#U 0 simdet_image 46d1362c-9557-45a5-aadd-407e0bd98646/0
-0.5 3.375 4.837675094604492 5 1 152894 159.0 11355578.0 -0.5 3.375 0
#U 1 simdet_image 46d1362c-9557-45a5-aadd-407e0bd98646/1
0.0 2.75 5.74786376953125 6 2 152897 164.0 11659418.0 0.0 2.75 0
#U 2 simdet_image 46d1362c-9557-45a5-aadd-407e0bd98646/2
0.5 2.125 6.649600028991699 7 3 152900 162.0 11536310.0 0.5 2.125 0
#U 3 simdet_image 46d1362c-9557-45a5-aadd-407e0bd98646/3
1.0 1.5 7.549147605895996 8 4 152903 163.0 11658922.0 1.0 1.5 0
#U 4 simdet_image 46d1362c-9557-45a5-aadd-407e0bd98646/4
#C Sat Jun 15 13:19:00 2024.  resource {'spec': 'AD_HDF5', 'root': '/', 'resource_path': 'mnt/iockad/tmp/6eafee88-ec97-4498-a6f5_000000.h5', 'resource_kwargs': {'frame_per_point': 3}, 'path_semantics': 'posix', 'uid': '46d1362c-9557-45a5-aadd-407e0bd98646', 'run_start': 'b0fc4001-c2e2-468a-ac82-1ccb19ddbdb3'}
#C Sat Jun 15 13:19:00 2024.  datum {'resource': '46d1362c-9557-45a5-aadd-407e0bd98646', 'datum_id': '46d1362c-9557-45a5-aadd-407e0bd98646/0', 'datum_kwargs': {'point_number': 0}}
#C Sat Jun 15 13:19:00 2024.  datum {'resource': '46d1362c-9557-45a5-aadd-407e0bd98646', 'datum_id': '46d1362c-9557-45a5-aadd-407e0bd98646/1', 'datum_kwargs': {'point_number': 1}}
#C Sat Jun 15 13:19:01 2024.  datum {'resource': '46d1362c-9557-45a5-aadd-407e0bd98646', 'datum_id': '46d1362c-9557-45a5-aadd-407e0bd98646/2', 'datum_kwargs': {'point_number': 2}}
#C Sat Jun 15 13:19:02 2024.  datum {'resource': '46d1362c-9557-45a5-aadd-407e0bd98646', 'datum_id': '46d1362c-9557-45a5-aadd-407e0bd98646/3', 'datum_kwargs': {'point_number': 3}}
#C Sat Jun 15 13:19:03 2024.  datum {'resource': '46d1362c-9557-45a5-aadd-407e0bd98646', 'datum_id': '46d1362c-9557-45a5-aadd-407e0bd98646/4', 'datum_kwargs': {'point_number': 4}}
#C Sat Jun 15 13:19:03 2024.  num_events_label_start_motor = 1
#C Sat Jun 15 13:19:03 2024.  num_events_primary = 5
#C Sat Jun 15 13:19:03 2024.  exit_status = success

#S 96  grid_scan(detectors=['simdet'], args='['m1', -1, 1, 5, 'm2', -0.5, 0.5, 4, True]', per_step='None')
#D Sat Jun 15 13:19:04 2024
#C Sat Jun 15 13:19:04 2024.  plan_type = generator
#C Sat Jun 15 13:19:04 2024.  uid = 5d5d851f-d953-4926-adb2-68e2cf658890
#MD uid = 5d5d851f-d953-4926-adb2-68e2cf658890
#MD beamline_id = Bluesky_training
#MD conda_prefix = /home/prjemian/.conda/envs/bluesky_2024_2
#MD databroker_catalog = training
#MD detectors = ['simdet']
#MD extents = ([-1, 1], [-0.5, 0.5])
#MD iconfig = {'ADSIM_IOC_PREFIX': 'ad:', 'GP_IOC_PREFIX': 'gp:', 'DATABROKER_CATALOG': 'training', 'RUNENGINE_METADATA': {'beamline_id': 'Bluesky_training', 'instrument_name': 'BCDA EPICS Bluesky training', 'proposal_id': 'training', 'databroker_catalog': 'training'}, 'RUN_ENGINE_SCAN_ID_PV': 'gp:gp:int20', 'AD_IMAGE_DIR': 'adsimdet/%Y/%m/%d', 'AD_MOUNT_PATH': '/tmp', 'BLUESKY_MOUNT_PATH': '/tmp/docker_ioc/iocad/tmp', 'ALLOW_AREA_DETECTOR_WARMUP': True, 'ENABLE_AREA_DETECTOR_IMAGE_PLUGIN': True, 'ENABLE_CALCS': True, 'USE_PROGRESS_BAR': False, 'WRITE_NEXUS_DATA_FILES': False, 'NEXUS_WARN_MISSING_CONTENT': False, 'NEXUS_FILE_EXTENSION': 'h5', 'WRITE_SPEC_DATA_FILES': True, 'RUNENGINE_MD_PATH': '/home/prjemian/.config/Bluesky_RunEngine_md', 'LOGGING': {'NUMBER_OF_PREVIOUS_BACKUPS': 9}, 'PV_READ_TIMEOUT': 15, 'PV_WRITE_TIMEOUT': 15, 'PV_CONNECTION_TIMEOUT': 15, 'XMODE_DEBUG_LEVEL': 'Minimal', 'MINIMUM_PYTHON_VERSION': [3, 8], 'MINIMUM_BLUESKY_VERSION': [1, 10], 'MINIMUM_OPHYD_VERSION': [1, 7], 'MINIMUM_DATABROKER_VERSION': [1, 2], 'ICONFIG_VERSION': '1.0.1'}
#MD instrument_name = BCDA EPICS Bluesky training
#MD login_id = prjemian@arf.jemian.org
#MD motors = ('m1', 'm2')
#MD num_intervals = 19
#MD num_points = 20
#MD pid = 154110
#MD plan_pattern = outer_product
#MD plan_pattern_args = {'args': ["MyEpicsMotor(prefix='gp:m1', name='m1', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu'])", -1, 1, 5, "MyEpicsMotor(prefix='gp:m2', name='m2', settle_time=0.0, timeout=None, read_attrs=['user_readback', 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity', 'acceleration', 'motor_egu'])", -0.5, 0.5, 4, True]}
#MD plan_pattern_module = bluesky.plan_patterns
#MD proposal_id = training
#MD shape = (5, 4)
#MD snaking = (False, True)
#MD versions = {'apstools': '1.6.19', 'bluesky': '1.13.0a3', 'databroker': '1.2.5', 'epics': '3.5.2', 'h5py': '3.9.0', 'intake': '0.6.4', 'matplotlib': '3.8.4', 'numpy': '1.26.4', 'ophyd': '1.9.0', 'pyRestTable': '2020.0.8', 'spec2nexus': '2021.2.6'}
#P0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
#P1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.5
#P2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
#P3 0.0 0.0 0.0
#N 11
#L m1  m2  Epoch_float  Epoch  simdet_image  simdet_stats1_unique_id  simdet_stats1_max_value  simdet_stats1_total  m1_user_setpoint  m2_user_setpoint  simdet
-1.0 -0.5 2.472050189971924 2 0 152906 164.0 11663011.0 -1.0 -0.5 0
#U 0 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/0
-1.0 -0.16670000000000001 3.0593597888946533 3 1 152909 160.0 11445949.0 -1.0 -0.16666666666666669 0
#U 1 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/1
-1.0 0.16670000000000001 3.6419265270233154 4 2 152912 159.0 11355981.0 -1.0 0.16666666666666663 0
#U 2 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/2
-1.0 0.5 4.243873596191406 4 3 152915 164.0 11677059.0 -1.0 0.5 0
#U 3 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/3
-0.5 0.5 5.065932035446167 5 4 152918 164.0 11708538.0 -0.5 0.5 0
#U 4 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/4
-0.5 0.16670000000000001 5.653802394866943 6 5 152921 166.0 11846736.0 -0.5 0.16666666666666663 0
#U 5 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/5
-0.5 -0.16670000000000001 6.257414102554321 6 6 152924 164.0 11692952.0 -0.5 -0.16666666666666669 0
#U 6 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/6
-0.5 -0.5 6.854701042175293 7 7 152927 164.0 11693749.0 -0.5 -0.5 0
#U 7 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/7
0.0 -0.5 7.652886867523193 8 8 152930 163.0 11657723.0 0.0 -0.5 0
#U 8 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/8
0.0 -0.16670000000000001 8.261860609054565 8 9 152933 162.0 11536782.0 0.0 -0.16666666666666669 0
#U 9 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/9
0.0 0.16670000000000001 8.861814975738525 9 10 152936 164.0 11717110.0 0.0 0.16666666666666663 0
#U 10 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/10
0.0 0.5 9.468685865402222 9 11 152939 160.0 11411453.0 0.0 0.5 0
#U 11 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/11
0.5 0.5 10.268848419189453 10 12 152942 161.0 11486128.0 0.5 0.5 0
#U 12 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/12
0.5 0.16670000000000001 10.868767976760864 11 13 152945 164.0 11702804.0 0.5 0.16666666666666663 0
#U 13 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/13
0.5 -0.16670000000000001 11.464916229248047 11 14 152948 164.0 11728435.0 0.5 -0.16666666666666669 0
#U 14 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/14
0.5 -0.5 12.057462930679321 12 15 152951 164.0 11695619.0 0.5 -0.5 0
#U 15 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/15
1.0 -0.5 12.87460470199585 13 16 152954 159.0 11388541.0 1.0 -0.5 0
#U 16 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/16
1.0 -0.16670000000000001 13.473078966140747 13 17 152957 160.0 11455055.0 1.0 -0.16666666666666669 0
#U 17 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/17
1.0 0.16670000000000001 14.072843313217163 14 18 152960 160.0 11394404.0 1.0 0.16666666666666663 0
#U 18 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/18
1.0 0.5 14.665706634521484 15 19 152963 165.0 11773811.0 1.0 0.5 0
#U 19 simdet_image 6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/19
#C Sat Jun 15 13:19:07 2024.  resource {'spec': 'AD_HDF5', 'root': '/', 'resource_path': 'mnt/iockad/tmp/f23af069-cf36-4939-ac63_000000.h5', 'resource_kwargs': {'frame_per_point': 3}, 'path_semantics': 'posix', 'uid': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'run_start': '5d5d851f-d953-4926-adb2-68e2cf658890'}
#C Sat Jun 15 13:19:07 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/0', 'datum_kwargs': {'point_number': 0}}
#C Sat Jun 15 13:19:07 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/1', 'datum_kwargs': {'point_number': 1}}
#C Sat Jun 15 13:19:08 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/2', 'datum_kwargs': {'point_number': 2}}
#C Sat Jun 15 13:19:08 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/3', 'datum_kwargs': {'point_number': 3}}
#C Sat Jun 15 13:19:09 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/4', 'datum_kwargs': {'point_number': 4}}
#C Sat Jun 15 13:19:10 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/5', 'datum_kwargs': {'point_number': 5}}
#C Sat Jun 15 13:19:10 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/6', 'datum_kwargs': {'point_number': 6}}
#C Sat Jun 15 13:19:11 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/7', 'datum_kwargs': {'point_number': 7}}
#C Sat Jun 15 13:19:12 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/8', 'datum_kwargs': {'point_number': 8}}
#C Sat Jun 15 13:19:12 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/9', 'datum_kwargs': {'point_number': 9}}
#C Sat Jun 15 13:19:13 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/10', 'datum_kwargs': {'point_number': 10}}
#C Sat Jun 15 13:19:14 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/11', 'datum_kwargs': {'point_number': 11}}
#C Sat Jun 15 13:19:14 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/12', 'datum_kwargs': {'point_number': 12}}
#C Sat Jun 15 13:19:15 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/13', 'datum_kwargs': {'point_number': 13}}
#C Sat Jun 15 13:19:16 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/14', 'datum_kwargs': {'point_number': 14}}
#C Sat Jun 15 13:19:16 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/15', 'datum_kwargs': {'point_number': 15}}
#C Sat Jun 15 13:19:17 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/16', 'datum_kwargs': {'point_number': 16}}
#C Sat Jun 15 13:19:18 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/17', 'datum_kwargs': {'point_number': 17}}
#C Sat Jun 15 13:19:18 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/18', 'datum_kwargs': {'point_number': 18}}
#C Sat Jun 15 13:19:19 2024.  datum {'resource': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180', 'datum_id': '6b69e3a2-9d68-4ea7-beaa-8ea32f0c0180/19', 'datum_kwargs': {'point_number': 19}}
#C Sat Jun 15 13:19:19 2024.  num_events_label_start_motor = 1
#C Sat Jun 15 13:19:19 2024.  num_events_primary = 20
#C Sat Jun 15 13:19:19 2024.  exit_status = success