Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
c1541cd
eod
MTakahashi-KWH Apr 29, 2026
5effe0a
[ENH] first "realization", onto sandbox
MTakahashi-KWH Apr 30, 2026
36db281
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH Apr 30, 2026
2c1470a
add submodule init
MTakahashi-KWH Apr 30, 2026
fce266b
fix
MTakahashi-KWH Apr 30, 2026
0ff3994
bugfixes
MTakahashi-KWH Apr 30, 2026
0ceeda2
do more than one iteration
MTakahashi-KWH Apr 30, 2026
25c388e
[IENH] added dual annealing support and cleaned worker prep
MTakahashi-KWH May 1, 2026
8dab4d7
ruff fixes
MTakahashi-KWH May 4, 2026
52495ca
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH May 4, 2026
9992b48
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH May 8, 2026
d95b2a7
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH May 14, 2026
6d1e44e
scipy opt best_points and axis rescaling
MTakahashi-KWH May 14, 2026
83d0e26
cleaning of print statements
MTakahashi-KWH May 14, 2026
28beeb7
fixes to dual annealing
MTakahashi-KWH May 15, 2026
bc4ee55
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH Jun 22, 2026
73f026f
updates to allow multi threaded optimizer sampling, more to come
MTakahashi-KWH Jun 22, 2026
cc6760e
initial test implementations
MTakahashi-KWH Jun 22, 2026
3bd6be0
ruff fixes
MTakahashi-KWH Jun 22, 2026
f4ead1e
first unit test fixes
MTakahashi-KWH Jun 22, 2026
4ec5846
final test fixes for the day
MTakahashi-KWH Jun 22, 2026
ab626e4
ruff
MTakahashi-KWH Jun 22, 2026
d806b80
bug fixes and code seperation. Continuing work on multi sampling
MTakahashi-KWH Jun 24, 2026
df39389
tiny patch to test now working multithread and imrove thread closure …
MTakahashi-KWH Jun 24, 2026
44de99d
GO MY BOTS, BUILD UNIT TESTS
MTakahashi-KWH Jun 24, 2026
0f3a3fa
removed debug prints
MTakahashi-KWH Jun 24, 2026
52fcec7
Merge branch 'alt-grad-llm-unit-tests' into alternate_optimizers
MTakahashi-KWH Jun 24, 2026
50fb5fb
ruff fixes
MTakahashi-KWH Jun 24, 2026
720593c
strenum flaky in 3.11 and race condition fix on resessioning
MTakahashi-KWH Jun 24, 2026
f1e981a
fix lint check from throwing error on backwards compat fix
MTakahashi-KWH Jun 25, 2026
d3b0008
added tutorial for gradient
MTakahashi-KWH Jun 25, 2026
b772bc3
lint fixes and new optimizer
MTakahashi-KWH Jun 25, 2026
dc41ff1
dual annealing qol for best points, better tutorail visuals and agent…
MTakahashi-KWH Jun 25, 2026
9e7c585
3.11 fix v2
MTakahashi-KWH Jun 25, 2026
9459083
juytext fix?
MTakahashi-KWH Jun 25, 2026
357fb1f
attempt doc fixes
MTakahashi-KWH Jun 25, 2026
3b5e693
3.11 fix
MTakahashi-KWH Jun 25, 2026
601b508
fix for 3.11 tests
MTakahashi-KWH Jun 25, 2026
0944010
seperated scipy and optimizer tests
MTakahashi-KWH Jun 25, 2026
3ba2135
ruff
MTakahashi-KWH Jun 25, 2026
38ed50d
edit to default resiliance in agent and cleaning of active queue with…
MTakahashi-KWH Jun 25, 2026
6e4d356
ruff
MTakahashi-KWH Jun 25, 2026
35d7245
cheeky shift to dual annealing for code cov
MTakahashi-KWH Jun 25, 2026
9544acc
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH Jul 6, 2026
ac73a58
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH Jul 22, 2026
c09b7ba
ruff woke up angry this morning
MTakahashi-KWH Jul 22, 2026
9d861f2
added lot more optimizers
MTakahashi-KWH Jul 22, 2026
1024c38
added SHGO
MTakahashi-KWH Jul 22, 2026
4a607e3
python 3.11 again doing its complaints (fix?)
MTakahashi-KWH Jul 22, 2026
36262d8
Merge branch 'main' of https://github.com/bluesky/blop into alternate…
MTakahashi-KWH Jul 23, 2026
33d77ef
Apply suggestion from @thopkins32
MTakahashi-KWH Jul 28, 2026
8a2b887
renaming and reorganizing of additions
MTakahashi-KWH Jul 29, 2026
e0693da
first protocol prototype
MTakahashi-KWH Jul 30, 2026
e8010a4
stable refactor, reorder next
MTakahashi-KWH Jul 30, 2026
eaa0c8b
minor fixes with tests and demo
MTakahashi-KWH Jul 30, 2026
00d37bc
test case name fixes
MTakahashi-KWH Jul 30, 2026
b6dd655
package reorder, unit test conversion and bug fixes
MTakahashi-KWH Jul 31, 2026
41a374c
had to re add the sleep statement. final has a race condition making …
MTakahashi-KWH Jul 31, 2026
c47ead4
ruff AAAAAAAAAAAAAAAAAAAA
MTakahashi-KWH Jul 31, 2026
9bd04e2
3.11 fix
MTakahashi-KWH Jul 31, 2026
979cfb9
Enum name improvements
MTakahashi-KWH Jul 31, 2026
f776ec8
fixed doc enum error
MTakahashi-KWH Jul 31, 2026
e00478a
eod
MTakahashi-KWH Apr 29, 2026
04bbcc8
[ENH] first "realization", onto sandbox
MTakahashi-KWH Apr 30, 2026
ee5e1fe
add submodule init
MTakahashi-KWH Apr 30, 2026
3dbbd41
fix
MTakahashi-KWH Apr 30, 2026
0b22fde
bugfixes
MTakahashi-KWH Apr 30, 2026
1dfd6ca
do more than one iteration
MTakahashi-KWH Apr 30, 2026
e812a52
[IENH] added dual annealing support and cleaned worker prep
MTakahashi-KWH May 1, 2026
7c660da
ruff fixes
MTakahashi-KWH May 4, 2026
d720085
scipy opt best_points and axis rescaling
MTakahashi-KWH May 14, 2026
49b6308
cleaning of print statements
MTakahashi-KWH May 14, 2026
47b95ce
fixes to dual annealing
MTakahashi-KWH May 15, 2026
f4c95f6
updates to allow multi threaded optimizer sampling, more to come
MTakahashi-KWH Jun 22, 2026
7bc1eec
initial test implementations
MTakahashi-KWH Jun 22, 2026
2d351f2
ruff fixes
MTakahashi-KWH Jun 22, 2026
8dde2be
first unit test fixes
MTakahashi-KWH Jun 22, 2026
36aae71
final test fixes for the day
MTakahashi-KWH Jun 22, 2026
3b0b0b8
ruff
MTakahashi-KWH Jun 22, 2026
71bcafa
bug fixes and code seperation. Continuing work on multi sampling
MTakahashi-KWH Jun 24, 2026
dec9ba9
tiny patch to test now working multithread and imrove thread closure …
MTakahashi-KWH Jun 24, 2026
fb2776e
removed debug prints
MTakahashi-KWH Jun 24, 2026
a693e07
GO MY BOTS, BUILD UNIT TESTS
MTakahashi-KWH Jun 24, 2026
4d1585d
ruff fixes
MTakahashi-KWH Jun 24, 2026
404bd60
strenum flaky in 3.11 and race condition fix on resessioning
MTakahashi-KWH Jun 24, 2026
93b41c8
fix lint check from throwing error on backwards compat fix
MTakahashi-KWH Jun 25, 2026
8499a66
added tutorial for gradient
MTakahashi-KWH Jun 25, 2026
5705c01
lint fixes and new optimizer
MTakahashi-KWH Jun 25, 2026
e329425
dual annealing qol for best points, better tutorail visuals and agent…
MTakahashi-KWH Jun 25, 2026
73bd6ee
3.11 fix v2
MTakahashi-KWH Jun 25, 2026
a4be441
juytext fix?
MTakahashi-KWH Jun 25, 2026
e1c9e1d
attempt doc fixes
MTakahashi-KWH Jun 25, 2026
4a89a1c
3.11 fix
MTakahashi-KWH Jun 25, 2026
a8dcb35
fix for 3.11 tests
MTakahashi-KWH Jun 25, 2026
89166a8
seperated scipy and optimizer tests
MTakahashi-KWH Jun 25, 2026
235ce7b
ruff
MTakahashi-KWH Jun 25, 2026
23f336f
edit to default resiliance in agent and cleaning of active queue with…
MTakahashi-KWH Jun 25, 2026
afc6777
ruff
MTakahashi-KWH Jun 25, 2026
1e6c9b3
cheeky shift to dual annealing for code cov
MTakahashi-KWH Jun 25, 2026
f6648b1
ruff woke up angry this morning
MTakahashi-KWH Jul 22, 2026
30576b3
added lot more optimizers
MTakahashi-KWH Jul 22, 2026
7e5c607
added SHGO
MTakahashi-KWH Jul 22, 2026
69f8535
python 3.11 again doing its complaints (fix?)
MTakahashi-KWH Jul 22, 2026
58e8656
Apply suggestion from @thopkins32
MTakahashi-KWH Jul 28, 2026
171ca3d
renaming and reorganizing of additions
MTakahashi-KWH Jul 29, 2026
214bfc3
first protocol prototype
MTakahashi-KWH Jul 30, 2026
6e00f82
stable refactor, reorder next
MTakahashi-KWH Jul 30, 2026
960d8d7
minor fixes with tests and demo
MTakahashi-KWH Jul 30, 2026
de1e7c9
test case name fixes
MTakahashi-KWH Jul 30, 2026
6a039a5
package reorder, unit test conversion and bug fixes
MTakahashi-KWH Jul 31, 2026
3869467
had to re add the sleep statement. final has a race condition making …
MTakahashi-KWH Jul 31, 2026
70141b0
ruff AAAAAAAAAAAAAAAAAAAA
MTakahashi-KWH Jul 31, 2026
d7a7ddd
3.11 fix
MTakahashi-KWH Jul 31, 2026
185600d
Enum name improvements
MTakahashi-KWH Jul 31, 2026
30ce1cd
fixed doc enum error
MTakahashi-KWH Jul 31, 2026
9a71a3e
Merge branch 'scipy_barebones' of https://github.com/bluesky/blop int…
MTakahashi-KWH Aug 4, 2026
4edcb4d
removed assertion around unguarenteed object data member with race co…
MTakahashi-KWH Aug 4, 2026
11894aa
.........................ruff
MTakahashi-KWH Aug 5, 2026
44c4d90
__ruff__
MTakahashi-KWH Aug 5, 2026
7579a3b
another enum fix
MTakahashi-KWH Aug 5, 2026
d04a998
removed waits and integration test, made better startup and error rai…
MTakahashi-KWH Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Tutorials
:maxdepth: 1

tutorials/simple-experiment.md
tutorials/gradient-optimization.md
tutorials/queueserver.md
tutorials/xrt-demo.md
tutorials/xrt-kb-mirrors.md
244 changes: 244 additions & 0 deletions docs/source/tutorials/gradient-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.17.3
kernelspec:
display_name: dev
language: python
name: python3
---

# Your first Scipy optimization with Blop

In this tutorial, you will learn the three core concepts of Blop: **DOFs** (the parameters you can adjust), **objectives** (what you want to optimize), and the **Agent** (which coordinates the optimization). We'll optimize a simple mathematical function using simulated devices—the same patterns apply to real hardware.

## Setup

First, let's import what we need and start the data infrastructure:

```{code-cell} ipython3
import logging
import time
from typing import Any

from bluesky.protocols import HasHints, HasParent, Hints, NamedMovable, Readable, Status
from bluesky.run_engine import RunEngine
from bluesky_tiled_plugins import TiledWriter
from tiled.client import from_uri
from tiled.client.container import Container
from tiled.server import SimpleTiledServer

from blop.scipy import SCP, ScipyCFG, Objective, RangeDOF, Scipy

# Suppress noisy logs from httpx
logging.getLogger("httpx").setLevel(logging.WARNING)
```

```{code-cell} ipython3
# Start a local Tiled server for data storage
tiled_server = SimpleTiledServer()

# Set up the Bluesky RunEngine and connect it to Tiled
RE = RunEngine({})
tiled_client = from_uri(tiled_server.uri)
tiled_writer = TiledWriter(tiled_client)
RE.subscribe(tiled_writer)
```

## Creating simulated devices

Bluesky controls devices through protocols. For this tutorial, we create simple simulated "movable" devices. In real experiments, you would use [Ophyd](https://blueskyproject.io/ophyd-async) devices or similar—the code below is just boilerplate to simulate hardware:

```{code-cell} ipython3
class AlwaysSuccessfulStatus(Status):
def add_callback(self, callback) -> None:
callback(self)

def exception(self, timeout=0.0):
return None

@property
def done(self) -> bool:
return True

@property
def success(self) -> bool:
return True


class ReadableSignal(Readable, HasHints, HasParent):
def __init__(self, name: str) -> None:
self._name = name
self._value = 0.0

@property
def name(self) -> str:
return self._name

@property
def hints(self) -> Hints:
return {"fields": [self._name], "dimensions": [], "gridding": "rectilinear"}

@property
def parent(self) -> Any | None:
return None

def read(self):
return {self._name: {"value": self._value, "timestamp": time.time()}}

def describe(self):
return {self._name: {"source": self._name, "dtype": "number", "shape": []}}


class MovableSignal(ReadableSignal, NamedMovable):
def __init__(self, name: str, initial_value: float = 0.0) -> None:
super().__init__(name)
self._value: float = initial_value

def set(self, value: float) -> Status:
self._value = value
return AlwaysSuccessfulStatus()
```

## Defining DOFs and objectives

**DOFs** (degrees of freedom) are the parameters the optimizer can adjust. **Objectives** are what you want to optimize. Here we define two DOFs (`x1` and `x2`) that can range from -5 to 5, and one objective (the Himmelblau function) that we want to minimize:

```{code-cell} ipython3
x1 = MovableSignal("x1", initial_value=0.1)
x2 = MovableSignal("x2", initial_value=0.23)

dofs = [
RangeDOF(actuator=x1, bounds=(-5, 5), parameter_type="float"),
RangeDOF(actuator=x2, bounds=(-5, 5), parameter_type="float"),
]
objectives = [
Objective(name="himmelblau_2d", minimize=True),
]
sensors = []
```

## Writing the evaluation function

The **evaluation function** computes objective values from experimental data. After each run, Blop calls this function with the run's unique ID and the suggestions that were tried. It returns the computed objective values:

```{code-cell} ipython3
class Himmelblau2DEvaluation:
def __init__(self, tiled_client: Container):
self.tiled_client = tiled_client

def __call__(self, uid: str, suggestions: list[dict]) -> list[dict]:
run = self.tiled_client[uid]
outcomes = []
reordered_suggestions = run.start["blop_suggestions"]
x1_data = run["primary/x1"].read()
x2_data = run["primary/x2"].read()

print(
"[Himmelblau] evaluating suggestions: ",
[s["_id"] for s in suggestions],
" reordered to: ",
[s["_id"] for s in reordered_suggestions],
)
for index, suggestion in enumerate(reordered_suggestions):
# Special key to identify a suggestion
suggestion_id = suggestion["_id"]
x1 = x1_data[index]
x2 = x2_data[index]
# Himmelblau function: has four global minima where value = 0
outcomes.append({"himmelblau_2d": (x1**2 + x2 - 11) ** 2 + (x1 + x2**2 - 7) ** 2, "_id": suggestion_id})

return outcomes
```

## Running the optimization

The **Agent** brings everything together. Create one with your DOFs, objectives, and evaluation function, then run the optimization:

```{code-cell} ipython3
agent = Scipy.Agent(
sensors=sensors,
dofs=dofs,
objectives=objectives,
evaluation_function=Himmelblau2DEvaluation(tiled_client=tiled_client),
name="simple-experiment",
description="A simple experiment optimizing the Himmelblau function",
)

RE(agent.optimize(10))
```

## Configuring the optimization

Sometimes a default **Agent** optimization may not do all that you'd like. We expose a configuration object called ScipyCFG and a pure scipy interface so that the classic parameters of scipy minimize can be tweaked (and some multipoint sampling can be used).

```{code-cell} ipython3
config = ScipyCFG(dofs=dofs, objective=objectives[0], optimizer=SCP.DUAL_ANNEALING, threads=4, max_iter=2, eps=0.1)
agent = Scipy(
sensors=sensors,
config=config,
evaluation_function=Himmelblau2DEvaluation(tiled_client=tiled_client),
name="test_experiment",
)
res_uid = RE(agent.optimize(20, n_points=2))
```

## Viewing the results

Scipy is a local optimizer so it doesn't have internal point tracking, but we can to grab it from our datastore.

```{code-cell} ipython3
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

res_client = tiled_client[res_uid[0]]
data = res_client["primary/internal"].read()
cols = ["suggestion_ids", "x1", "x2", "himmelblau_2d"]
vec = data[cols]
res = []
for _, row in vec.iterrows():
vic = [row.suggestion_ids, row.x1, row.x2, row.himmelblau_2d]
vic = [x.strip("[]").split() for x in vic]
for id, x, y, obj in zip(*vic, strict=True):
if id != "''":
res.append([int(id.strip("'")), float(x), float(y), float(obj)])
res = np.array(res)

fig, ax = plt.subplots(figsize=(12, 8))

xb, yb = np.random.uniform(-5, 5, (2, 1000))
ax.tripcolor(xb, yb, (xb**2 + yb - 11) ** 2 + (xb + yb**2 - 7) ** 2, shading="gouraud")

i, x, y, z = res.T
ps = ax.scatter(x, y, c=range(len(x)), cmap="plasma", s=50)
plt.colorbar(ps).set_label("sample index")
plt.title("Visualizing Scipy's traversal of Himmelblau")
```

Seeing the sample history

```{code-cell} ipython3
pd.DataFrame(data=res, columns=cols)
```

```{code-cell} ipython3
print(agent.get_best_points())
```

The Himmelblau function has four global minima (all with value 0). The `summarize` output shows which one(s) the optimizer found.

## What you learned

You now understand the three core concepts of Blop:

- **DOFs**: The parameters the optimizer adjusts (here, `x1` and `x2` with bounds)
- **Objectives**: What you're optimizing (here, minimizing the Himmelblau function)
- **Agent**: Coordinates the optimization loop between Bluesky and the evaluation function

## Next steps

For a more comprehensive tutorial with multiple objectives and diagnostic tools, see [Optimizing KB Mirrors](./xrt-kb-mirrors.md).
18 changes: 18 additions & 0 deletions src/blop/scipy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Scipy Backend for Pertubative gradient and in house global optimizers."""

from .configs import SCP, Objective, RangeDOF, ScipyCFG
from .inverter import InteractiveOptimizer
from .normalizers import SHGO, DualAnnealing, Minimize
from .scipy import Scipy

__all__ = [
"SCP",
"ScipyCFG",
"Scipy",
"DualAnnealing",
"Minimize",
"SHGO",
"InteractiveOptimizer",
"Objective",
"RangeDOF",
]
Loading
Loading