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:

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)
# 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)
0

Creating simulated devices#

Bluesky controls devices through protocols. For this tutorial, we create simple simulated “movable” devices. In real experiments, you would use Ophyd devices or similar—the code below is just boilerplate to simulate hardware:

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:

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. Blop passes it the uid returned by the acquisition plan and the suggestions that were tried. This tutorial uses the default acquisition plan, so the uid is a Bluesky run UID and blop_acquisition_order associates measurements with outcomes.

from collections.abc import Mapping, Sequence

class Himmelblau2DEvaluation:
    def __init__(self, tiled_client: Container):
        self.tiled_client = tiled_client

    def __call__(self, uid: str, suggestions: Sequence[Mapping]) -> Sequence[Mapping]:
        run = self.tiled_client[uid]
        outcomes = []
        acquisition_order = run.start["blop_acquisition_order"]
        x1_data = run["primary/x1"].read()
        x2_data = run["primary/x2"].read()

        for index, suggestion_id in enumerate(acquisition_order):
            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:

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))
╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮
│ Optimizer  InteractiveOptimizer                                                                                 │
│ Actuators  x1, x2                                                                                               │
│ Sensors    N/A                                                                                                  │
│ Iterations 10                                                                                                   │
│ Run UID    45a514b5-2ee4-4a08-b0b2-8fc1ac4d69cb                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Suggestion ID              ┃ x1                         ┃ x2                        ┃ himmelblau_2d             ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
└────────────────────────────┴────────────────────────────┴───────────────────────────┴───────────────────────────┘
┃                            ┃                            ┃                           ┃                           ┃
┃ 0                          ┃                          0 ┃                         0 ┃                       170 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 1                          ┃                      1e-08 ┃                         0 ┃                       170 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 2                          ┃                          0 ┃                     1e-08 ┃                       170 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 3                          ┃                          5 ┃                         5 ┃                       890 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 4                          ┃                          5 ┃                         5 ┃                       890 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 5 / 10 ─────────────────────────────────────────────────
  himmelblau_2d  min: 170  max: 890  mean: 458
  (5 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 5                          ┃                          5 ┃                         5 ┃                       890 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 6                          ┃                    1.51545 ┃                   1.51545 ┃                   61.8302 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 7                          ┃                    1.51545 ┃                   1.51545 ┃                   61.8302 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 8                          ┃                    1.51545 ┃                   1.51545 ┃                   61.8302 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 9                          ┃                    3.25772 ┃                   3.25772 ┃                   55.4432 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 10 / 10 ────────────────────────────────────────────────
  himmelblau_2d  min: 55.4432  max: 890  mean: 342.093
  (10 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────

                          Summary Statistics                           
┏━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓
┃ Name          ┃ Type    ┃     Min ┃ Max ┃    Mean ┃     Std ┃ Count ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩
│ x1            │ param   │       0 │   5 │ 2.28041 │ 2.12132 │    10 │
│ x2            │ param   │       0 │   5 │ 2.28041 │ 2.12132 │    10 │
│ himmelblau_2d │ outcome │ 55.4432 │ 890 │ 342.093 │ 381.119 │    10 │
└───────────────┴─────────┴─────────┴─────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────
('45a514b5-2ee4-4a08-b0b2-8fc1ac4d69cb',
 'b09e7268-0d09-4d9c-8302-b439cdd71555',
 '40a85eaf-cfd4-4a80-afd5-60e508878e30',
 'c367b969-cf27-4583-9ea4-37991b76e1c7',
 '95e76a93-4a9c-4b75-b194-51b495c044d9',
 '3b921ed8-6f16-4539-b57f-495c4f4a8171',
 'bc8174e9-7d21-434d-9901-207d78b3cb83',
 'bbefde3a-41a0-4802-bbea-2c01d272f900',
 'd8695b47-1e21-497f-89e2-a75e2e6337ea',
 '0921c909-346b-4fdb-9e10-254ecf37a5b0',
 'b9d7360d-f295-4940-832f-d759ac02460f')

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).

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))
╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮
│ Optimizer  InteractiveOptimizer                                                                                 │
│ Actuators  x1, x2                                                                                               │
│ Sensors    N/A                                                                                                  │
│ Iterations 20  Points/iter 2                                                                                    │
│ Run UID    46080d2d-2b7e-4adf-990c-db1d047f46f5                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Suggestion ID              ┃ x1                         ┃ x2                        ┃ himmelblau_2d             ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
└────────────────────────────┴────────────────────────────┴───────────────────────────┴───────────────────────────┘
┃                            ┃                            ┃                           ┃                           ┃
┃ 0                          ┃                          0 ┃                         0 ┃                       170 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 1                          ┃                     1.5644 ┃                   1.77338 ┃                   51.2061 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 2                          ┃                   -1.39026 ┃                  0.742705 ┃                   130.741 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 3                          ┃                     1.3806 ┃                  0.742705 ┃                   95.4255 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/scipy/optimize/_dual_annealing.py:434: OptimizeWarning: Unknown solver options: max_iter
  mres = self.minimizer(self.func_wrapper.fun, x, **self.kwargs)
┃                            ┃                            ┃                           ┃                           ┃
┃ 4                          ┃                     1.3806 ┃                  -4.80675 ┃                   498.971 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 5 / 20 ─────────────────────────────────────────────────
  himmelblau_2d  min: 51.2061  max: 498.971  mean: 189.269
  (5 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 5                          ┃                     1.5644 ┃                   1.77338 ┃                   51.2061 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 6                          ┃                     1.6644 ┃                   1.77338 ┃                   46.4845 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 7                          ┃                     1.5644 ┃                   1.87338 ┃                   48.3225 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 8                          ┃                          5 ┃                         5 ┃                       890 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 10                         ┃                          5 ┃                       4.9 ┃                    841.65 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 9 / 20 ─────────────────────────────────────────────────
  himmelblau_2d  min: 46.4845  max: 890  mean: 282.401
  (10 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 9                          ┃                        4.9 ┃                         5 ┃                    848.77 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 11                         ┃                    2.22842 ┃                   2.39701 ┃                   14.1774 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 12                         ┃                    2.22842 ┃                   2.49701 ┃                    14.653 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 13                         ┃                    2.32842 ┃                   2.39701 ┃                   11.2752 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 14                         ┃                    3.17006 ┃                   2.37243 ┃                    5.2558 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 12 / 20 ────────────────────────────────────────────────
  himmelblau_2d  min: 5.2558  max: 890  mean: 247.876
  (15 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 15                         ┃                    3.17006 ┃                   2.47243 ┃                   7.52755 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 16                         ┃                    3.27006 ┃                   2.37243 ┃                   7.87143 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 17                         ┃                    2.80499 ┃                    2.1538 ┃                   1.15391 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 18                         ┃                    2.90499 ┃                    2.1538 ┃                  0.461583 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 19                         ┃                    2.80499 ┃                    2.2538 ┃                   1.55378 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 15 / 20 ────────────────────────────────────────────────
  himmelblau_2d  min: 0.461583  max: 890  mean: 186.835
  (20 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 20                         ┃                    2.91353 ┃                    2.0503 ┃                    0.2263 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 21                         ┃                    2.91353 ┃                    2.1503 ┃                   0.41907 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 22                         ┃                    3.01353 ┃                    2.0503 ┃                 0.0645473 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 23                         ┃                    2.95867 ┃                   1.98483 ┃                 0.0787208 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 24                         ┃                    2.95867 ┃                   2.08483 ┃                  0.119203 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
──────────────────────────────────────────────── Iteration 19 / 20 ────────────────────────────────────────────────
  himmelblau_2d  min: 0.0645473  max: 890  mean: 149.505
  (25 pts sampled)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┃                            ┃                            ┃                           ┃                           ┃
┃ 25                         ┃                    3.05867 ┃                   1.98483 ┃                  0.115791 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩
┃                            ┃                            ┃                           ┃                           ┃
┃ 26                         ┃                    2.95686 ┃                   1.97605 ┃                 0.0980534 ┃
┡────────────────────────────╇────────────────────────────╇───────────────────────────╇───────────────────────────┩

                           Summary Statistics                            
┏━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓
┃ Name          ┃ Type    ┃       Min ┃ Max ┃    Mean ┃     Std ┃ Count ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩
│ x1            │ param   │  -1.39026 │   5 │ 2.53009 │ 1.37303 │    27 │
│ x2            │ param   │  -4.80675 │   5 │ 2.00457 │ 1.76813 │    27 │
│ himmelblau_2d │ outcome │ 0.0645473 │ 890 │ 138.438 │ 278.591 │    27 │
└───────────────┴─────────┴───────────┴─────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────

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.

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

res_client = tiled_client[res_uid[0]]
data = res_client["primary"].read().to_dataframe()

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")

ps = ax.scatter(data.x1, data.x2, marker='+', c=range(len(data.x1)), cmap="plasma", s=50)
plt.colorbar(ps).set_label("sample index")
plt.title("Visualizing Scipy's traversal of Himmelblau")
Text(0.5, 1.0, "Visualizing Scipy's traversal of Himmelblau")
../_images/165fd421e476c3a35eed50def6e58b2051dbe6c951f4d73229920e9f78e7ac80.png

Seeing the sample history

data
x2 suggestion_ids iteration x1 acquisition_uid himmelblau_2d
time
1.790794e+09 0.000000 0 0 0.000000 6d5c96b0-7cbf-448e-bf33-1d443c711d20 170.000000
1.790794e+09 1.773378 1 1 1.564397 474de801-0a7d-4352-a0bf-de155cf7f426 51.206145
1.790794e+09 0.742705 2 2 -1.390258 82936943-0130-4c3e-96b2-1bef03e1635f 130.741321
1.790794e+09 0.742705 3 3 1.380603 607250c6-b80f-4320-bc17-622e379e2671 95.425488
1.790794e+09 -4.806754 4 4 1.380603 75defabf-0f58-405a-8295-099170a568cc 498.971292
1.790794e+09 1.773378 5 5 1.564397 3cedee12-0198-4fcd-a662-03c1a7fd2307 51.206145
1.790794e+09 1.773378 6 6 1.664397 df85290e-a0c3-4e8c-b089-174f66182e43 46.484467
1.790794e+09 1.873378 7 6 1.564397 df85290e-a0c3-4e8c-b089-174f66182e43 48.322527
1.790794e+09 5.000000 8 7 5.000000 1bb0cf01-cd05-4834-ba8a-fa43a2a48b1f 890.000000
1.790794e+09 4.900000 10 8 5.000000 107801d5-98f1-4192-aed2-b56142c97ff4 841.650100
1.790794e+09 5.000000 9 8 4.900000 107801d5-98f1-4192-aed2-b56142c97ff4 848.770100
1.790794e+09 2.397013 11 9 2.228424 7d5cbc71-6445-4203-a2ab-c182b81aa62c 14.177442
1.790794e+09 2.497013 12 10 2.228424 5079be36-51ad-43c9-b762-ae26d85a58fa 14.652987
1.790794e+09 2.397013 13 10 2.328424 5079be36-51ad-43c9-b762-ae26d85a58fa 11.275158
1.790794e+09 2.372432 14 11 3.170058 5f49861d-97a6-403a-b20c-dae69face431 5.255798
1.790794e+09 2.472432 15 12 3.170058 e6ebb77a-a2f9-49e5-b689-5334ab035051 7.527554
1.790794e+09 2.372432 16 12 3.270058 e6ebb77a-a2f9-49e5-b689-5334ab035051 7.871427
1.790794e+09 2.153796 17 13 2.804992 b66ec9c1-7add-436e-b165-baf212c84c5a 1.153910
1.790794e+09 2.153796 18 14 2.904992 3ad395a2-ea88-4064-a542-39f3d3eebc7b 0.461583
1.790794e+09 2.253796 19 14 2.804992 3ad395a2-ea88-4064-a542-39f3d3eebc7b 1.553776
1.790794e+09 2.050303 20 15 2.913532 8bbab173-052b-44d2-b37a-4e8aa2653eb2 0.226300
1.790794e+09 2.150303 21 16 2.913532 e3ada706-655a-4aeb-8a1a-1213cc5f2bb8 0.419070
1.790794e+09 2.050303 22 16 3.013532 e3ada706-655a-4aeb-8a1a-1213cc5f2bb8 0.064547
1.790794e+09 1.984829 23 17 2.958667 f38d53ab-2e34-4647-bf12-9ea9e9e5fbac 0.078721
1.790794e+09 2.084829 24 18 2.958667 fd3e0fe0-4195-44f1-8294-1b668bafee73 0.119203
1.790794e+09 1.984829 25 18 3.058667 fd3e0fe0-4195-44f1-8294-1b668bafee73 0.115791
1.790794e+09 1.976054 26 19 2.956862 5302cfa9-998d-4367-a182-d48327e1e111 0.098053
print(agent.get_best_points())
[25, {'x1': np.float64(2.9568618839460483), 'x2': np.float64(1.9760537191898677)}, {'himmelblau_2d': np.float64(0.0787208067473558)}]

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.