{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Hello Bluesky: Reading detectors and scanning\n", "\n", "In this notebook you will:\n", "\n", "* Connect to some simulated hardware.\n", "* Acquire some data via two common experimental procedures (\"plans\"), ``count`` and ``scan``.\n", "* Write a custom plan.\n", "\n", "Recommend Prerequisites:\n", "\n", "* [Hello Python and Jupyter](./Hello%20Python%20and%20Jupyter.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Configuration\n", "Below, we will connect to EPICS IOC(s) controlling simulated hardware in lieu of actual motors and detectors. An EPICS IOC is control system software that allows communication with a wide variety of hardware using a common interface. The IOCs should already be running in the background. Run this command to verify that they are running: it should produce output with RUNNING on each line. In the event of a problem, edit this command to replace `status` with `restart all` and run again." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!supervisor/start_supervisor.sh status" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from bluesky_tutorial_utils.beamline_configuration import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check that we can communicate with the hardware. If this doesn't raise an error, it worked." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "det.wait_for_connection()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Acquisition\n", "\n", "### Executing a `count` plan with various parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the example below, the Bluesky run engine is the interpreter of experiment plans and `count` is an experiment plan used here to acquire one reading from a point detector." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from bluesky.plans import count\n", "RE(count([det]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The return value is a list of the run IDs that uniquely identify this data set. The \"scan num\" is easier to remember but is not good for long-term reference because it may not be unique.\n", "\n", "Let's looks at the documentation for `count` to see what our other options are." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "help(count) # or, equiavently, type count? or ?count" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Executing the next cell will display an empty widget. In the sections below, the scans that we run will add figures to this widget.\n", "\n", "If you are reading this in JupyterLab, right-click somewhere in the output area below and choose \"Create New View for Output\". This will display a up-to-date copy of the figures off to the side of this notebook, and avoid the need for frequent scrolling between this widget and the code that follows." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "auto_plot_view" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# five consecutive readings\n", "RE(count([det], num=5))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# five sequential readings separated by a 1-second delay\n", "RE(count([det], num=5, delay=1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scan\n", "\n", "Scan ``motor`` from -10 to 10, stopping at 15 equally-spaced points along the way and reading ``det``." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "RE(scan([det], motor, -10, 10, 15))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simulators\n", "\n", "Bluesky includes utilities to inspecting plans before they are run. You can imagine various reasons you might want to do this. Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from bluesky.simulators import summarize_plan\n", "\n", "summarize_plan(scan([det], motor, -1, 1, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Custom plan\n", "\n", "Define a custom \"plan\", using the Python syntax ``yield from`` to dispatch out to built-in plans." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The plan_stubs module contains smaller plans.\n", "# They can be used alone or as buildling blocks for larger plans.\n", "from bluesky.plan_stubs import mv\n", "\n", "\n", "def sweep_exposure_time(times):\n", " \"Multiple scans: one per exposure time setting.\"\n", " for t in times:\n", " yield from mv(det.exp, t)\n", " yield from scan([det], motor, -10, 10, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we run, let's make our simulated motor move faster, just to save time in this example." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "motor.delay = 0" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "RE(sweep_exposure_time([0.01, 0.1, 1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercises" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Q1: Above we ran a `count` with multiple readings separated by a fixed delay. The ``delay`` parameter also accepts a list of values. Try a `count` with a variable delay.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Try your solution here. Fill in the blank:\n", "# RE(count(____)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Execute the following cell to reveal a solution:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load solutions/count_variable_delay.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Q2: Write a custom plan that scans the same region twice, first with coarse steps and then with fine steps." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Try your solution here. Fill in the blank:\n", "# def coarse_and_fine(detectors, motor, start, stop):\n", "# yield from scan(___)\n", "# yield from scan(___)\n", "#\n", "# RE(coarse_and_fine([det], motor, -10, 10))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load solutions/scan_coarse_and_fine.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Q3. All of the usages of scan we have seen so far scan from negative to positive. Scan from positive to negative." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Try your solution here." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load solutions/scan_positive_to_negative.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Q4: The ``scan`` plan samples equally-spaced points. To sample *arbitrary* points, you can use ``list_scan``. Import it from the same module that we imported ``scan`` from, then use ``list_scan?`` to view its documentation and figure out how to use it. Scan the positions ``[1, 1, 2, 3, 5, 8]``." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Try your solution here." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load solutions/scan_fibonacci.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Q5: What's wrong with this? (What does it do?)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Broken example\n", "def sweep_exposure_time(times):\n", " \"Multiple scans: one per exposure time setting.\"\n", " for t in times:\n", " mv(det.exp, t)\n", " scan([det], motor, -10, 10, 15)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load solutions/broken_sweep_exposure_time_explanation.txt" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.10" } }, "nbformat": 4, "nbformat_minor": 4 }