XRT KB Mirror Demo¶
For ophyd beamline setup see:
https://github.com/NSLS-II/blop/blob/main/src/blop/sim/xrt_beamline.py
https://github.com/NSLS-II/blop/blob/main/src/blop/sim/xrt_kb_model.py
The picture below displays beam from geometric source propagating through a pair of toroidal mirrors focusing the beam on screen. Simulation of a KB setup.

import time
from datetime import datetime
import logging
import plotly.io as pio
pio.renderers.default = "notebook"
import bluesky.plan_stubs as bps # noqa F401
import bluesky.plans as bp # noqa F401
import databroker # type: ignore[import-untyped]
import matplotlib.pyplot as plt
import tiled.client.container
from bluesky.callbacks import best_effort
from bluesky.callbacks.tiled_writer import TiledWriter
from bluesky.run_engine import RunEngine
from databroker import Broker
from ophyd.utils import make_dir_tree # type: ignore[import-untyped]
from tiled.client import from_uri # type: ignore[import-untyped]
from tiled.server import SimpleTiledServer
from blop import DOF, Objective
from blop.ax import Agent
from blop.sim import HDF5Handler
from blop.sim.xrt_beamline import DatabrokerBeamline, TiledBeamline
# Suppress noisy logs from httpx
logging.getLogger("httpx").setLevel(logging.WARNING)
DETECTOR_STORAGE = "/tmp/blop/sim"
[WARNING 10-13 20:44:25] ax.service.utils.with_db_settings_base: Ax currently requires a sqlalchemy version below 2.0. This will be addressed in a future release. Disabling SQL storage in Ax for now, if you would like to use SQL storage please install Ax with mysql extras via `pip install ax-platform[mysql]`.
tiled_server = SimpleTiledServer(readable_storage=[DETECTOR_STORAGE])
tiled_client = from_uri(tiled_server.uri)
tiled_writer = TiledWriter(tiled_client)
def setup_re_env(db_type="default", root_dir="/default/path", method="tiled"):
RE = RunEngine({})
bec = best_effort.BestEffortCallback()
RE.subscribe(bec)
_ = make_dir_tree(datetime.now().year, base_path=root_dir)
if method == "tiled":
RE.subscribe(tiled_writer)
return {"RE": RE, "db": tiled_client, "bec": bec}
elif method == "databroker":
db = Broker.named(db_type)
db.reg.register_handler("HDF5", HDF5Handler, overwrite=True)
try:
databroker.assets.utils.install_sentinels(db.reg.config, version=1)
except Exception:
pass
RE.subscribe(db.insert)
return {
"RE": RE,
"db": db,
"bec": bec,
}
else:
raise ValueError("The method for data storage used is not supported")
def register_handlers(db, handlers):
for handler_spec, handler_class in handlers.items():
db.reg.register_handler(handler_spec, handler_class, overwrite=True)
env = setup_re_env(db_type="temp", root_dir="/tmp/blop/sim", method="tiled")
globals().update(env)
bec.disable_plots()
2025-10-13 20:44:29.030 INFO: Subprocess stdout:
2025-10-13 20:44:29.031 INFO: Subprocess stderr: Database sqlite+aiosqlite:////tmp/tmpgc5n9umh/catalog.db is new. Creating tables.
Database initialized.
Tiled version 0.1.6
2025-10-13 20:44:29.347 INFO: Tiled version 0.1.6
2025-10-13 20:44:29.353 INFO: Context impl SQLiteImpl.
2025-10-13 20:44:29.354 INFO: Will assume non-transactional DDL.
plt.ion()
h_opt = 0
dh = 5
R1, dR1 = 40000, 10000
R2, dR2 = 20000, 10000
if isinstance(db, tiled.client.container.Container):
beamline = TiledBeamline(name="bl")
else:
beamline = DatabrokerBeamline(name="bl")
time.sleep(1)
dofs = [
DOF(movable=beamline.kbv_dsv, search_domain=(R1 - dR1, R1 + dR1)),
DOF(movable=beamline.kbh_dsh, search_domain=(R2 - dR2, R2 + dR2)),
]
objectives = [
Objective(name="bl_det_sum", target="max"),
Objective(name="bl_det_wid_x", target="min"),
Objective(name="bl_det_wid_y", target="min"),
]
agent = Agent(
readables=[beamline.det],
dofs=dofs,
objectives=objectives,
db=db,
)
agent.configure_experiment(
name="xrt-blop-demo",
description="A demo of the Blop agent with XRT simulated beamline",
experiment_type="demo",
)
2025-10-13 20:44:30.627 INFO: Configuring optimization with objective: bl_det_sum, -bl_det_wid_x, -bl_det_wid_y and outcome constraints: []
# Number of iterations can be increased to be more specific
RE(agent.learn(iterations=15))
Transient Scan ID: 1 Time: 2025-10-13 20:44:30
Persistent Unique Scan ID: '39fb2b45-83ee-49f6-b66d-96b37984e999'
ToroidMirror2
center:
[0, 11000, np.float64(176.33091137593323)]
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:30.8 | 40000.000 | 20000.000 | 22335.931 | 201.892 | 145.020 | 19.000 | 42.198 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['39fb2b45'] (scan num: 1)
Found duckdb shared library at /home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.12/site-packages/_duckdb.cpython-312-x86_64-linux-gnu.so
Transient Scan ID: 2 Time: 2025-10-13 20:44:31
Persistent Unique Scan ID: '76aedfea-2631-4352-bdbd-be3cf1056ab5'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:31.7 | 36759.288 | 22505.848 | 21362.177 | 201.214 | 154.249 | 79.028 | 29.103 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['76aedfea'] (scan num: 2)
Transient Scan ID: 3 Time: 2025-10-13 20:44:32
Persistent Unique Scan ID: '57cf73fe-f894-439b-9563-a29ef7ffe2a0'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:32.4 | 40571.711 | 10788.837 | 466.025 | 224.029 | 150.883 | 324.292 | 34.467 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['57cf73fe'] (scan num: 3)
Transient Scan ID: 4 Time: 2025-10-13 20:44:33
Persistent Unique Scan ID: '6b78b0c7-1a00-4c90-925f-d470920112e3'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:33.1 | 45728.317 | 26884.119 | 2697.599 | 212.667 | 151.821 | 202.667 | 103.357 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['6b78b0c7'] (scan num: 4)
Transient Scan ID: 5 Time: 2025-10-13 20:44:33
Persistent Unique Scan ID: '2321cf00-114e-4ea9-ae54-e4512eab161b'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:33.8 | 31916.266 | 18912.988 | 10911.149 | 209.469 | 149.728 | 75.075 | 105.232 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['2321cf00'] (scan num: 5)
Transient Scan ID: 6 Time: 2025-10-13 20:44:36
Persistent Unique Scan ID: '17df7a3d-f3a8-4cb6-b4ea-69ca2f89ee10'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:37.0 | 37985.346 | 20466.393 | 23667.491 | 194.224 | 147.750 | 14.790 | 18.511 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['17df7a3d'] (scan num: 6)
Transient Scan ID: 7 Time: 2025-10-13 20:44:40
Persistent Unique Scan ID: 'f71b0182-d5db-472f-ae16-b33de3ccc77e'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:40.7 | 38938.899 | 20544.059 | 23448.876 | 193.865 | 148.229 | 14.504 | 25.292 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['f71b0182'] (scan num: 7)
Transient Scan ID: 8 Time: 2025-10-13 20:44:44
Persistent Unique Scan ID: '85d6c446-a637-4840-a492-d66c7f0a694a'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:44.7 | 38307.641 | 20725.563 | 23650.836 | 193.627 | 149.045 | 14.561 | 19.145 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['85d6c446'] (scan num: 8)
Transient Scan ID: 9 Time: 2025-10-13 20:44:50
Persistent Unique Scan ID: '572c8538-95b2-4cde-bce2-0cabf8746e45'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:50.6 | 37266.567 | 20471.659 | 23627.285 | 193.125 | 148.628 | 14.000 | 22.590 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['572c8538'] (scan num: 9)
Transient Scan ID: 10 Time: 2025-10-13 20:44:57
Persistent Unique Scan ID: '02d41b8c-afdd-429b-bc7e-364ceb3551f5'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:44:57.1 | 38172.910 | 20582.667 | 23692.739 | 194.329 | 148.228 | 13.869 | 18.435 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['02d41b8c'] (scan num: 10)
Transient Scan ID: 11 Time: 2025-10-13 20:45:04
Persistent Unique Scan ID: '3deab208-6b5c-4412-9a32-3638e40d081a'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:04.7 | 38577.190 | 20597.294 | 23580.191 | 193.690 | 148.292 | 14.519 | 22.266 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['3deab208'] (scan num: 11)
Transient Scan ID: 12 Time: 2025-10-13 20:45:12
Persistent Unique Scan ID: 'aa1af7a6-07b8-41d0-bb18-d6d7eaceffbd'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:12.5 | 37809.246 | 20584.967 | 23685.558 | 193.327 | 148.790 | 13.855 | 17.180 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['aa1af7a6'] (scan num: 12)
Transient Scan ID: 13 Time: 2025-10-13 20:45:21
Persistent Unique Scan ID: 'c17fe558-31ec-4813-97d5-567082da4b40'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:21.9 | 38437.492 | 20486.574 | 23859.389 | 194.384 | 147.443 | 15.417 | 20.376 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['c17fe558'] (scan num: 13)
Transient Scan ID: 14 Time: 2025-10-13 20:45:30
Persistent Unique Scan ID: '27f98a83-ad4e-422d-99c4-2f4fdb069971'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:30.2 | 37616.676 | 20502.680 | 23677.569 | 193.763 | 148.455 | 14.280 | 17.936 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['27f98a83'] (scan num: 14)
Transient Scan ID: 15 Time: 2025-10-13 20:45:38
Persistent Unique Scan ID: '3fa627ed-1b4a-4902-9eac-b47a20c89c0f'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:38.6 | 38380.369 | 20583.378 | 23786.677 | 193.806 | 148.157 | 13.438 | 19.385 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['3fa627ed'] (scan num: 15)
2025-10-13 20:44:30.654 INFO: Executing plan <generator object Agent.learn at 0x7fede4461440>
2025-10-13 20:44:30.656 INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fede48d88f0> from 'idle' -> 'running'
2025-10-13 20:45:39.152 INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fede48d88f0> from 'running' -> 'idle'
2025-10-13 20:45:39.153 INFO: Cleaned up from plan <generator object Agent.learn at 0x7fede4461440>
('39fb2b45-83ee-49f6-b66d-96b37984e999',
'76aedfea-2631-4352-bdbd-be3cf1056ab5',
'57cf73fe-f894-439b-9563-a29ef7ffe2a0',
'6b78b0c7-1a00-4c90-925f-d470920112e3',
'2321cf00-114e-4ea9-ae54-e4512eab161b',
'17df7a3d-f3a8-4cb6-b4ea-69ca2f89ee10',
'f71b0182-d5db-472f-ae16-b33de3ccc77e',
'85d6c446-a637-4840-a492-d66c7f0a694a',
'572c8538-95b2-4cde-bce2-0cabf8746e45',
'02d41b8c-afdd-429b-bc7e-364ceb3551f5',
'3deab208-6b5c-4412-9a32-3638e40d081a',
'aa1af7a6-07b8-41d0-bb18-d6d7eaceffbd',
'c17fe558-31ec-4813-97d5-567082da4b40',
'27f98a83-ad4e-422d-99c4-2f4fdb069971',
'3fa627ed-1b4a-4902-9eac-b47a20c89c0f')
_ = agent.plot_objective(x_dof_name="bl_kbh_dsh", y_dof_name="bl_kbv_dsv", objective_name="bl_det_sum")
The contour plot visualizes the predicted outcomes for bl_det_sum across a two-dimensional parameter space, with other parameters held fixed at their status_quo value (or mean value if status_quo is unavailable). This plot helps in identifying regions of optimal performance and understanding how changes in the selected parameters influence the predicted outcomes. Contour lines represent levels of constant predicted values, providing insights into the gradient and potential optima within the parameter space.
Visualizing the optimal beam¶
Below we get the optimal parameters, move the motors to their optimal positions, and observe the resulting beam.
optimal_parameters = next(iter(agent.client.get_pareto_frontier()))[0]
optimal_parameters
[INFO 10-13 20:45:40] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(bl_det_sum >= 23409.33930513235), ObjectiveThreshold(bl_det_wid_x <= 14.424786115166214), ObjectiveThreshold(bl_det_wid_y <= 26.43226737474903)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
{'bl_kbv_dsv': 38172.90959052969, 'bl_kbh_dsh': 20582.66742870973}
from bluesky.plans import list_scan
scan_motor_params = []
for motor in [beamline.kbv_dsv, beamline.kbh_dsh]:
scan_motor_params.append(motor)
scan_motor_params.append([optimal_parameters[motor.name]])
uid = RE(list_scan([beamline.det], *scan_motor_params))
Transient Scan ID: 16 Time: 2025-10-13 20:45:40
Persistent Unique Scan ID: 'bbea78d0-df25-4423-8db0-055cddb26e6d'
New stream: 'primary'
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| seq_num | time | bl_kbv_dsv | bl_kbh_dsh | bl_det_sum | bl_det_cen_x | bl_det_cen_y | bl_det_wid_x | bl_det_wid_y |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
| 1 | 20:45:40.4 | 38172.910 | 20582.667 | 23899.754 | 194.058 | 148.092 | 14.165 | 18.496 |
+-----------+------------+------------+------------+------------+--------------+--------------+--------------+--------------+
generator list_scan ['bbea78d0'] (scan num: 16)
2025-10-13 20:45:40.332 INFO: Executing plan <generator object list_scan at 0x7feda04bcc40>
2025-10-13 20:45:40.333 INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fede48d88f0> from 'idle' -> 'running'
2025-10-13 20:45:40.737 INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fede48d88f0> from 'running' -> 'idle'
2025-10-13 20:45:40.738 INFO: Cleaned up from plan <generator object list_scan at 0x7feda04bcc40>