-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,351 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Trigger a Device with the EPICS record .PROC field\n", | ||
"\n", | ||
"The EPICS `.PROC` field is one of the fields\n", | ||
"[common](https://epics-base.github.io/epics-base/dbCommonRecord.html) to all\n", | ||
"EPICS records. It tells the IOC's database to execute the standard actions for\n", | ||
"that record's data. When the record is in `Passive` [scan\n", | ||
"mode](https://docs.epics-controls.org/en/latest/process-database/EPICS_Process_Database_Concepts.html#scanning-specification),\n", | ||
"sending a `1` value to the `.PROC` field *processes* the record.\n", | ||
"\n", | ||
"EPICS record processing is similar to the ophyd `trigger()`\n", | ||
"[method](https://github.com/bluesky/ophyd/blob/5c03c3fff974dc6390836fc83dae4c247a35e662/ophyd/device.py#L1438-L1439)\n", | ||
"which tells the [Device](https://github.com/bluesky/ophyd/blob/5c03c3fff974dc6390836fc83dae4c247a35e662/ophyd/device.py#L780-L784) to run its data acquisition method." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from ophyd import Component, Device, EpicsSignal" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Let's make a custom ophyd `Device`, limiting our attention only to the fields of interest for this howto guide.\n", | ||
"\n", | ||
"field | description\n", | ||
"---- | ----\n", | ||
"`.A` | The *a* value.\n", | ||
"`.CLCA` | The calculation to produce a new *A* value when the record is processed.\n", | ||
"`.PROC` | Send a `1` to this field to process the record.\n", | ||
"`.SCAN` | The record's scan mode selection.\n", | ||
"\n", | ||
"Here, we add the `trigger_value` [keyword argument](https://github.com/bluesky/ophyd/blob/master/ophyd/device.py#L139-L141). **This** is how we send a `1` to the `.PROC` field when the Device is triggered.\n", | ||
"\n", | ||
"It is worth commenting about the `kind` keyword value. The [kind](https://blueskyproject.io/ophyd/user/reference/signals.html#kind) attribute is the means to identify a signal that is relevant for handling by a callback.\n", | ||
"\n", | ||
"kind | usage\n", | ||
"---- | ----\n", | ||
"hinted | attribute should be reported by `.read()`\n", | ||
"config | value is metadata, should be reported by `.read_configuration()`\n", | ||
"omitted | value is not reportable" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"class Transform(Device):\n", | ||
" a = Component(EpicsSignal, \".A\", kind=\"hinted\")\n", | ||
" calc_a = Component(EpicsSignal, \".CLCA\", kind=\"config\", string=True)\n", | ||
" process_record = Component(EpicsSignal, \".PROC\", kind=\"omitted\", trigger_value=1)\n", | ||
" scan_mode = Component(EpicsSignal, \".SCAN\", kind=\"config\", string=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Create an ophyd object and connect it with EPICS." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"xform = Transform(\"gp:userTran11\", name=\"xform\")\n", | ||
"xform.wait_for_connection()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Print the summary ophyd of the Device." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"data keys (* hints)\n", | ||
"-------------------\n", | ||
"*xform_a\n", | ||
"\n", | ||
"read attrs\n", | ||
"----------\n", | ||
"a EpicsSignal ('xform_a')\n", | ||
"\n", | ||
"config keys\n", | ||
"-----------\n", | ||
"xform_calc_a\n", | ||
"xform_scan_mode\n", | ||
"\n", | ||
"configuration attrs\n", | ||
"-------------------\n", | ||
"calc_a EpicsSignal ('xform_calc_a')\n", | ||
"scan_mode EpicsSignal ('xform_scan_mode')\n", | ||
"\n", | ||
"unused attrs\n", | ||
"------------\n", | ||
"process_record EpicsSignal ('xform_process_record')\n", | ||
"\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"xform.summary()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Show the values as they exist now using the `.read()` method." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"xform.read()=OrderedDict([('xform_a', {'value': 2.0, 'timestamp': 1714336346.373808})])\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(f\"{xform.read()=}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Tell ophyd to trigger the Device (which tells the transform record to process) using the `.trigger()` method.\n", | ||
"\n", | ||
"Note that only the *a* value is reported. All other attributes are either\n", | ||
"configuration or not reportable (such as `process_record`)." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"xform.read()=OrderedDict([('xform_a', {'value': 3.0, 'timestamp': 1714337169.963434})])\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"xform.trigger()\n", | ||
"print(f\"{xform.read()=}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Reset the Device before we demonstrate." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 7, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"xform.read()=OrderedDict([('xform_a', {'value': 0.0, 'timestamp': 1714337169.970021})])\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"xform.calc_a.put(\"\")\n", | ||
"xform.a.put(0)\n", | ||
"xform.scan_mode.put(\"Passive\")\n", | ||
"print(f\"{xform.read()=}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Define the calculation to run (increment *a*) each time the record is processed." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 8, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"xform.calc_a.put(\"A+1\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Print the value before triggering (processing), trigger the, then print the\n", | ||
"value afterwards. We expect the value will increment by `1`." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 9, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"xform.read()=OrderedDict([('xform_a', {'value': 0.0, 'timestamp': 1714337169.970021})])\n", | ||
"xform.read()=OrderedDict([('xform_a', {'value': 1.0, 'timestamp': 1714337169.982637})])\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(f\"{xform.read()=}\")\n", | ||
"xform.trigger()\n", | ||
"print(f\"{xform.read()=}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Let's do the same thing in a bluesky plan. First, we need some parts from the bluesky package. These are the most basic parts:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 10, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from bluesky import RunEngine\n", | ||
"from bluesky import plan_stubs as bps\n", | ||
"\n", | ||
"RE = RunEngine()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Define the bluesky plan. Instead of calling the Device's `.trigger()` method\n", | ||
"directly, we let the RunEngine\n", | ||
"[handle](https://github.com/bluesky/bluesky/blob/main/src/bluesky/plan_stubs.py#L447-L449)\n", | ||
"that task (with `bps.trigger()`), in case the device takes some time to\n", | ||
"complete its trigger action(s)." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 11, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"def plan():\n", | ||
" print(f\"{xform.read()=}\")\n", | ||
" yield from bps.trigger(xform)\n", | ||
" print(f\"{xform.read()=}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Run the plan." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 12, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"xform.read()=OrderedDict([('xform_a', {'value': 1.0, 'timestamp': 1714337169.982637})])\n", | ||
"xform.read()=OrderedDict([('xform_a', {'value': 2.0, 'timestamp': 1714337170.147542})])\n" | ||
] | ||
}, | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"()" | ||
] | ||
}, | ||
"execution_count": 12, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"RE(plan())" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "bluesky_2024_2", | ||
"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.11.8" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |