diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f8fdf3d..f0581cb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,14 +1,14 @@ # Contribute to the project Contributions and issues are most welcome! All issues and pull requests are -handled through [GitHub](https://github.com/Relm-Arrowny/p99_bluesky/issues). Also, please check for any existing issues before +handled through [GitHub](https://github.com/DiamondLightSource/p99-bluesky/issues). Also, please check for any existing issues before filing a new one. If you have a great idea but it involves big changes, please file a ticket before making a pull request! We want to make sure you don't spend your time coding something that might not fit the scope of the project. ## Issue or Discussion? -Github also offers [discussions](https://github.com/Relm-Arrowny/p99_bluesky/discussions) as a place to ask questions and share ideas. If +Github also offers [discussions](https://github.com/DiamondLightSource/p99-bluesky/discussions) as a place to ask questions and share ideas. If your issue is open ended and it is not obvious when it can be "closed", please raise it as a discussion instead. diff --git a/src/p99_bluesky/beamlines/p99.py b/src/p99_bluesky/beamlines/p99.py index b23cef4..59c9318 100644 --- a/src/p99_bluesky/beamlines/p99.py +++ b/src/p99_bluesky/beamlines/p99.py @@ -1,5 +1,5 @@ -from dodal.beamlines.beamline_utils import device_instantiation -from dodal.beamlines.beamline_utils import set_beamline as set_utils_beamline +from dodal.common.beamlines.beamline_utils import device_instantiation +from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.log import set_beamline as set_log_beamline from dodal.utils import get_beamline_name diff --git a/tests/epics/soft_ioc/p99_softioc.py b/tests/epics/soft_ioc/p99_softioc.py new file mode 100644 index 0000000..3bb9321 --- /dev/null +++ b/tests/epics/soft_ioc/p99_softioc.py @@ -0,0 +1,56 @@ +import asyncio + +from softioc import asyncio_dispatcher, builder, softioc +from softsignal import soft_mbb, soft_motor, soft_signal + + +async def p99_fake() -> None: + async def _delay_move(signal, v, vel, dmov): + diff = signal.get() - v.get() + if abs(diff) < vel.get() * 0.04: + signal.set(v.get()) + dmov.set(True) + + elif diff < 0: + dmov.set(False) + signal.set(signal.get() + vel.get() * 0.02) + elif diff > 0: + dmov.set(False) + signal.set(signal.get() - vel.get() * 0.02) + + # Sample AngleStage softioc + dispatcher = asyncio_dispatcher.AsyncioDispatcher() + soft_signal("p99-MO-TABLE-01", "WRITETHETA", "WRITETHETA:RBV") + soft_signal("p99-MO-TABLE-01", "WRITEROLL", "WRITEROLL:RBV") + soft_signal("p99-MO-TABLE-01", "WRITEPITCH", "WRITEPITCH:RBV") + # sample selection staged + soft_mbb("p99-MO-STAGE-02", "MP:SELECT") + # xyz stage + x_set, x_vel, x_rbv, x_dmov = await soft_motor( + prefix="p99-MO-STAGE-02", name="X", unit="mm" + ) + y_set, y_vel, y_rbv, y_dmov = await soft_motor( + prefix="p99-MO-STAGE-02", name="Y", unit="mm" + ) + z_set, z_vel, z_rbv, z_dmov = await soft_motor( + prefix="p99-MO-STAGE-02", name="Z", unit="mm" + ) + # build the ioc + builder.LoadDatabase() + softioc.iocInit(dispatcher) + + # print(softioc.dbnr(), softioc.dbl()) # type: ignore + + async def update(y_rbv, y_set, y_vel, y_dmov): + await _delay_move(y_rbv, y_set, y_vel, y_dmov) + + while True: + dispatcher(update, [z_rbv, z_set, z_vel, z_dmov]) + dispatcher(update, [y_rbv, y_set, y_vel, y_dmov]) + dispatcher(update, [x_rbv, x_set, x_vel, x_dmov]) + await asyncio.sleep(0.01) + # softioc.interactive_ioc(globals()) + + +if __name__ == "__main__": + asyncio.run(p99_fake()) diff --git a/tests/epics/soft_ioc/softsignal.py b/tests/epics/soft_ioc/softsignal.py new file mode 100644 index 0000000..1a591d4 --- /dev/null +++ b/tests/epics/soft_ioc/softsignal.py @@ -0,0 +1,94 @@ +from softioc import builder + + +def soft_signal(prefix: str, input_name: str, readback_name: str) -> None: + # Create some records + builder.SetDeviceName(prefix) + rbv = builder.aIn(readback_name, initial_value=0) + # rbv.append(temp) + builder.aOut( + input_name, + initial_value=0.1, + always_update=True, + on_update=lambda v: rbv.set(v), + ) + + +def soft_mbb(prefix: str, name: str, *option): + builder.SetDeviceName(prefix) + # temp = builder.mbbIn(readback_name, initial_value=0) + builder.mbbOut( + name, + "Empty", + "Mn 5um", + "Fe (empty)", + "Co 5um", + "Ni 5um", + "Cu 5um", + "Zn 5um", + "Zr (empty)", + "Mo (empty)", + "Rh (empty)", + "Pd (empty)", + "Ag (empty)", + "Cd 25um", + "W (empty)", + "Pt (empty)", + "User", + ) + + +async def soft_motor(prefix: str, name: str, unit: str = "mm"): + builder.SetDeviceName(prefix) + builder.aOut( + name, + initial_value=1.1, + EGU=unit, + VAL=1.1, + PREC=0, + ) + rbv = builder.aOut( + name + "RBV", + initial_value=0.0, + ) + vel = builder.aOut( + name + "VELO", + initial_value=1.5, + ) + dmov = builder.boolOut( + name + "DMOV", + initial_value=True, + ) + ai = builder.aOut( + name + "VAL", + initial_value=0.0, + always_update=True, + on_update=lambda v: dmov.set(False), + ) + + builder.aOut( + name + "VMAX", + initial_value=2, + ) + builder.aOut( + name + "ACCL", + initial_value=1, + ) + builder.aOut( + name + "RDBD", + initial_value=0.1, + ) + + builder.aOut( + name + "LLM", + initial_value=-100, + ) + builder.aOut( + name + "HLM", + initial_value=100, + ) + builder.aOut( + name + "STOP", + initial_value=0, + ) + return ai, vel, rbv, dmov diff --git a/tests/epics/soft_ioc/test.py b/tests/epics/soft_ioc/test.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/jupyter_tests/p99_fake_test.ipynb b/tests/jupyter_tests/p99_fake_test.ipynb new file mode 100644 index 0000000..676fdc8 --- /dev/null +++ b/tests/jupyter_tests/p99_fake_test.ipynb @@ -0,0 +1,876 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "c3412e6e-19fb-4dff-9279-72ec86a1885f", + "metadata": {}, + "outputs": [], + "source": [ + "import os \n", + "os.chdir(\"/workspaces/p99-bluesky/tests/\")\n", + "\n", + "import asyncio\n", + "import subprocess, os\n", + "from bluesky.run_engine import RunEngine\n", + "from ophyd_async.core import DeviceCollector\n", + "from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw\n", + "from ophyd_async.core.signal import observe_value, wait_for_value\n", + "from p99_bluesky.devices.p99.sample_stage import (\n", + " FilterMotor,\n", + " SampleAngleStage,\n", + " p99StageSelections,\n", + ")\n", + "from soft_motor import SoftThreeAxisStage\n", + "from bluesky.run_engine import RunEngine\n", + "from bluesky.callbacks.best_effort import BestEffortCallback\n", + "from bluesky.plans import count, scan \n", + "from ophyd.sim import det\n", + "bec = BestEffortCallback()\n", + "RE = RunEngine({})" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "115f98ae-22c9-49a9-a388-e0f7ccb56bcd", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XLLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470848612\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XHLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470855933\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XSTOP\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470858577\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:Y.EGU\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470861366\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YVELO\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470864171\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YRBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470866584\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YVAL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470868925\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YVMAX\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470877065\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YACCL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470879556\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:Y.PREC\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470883388\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YRDBD\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470885761\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YDMOV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470888147\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YLLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470890571\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YHLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470893236\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:YSTOP\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470895602\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:Z.EGU\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470897967\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZVELO\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470900437\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZRBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470902916\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZVAL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470905600\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZVMAX\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470908959\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZACCL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470911316\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:Z.PREC\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470913709\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZRDBD\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470916055\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZDMOV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470918458\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZLLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.470922177\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZHLM\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.472251926\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:MP:SELECT\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.472261375\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITETHETA:RBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.472598331\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITETHETA\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.473078709\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITEROLL:RBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.473575293\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITEROLL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.474046060\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITEPITCH:RBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.474571073\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-TABLE-01:WRITEPITCH\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.475067138\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:X.EGU\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.475572023\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XVELO\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.476080691\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XRBV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.476573586\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XVAL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.477123707\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XVMAX\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.477659006\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XACCL\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.478090060\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:X.PREC\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.478561058\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XRDBD\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.479077504\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:XDMOV\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.479569794\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-MO-STAGE-02:ZSTOP\", Connecting to: host.containers.internal:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Fri Jun 14 2024 12:44:29.480063753\n", + "..................................................................\n" + ] + } + ], + "source": [ + "with DeviceCollector(mock=False):\n", + " mock_sampleAngleStage = SampleAngleStage(\n", + " \"p99-MO-TABLE-01:\", name=\"mock_sampleAngleStage\"\n", + " )\n", + " mock_filter_wheel = FilterMotor(\n", + " \"p99-MO-STAGE-02:MP:SELECT\", name=\"mock_filter_wheel\"\n", + " )\n", + " xyz_motor = SoftThreeAxisStage(\"p99-MO-STAGE-02:\", name=\"xyz_motor\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1eee82a2-d605-4964-a0ab-b82797d8d786", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Transient Scan ID: 12 Time: 2024-06-14 13:34:19\n", + "Persistent Unique Scan ID: 'a0d83531-270c-498d-95e4-eb1e6891582a'\n", + "New stream: 'primary'\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "| seq_num | time | xyz_motor-y | xyz_motor-z | xyz_motor-x | mock_sampleAngleStage-theta | det |\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "| 1 | 13:34:19.4 | -1.000 | 1.000 | 1.000 | -1.000 | 1.000 |\n", + "| 2 | 13:34:19.6 | -0.556 | 0.667 | 0.700 | -0.778 | 1.000 |\n", + "| 3 | 13:34:19.9 | -0.111 | 0.333 | 0.400 | -0.556 | 1.000 |\n", + "| 4 | 13:34:20.1 | 0.333 | 0.000 | 0.100 | -0.333 | 1.000 |\n", + "| 5 | 13:34:20.3 | 0.778 | -0.333 | -0.200 | -0.111 | 1.000 |\n", + "| 6 | 13:34:20.5 | 1.222 | -0.667 | -0.500 | 0.111 | 1.000 |\n", + "| 7 | 13:34:20.8 | 1.667 | -1.000 | -0.800 | 0.333 | 1.000 |\n", + "| 8 | 13:34:21.0 | 2.111 | -1.333 | -1.100 | 0.556 | 1.000 |\n", + "| 9 | 13:34:21.2 | 2.556 | -1.667 | -1.400 | 0.778 | 1.000 |\n", + "| 10 | 13:34:21.4 | 3.000 | -2.000 | -1.700 | 1.000 | 1.000 |\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "generator scan ['a0d83531'] (scan num: 12)\n", + "\n", + "\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "('a0d83531-270c-498d-95e4-eb1e6891582a',)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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l9SnTx9999136tq1qyRpw4YNSk5O1tdff+3UgH8/d40aNdSpUyf7sh49esjLy0sbN27ULbfccs5t3333XS1evFhhYWHq27evnnzyyfPu/efn5ys/P99+PzMz0zkvAh7hVG6BYuIT9OfJ02pcO1ALhzGoB0Dl41D5X3PNNdqzZ4/eeust7dq1S5J066236oEHHiiXy/umpKQoJKTkxVSqVKmiWrVqKSUl5Zzb3X333WrUqJHCw8P166+/aty4cdqzZ4+WLl16zm2mTJmiZ555xmnZ4TlyC4o0bP4m7UnNUmiQnxYN76K61TmFFUDl4/B5/rVr11a/fv10+eWX20/v27x5sySpX79+pXqO8ePHX3AE8N+/XDjivvvus/+5TZs2qlevnq6//nr98ccfatas2Vm3mTBhguLi4uz3MzMzFRER4XAGeIaCIptGLt6qrcmnFBzgo4XDuiiiFseHAKicHCr/FStWKCYmRsePH9f/XiDQYrHIarWW6nkeffRRDRky5LzrNG3aVGFhYUpLSyuxvKioSCdOnFBYWFipc3fp0kWStG/fvnOWv5+fHxcsMhmrzVDch4latzddAT7emjuksy4Nq+7qWABQbhwq/4ceeki33367Jk2apNDQUId/eN26dVW3bt0Lrte1a1edOnVKW7ZsUceOHSVJq1evls1msxd6aSQmJkrSWccRw5wMw9CkT3foi1+PysfbolmDO6pjo5qujgUA5cqho/1TU1MVFxdXpuK/GC1bttRNN92ke++9VwkJCVq/fr0efPBB3XnnnfZjDA4fPqzIyEglJCRIkv744w89++yz2rJliw4cOKDPPvtMMTExuvrqq9W2bdsKyQ33N23lXr27MVkWizTtjna65pIL/zIKAJ7OofL/17/+pbVr1zo5yvm9++67ioyM1PXXX6/evXvryiuv1Ntvv21/vLCwUHv27FFubq4kydfXV999951uvPFGRUZG6tFHH9Vtt92mzz//vEJzw33F/5ikN1bvkyQ927+1+kY5/2BVAHBHDk31y83N1e233666deuqTZs28vEpeSrUww8/7LSArsZUv8rpky1/2q/X/383XqIHr2vh4kQAUHblOtXvvffe07fffit/f3+tXbu2xLXOLRZLpSp/VD7f7UzV45/8KkkafmUTje7OoB4A5uLwYJ9nnnlG48ePl5cXlzyF59i4/7hG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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Fri Jun 14 2024 13:35:44.719455648\n", + "..................................................................\n" + ] + } + ], + "source": [ + "from collections import defaultdict\n", + "docs = defaultdict(list)\n", + "def capture_emitted(name, doc):\n", + " docs[name].append(doc)\n", + "\n", + "RE(scan([det],mock_sampleAngleStage.theta, -1,1, xyz_motor.y, -1, 3, xyz_motor.z,1, -2,xyz_motor.x, 1,-1.7,num = 10),[bec,capture_emitted])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f8d79a4c-daf9-4fca-9fb2-2a0768d1af27", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "defaultdict(list,\n", + " {'start': [{'uid': '33783bdd-412a-4dee-992c-b5b2eb19dafe',\n", + " 'time': 1718370225.951389,\n", + " 'versions': {'ophyd': '1.9.0', 'bluesky': '1.13.0a3'},\n", + " 'scan_id': 9,\n", + " 'plan_type': 'generator',\n", + " 'plan_name': 'scan',\n", + " 'detectors': ['mock_sampleAngleStage-theta', 'det'],\n", + " 'motors': ('xyz_motor-y', 'xyz_motor-z', 'xyz_motor-x'),\n", + " 'num_points': 10,\n", + " 'num_intervals': 9,\n", + " 'plan_args': {'detectors': ['',\n", + " \"SynGauss(prefix='', name='det', read_attrs=['val'], configuration_attrs=['Imax', 'center', 'sigma', 'noise', 'noise_multiplier'])\"],\n", + " 'num': 10,\n", + " 'args': ['',\n", + " -1,\n", + " 3,\n", + " '',\n", + " 1,\n", + " -2,\n", + " '',\n", + " 1,\n", + " -1.7],\n", + " 'per_step': 'None'},\n", + " 'hints': {'dimensions': [(['xyz_motor-y',\n", + " 'xyz_motor-z',\n", + " 'xyz_motor-x'],\n", + " 'primary')]},\n", + " 'plan_pattern': 'inner_product',\n", + " 'plan_pattern_module': 'bluesky.plan_patterns',\n", + " 'plan_pattern_args': {'num': 10,\n", + " 'args': ['',\n", + " -1,\n", + " 3,\n", + " '',\n", + " 1,\n", + " -2,\n", + " '',\n", + " 1,\n", + " -1.7]}}],\n", + " 'descriptor': [{'configuration': {'mock_sampleAngleStage-theta': {'data': {},\n", + " 'timestamps': {},\n", + " 'data_keys': {}},\n", + " 'xyz_motor-z': {'data': {'xyz_motor-z-velocity': 0.1,\n", + " 'xyz_motor-z-motor_egu': 'mm'},\n", + " 'timestamps': {'xyz_motor-z-velocity': 1718369465.29594,\n", + " 'xyz_motor-z-motor_egu': 1718369465.295818},\n", + " 'data_keys': {'xyz_motor-z-velocity': {'source': 'ca://p99-MO-STAGE-02:ZVELO',\n", + " 'dtype': 'number',\n", + " 'shape': []},\n", + " 'xyz_motor-z-motor_egu': {'source': 'ca://p99-MO-STAGE-02:Z.EGU',\n", + " 'dtype': 'string',\n", + " 'shape': []}}},\n", + " 'xyz_motor-y': {'data': {'xyz_motor-y-velocity': 0.1,\n", + " 'xyz_motor-y-motor_egu': 'mm'},\n", + " 'timestamps': {'xyz_motor-y-velocity': 1718369465.295785,\n", + " 'xyz_motor-y-motor_egu': 1718369465.295663},\n", + " 'data_keys': {'xyz_motor-y-velocity': {'source': 'ca://p99-MO-STAGE-02:YVELO',\n", + " 'dtype': 'number',\n", + " 'shape': []},\n", + " 'xyz_motor-y-motor_egu': {'source': 'ca://p99-MO-STAGE-02:Y.EGU',\n", + " 'dtype': 'string',\n", + " 'shape': []}}},\n", + " 'xyz_motor-x': {'data': {'xyz_motor-x-velocity': 0.1,\n", + " 'xyz_motor-x-motor_egu': 'mm'},\n", + " 'timestamps': {'xyz_motor-x-velocity': 1718369465.295628,\n", + " 'xyz_motor-x-motor_egu': 1718369465.295458},\n", + " 'data_keys': {'xyz_motor-x-velocity': {'source': 'ca://p99-MO-STAGE-02:XVELO',\n", + " 'dtype': 'number',\n", + " 'shape': []},\n", + " 'xyz_motor-x-motor_egu': {'source': 'ca://p99-MO-STAGE-02:X.EGU',\n", + " 'dtype': 'string',\n", + " 'shape': []}}},\n", + " 'det': {'data': {'det_Imax': 1,\n", + " 'det_center': 0,\n", + " 'det_sigma': 1,\n", + " 'det_noise': 'none',\n", + " 'det_noise_multiplier': 1},\n", + " 'timestamps': {'det_Imax': 1718369066.6210387,\n", + " 'det_center': 1718369066.6210353,\n", + " 'det_sigma': 1718369066.6210427,\n", + " 'det_noise': 1718369066.6210213,\n", + " 'det_noise_multiplier': 1718369066.6210306},\n", + " 'data_keys': OrderedDict([('det_Imax',\n", + " {'source': 'SIM:det_Imax',\n", + " 'dtype': 'integer',\n", + " 'shape': []}),\n", + " ('det_center',\n", + " {'source': 'SIM:det_center',\n", + " 'dtype': 'integer',\n", + " 'shape': []}),\n", + " ('det_sigma',\n", + " {'source': 'SIM:det_sigma',\n", + " 'dtype': 'integer',\n", + " 'shape': []}),\n", + " ('det_noise',\n", + " {'source': 'SIM:det_noise',\n", + " 'dtype': 'integer',\n", + " 'shape': [],\n", + " 'enum_strs': ('none', 'poisson', 'uniform')}),\n", + " ('det_noise_multiplier',\n", + " {'source': 'SIM:det_noise_multiplier',\n", + " 'dtype': 'integer',\n", + " 'shape': []})])}},\n", + " 'data_keys': {'mock_sampleAngleStage-theta': {'source': 'ca://p99-MO-TABLE-01:WRITETHETA:RBV',\n", + " 'dtype': 'number',\n", + " 'shape': [],\n", + " 'object_name': 'mock_sampleAngleStage-theta'},\n", + " 'xyz_motor-z': {'source': 'ca://p99-MO-STAGE-02:ZRBV',\n", + " 'dtype': 'number',\n", + " 'shape': [],\n", + " 'object_name': 'xyz_motor-z'},\n", + " 'xyz_motor-y': {'source': 'ca://p99-MO-STAGE-02:YRBV',\n", + " 'dtype': 'number',\n", + " 'shape': [],\n", + " 'object_name': 'xyz_motor-y'},\n", + " 'xyz_motor-x': {'source': 'ca://p99-MO-STAGE-02:XRBV',\n", + " 'dtype': 'number',\n", + " 'shape': [],\n", + " 'object_name': 'xyz_motor-x'},\n", + " 'det': {'source': 'SIM:det',\n", + " 'dtype': 'number',\n", + " 'shape': [],\n", + " 'precision': 3,\n", + " 'object_name': 'det'}},\n", + " 'name': 'primary',\n", + " 'object_keys': {'mock_sampleAngleStage-theta': ['mock_sampleAngleStage-theta'],\n", + " 'xyz_motor-z': ['xyz_motor-z'],\n", + " 'xyz_motor-y': ['xyz_motor-y'],\n", + " 'xyz_motor-x': ['xyz_motor-x'],\n", + " 'det': ['det']},\n", + " 'run_start': '33783bdd-412a-4dee-992c-b5b2eb19dafe',\n", + " 'time': 1718370246.1657035,\n", + " 'uid': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82',\n", + " 'hints': {'xyz_motor-z': {'fields': ['xyz_motor-z']},\n", + " 'xyz_motor-y': {'fields': ['xyz_motor-y']},\n", + " 'xyz_motor-x': {'fields': ['xyz_motor-x']},\n", + " 'det': {'fields': ['det']}}}],\n", + " 'event': [{'uid': 'a2b5c7fe-dd2d-4e86-a520-77186009b6f6',\n", + " 'time': 1718370246.1676013,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': -1.0,\n", + " 'xyz_motor-z': 1.0,\n", + " 'xyz_motor-x': 1.0},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370246.163833,\n", + " 'xyz_motor-y': 1718370246.163148,\n", + " 'xyz_motor-z': 1718370246.163126,\n", + " 'xyz_motor-x': 1718370246.163189},\n", + " 'seq_num': 1,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': 'a6d40fc3-7aa6-434d-b49e-1e857ea3b956',\n", + " 'time': 1718370248.4121332,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': -0.5555555555555556,\n", + " 'xyz_motor-z': 0.6666666666666667,\n", + " 'xyz_motor-x': 0.7},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370248.4113715,\n", + " 'xyz_motor-y': 1718370248.410863,\n", + " 'xyz_motor-z': 1718370248.410834,\n", + " 'xyz_motor-x': 1718370248.410911},\n", + " 'seq_num': 2,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': '93d4cf06-8217-4608-bace-bcf32c1d8fd6',\n", + " 'time': 1718370250.657558,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': -0.11111111111111116,\n", + " 'xyz_motor-z': 0.33333333333333337,\n", + " 'xyz_motor-x': 0.3999999999999999},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370250.6564853,\n", + " 'xyz_motor-y': 1718370250.655936,\n", + " 'xyz_motor-z': 1718370250.65591,\n", + " 'xyz_motor-x': 1718370250.655959},\n", + " 'seq_num': 3,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': '9f1dbcc5-5b78-4382-906e-4cc77f9878e9',\n", + " 'time': 1718370252.901921,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 0.33333333333333326,\n", + " 'xyz_motor-z': 0.0,\n", + " 'xyz_motor-x': 0.09999999999999987},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370252.9011827,\n", + " 'xyz_motor-y': 1718370252.900766,\n", + " 'xyz_motor-z': 1718370252.900745,\n", + " 'xyz_motor-x': 1718370252.90079},\n", + " 'seq_num': 4,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': 'e4925210-4aea-469d-a19b-860de95bdbca',\n", + " 'time': 1718370255.1434622,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 0.7777777777777777,\n", + " 'xyz_motor-z': -0.33333333333333326,\n", + " 'xyz_motor-x': -0.20000000000000018},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370255.1426117,\n", + " 'xyz_motor-y': 1718370255.142029,\n", + " 'xyz_motor-z': 1718370255.142009,\n", + " 'xyz_motor-x': 1718370255.142049},\n", + " 'seq_num': 5,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': '8e8e8a1d-9df0-4b8b-bd44-afd77089a942',\n", + " 'time': 1718370257.387028,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 1.2222222222222223,\n", + " 'xyz_motor-z': -0.6666666666666665,\n", + " 'xyz_motor-x': -0.5000000000000002},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370257.3859055,\n", + " 'xyz_motor-y': 1718370257.38532,\n", + " 'xyz_motor-z': 1718370257.385301,\n", + " 'xyz_motor-x': 1718370257.385341},\n", + " 'seq_num': 6,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': 'd9d059d9-61ca-4b5d-a221-db2e13d57cc8',\n", + " 'time': 1718370259.632288,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 1.6666666666666665,\n", + " 'xyz_motor-z': -1.0,\n", + " 'xyz_motor-x': -0.8000000000000003},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370259.630015,\n", + " 'xyz_motor-y': 1718370259.629147,\n", + " 'xyz_motor-z': 1718370259.629126,\n", + " 'xyz_motor-x': 1718370259.629169},\n", + " 'seq_num': 7,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': 'd6d40a64-34e3-4691-bca4-1d03d2463603',\n", + " 'time': 1718370261.8723626,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 2.1111111111111107,\n", + " 'xyz_motor-z': -1.333333333333333,\n", + " 'xyz_motor-x': -1.1000000000000005},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370261.8714201,\n", + " 'xyz_motor-y': 1718370261.870988,\n", + " 'xyz_motor-z': 1718370261.87096,\n", + " 'xyz_motor-x': 1718370261.871011},\n", + " 'seq_num': 8,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': 'b7d35df8-accb-4213-bd61-cd91d481bb17',\n", + " 'time': 1718370264.1148915,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 2.5555555555555554,\n", + " 'xyz_motor-z': -1.6666666666666665,\n", + " 'xyz_motor-x': -1.4000000000000004},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370264.1140733,\n", + " 'xyz_motor-y': 1718370264.113301,\n", + " 'xyz_motor-z': 1718370264.113277,\n", + " 'xyz_motor-x': 1718370264.113323},\n", + " 'seq_num': 9,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'},\n", + " {'uid': '33e7760c-39f9-4267-b4c3-983b4b9d5d4e',\n", + " 'time': 1718370266.3618267,\n", + " 'data': {'mock_sampleAngleStage-theta': 0.0,\n", + " 'det': 1.0,\n", + " 'xyz_motor-y': 3.0,\n", + " 'xyz_motor-z': -2.0,\n", + " 'xyz_motor-x': -1.7},\n", + " 'timestamps': {'mock_sampleAngleStage-theta': 1718369465.796649,\n", + " 'det': 1718370266.3611083,\n", + " 'xyz_motor-y': 1718370266.360636,\n", + " 'xyz_motor-z': 1718370266.360602,\n", + " 'xyz_motor-x': 1718370266.360683},\n", + " 'seq_num': 10,\n", + " 'filled': {},\n", + " 'descriptor': 'afe2ccfa-00db-4e90-8f44-39184ac3ea82'}],\n", + " 'stop': [{'uid': 'a98a3aaf-519d-431d-a4cb-1810b2f50ca1',\n", + " 'time': 1718370266.3619263,\n", + " 'run_start': '33783bdd-412a-4dee-992c-b5b2eb19dafe',\n", + " 'exit_status': 'success',\n", + " 'reason': '',\n", + " 'num_events': {'primary': 10}}]})" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "docs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "48c8d368-0187-4d77-94d2-0ca9ae253e5d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Transient Scan ID: 6 Time: 2024-06-14 12:51:47\n", + "Persistent Unique Scan ID: '72b465ad-6f6b-4faf-9828-3958e41e7c1b'\n", + "New stream: 'primary'\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "| seq_num | time | xyz_motor-y | xyz_motor-z | xyz_motor-x | mock_sampleAngleStage-theta | det |\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "| 1 | 12:51:47.8 | 3.000 | -2.000 | -1.700 | 0.000 | 1.000 |\n", + "| 2 | 12:51:48.4 | 2.897 | -1.923 | -1.631 | 0.000 | 1.000 |\n", + "| 3 | 12:51:49.0 | 2.795 | -1.846 | -1.562 | 0.000 | 1.000 |\n", + "| 4 | 12:51:49.6 | 2.692 | -1.769 | -1.492 | 0.000 | 1.000 |\n", + "| 5 | 12:51:50.2 | 2.590 | -1.692 | -1.423 | 0.000 | 1.000 |\n", + "| 6 | 12:51:50.8 | 2.487 | -1.615 | -1.354 | 0.000 | 1.000 |\n", + "| 7 | 12:51:51.4 | 2.385 | -1.538 | -1.285 | 0.000 | 1.000 |\n", + "| 8 | 12:51:51.9 | 2.282 | -1.462 | -1.215 | 0.000 | 1.000 |\n", + "| 9 | 12:51:52.6 | 2.179 | -1.385 | -1.146 | 0.000 | 1.000 |\n", + "| 10 | 12:51:53.1 | 2.077 | -1.308 | -1.077 | 0.000 | 1.000 |\n", + "| 11 | 12:51:53.7 | 1.974 | -1.231 | -1.008 | 0.000 | 1.000 |\n", + "| 12 | 12:51:54.3 | 1.872 | -1.154 | -0.938 | 0.000 | 1.000 |\n", + "| 13 | 12:51:54.9 | 1.769 | -1.077 | -0.869 | 0.000 | 1.000 |\n", + "| 14 | 12:51:55.5 | 1.667 | -1.000 | -0.800 | 0.000 | 1.000 |\n", + "| 15 | 12:51:56.1 | 1.564 | -0.923 | -0.731 | 0.000 | 1.000 |\n", + "| 16 | 12:51:56.6 | 1.488 | -0.846 | -0.662 | 0.000 | 1.000 |\n", + "| 17 | 12:51:57.3 | 1.359 | -0.769 | -0.592 | 0.000 | 1.000 |\n", + "| 18 | 12:51:57.8 | 1.256 | -0.692 | -0.523 | 0.000 | 1.000 |\n", + "| 19 | 12:51:58.5 | 1.154 | -0.615 | -0.454 | 0.000 | 1.000 |\n", + "| 20 | 12:51:59.1 | 1.051 | -0.538 | -0.385 | 0.000 | 1.000 |\n", + "| 21 | 12:51:59.7 | 0.949 | -0.462 | -0.315 | 0.000 | 1.000 |\n", + "| 22 | 12:52:00.2 | 0.846 | -0.385 | -0.246 | 0.000 | 1.000 |\n", + "| 23 | 12:52:00.8 | 0.744 | -0.308 | -0.177 | 0.000 | 1.000 |\n", + "| 24 | 12:52:01.4 | 0.641 | -0.231 | -0.108 | 0.000 | 1.000 |\n", + "| 25 | 12:52:02.0 | 0.538 | -0.154 | -0.038 | 0.000 | 1.000 |\n", + "| 26 | 12:52:02.6 | 0.436 | -0.077 | 0.031 | 0.000 | 1.000 |\n", + "| 27 | 12:52:03.2 | 0.333 | 0.000 | 0.100 | 0.000 | 1.000 |\n", + "| 28 | 12:52:03.8 | 0.231 | 0.077 | 0.169 | 0.000 | 1.000 |\n", + "| 29 | 12:52:04.4 | 0.128 | 0.154 | 0.238 | 0.000 | 1.000 |\n", + "| 30 | 12:52:05.0 | 0.026 | 0.231 | 0.308 | 0.000 | 1.000 |\n", + "| 31 | 12:52:05.6 | -0.077 | 0.308 | 0.377 | 0.000 | 1.000 |\n", + "| 32 | 12:52:06.2 | -0.179 | 0.385 | 0.446 | 0.000 | 1.000 |\n", + "| 33 | 12:52:06.8 | -0.282 | 0.462 | 0.515 | 0.000 | 1.000 |\n", + "| 34 | 12:52:07.4 | -0.385 | 0.538 | 0.585 | 0.000 | 1.000 |\n", + "| 35 | 12:52:08.0 | -0.487 | 0.615 | 0.654 | 0.000 | 1.000 |\n", + "| 36 | 12:52:08.6 | -0.590 | 0.692 | 0.723 | 0.000 | 1.000 |\n", + "| 37 | 12:52:09.2 | -0.692 | 0.769 | 0.792 | 0.000 | 1.000 |\n", + "| 38 | 12:52:09.8 | -0.795 | 0.846 | 0.862 | 0.000 | 1.000 |\n", + "| 39 | 12:52:10.4 | -0.897 | 0.923 | 0.931 | 0.000 | 1.000 |\n", + "| 40 | 12:52:11.0 | -1.000 | 1.000 | 1.000 | 0.000 | 1.000 |\n", + "+-----------+------------+-------------+-------------+-------------+-----------------------------+------------+\n", + "generator scan ['72b465ad'] (scan num: 6)\n", + "\n", + "\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "('72b465ad-6f6b-4faf-9828-3958e41e7c1b',)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAf8AAAPzCAYAAAC5rAXsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABiYElEQVR4nO3deVTVdf7H8dcF2VzAjUUU1yw0Fc0FySbHpCgttaxRsxGXbCqXFCeTMi0radOstNRqMivLynTKCnNwKyN3y90aTQwFNAMUFZF7f390vL+5gYrXe7lcPs/HOfeM9/P9fL7f9+eezrz47habzWYTAAAwho+nCwAAAOWL8AcAwDCEPwAAhiH8AQAwDOEPAIBhCH8AAAxD+AMAYBjCHwAAwxD+AAAYhvAHAMAwXhf+s2bNUuPGjRUYGKjY2FitX7/+gv0//vhjRUdHKzAwUK1bt9aXX35Zos+uXbvUq1cvhYSEqFq1aurYsaMyMjLcNQUAADzKq8J/4cKFSkpK0uTJk7V582bFxMQoISFBOTk5pfb/7rvvNGDAAA0bNkxbtmxRnz591KdPH23fvt3e57///a+uu+46RUdHa9WqVfrxxx/1+OOPKzAwsLymBQBAubJ404t9YmNj1bFjR82cOVOSZLVaFRUVpVGjRmnChAkl+vfr108FBQVaunSpva1z585q27atZs+eLUnq37+//Pz89O6775bPJAAA8LAqni6grM6cOaNNmzYpOTnZ3ubj46P4+Hilp6eXOiY9PV1JSUkObQkJCVqyZImkP/54+OKLLzR+/HglJCRoy5YtatKkiZKTk9WnT5/z1lJYWKjCwkL7d6vVqmPHjqlOnTqyWCzOTxIAgMtgs9l0/PhxRUZGysfn/Af3vSb8jx49quLiYoWHhzu0h4eHa/fu3aWOycrKKrV/VlaWJCknJ0cnTpzQs88+q6efflrPPfecUlNTdccdd2jlypXq2rVrqetNSUnRk08+6YJZAQDgegcPHlSDBg3Ou9xrwt8drFarJKl3794aO3asJKlt27b67rvvNHv27POGf3JyssMRhby8PDVs2FAHDx5UcHCw+wsHAKAU+fn5ioqKUo0aNS7Yz2vCv27duvL19VV2drZDe3Z2tiIiIkodExERccH+devWVZUqVdSyZUuHPi1atNC333573loCAgIUEBBQoj04OJjwBwB43MVOQXvN1f7+/v5q37690tLS7G1Wq1VpaWmKi4srdUxcXJxDf0lavny5vb+/v786duyoPXv2OPTZu3evGjVq5OIZAABQMXjNnr8kJSUlKTExUR06dFCnTp00Y8YMFRQUaMiQIZKkQYMGqX79+kpJSZEkPfTQQ+rataumTZumnj176sMPP9TGjRs1d+5c+zoffvhh9evXT9dff726deum1NRUff7551q1apUnpggAgNt5Vfj369dPR44c0aRJk5SVlaW2bdsqNTXVflFfRkaGw9WN1157rRYsWKCJEyfq0UcfVfPmzbVkyRK1atXK3uf222/X7NmzlZKSotGjR+uqq67SokWLdN1115X7/AAAKA9edZ9/RZWfn6+QkBDl5eVxzh8APKy4uFhFRUWeLsMt/Pz85Ovre97lZc0jr9rzBwDgfGw2m7KyspSbm+vpUtyqZs2aioiIuKznyhD+AIBK4Vzwh4WFqWrVqpXuoWs2m00nT560P9K+Xr16Tq+L8AcAeL3i4mJ78NepU8fT5bhNUFCQpD8eUhcWFnbBUwAX4jW3+gEAcD7nzvFXrVrVw5W437k5Xs51DYQ/AKDSqGyH+kvjijkS/gAAGIbwBwDAMIQ/AAAelJmZqXvuuUd16tRRUFCQWrdurY0bN7p1m1ztDwCAh/z+++/q0qWLunXrpq+++kqhoaH66aefVKtWLbdul/AHAFQ6NptNp4qKPbLtID/fMl+U99xzzykqKkpvv/22va1JkybuKs2O8AcAVDqniorVctIyj2x755QEVfUvW7x+9tlnSkhI0F133aXVq1erfv36evDBBzV8+HC31sg5fwAAPGTfvn16/fXX1bx5cy1btkwPPPCARo8erXfeecet22XPHwBQ6QT5+WrnlASPbbusrFarOnTooKlTp0qS2rVrp+3bt2v27NlKTEx0V4mEPwCg8rFYLGU+9O5J9erVU8uWLR3aWrRooUWLFrl1uxz2BwDAQ7p06aI9e/Y4tO3du1eNGjVy63YJfwAAPGTs2LH6/vvvNXXqVP38889asGCB5s6dqxEjRrh1u4Q/AAAe0rFjRy1evFgffPCBWrVqpaeeekozZszQwIED3brdin9CBACASuzWW2/VrbfeWq7bZM8fAADDEP4AABiG8AcAwDCEPwAAhiH8AQCVhs1m83QJbueKORL+AACv5+fnJ0k6efKkhytx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tm3b1KJFC40ePVpnz57VM888o+XLl7vtAT8AAMA1nL7av1mzZnr66ad14MABLV26VIWFhbr11lsVFhbmyvoAAICLXfYr4Hx8fNSjRw/16NFDR44c0bvvvuuKugAAgJs4veefm5urN998U8nJyTp27JikP+7979evn8uKAwAArufUnv+PP/6o+Ph4hYSE6JdfftHw4cNVu3Ztffrpp8rIyND8+fNdXScAAHARp/b8k5KSNHjwYP30008Ob7/r0aOH1qxZ47LiAACA6zkV/hs2bNA//vGPEu3169fn8b4AAFRwToV/QECA8vPzS7Tv3btXoaGhl10UAABwH6fCv1evXpoyZYqKiookSRaLRRkZGXrkkUfUt29flxYIAABcy6nwnzZtmk6cOKGwsDCdOnVKXbt21RVXXKEaNWromWeecXWNAADAhZy62j8kJETLly/Xt99+qx9//FEnTpzQNddco/j4eFfXBwAAXMxis9lsni7C2+Xn5yskJER5eXkKDg72dDkAAEOVNY/KvOf/yiuvlHnjo0ePLnNfAABQvsq859+kSZOyrdBi0b59+y6rKG/Dnj8AoCJw+Z7//v37XVIYAADwLKef7X+OzWYTlw0AAOA9nA7/t956S61atVJgYKACAwPVqlUrvfnmm66sDQAAuIFTt/pNmjRJ06dP16hRoxQXFydJSk9P19ixY5WRkaEpU6a4tEgAAOA6Tt3qFxoaqldeeUUDBgxwaP/ggw80atQoHT161GUFegMu+AMAVARlzSOnDvsXFRWpQ4cOJdrbt2+vs2fPOrNKAABQTpwK/7///e96/fXXS7TPnTtXAwcOvOyiAACA+zh1zl/644K/r7/+Wp07d5YkrVu3ThkZGRo0aJCSkpLs/aZPn375VQIAAJdxKvy3b9+ua665RpL03//+V5JUt25d1a1bV9u3b7f3s1gsLigRAAC4klPhv3LlSlfXAQAAysllP+QHAAB4F6f2/E+fPq1XX31VK1euVE5OjqxWq8PyzZs3u6Q4AADgek6F/7Bhw/T111/rzjvvVKdOnTi3DwCAF3Eq/JcuXaovv/xSXbp0cXU9AADAzZw651+/fn3VqFHD1bUAAIBy4FT4T5s2TY888ogOHDjg6noAAICbOXXYv0OHDjp9+rSaNm2qqlWrys/Pz2H5sWPHXFIcAABwPafCf8CAAcrMzNTUqVMV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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "RE(scan([mock_sampleAngleStage.theta, det], xyz_motor.y, 3, -1, xyz_motor.z,-2, 1,xyz_motor.x, -1.7,1,num = 40),bec)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "debf899e-c88a-4d2e-a6a1-6ddb400ab285", + "metadata": {}, + "outputs": [], + "source": [ + "result = asyncio.gather(xyz_motor.y.user_setpoint.set(-3),xyz_motor.z.user_setpoint.set(3))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0da1cc4d-dfa1-4111-bfa3-95f77bee1803", + "metadata": {}, + "outputs": [], + "source": [ + "result = asyncio.gather(xyz_motor.z.user_readback.get_value(),xyz_motor.y.user_readback.get_value(),xyz_motor.x.user_readback.get_value())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "479e4082-8353-409b-ab80-6a03563be99f", + "metadata": {}, + "outputs": [], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c885d75-0e97-4065-89da-ad2b0a3549df", + "metadata": {}, + "outputs": [], + "source": [ + "result = asyncio.gather(wait_for_value(xyz_motor.z.motor_done_move,True, timeout = None))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0446afc-26cc-45d4-89dc-5f1d34210c80", + "metadata": {}, + "outputs": [], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7371613-97c1-4bf4-af8e-27daf15e0b5c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/jupyter_tests/test_simstage.ipynb b/tests/jupyter_tests/test_simstage.ipynb new file mode 100644 index 0000000..6d3bae3 --- /dev/null +++ b/tests/jupyter_tests/test_simstage.ipynb @@ -0,0 +1,439 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "e1e5d22d-4b5b-4820-89d8-47a769509801", + "metadata": {}, + "outputs": [], + "source": [ + "from ophyd_async.core import (\n", + " DeviceCollector,\n", + " callback_on_mock_put,\n", + " get_mock_put,\n", + " set_mock_value,\n", + ")\n", + "from ophyd_async.epics.motion.motor import Motor\n", + "from ophyd_async.core import Device\n", + "from ophyd_async.epics.signal import epics_signal_rw\n", + "from bluesky.callbacks.best_effort import BestEffortCallback\n", + "from bluesky import RunEngine\n", + "from bluesky.plans import count, scan \n", + "#from ophyd.mock import det1\n", + "from bluesky import utils\n", + "from bluesky.utils import Msg\n", + "#from dodal.beamlines.beamline_utils import set_directory_provider\n", + "from ophyd_async.core._providers import StaticDirectoryProvider\n", + "from ophyd_async.epics.signal import (\n", + " epics_signal_r,\n", + " epics_signal_rw,\n", + " epics_signal_x,\n", + " epics_signal_w\n", + ")\n", + "\n", + "import asyncio\n", + "from enum import Enum\n", + "loop = asyncio.get_event_loop()\n", + "bec = BestEffortCallback()\n", + "RE = RunEngine({})\n", + "from unittest.mock import ANY, Mock\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3148be78-0ee9-45c1-b858-6c72c70a0d18", + "metadata": {}, + "outputs": [], + "source": [ + "motor_rbv_mocks = Mock()\n", + "motor_rbv_mocks.get.side_effect = np.arange(0,30,0.1)" + ] + }, + { + "cell_type": "markdown", + "id": "96990788-8040-457a-81ca-1d522164107e", + "metadata": {}, + "source": [ + "for i in range(0,10):\n", + " print(motor_rbv_mocks.get())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23298f32-7a6d-4b5a-b8af-d675550172a2", + "metadata": {}, + "outputs": [], + "source": [ + "from p99Bluesky.devices.stages import ThreeAxisStage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87bf4f05-47aa-4f3c-ae05-e9f8cb86ae07", + "metadata": {}, + "outputs": [], + "source": [ + "with DeviceCollector(mock=True):\n", + " sample_angle_stage = ThreeAxisStage('BL99P-MO-STAGE-01:',name = \"sample_angle_stage\")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "ce9d3acc-a387-4038-b32c-6ce824070fd0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Starting iocInit\n", + "iocRun: All initialization complete\n", + "Python 3.11.9 (main, May 14 2024, 08:04:54) [GCC 12.2.0] on linux\n", + "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", + "(InteractiveConsole)\n", + "\n" + ] + } + ], + "source": [ + "import subprocess\n", + "p = subprocess.Popen([\"python\", \"../junk.py\"], stdout=subprocess.PIPE)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a2607554-3136-4685-ab42-ae588a3f96c5", + "metadata": {}, + "outputs": [], + "source": [ + "from epics import caget, caput,cainfo" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f36722c2-0744-4538-a66f-c106f81a1cfa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cannot connect to p99-motor:AI\n" + ] + } + ], + "source": [ + "caget(\"p99-motor:AI\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "3ffca3dd-dea0-48b1-b265-94a02e3944c3", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "read of closed file", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[50], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcommunicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mexit\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/usr/local/lib/python3.11/subprocess.py:1196\u001b[0m, in \u001b[0;36mPopen.communicate\u001b[0;34m(self, input, timeout)\u001b[0m\n\u001b[1;32m 1194\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_stdin_write(\u001b[38;5;28minput\u001b[39m)\n\u001b[1;32m 1195\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout:\n\u001b[0;32m-> 1196\u001b[0m stdout \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout\u001b[38;5;241m.\u001b[39mread()\n\u001b[1;32m 1197\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout\u001b[38;5;241m.\u001b[39mclose()\n\u001b[1;32m 1198\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr:\n", + "\u001b[0;31mValueError\u001b[0m: read of closed file" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 14:57:44.758942689\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 14:57:44.759415284\n", + "..................................................................\n" + ] + } + ], + "source": [ + "p.communicate(\"exit\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06d1db87-ef4c-4c84-aa78-ac513cda415e", + "metadata": {}, + "outputs": [], + "source": [ + "p.communicate()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "00af3691-45b8-43a4-8ad1-dc3bdcb42a86", + "metadata": {}, + "outputs": [], + "source": [ + "sig = epics_signal_r(float, \"p99-motor:AI\")" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "87e36631-3562-4388-92cf-671763a46fb0", + "metadata": {}, + "outputs": [], + "source": [ + "result = asyncio.create_task(sig.connect())" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "466db0fd-ecca-498a-83d9-9355ad1baa27", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + " result=None>" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "1c03876e-a4f1-419e-b4cf-8dbc2ac0a086", + "metadata": {}, + "outputs": [], + "source": [ + "result = asyncio.create_task(sig.get_value())" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "36b877ef-639a-4f6d-a93c-56752dff80b6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + " wait_for=>" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:06:20.554814900\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:06:20.555540568\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Thu Jun 06 2024 15:07:53.177848331\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:08:23.352324049\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:08:23.352711500\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Thu Jun 06 2024 15:10:42.226600528\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:19:18.318243397\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:19:18.318647210\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Thu Jun 06 2024 15:25:01.030747101\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:25:59.486275531\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:25:59.486658851\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Thu Jun 06 2024 15:26:04.844458905\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:26:10.734626820\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:26:10.735149692\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Virtual circuit disconnect\"\n", + " Context: \"host.containers.internal:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1237\n", + " Current Time: Thu Jun 06 2024 15:26:12.041809116\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.099014704\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:5064\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.099428411\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: host.containers.internal:37957\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.099433488\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"errlog: lost 5 messages\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:37957\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.100127929\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:37957\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.100455936\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: host.containers.internal:35651\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.100461267\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"errlog: lost 5 messages\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:35651\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.100948666\n", + "..................................................................\n", + "CA.Client.Exception...............................................\n", + " Warning: \"Identical process variable names on multiple servers\"\n", + " Context: \"Channel: \"p99-motor:AI\", Connecting to: 172.23.241.223:5064, Ignored: 192.168.122.1:35651\"\n", + " Source File: modules/ca/src/client/cac.cpp line 1320\n", + " Current Time: Thu Jun 06 2024 15:30:05.101454749\n", + "..................................................................\n" + ] + } + ], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73616eae-3454-4cb9-8903-758c8c446adc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/soft_motor.py b/tests/soft_motor.py new file mode 100644 index 0000000..5333529 --- /dev/null +++ b/tests/soft_motor.py @@ -0,0 +1,149 @@ +import asyncio +from collections.abc import Callable + +from bluesky.protocols import Movable, Stoppable +from ophyd_async.core import ( + ConfigSignal, + Device, + HintedSignal, + StandardReadable, + WatchableAsyncStatus, +) +from ophyd_async.core.signal import AsyncStatus, SignalR, T, observe_value, wait_for_value +from ophyd_async.core.utils import ( + DEFAULT_TIMEOUT, + CalculatableTimeout, + CalculateTimeout, + WatcherUpdate, +) +from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw, epics_signal_x + + +class SoftThreeAxisStage(Device): + """ + + Standard ophyd_async xyz motor stage, by combining 3 Motors. + + Parameters + ---------- + prefix: + EPICS PV (None common part up to and including :). + name: + name for the stage. + infix: + EPICS PV, default is the ["X", "Y", "Z"]. + Notes + ----- + Example usage:: + async with DeviceCollector(): + xyz_stage = ThreeAxisStage("BLXX-MO-STAGE-XX:") + Or:: + with DeviceCollector(): + xyz_stage = ThreeAxisStage("BLXX-MO-STAGE-XX:", suffix = [".any", + ".there", ".motorPv"]) + + """ + + def __init__(self, prefix: str, name: str, infix: list[str] | None = None): + if infix is None: + infix = ["X", "Y", "Z"] + self.x = SoftMotor(prefix + infix[0]) + self.y = SoftMotor(prefix + infix[1]) + self.z = SoftMotor(prefix + infix[2]) + super().__init__(name=name) + + +class SoftMotor(StandardReadable, Movable, Stoppable): + """Device that moves a motor record + ToDo: this should not be needed, + rather I should try change the record in the softioc to match motor + """ + + def __init__(self, prefix: str, name="") -> None: + # Define some signals + with self.add_children_as_readables(ConfigSignal): + self.motor_egu = epics_signal_r(str, prefix + ".EGU") + self.velocity = epics_signal_rw(float, prefix + "VELO") + + with self.add_children_as_readables(HintedSignal): + self.user_readback = epics_signal_r(float, prefix + "RBV") + + self.user_setpoint = epics_signal_rw(float, prefix + "VAL") + self.max_velocity = epics_signal_r(float, prefix + "VMAX") + self.acceleration_time = epics_signal_rw(float, prefix + "ACCL") + self.precision = epics_signal_r(int, prefix + ".PREC") + self.deadband = epics_signal_r(float, prefix + "RDBD") + self.motor_done_move = epics_signal_r(bool, prefix + "DMOV") + self.low_limit_travel = epics_signal_rw(float, prefix + "LLM") + self.high_limit_travel = epics_signal_rw(float, prefix + "HLM") + + self.motor_stop = epics_signal_x(prefix + "STOP") + # Whether set() should complete successfully or not + self._set_success = True + super().__init__(name=name) + + def set_name(self, name: str): + super().set_name(name) + # Readback should be named the same as its parent in read() + self.user_readback.set_name(name) + + @AsyncStatus.wrap + async def wait_for_value_with_status( + self, + signal: SignalR[T], + match: T | Callable[[T], bool], + timeout: float | None, + ): + """wrap wait for value so it return an asyncStatus""" + await wait_for_value(signal, match, timeout) + + @WatchableAsyncStatus.wrap + async def set(self, value: float, timeout: CalculatableTimeout = CalculateTimeout): + self._set_success = True + ( + old_position, + units, + precision, + velocity, + acceleration_time, + ) = await asyncio.gather( + self.user_setpoint.get_value(), + self.motor_egu.get_value(), + self.precision.get_value(), + self.velocity.get_value(), + self.acceleration_time.get_value(), + ) + if timeout is CalculateTimeout: + assert velocity > 0, "Motor has zero velocity" + timeout = ( + abs(value - old_position) / velocity + + 2 * acceleration_time + + DEFAULT_TIMEOUT + ) + # modified to actually wait for set point to be set + await self.user_setpoint.set(value, wait=True, timeout=timeout) + # changed this so that the watcher keep going until the motor is stopped + move_status = self.wait_for_value_with_status( + self.motor_done_move, True, timeout=None + ) + async for current_position in observe_value( + self.user_readback, done_status=move_status + ): + yield WatcherUpdate( + current=current_position, + initial=old_position, + target=value, + name=self.name, + unit=units, + precision=precision, + ) + if not self._set_success: + raise RuntimeError("Motor was stopped") + + async def stop(self, success=False): + self._set_success = success + # Put with completion will never complete as we are waiting for completion on + # the move above, so need to pass wait=False + await self.motor_stop.trigger(wait=False) + # Trigger any callbacks + # await self.user_setpoint.set(await self.user_readback.get_value()) diff --git a/tests/test_p99_stage.py b/tests/test_p99_stage.py index 7a4edde..8d2fa91 100644 --- a/tests/test_p99_stage.py +++ b/tests/test_p99_stage.py @@ -18,7 +18,6 @@ async def mock_sampleAngleStage(): mock_sampleAngleStage = SampleAngleStage( "p99-MO-TABLE-01:", name="mock_sampleAngleStage" ) - # Signals connected here yield mock_sampleAngleStage diff --git a/tests/test_p99_stages_softioc.py b/tests/test_p99_stages_softioc.py new file mode 100644 index 0000000..730fe08 --- /dev/null +++ b/tests/test_p99_stages_softioc.py @@ -0,0 +1,64 @@ +import asyncio +import subprocess + +from bluesky.run_engine import RunEngine +from ophyd_async.core import DeviceCollector + +from p99_bluesky.devices.p99.sample_stage import ( + FilterMotor, + SampleAngleStage, + p99StageSelections, +) +from soft_motor import SoftThreeAxisStage + +# Long enough for multiple asyncio event loop cycles to run so +# all the tasks have a chance to run +A_BIT = 0.001 + + +async def test_soft_sampleAngleStage(RE: RunEngine) -> None: + p = subprocess.Popen( + [ + "python", + "tests/epics/soft_ioc/p99_softioc.py", + ], + ) + + await asyncio.sleep(A_BIT) + with DeviceCollector(mock=False): + mock_sampleAngleStage = SampleAngleStage( + "p99-MO-TABLE-01:", name="mock_sampleAngleStage" + ) + mock_filter_wheel = FilterMotor( + "p99-MO-STAGE-02:MP:SELECT", name="mock_filter_wheel" + ) + xyz_motor = SoftThreeAxisStage("p99-MO-STAGE-02:", name="xyz_motor") + + assert mock_sampleAngleStage.roll.name == "mock_sampleAngleStage-roll" + assert mock_sampleAngleStage.pitch.name == "mock_sampleAngleStage-pitch" + assert mock_filter_wheel.user_setpoint.name == "mock_filter_wheel-user_setpoint" + + await asyncio.gather( + mock_sampleAngleStage.theta.set(2), + mock_sampleAngleStage.pitch.set(3.1), + mock_sampleAngleStage.roll.set(4), + mock_filter_wheel.user_setpoint.set(p99StageSelections.Cd25um), + xyz_motor.x.user_setpoint.set(0), + ) + await asyncio.sleep(A_BIT) + result = asyncio.gather( + mock_sampleAngleStage.theta.get_value(), + mock_sampleAngleStage.pitch.get_value(), + mock_sampleAngleStage.roll.get_value(), + mock_filter_wheel.user_setpoint.get_value(), + xyz_motor.x.user_readback.get_value(), + ) + await asyncio.wait_for(result, timeout=2) + assert result.result() == [2.0, 3.1, 4.0, p99StageSelections.Cd25um, 0.0] + from bluesky.plans import scan + from ophyd.sim import det # type: ignore + + RE(scan([mock_sampleAngleStage.theta, det], xyz_motor.y, -1, 1, 10)) + + p.terminate() + p.wait() diff --git a/tests/test_stage.py b/tests/test_stage.py index 77a2f43..9c87ee8 100644 --- a/tests/test_stage.py +++ b/tests/test_stage.py @@ -18,3 +18,41 @@ async def test_there_axis_motor(mock_three_axis_motor: ThreeAxisStage) -> None: assert mock_three_axis_motor.x.name == "mock_three_axis_motor-x" assert mock_three_axis_motor.y.name == "mock_three_axis_motor-y" assert mock_three_axis_motor.z.name == "mock_three_axis_motor-z" + + +""" +import asyncio +import subprocess + + +async def test_nothing(): + p = subprocess.Popen( + [ + "python", + "/workspaces/p99-bluesky/tests/epics/softioc/softsignal.py", + "p99-motor", + "AI", + "AO", + ], + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + # async with DeviceCollector(): + sig = epics_signal_rw(float, "p99-motor:AI") + sig2 = epics_signal_rw(float, "p99-motor:AO") + await asyncio.create_task(sig.connect()) + await asyncio.create_task(sig2.connect()) + await asyncio.gather(sig2.set(2)) + for i in range(20): + result = asyncio.create_task(sig.get_value()) + await asyncio.wait_for(result, timeout=2) + await asyncio.sleep(0.2) + print(result) + result = asyncio.create_task(sig.get_value()) + await asyncio.wait_for(result, timeout=2) + # await asyncio.sleep(0.2) + assert result.result() == pytest.approx(2.0, 0.1) + p.communicate(b"exit") +"""