{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Area Detector with default HDF5 File Name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Objective**\n", "\n", "Demonstrate and explain the setup of an [EPICS area detector](https://areadetector.github.io/master/index.html) to acquire an image with [bluesky](https://blueskyproject.io/) and write it to an [HDF5](https://www.hdfgroup.org/solutions/hdf5) file. Use the standard [ophyd conventions](https://blueskyproject.io/ophyd) for file naming and other setup. Show how to retrieve the image using the [databroker](https://blueskyproject.io/databroker).\n", "\n", "**Contents**\n", "\n", "- [EPICS Area Detector IOC](#EPICS-Area-Detector-IOC) is pre-built\n", "- [File Directories](#File-Directories) are different on IOC and bluesky workstation\n", "- [ophyd](#ophyd) to describe the hardware\n", "- [bluesky](#bluesky) for the measurement\n", "- [databroker](#databroker) to view the image\n", "- [punx](#punx) (not part of Bluesky) to look at the HDF5 file\n", "- [Recapitulation](#Recapitulation) - rendition with no explanations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EPICS Area Detector IOC\n", "\n", "This example uses a prebuilt [ADSimDetector](https://areadetector.github.io/master/ADSimDetector/simDetector.html) driver, packaged in a [docker](https://www.docker.com/) image\n", "([prjemian/custom-synapps-6.2-ad-3.10](https://hub.docker.com/r/prjemian/custom-synapps-6.2-ad-3.10/tags)). The [EPICS IOC](https://docs.epics-controls.org/projects/how-tos/en/latest/getting-started/creating-ioc.html) is configured with prefix `ad:` using the [bash shell script](https://github.com/prjemian/epics-docker/blob/main/v1.1/n6_custom_areaDetector/start_adsim.sh):\n", "\n", "```bash\n", "user@workstation:~$ start_adsim.sh ad\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "IOC = \"ad:\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## File Directories\n", "\n", "Files from the IOC are mounted on the docker host in the directory `/tmp/docker_ioc/iocad`. The bluesky session runs on the docker host.\n", "\n", "system | file directory\n", "--- | ---\n", "area detector IOC | `/tmp`\n", "bluesky | `/tmp/docker_ioc/iocad/tmp`\n", "\n", "***details***\n", "\n", "It is important to understand that, while the EPICS IOC and the Python process where the user interacts (with bluesky and databroker) should both see the same image file written by acquisition, the directory path to that file may be different on the two systems. Typically, the file system is mounted on both (IOC & Python) at the time of acquisition, perhaps at different mount points on each. Alternatively, the image file written by the IOC may be copied to a directory where Python can find the file **when** the user attempts to read the image data via databroker.\n", "\n", "For convenience now and later, define these two directories using [pathlib](https://docs.python.org/3/library/pathlib.html), from the Python standard library." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pathlib\n", "\n", "AD_IOC_MOUNT_PATH = pathlib.Path(\"/tmp\")\n", "BLUESKY_MOUNT_PATH = pathlib.Path(\"/tmp/docker_ioc/iocad/tmp\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Image files are written to a subdirectory (*image directory*) of the mount path.\n", "\n", "***details***\n", "\n", "In this case, we use a feature of the area detector [HDF5 file writer](https://areadetector.github.io/master/ADCore/NDFileHDF5.html) plugin that accepts [time format codes](https://cplusplus.com/reference/ctime/strftime/), such as `%Y` for 4-digit year, to build the image directory path based on the current date. (For reference, Python's [datetime](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) package uses these same codes.)\n", "\n", "Here, we create an `example` directory with subdirectory for year, month, and day (such as: `example/2022/07/04`):" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "IMAGE_DIR = \"example/%Y/%m/%d\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the two pathlib objects created above, create two string objects for configuration of the HDF5 plugin.\n", "\n", "***details***\n", "\n", "The area detector IOC expects each string to end with a `/` character but will add it if it is not provided. But ophyd requires the value sent to EPICS to match exactly the value that the IOC reports, thus we make the correct ending here." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# MUST end with a `/`, pathlib will NOT provide it\n", "WRITE_PATH_TEMPLATE = f\"{AD_IOC_MOUNT_PATH / IMAGE_DIR}/\"\n", "READ_PATH_TEMPLATE = f\"{BLUESKY_MOUNT_PATH / IMAGE_DIR}/\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ophyd\n", "\n", "In ophyd, the support for hardware involving multiple PVs is constructed as a subclass of `ophyd.Device`.\n", "\n", "***details***\n", "\n", "The EPICS area detector is described with a special `Device` subclass called `ophyd.areadetector.DetectorBase`. An area detector has a detector driver, called a `cam` in the ophyd support, which is another subclass.\n", "\n", "Before you can create an ophyd object for your ADSimDetector detector, you'll need to create an ophyd class that describes the features of the EPICS Area Detector interface you plan to use, such as the camera (*ADSimDetector*, in this case) and any plugins such as computations or file writers.\n", "\n", "Each of the plugins (image, PVA, HDF5, ...) has its own subclass. The general structure is:\n", "\n", "```\n", "DetectorBase\n", " CamBase\n", " ImagePlugin\n", " HDF5Plugin\n", " PvaPlugin\n", " ...\n", "```\n", "\n", "***Which plugins are needed by bluesky?***\n", "\n", "In this example, we must define:\n", "\n", "name | subclass of | why?\n", "--- | --- | ---\n", "`cam` | `CamBase` | generates the image data\n", "`hdf1` | `HDF5Plugin` | output to an HDF5 file\n", "`image1` | `ImagePlugin` | make the image viewable\n", "\n", "The component name `hdf1`, the `1` is customary, referring to the `HDF1:` part of the EPICS PV name for the *first* HDF5 file writer plugin in the EPICS IOC. (It is possible to create an IOC with more than one HDF5 file writer plugin.) Similar for the `image1` component.\n", "\n", "In EPICS Area Detector, an [NDArray](https://areadetector.github.io/master/ADCore/NDArray.html) is the data passed from a detector `cam` to plugins. Each plugin references its input NDArray by the port name of the source.\n", "\n", "> To connect plugin `downstream` to plugin `upstream`, set `downstream.nd_array_port` (**Port**) to `upstream.port_name` (**Plugin name**).\n", "\n", "In this example screen view, using the ADSimDetector, all the plugins shown are\n", "configured to receive their input from `SIM1` which is the `cam`. (While the\n", "screen view shows the PVA1 plugin enabled, we will not enable that in this example.)\n", "\n", "![](./2022-08-03-commonPlugins-snapshot.png)\n", "\n", "Each [port](https://blueskyproject.io/ophyd/explanations/area-detector.html?highlight=singletrigger#ports) named by the detector ***must*** have its plugin (or `cam`) defined in the ophyd detector class. \n", "\n", "You can check if you missed any plugins once you have created your detector object by calling its `.missing_plugins()` method. For example, where our example ADSimDetector IOC uses the `ad:` PV prefix:\n", "\n", "```py\n", "from ophyd.areadetector import SimDetector\n", "det = PilatusDetector(\"ad:\", name=\"det\")\n", "det.missing_plugins()\n", "```\n", "\n", "We expect to see an empty list, `[]`, as the result of this last command. Otherwise, the list will describe the plugins needed." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### cam\n", "\n", "The `cam` Device describes the EPICS area detector camera driver for this detector.\n", "\n", "***details***\n", "\n", "The [ophyd package](https://blueskyproject.io/ophyd/explanations/area-detector.html#specific-hardware) has support for many of the area detector drivers. A complete list is available in the [ophyd source code](https://github.com/bluesky/ophyd/blob/master/ophyd/areadetector/cam.py). The principle difference between area detector drivers is the `cam` support, which is specific to the detector driver being configured. All the other plugin support is independent of the `cam` support. Use steps similar to these to implement for a different detector driver.\n", "\n", "The ADSimDetector driver is in this list, as `SimDetectorCam`. But the ophyd support is out of date for the EPICS area detector release 3.10 used here, so we need to make modifications with a subclass, as is typical. The changes we see are current since ADSimDetector v3.1.1.\n", "\n", "In the [apstools](https://bcda-aps.github.io/apstools/latest/) package, `apstools.devices.CamMixin_V34` provides the updates needed. (Eventually, these updates will be *hoisted* into the ophyd package.)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "from apstools.devices import CamMixin_V34\n", "from ophyd.areadetector import SimDetectorCam\n", "from ophyd import ADComponent\n", "\n", "class SimDetectorCam_V34(CamMixin_V34, SimDetectorCam):\n", " \"\"\"Revise SimDetectorCam for ADCore revisions.\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### HDF5\n", "\n", "The `hdf1` Device describes the HDF5 File Writing plugin for this detector.\n", "\n", "***details***\n", "\n", "Support for writing images to HDF5 files using the area detector [HDF5 File Writer plugin](https://github.com/bluesky/ophyd/blob/master/ophyd/areadetector/plugins.py) comes from the `ophyd.areadetector.HDF5Plugin`. This plugin comes in different versions for different versions of area detector `ADCore`. The `HDF5Plugin` ophyd support was written for an older version of the HDF5 File Writer plugin, but there is a `HDF5Plugin_V34` version that may be used with Area Detector release 3.4 and above. Our IOC uses release 3.10.\n", "\n", "The plugin provides supports writing HDF5 files. Some modification is needed, via a mixin class, for the manner of acquisition.\n", "\n", "Here we build a custom HDF5 plugin class with `FileStoreHDF5IterativeWrite`. This mixin class configures the HDF5 plugin to collect one or more images with the IOC, then writes file name and path and HDF5 address information of each frame in the data stream from the bluesky RunEngine.\n", "\n", "We make one modification to the `stage()` method, to move the setting of `capture` to be last in the list. If it is not last, then any HDF5 plugin settings coming after might not succeed, since they cannot be done in capture mode." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from ophyd.areadetector.filestore_mixins import FileStoreHDF5IterativeWrite\n", "from ophyd.areadetector.plugins import HDF5Plugin_V34 as HDF5Plugin\n", "\n", "class MyHDF5Plugin(FileStoreHDF5IterativeWrite, HDF5Plugin):\n", " \"\"\"\n", " Add data acquisition methods to HDF5Plugin.\n", "\n", " * ``stage()`` - prepare device PVs befor data acquisition\n", " * ``unstage()`` - restore device PVs after data acquisition\n", " * ``generate_datum()`` - coordinate image storage metadata\n", " \"\"\"\n", "\n", " def stage(self):\n", " self.stage_sigs.move_to_end(\"capture\", last=True)\n", " super().stage()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### detector\n", "\n", "The detector class, a subclass of `DetectorBase`, brings together the detector driver `cam` and plugins.\n", "\n", "***details***\n", "\n", "This class will be used to build the Python object for the detector. In addition to the `cam` and HDF5 plugin, we'll enable the image plugin (`ImagePlugin`) so that a client viewer can view the image.\n", "\n", "The `SingleTrigger` mixin class configures the `cam` for data acquisition as [explained](https://blueskyproject.io/ophyd/explanations/area-detector.html?highlight=singletrigger#callbacks). As with the `HDF5Plugin` above, the ophyd support is not up to date with more recent developments in EPICS Area Detector. The updates are available from `apstools.devices.SingleTrigger_V34`.\n", "\n", "When configuring the custom `MyHDF5Plugin` class, we apply the two strings defined above for the file paths on the IOC (write) and on the bluesky workstation (read).\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from apstools.devices import SingleTrigger_V34\n", "from ophyd.areadetector import DetectorBase\n", "from ophyd.areadetector.plugins import ImagePlugin_V34 as ImagePlugin\n", "\n", "class SimDetector_V34(SingleTrigger_V34, DetectorBase):\n", " \"\"\"\n", " ADSimDetector\n", "\n", " SingleTrigger:\n", "\n", " * stop any current acquisition\n", " * sets image_mode to 'Multiple'\n", " \"\"\"\n", "\n", " cam = ADComponent(SimDetectorCam_V34, \"cam1:\")\n", " hdf1 = ADComponent(\n", " MyHDF5Plugin,\n", " \"HDF1:\",\n", " write_path_template=WRITE_PATH_TEMPLATE,\n", " read_path_template=READ_PATH_TEMPLATE,\n", " )\n", " image = ADComponent(ImagePlugin, \"image1:\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With all the above setup, create the Python detector object, `adsimdet` and wait for it to connect with EPICS." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "adsimdet = SimDetector_V34(IOC, name=\"adsimdet\")\n", "adsimdet.wait_for_connection(timeout=15)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check that all plugins used by the IOC have been defined in the Python structure. Expect that this function returns an empty list: `[]`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adsimdet.missing_plugins()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We must configure `adsimdet` so the HDF5 plugin (by its attribute name `hdf1`) will be called during `adsimdet.read()`, as used by data acquisition." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "adsimdet.read_attrs.append(\"hdf1\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Configure the HDF5 plugin so it will create up to 5 subdirectories for the image directory.\n", "\n", "***details***\n", "\n", "We *must* do this step before staging so the IOC is prepared when the `FilePath` PV is set during `adsimdet.stage()`." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "adsimdet.hdf1.create_directory.put(-5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wait for all plugins to finish.\n", "\n", "***details***\n", "\n", "One of the [changes for the SingleTrigger mixin](https://blueskyproject.io/ophyd/explanations/area-detector.html?highlight=singletrigger#callbacks) adds the `adsimdet.cam.wait_for_plugins` signal. This enables clients to know, via the `adsimdet.cam.acquire_busy` signal, when the camera and *all* enabled plugins are finished. For this to work, each plugin has `blocking_callbacks` set to `\"No\"` and the cam has `wait_for_plugins` set to `\"Yes\"`. Then, `cam.acquire_busy` will remain `\"Acquiring\"` (or `1`) until all plugins have finished processing, then it goes to `\"Done\"` (or `0`)." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# override default setting from ophyd\n", "adsimdet.hdf1.stage_sigs[\"blocking_callbacks\"] = \"No\"\n", "adsimdet.cam.stage_sigs[\"wait_for_plugins\"] = \"Yes\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For good measure, also make sure the `image` plugin does not block." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "adsimdet.image.stage_sigs[\"blocking_callbacks\"] = \"No\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consider enabling and setting any of these additional configurations, or others as appropriate to your situation.\n", "\n", "***details***\n", "\n", "Here, we accept the default acquisition time, but acquire 5 frames with `zlib` data compression.\n", "\n", "The `\"LZ4\"` compression is good for speed and compression but requires the [hdf5plugin](https://github.com/silx-kit/hdf5plugin) package to read the compressed data from the HDF5 file.\n", "\n", "But since our [last step](#punx) uses a tool that does not yet have this package, we'll use `zlib` compression." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "adsimdet.cam.stage_sigs[\"acquire_period\"] = 0.015\n", "adsimdet.cam.stage_sigs[\"acquire_time\"] = 0.01\n", "adsimdet.cam.stage_sigs[\"num_images\"] = 5\n", "adsimdet.hdf1.stage_sigs[\"num_capture\"] = 0 # capture ALL frames received\n", "adsimdet.hdf1.stage_sigs[\"compression\"] = \"zlib\" # LZ4\n", "# adsimdet.hdf1.stage_sigs[\"queue_size\"] = 20" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Prime* the HDF5 plugin, if necessary.\n", "\n", "***details***\n", "\n", "Even though area detector has a `LazyOpen` feature, ophyd needs to know how to describe the image structure before it starts saving data. If the file writing (HDF5) plugin does not have the dimensions, bit depth, color mode, ... of the expected image, then ophyd does not have access to the metadata it needs.\n", "\n", "NOTE: The `adsimdet.hdf1.lazy_open` signal should remain `\"No\"` if data is to be read later from the databroker. Attempts to read the data (via `run.primary.read()`) will see this exception raised:\n", "\n", "> `event_model.EventModelError: Error instantiating handler class `\n", "\n", "This code checks if the plugin is ready and, if not, makes the plugin ready by acquiring (a.k.a. *priming*) a single image into the plugin." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Priming hdf1\n" ] } ], "source": [ "from apstools.devices import AD_plugin_primed\n", "from apstools.devices import AD_prime_plugin2\n", "\n", "# this step is needed for ophyd\n", "if not AD_plugin_primed(adsimdet.hdf1):\n", " print(f\"Priming {adsimdet.hdf1.dotted_name}\")\n", " AD_prime_plugin2(adsimdet.hdf1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print some values as diagnostics." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['hdf1']" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adsimdet.read_attrs" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('cam.acquire', 0), ('cam.image_mode', 1)])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adsimdet.stage_sigs" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('wait_for_plugins', 'Yes'),\n", " ('acquire_period', 0.015),\n", " ('acquire_time', 0.01),\n", " ('num_images', 5)])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adsimdet.cam.stage_sigs" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('enable', 1),\n", " ('blocking_callbacks', 'No'),\n", " ('parent.cam.array_callbacks', 1),\n", " ('create_directory', -3),\n", " ('auto_increment', 'Yes'),\n", " ('array_counter', 0),\n", " ('auto_save', 'Yes'),\n", " ('num_capture', 0),\n", " ('file_template', '%s%s_%6.6d.h5'),\n", " ('file_write_mode', 'Stream'),\n", " ('capture', 1),\n", " ('compression', 'zlib')])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adsimdet.hdf1.stage_sigs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## bluesky\n", "\n", "Within the [Bluesky framework](https://blueskyproject.io/), [bluesky](https://blueskyproject.io/bluesky) is the package that orchestrates the data acquisition steps, including where to direct acquired data for storage. [Later](#databroker), we'll use [databroker](https://blueskyproject.io/databroker) to access the image data.\n", "\n", "As a first step, configure the notebook for graphics. (While `%matplotlib inline` works well for documentation, you might prefer the additional interactive features possible by changing to `%matplotlib widget`.)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Import matplotlib for inline graphics\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "plt.ion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll use a temporary databroker catalog for this example and setup the RunEngine object `RE`.\n", "\n", "***details***\n", "\n", "You may wish to use your own catalog:\n", "\n", "```py\n", "cat = databroker.catalog[YOUR_CATALOG_NAME]\n", "```\n", "\n", "Then setup the bluesky run engine `RE`, connect it with the databroker catalog, and enable (via `BestEffortCallback`) some screen output during data collection." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "from bluesky import plans as bp\n", "from bluesky import RunEngine\n", "from bluesky import SupplementalData\n", "from bluesky.callbacks.best_effort import BestEffortCallback\n", "import databroker\n", "\n", "cat = databroker.temp().v2\n", "RE = RunEngine({})\n", "RE.subscribe(cat.v1.insert)\n", "RE.subscribe(BestEffortCallback())\n", "RE.preprocessors.append(SupplementalData())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "***Take an image with the area detector***\n", "\n", "***details***\n", "\n", "Also, capture the list of identifiers (there will be only one item). Add custom metadata to identify the imaging run.\n", "\n", "Note that the HDF plugin will report, briefly before acquisition, (in its `WriteMessage` PV):\n", "\n", "> ERROR: capture is not permitted in Single mode\n", "\n", "Ignore that." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Transient Scan ID: 1 Time: 2022-09-27 10:59:03\n", "Persistent Unique Scan ID: 'df16fb86-e3f5-4f3e-a423-fdd7f3ab01a3'\n", "New stream: 'primary'\n", "+-----------+------------+\n", "| seq_num | time |\n", "+-----------+------------+\n", "| 1 | 10:59:03.6 |\n", "+-----------+------------+\n", "generator count ['df16fb86'] (scan num: 1)\n", "\n", "\n", "\n" ] } ], "source": [ "uids = RE(bp.count([adsimdet], md=dict(title=\"Area Detector with default HDF5 File Name\", purpose=\"image\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## databroker\n", "\n", "To emphasize the decisions associated with each step to get the image data, the procedure is shown in parts.\n", "\n", "***Get the run from the catalog***\n", "\n", "The run data comes from the databroker catalog.\n", "\n", "***details***\n", "\n", "We *could* assume we want the most recent run in the catalog (`run = cat.v2[-1]`). But, since we have a list of run *uid* strings, let's use that instead. If we wanted to access this run later, when neither of those two choices are possible, then the run could be access by its *Transient Scan ID* as reported above: `run = cat.v2[1]`\n", "\n", "There are three ways to reference a run in the catalog:\n", "\n", "argument | example | description\n", "--- | --- | ---\n", "negative integer | `cat.v2[-1]` | ***list*-like**, `-1` is most recent, `-2` is 2nd most recent, ...\n", "positive integer | `cat.v2[1]` | argument is the **Scan ID** (if search is not unique, returns most recent)\n", "string | `cat.v2[\"a1b2c3d\"]` | argument is a **`uid`** (just the first few characters that make the catalog search unique are needed)\n", "\n", "We called the `RE` with `bp.count()`, which only generates a single run, so there is no assumption here using the `uids` list from this session." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BlueskyRun\n", " uid='df16fb86-e3f5-4f3e-a423-fdd7f3ab01a3'\n", " exit_status='success'\n", " 2022-09-27 10:59:03.491 -- 2022-09-27 10:59:03.634\n", " Streams:\n", " * primary\n" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "run = cat.v2[uids[0]]\n", "run" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "***Get the image frame from the run***\n", "\n", "From the run, we know the image data is in the primary stream.\n", "\n", "***details***\n", "\n", "(In fact, that is the only stream in this run.) Get the run's data as an [xarray Dataset](https://docs.xarray.dev/en/stable/generated/xarray.Dataset.html) object.\n", "\n", "Recall, above, we said that the `LZ4` compression needs help from the `hdf5plugin` package, all we have to do is `import` it. The package installs entry points to assist the h5py library to uncompress the data.\n", "\n", "Since we used `zlib` above, we comment the import for now." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.Dataset>\n",
       "Dimensions:         (time: 1, dim_0: 5, dim_1: 1024, dim_2: 1024)\n",
       "Coordinates:\n",
       "  * time            (time) float64 1.664e+09\n",
       "Dimensions without coordinates: dim_0, dim_1, dim_2\n",
       "Data variables:\n",
       "    adsimdet_image  (time, dim_0, dim_1, dim_2) uint8 1 2 3 4 5 ... 255 0 1 2 3
" ], "text/plain": [ "\n", "Dimensions: (time: 1, dim_0: 5, dim_1: 1024, dim_2: 1024)\n", "Coordinates:\n", " * time (time) float64 1.664e+09\n", "Dimensions without coordinates: dim_0, dim_1, dim_2\n", "Data variables:\n", " adsimdet_image (time, dim_0, dim_1, dim_2) uint8 1 2 3 4 5 ... 255 0 1 2 3" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# import hdf5plugin # required for LZ4, Blosc, and other compression codecs\n", "\n", "dataset = run.primary.read()\n", "dataset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The image is recorded under the name `\"adsimdet_image\"`.\n", "\n", "***details***\n", "\n", "This `image` object has rank of 4 (1 timestamp and 5 frames of 1k x 1k)." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "image = dataset[\"adsimdet_image\"]\n", "# image is an xarray.DataArray with 1 timestamp and 5 frames of 1k x 1k" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We just want the `image` frame (the last two indices).\n", "\n", "***details***\n", "\n", "Select the first item of each of the first two indices (time, frame number)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "frame = image[0][0]\n", "# frame is an xarray.DataArray of 1k x 1k" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "***Visualize the image***\n", "\n", "The `frame` is an [xarray Dataset](https://docs.xarray.dev/en/stable/generated/xarray.Dataset.html), which has a method to visualize the data as shown here:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "frame.plot.pcolormesh()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Resource({'path_semantics': 'posix',\n", " 'resource_kwargs': {'frame_per_point': 5},\n", " 'resource_path': 'tmp/docker_ioc/iocad/tmp/example/2022/09/27/de3362ec-5271-4715-a03e_000000.h5',\n", " 'root': '/',\n", " 'run_start': 'df16fb86-e3f5-4f3e-a423-fdd7f3ab01a3',\n", " 'spec': 'AD_HDF5',\n", " 'uid': '6c233353-215e-433c-a100-beb4e8ccf03f'})]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "run.primary._resources" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "***Find the image file on local disk***\n", "\n", "Get the name of the image file on the bluesky (local) workstation from the `adsimdet` object." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "local_file_name.exists()=True\n", "local_file_name=PosixPath('/tmp/docker_ioc/iocad/tmp/example/2022/09/27/de3362ec-5271-4715-a03e_000000.h5')\n" ] } ], "source": [ "from apstools.devices import AD_full_file_name_local\n", "\n", "local_file_name = AD_full_file_name_local(adsimdet.hdf1)\n", "print(f\"{local_file_name.exists()=}\\n{local_file_name=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we might get the name of the file from the run stream." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "fname.exists()=True\n", "fname=PosixPath('/tmp/docker_ioc/iocad/tmp/example/2022/09/27/de3362ec-5271-4715-a03e_000000.h5')\n", "(local_file_name == fname)=True\n" ] } ], "source": [ "rsrc = run.primary._resources[0]\n", "fname = pathlib.Path(f\"{rsrc['root']}{rsrc['resource_path']}\")\n", "print(f\"{fname.exists()=}\\n{fname=}\")\n", "\n", "# confirm they are the same\n", "print(f\"{(local_file_name == fname)=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## punx\n", "\n", "Next, we demonstrate access to the HDF5 image file using the [punx](https://punx.readthedocs.io) program.\n", "\n", "***details***\n", "\n", "We run `punx` from within the notebook to read this HDF5 file and shows its tree structure. (Since we can't easily pass a Python object to the notebook magic command `!` which executes a shell command, we'll call a library routine from [apstools](https://apstools.readthedocs.io/en/latest/api/_utils.html?highlight=unix#apstools.utils.misc.unix) to make this work.)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "!!! WARNING: this program is not ready for distribution.\n", "\n", "/tmp/docker_ioc/iocad/tmp/example/2022/09/27/de3362ec-5271-4715-a03e_000000.h5 : NeXus data file\n", " entry:NXentry\n", " @NX_class = \"NXentry\"\n", " data:NXdata\n", " @NX_class = \"NXdata\"\n", " data:NX_UINT8[5,1024,1024] = __array\n", " __array = [\n", " [\n", " [1, 2, 3, '...', 0]\n", " [2, 3, 4, '...', 1]\n", " [3, 4, 5, '...', 2]\n", " ...\n", " [0, 1, 2, '...', 255]\n", " ]\n", " [\n", " [2, 3, 4, '...', 1]\n", " [3, 4, 5, '...', 2]\n", " [4, 5, 6, '...', 3]\n", " ...\n", " [1, 2, 3, '...', 0]\n", " ]\n", " [\n", " [3, 4, 5, '...', 2]\n", " [4, 5, 6, '...', 3]\n", " [5, 6, 7, '...', 4]\n", " ...\n", " [2, 3, 4, '...', 1]\n", " ]\n", " [\n", " [4, 5, 6, '...', 3]\n", " [5, 6, 7, '...', 4]\n", " [6, 7, 8, '...', 5]\n", " ...\n", " [3, 4, 5, '...', 2]\n", " ]\n", " [\n", " [5, 6, 7, '...', 4]\n", " [6, 7, 8, '...', 5]\n", " [7, 8, 9, '...', 6]\n", " ...\n", " [4, 5, 6, '...', 3]\n", " ]\n", " ]\n", " @NDArrayDimBinning = [1 1]\n", " @NDArrayDimOffset = [0 0]\n", " @NDArrayDimReverse = [0 0]\n", " @NDArrayNumDims = 2\n", " @signal = 1\n", " instrument:NXinstrument\n", " @NX_class = \"NXinstrument\"\n", " NDAttributes:NXcollection\n", " @NX_class = \"NXcollection\"\n", " @hostname = \"zap\"\n", " NDArrayEpicsTSSec:NX_UINT32[5] = [1033142343, 1033142343, 1033142343, 1033142343, 1033142343]\n", " @NDAttrDescription = \"The NDArray EPICS timestamp seconds past epoch\"\n", " @NDAttrName = \"NDArrayEpicsTSSec\"\n", " @NDAttrSource = \"Driver\"\n", " @NDAttrSourceType = \"NDAttrSourceDriver\"\n", " NDArrayEpicsTSnSec:NX_UINT32[5] = [549046609, 564316440, 579234540, 594335673, 609497474]\n", " @NDAttrDescription = \"The NDArray EPICS timestamp nanoseconds\"\n", " @NDAttrName = \"NDArrayEpicsTSnSec\"\n", " @NDAttrSource = \"Driver\"\n", " @NDAttrSourceType = \"NDAttrSourceDriver\"\n", " NDArrayTimeStamp:NX_FLOAT64[5] = [1033142343.538874, 1033142343.5539901, 1033142343.5690963, 1033142343.5842175, 1033142343.5993518]\n", " @NDAttrDescription = \"The timestamp of the NDArray as float64\"\n", " @NDAttrName = \"NDArrayTimeStamp\"\n", " @NDAttrSource = \"Driver\"\n", " @NDAttrSourceType = \"NDAttrSourceDriver\"\n", " NDArrayUniqueId:NX_INT32[5] = [2, 3, 4, 5, 6]\n", " @NDAttrDescription = \"The unique ID of the NDArray\"\n", " @NDAttrName = \"NDArrayUniqueId\"\n", " @NDAttrSource = \"Driver\"\n", " @NDAttrSourceType = \"NDAttrSourceDriver\"\n", " detector:NXdetector\n", " @NX_class = \"NXdetector\"\n", " data:NX_UINT8[5,1024,1024] = __array\n", " __array = [\n", " [\n", " [1, 2, 3, '...', 0]\n", " [2, 3, 4, '...', 1]\n", " [3, 4, 5, '...', 2]\n", " ...\n", " [0, 1, 2, '...', 255]\n", " ]\n", " [\n", " [2, 3, 4, '...', 1]\n", " [3, 4, 5, '...', 2]\n", " [4, 5, 6, '...', 3]\n", " ...\n", " [1, 2, 3, '...', 0]\n", " ]\n", " [\n", " [3, 4, 5, '...', 2]\n", " [4, 5, 6, '...', 3]\n", " [5, 6, 7, '...', 4]\n", " ...\n", " [2, 3, 4, '...', 1]\n", " ]\n", " [\n", " [4, 5, 6, '...', 3]\n", " [5, 6, 7, '...', 4]\n", " [6, 7, 8, '...', 5]\n", " ...\n", " [3, 4, 5, '...', 2]\n", " ]\n", " [\n", " [5, 6, 7, '...', 4]\n", " [6, 7, 8, '...', 5]\n", " [7, 8, 9, '...', 6]\n", " ...\n", " [4, 5, 6, '...', 3]\n", " ]\n", " ]\n", " @NDArrayDimBinning = [1 1]\n", " @NDArrayDimOffset = [0 0]\n", " @NDArrayDimReverse = [0 0]\n", " @NDArrayNumDims = 2\n", " @signal = 1\n", " NDAttributes:NXcollection\n", " @NX_class = \"NXcollection\"\n", " ColorMode:NX_INT32[5] = [0, 0, 0, 0, 0]\n", " @NDAttrDescription = \"Color mode\"\n", " @NDAttrName = \"ColorMode\"\n", " @NDAttrSource = \"Driver\"\n", " @NDAttrSourceType = \"NDAttrSourceDriver\"\n", " performance\n", " timestamp:NX_FLOAT64[5,5] = __array\n", " __array = [\n", " [0.003102612, 0.191079478, 1033120447.5522685, 41.86739509514465, 0.0]\n", " [0.021867227, 0.034026341, 0.02187464, 235.11196810729663, 365.7203044255814]\n", " [0.012927982, 0.012991135, 0.034865775, 615.8045467158952, 458.9027491859854]\n", " [0.008577395, 0.008611418, 0.043477193, 928.9991497335283, 552.0135580049982]\n", " [0.006839059, 0.008502173, 0.051979366, 940.9359230869567, 615.6289016684044]\n", " ]\n", "\n" ] } ], "source": [ "from apstools.utils import unix\n", "\n", "for line in unix(f\"punx tree {local_file_name}\"):\n", " print(line.decode().strip())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Recapitulation\n", "\n", "Let's gather the above parts together as one would usually write code. First, all the imports, constants, and classes." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "# matplotlib graphics, choices include: inline, notebook, auto\n", "%matplotlib inline\n", "\n", "from apstools.devices import AD_full_file_name_local\n", "from apstools.devices import AD_plugin_primed\n", "from apstools.devices import AD_prime_plugin2\n", "from apstools.devices import CamMixin_V34\n", "from apstools.devices import SingleTrigger_V34\n", "from bluesky.callbacks.best_effort import BestEffortCallback\n", "from ophyd import ADComponent\n", "from ophyd.areadetector import DetectorBase\n", "from ophyd.areadetector import SimDetectorCam\n", "from ophyd.areadetector.filestore_mixins import FileStoreHDF5IterativeWrite\n", "from ophyd.areadetector.plugins import HDF5Plugin_V34 as HDF5Plugin\n", "from ophyd.areadetector.plugins import ImagePlugin_V34 as ImagePlugin\n", "import bluesky\n", "import bluesky.plans as bp\n", "import databroker\n", "import hdf5plugin # for LZ4, Blosc, or other compression codecs (not already in h5py)\n", "import matplotlib.pyplot as plt\n", "import pathlib\n", "\n", "plt.ion() # turn on matplotlib plots\n", "IOC = \"ad:\"\n", "\n", "AD_IOC_MOUNT_PATH = pathlib.Path(\"/tmp\")\n", "BLUESKY_MOUNT_PATH = pathlib.Path(\"/tmp/docker_ioc/iocad/tmp\")\n", "IMAGE_DIR = \"example/%Y/%m/%d\"\n", "\n", "# MUST end with a `/`, pathlib will NOT provide it\n", "WRITE_PATH_TEMPLATE = f\"{AD_IOC_MOUNT_PATH / IMAGE_DIR}/\"\n", "READ_PATH_TEMPLATE = f\"{BLUESKY_MOUNT_PATH / IMAGE_DIR}/\"\n", "\n", "class SimDetectorCam_V34(CamMixin_V34, SimDetectorCam):\n", " \"\"\"Revise SimDetectorCam for ADCore revisions.\"\"\"\n", "\n", "class MyHDF5Plugin(FileStoreHDF5IterativeWrite, HDF5Plugin):\n", " \"\"\"\n", " Add data acquisition methods to HDF5Plugin.\n", "\n", " * ``stage()`` - prepare device PVs befor data acquisition\n", " * ``unstage()`` - restore device PVs after data acquisition\n", " * ``generate_datum()`` - coordinate image storage metadata\n", " \"\"\"\n", "\n", " def stage(self):\n", " self.stage_sigs.move_to_end(\"capture\", last=True)\n", " super().stage()\n", "\n", "class SimDetector_V34(SingleTrigger_V34, DetectorBase):\n", " \"\"\"\n", " ADSimDetector\n", "\n", " SingleTrigger:\n", "\n", " * stop any current acquisition\n", " * sets image_mode to 'Multiple'\n", " \"\"\"\n", "\n", " cam = ADComponent(SimDetectorCam_V34, \"cam1:\")\n", " hdf1 = ADComponent(\n", " MyHDF5Plugin,\n", " \"HDF1:\",\n", " write_path_template=WRITE_PATH_TEMPLATE,\n", " read_path_template=READ_PATH_TEMPLATE,\n", " )\n", " image = ADComponent(ImagePlugin, \"image1:\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, create and configure the Python object for the detector:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "adsimdet = SimDetector_V34(IOC, name=\"adsimdet\")\n", "adsimdet.wait_for_connection(timeout=15)\n", "adsimdet.missing_plugins() # confirm all plugins are defined\n", "\n", "adsimdet.read_attrs.append(\"hdf1\") # include `hdf1` plugin with 'adsimdet.read()'\n", "adsimdet.hdf1.create_directory.put(-5) # IOC may create up to 5 new subdirectories, as needed\n", "\n", "# override default settings from ophyd\n", "adsimdet.cam.stage_sigs[\"wait_for_plugins\"] = \"Yes\"\n", "adsimdet.hdf1.stage_sigs[\"blocking_callbacks\"] = \"No\"\n", "adsimdet.image.stage_sigs[\"blocking_callbacks\"] = \"No\"\n", "\n", "# apply some of our own customizations\n", "NUM_FRAMES = 5\n", "adsimdet.cam.stage_sigs[\"acquire_period\"] = 0.002\n", "adsimdet.cam.stage_sigs[\"acquire_time\"] = 0.001\n", "adsimdet.cam.stage_sigs[\"num_images\"] = NUM_FRAMES\n", "adsimdet.hdf1.stage_sigs[\"num_capture\"] = 0 # capture ALL frames received\n", "adsimdet.hdf1.stage_sigs[\"compression\"] = \"zlib\" # LZ4\n", "# adsimdet.hdf1.stage_sigs[\"queue_size\"] = 20\n", "\n", "# this step is needed for ophyd\n", "if not AD_plugin_primed(adsimdet.hdf1):\n", " print(f\"Priming {adsimdet.hdf1.dotted_name}\")\n", " AD_prime_plugin2(adsimdet.hdf1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Prepare for data acquisition." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "cat = databroker.temp().v2 # or use your own catalog: databroker.catalog[\"CATALOG_NAME\"]\n", "RE = bluesky.RunEngine({})\n", "RE.subscribe(cat.v1.insert)\n", "RE.subscribe(BestEffortCallback())\n", "RE.preprocessors.append(bluesky.SupplementalData())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Take an image." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Transient Scan ID: 1 Time: 2022-09-27 10:59:05\n", "Persistent Unique Scan ID: '91efb8b6-1b36-499b-b16a-dc9c131b23ca'\n", "New stream: 'primary'\n", "+-----------+------------+\n", "| seq_num | time |\n", "+-----------+------------+\n", "| 1 | 10:59:05.6 |\n", "+-----------+------------+\n", "generator count ['91efb8b6'] (scan num: 1)\n", "\n", "\n", "\n", "local_file_name.exists()=True local_file_name=PosixPath('/tmp/docker_ioc/iocad/tmp/example/2022/09/27/f631740c-1baa-46fb-8f05_000000.h5')\n" ] } ], "source": [ "uids = RE(\n", " bp.count(\n", " [adsimdet],\n", " md=dict(\n", " title=\"Area Detector with default HDF5 File Name\",\n", " purpose=\"image\",\n", " image_file_name_style=\"ophyd(uid)\",\n", " )\n", " )\n", ")\n", "\n", "# confirm the plugin captured the expected number of frames\n", "assert adsimdet.hdf1.num_captured.get() == NUM_FRAMES\n", "\n", "# Show the image file name on the bluesky (local) workstation\n", "# Use information from the 'adsimdet' object\n", "local_file_name = AD_full_file_name_local(adsimdet.hdf1)\n", "print(f\"{local_file_name.exists()=} {local_file_name=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "View the image using databroker." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "fname.exists()=True\n", "fname=PosixPath('/tmp/docker_ioc/iocad/tmp/example/2022/09/27/f631740c-1baa-46fb-8f05_000000.h5')\n", "(local_file_name == fname)=True\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "run = cat.v2[uids[0]]\n", "dataset = run.primary.read()\n", "dataset[\"adsimdet_image\"][0][0].plot.pcolormesh()\n", "\n", "# Show the image file name on the bluesky (local) workstation\n", "# Use information from the databroker run\n", "_r = run.primary._resources[0]\n", "fname = pathlib.Path(f\"{_r['root']}{_r['resource_path']}\")\n", "print(f\"{fname.exists()=}\\n{fname=}\")\n", "\n", "# confirm the name above () is the same\n", "print(f\"{(local_file_name == fname)=}\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.13 ('base')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "f38aef175fb08dfc130a7d9bb9234f0792dc9ad861f95b6c05aedd1b380356e2" } } }, "nbformat": 4, "nbformat_minor": 2 }