Optimizing KB Mirrors with Bayesian Optimization#

In this tutorial, you will learn how to use Blop to optimize a Kirkpatrick-Baez (KB) mirror system. By the end, you will understand:

  • How degrees of freedom (DOFs) represent the parameters you can adjust in an experiment

  • How objectives define what you’re trying to optimize

  • How to write an evaluation function that extracts results from experimental data

  • How the Agent coordinates the optimization loop

  • How to check optimization health mid-run and continue

We’ll work with a simulated KB mirror beamline, but the concepts apply directly to real experimental setups.

What are KB Mirrors?#

KB mirror systems use two curved mirrors to focus X-ray beams. Each mirror has adjustable curvature—getting both just right produces a tight, intense focal spot. This is a multi-objective optimization problem: we want to maximize beam intensity while minimizing the spot size in both X and Y directions.

The image below shows our simulated setup: a beam from a geometric source propagates through a pair of toroidal mirrors that focus it onto a screen.

xrt_blop_layout_w.jpg

Setting Up the Environment#

Before we can optimize, we need to set up the data infrastructure. Blop uses Bluesky to run experiments and Tiled to store and retrieve data.

import logging
from pathlib import PurePath

import cv2
import numpy as np
import matplotlib.pyplot as plt
from tiled.client.container import Container
from bluesky_tiled_plugins import TiledWriter
from bluesky.run_engine import RunEngine
from tiled.client import from_uri  # type: ignore[import-untyped]
from tiled.server import SimpleTiledServer
from ophyd_async.core import StaticPathProvider, UUIDFilenameProvider

from blop.ax import Agent, RangeDOF, Objective
from blop.protocols import EvaluationFunction

# Import simulation devices (requires: pip install -e sim/)
from blop_sim.backends.xrt import XRTBackend
from blop_sim.devices.xrt import KBMirror
from blop_sim.devices import DetectorDevice

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

# Enable interactive plotting
plt.ion()

DETECTOR_STORAGE = "/tmp/blop/sim"
[WARNING 04-19 07:11:00] ax.storage.sqa_store.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]`.

Next, we create a local Tiled server. The TiledWriter callback will save experimental data to this server, and our evaluation function will read from it.

tiled_server = SimpleTiledServer(readable_storage=[DETECTOR_STORAGE])
tiled_client = from_uri(tiled_server.uri)
tiled_writer = TiledWriter(tiled_client)

RE = RunEngine({})
RE.subscribe(tiled_writer)
Tiled version 0.2.9
0

Defining Degrees of Freedom#

Degrees of freedom (DOFs) are the parameters the optimizer can adjust. In our KB system, we control the curvature radius of each mirror. Let’s define the search space:

# Define search ranges for each mirror's curvature radius
# The optimal values (~38000 and ~21000) are intentionally placed
# away from the center to make the optimization more realistic
VERTICAL_BOUNDS = (25000, 45000)    # Optimal ~38000 is in upper portion
HORIZONTAL_BOUNDS = (15000, 35000)  # Optimal ~21000 is in lower portion

Now we create the simulation backend and individual devices. Each RangeDOF wraps an actuator (something we can move) with bounds that constrain the search space:

# Create XRT simulation backend
backend = XRTBackend()

# Create individual KB mirror devices
kbv = KBMirror(backend, mirror_index=0, initial_radius=38000, name="kbv")
kbh = KBMirror(backend, mirror_index=1, initial_radius=21000, name="kbh")

# Create detector device
det = DetectorDevice(backend, StaticPathProvider(UUIDFilenameProvider(), PurePath(DETECTOR_STORAGE)), name="det")

# Define DOFs using mirror radius signals
dofs = [
    RangeDOF(actuator=kbv.radius, bounds=VERTICAL_BOUNDS, parameter_type="float"),
    RangeDOF(actuator=kbh.radius, bounds=HORIZONTAL_BOUNDS, parameter_type="float"),
]

The actuator is the device that physically changes the parameter. The bounds tell the optimizer what range of values to explore. Think of DOFs as the “knobs” the optimizer can turn.

Defining Objectives#

Objectives specify what you want to optimize. Each objective has a name (matching a value your evaluation function will return) and a direction: minimize=True for things you want smaller, minimize=False for things you want larger.

For our KB mirrors, we have three objectives:

  • Intensity (intensity): We want more signal → minimize=False

  • Spot width (width): We want a tighter spot → minimize=True

  • Spot height (height): We want a tighter spot → minimize=True

objectives = [
    Objective(name="intensity", minimize=False),
    Objective(name="width", minimize=True),
    Objective(name="height", minimize=True),
]

With multiple objectives that can conflict (maximizing intensity might increase spot size), the optimizer finds the Pareto frontier—the set of solutions where you can’t improve one objective without sacrificing another.

Writing an Evaluation Function#

The evaluation function is the bridge between raw experimental data and the optimizer. After each measurement, the optimizer needs to know how well that configuration performed. Your evaluation function:

  1. Receives a run UID and the suggestions that were tested

  2. Reads the beam images from Tiled

  3. Computes statistics (intensity, width, centroid, etc.) from the images

  4. Returns outcome values for each suggestion

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

    def _compute_stats(self, image: np.array) -> tuple[str, str, str]:
        """Compute integrated intensity and beam width/height from a beam image."""
        # Convert to grayscale
        gray = image.squeeze()
        if gray.ndim == 3:
            gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
        
        # Convert data type for numerical stability
        gray = gray.astype(np.float32)

        # Smooth w/ (5, 5) kernel and threshold
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        max_val = np.max(blurred)
        if max_val == 0:
            return 0.0, 0.0, 0.0

        thresh_value = 0.2 * max_val
        _, thresh = cv2.threshold(blurred, thresh_value, 255, cv2.THRESH_TOZERO)

        # Total integrated intensity
        total_intensity = np.sum(thresh)

        # Beam width/height from intensity-weighted second moment (σ)
        total_weight = np.sum(thresh)
        if total_weight <= 0:
            return total_intensity, 0.0, 0.0

        h, w = thresh.shape
        y_coords = np.arange(h, dtype=np.float32)
        x_coords = np.arange(w, dtype=np.float32)

        x_bar = np.sum(x_coords * np.sum(thresh, axis=0)) / total_weight
        y_bar = np.sum(y_coords * np.sum(thresh, axis=1)) / total_weight

        x_var = np.sum((x_coords - x_bar) ** 2 * np.sum(thresh, axis=0)) / total_weight
        y_var = np.sum((y_coords - y_bar) ** 2 * np.sum(thresh, axis=1)) / total_weight

        width = 2 * np.sqrt(x_var)   # ~2σ width
        height = 2 * np.sqrt(y_var)   # ~2σ height

        return total_intensity, width, height

    def __call__(self, uid: str, suggestions: list[dict]) -> list[dict]:
        outcomes = []
        run = self.tiled_client[uid]
        
        # Read beam images from detector
        images = run["primary/det_image"].read()

        # Suggestions are stored in the start document's metadata when
        # using the `blop.plans.default_acquire` plan.
        # You may want to store them differently in your experiment when writing
        # a custom acquisition plan.
        suggestion_ids = [suggestion["_id"] for suggestion in run.metadata["start"]["blop_suggestions"]]

        # Compute statistics from each image
        for idx, sid in enumerate(suggestion_ids):
            image = images[idx]
            intensity, width, height = self._compute_stats(image)
            
            outcome = {
                "_id": sid,
                "intensity": intensity,
                "width": width,
                "height": height,
            }
            outcomes.append(outcome)
        return outcomes

Note how we:

  1. Read the image data from the stored detector data

  2. Use image processing techniques to compute beam metrics from the raw detector images

  3. Link each outcome back to its suggestion via the _id field

Creating and Running the Agent#

The Agent brings everything together. It:

  • Uses DOFs to know what parameters to adjust

  • Uses objectives to know what to optimize

  • Calls the evaluation function to assess each configuration

  • Builds a surrogate model to predict outcomes across the parameter space

  • Suggests the next configurations to try

agent = Agent(
    sensors=[det],
    dofs=dofs,
    objectives=objectives,
    evaluation_function=DetectorEvaluation(tiled_client),
    name="xrt-blop-demo",
    description="A demo of the Blop agent with XRT simulated beamline",
    experiment_type="demo",
)

The sensors list contains any devices that produce data during acquisition. Here, det is our detector device.

Running the Optimization#

Let’s start the optimization. Rather than running all iterations at once, we’ll pause partway through to check the optimization’s health—a practical workflow you’ll use in real experiments.

# Run first 10 iterations
RE(agent.optimize(10))

╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮
 Optimizer  AxOptimizer                                                                                          
 Actuators  kbv-radius, kbh-radius                                                                               
 Sensors    det                                                                                                  
 Iterations 10                                                                                                   
 Run UID    3de7fa77-0bf3-4edf-9a37-46acba2cd653                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ToroidMirror2
center:
[0, 11000, np.float64(176.32899989366115)]
[INFO 04-19 07:11:04] ax.api.client: GenerationStrategy(name='Center+Sobol+MBM:fast', nodes=[CenterGenerationNode(next_node_name='Sobol'), GenerationNode(name='Sobol', generator_specs=[GeneratorSpec(generator_enum=Sobol, generator_key_override=None)], transition_criteria=[MinTrials(transition_to='MBM'), MinTrials(transition_to='MBM')], suggested_experiment_status=ExperimentStatus.INITIALIZATION, pausing_criteria=[MaxTrialsAwaitingData(threshold=5)]), GenerationNode(name='MBM', generator_specs=[GeneratorSpec(generator_enum=BoTorch, generator_key_override=None)], transition_criteria=None, suggested_experiment_status=ExperimentStatus.OPTIMIZATION, pausing_criteria=None)]) chosen based on user input and problem structure.
[INFO 04-19 07:11:04] ax.api.client: Generated new trial 0 with parameters {'kbv-radius': 35000.0, 'kbh-radius': 25000.0} using GenerationNode CenterOfSearchSpace.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:05] ax.api.client: Trial 0 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:05] ax.api.client: Generated new trial 1 with parameters {'kbv-radius': 35528.516769, 'kbh-radius': 29308.345318} using GenerationNode Sobol.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:05] ax.api.client: Trial 1 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:05] ax.api.client: Generated new trial 2 with parameters {'kbv-radius': 27542.769965, 'kbh-radius': 20028.450154} using GenerationNode Sobol.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:06] ax.api.client: Trial 2 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:06] ax.api.client: Generated new trial 3 with parameters {'kbv-radius': 31476.355288, 'kbh-radius': 31937.575676} using GenerationNode Sobol.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:06] ax.api.client: Trial 3 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:06] ax.api.client: Generated new trial 4 with parameters {'kbv-radius': 44114.464223, 'kbh-radius': 18727.302644} using GenerationNode Sobol.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:06] ax.api.client: Trial 4 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:09] ax.api.client: Generated new trial 5 with parameters {'kbv-radius': 37684.518752, 'kbh-radius': 17302.231826} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:09] ax.api.client: Trial 5 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:11] ax.api.client: Generated new trial 6 with parameters {'kbv-radius': 40522.428456, 'kbh-radius': 22657.060851} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:12] ax.api.client: Trial 6 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:14] ax.api.client: Generated new trial 7 with parameters {'kbv-radius': 38615.92055, 'kbh-radius': 21656.046132} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:14] ax.api.client: Trial 7 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:17] ax.api.client: Generated new trial 8 with parameters {'kbv-radius': 37873.970853, 'kbh-radius': 20617.303811} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:17] ax.api.client: Trial 8 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:20] ax.api.client: Generated new trial 9 with parameters {'kbv-radius': 38158.3474, 'kbh-radius': 18640.476644} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:21] ax.api.client: Trial 9 marked COMPLETED.
──────────────────────────────────────────────── Iteration 1 / 10 ─────────────────────────────────────────────────
  Acquire UID  4980e741-7903-4b7b-835a-3fc73db9b7c1
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             0 │      25000       35000  51.7303      16411  149.344 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 51.7303  max: 51.7303  mean: 51.7303
  intensity  min: 16411  max: 16411  mean: 16411
  width  min: 149.344  max: 149.344  mean: 149.344
  (1 pts sampled)
──────────────────────────────────────────────── Iteration 2 / 10 ─────────────────────────────────────────────────
  Acquire UID  d4a8f09b-4a3a-4f75-9da4-0da493635284
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             1 │    29308.3     35528.5  42.1793    13512.1  201.431 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 42.1793  max: 51.7303  mean: 46.9548
  intensity  min: 13512.1  max: 16411  mean: 14961.5
  width  min: 149.344  max: 201.431  mean: 175.387
  (2 pts sampled)
──────────────────────────────────────────────── Iteration 3 / 10 ─────────────────────────────────────────────────
  Acquire UID  58dd6279-4ee5-4cb1-8c13-bd39e04df63e
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             2 │    20028.5     27542.8  157.145    12027.5  20.9125 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 42.1793  max: 157.145  mean: 83.6849
  intensity  min: 12027.5  max: 16411  mean: 13983.5
  width  min: 20.9125  max: 201.431  mean: 123.896
  (3 pts sampled)
──────────────────────────────────────────────── Iteration 4 / 10 ─────────────────────────────────────────────────
  Acquire UID  fd6d7297-d786-460b-9267-d5e3f84b1413
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity   width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━┩
│     0 │             3 │    31937.6     31476.4  116.764    8454.65  208.19 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴────────┘
  height  min: 42.1793  max: 157.145  mean: 91.9548
  intensity  min: 8454.65  max: 16411  mean: 12601.3
  width  min: 20.9125  max: 208.19  mean: 144.969
  (4 pts sampled)
──────────────────────────────────────────────── Iteration 5 / 10 ─────────────────────────────────────────────────
  Acquire UID  965a0963-e0e7-4918-b86d-d3b1e3655769
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity   width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━┩
│     0 │             4 │    18727.3     44114.5  81.0443    16573.8  87.833 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴────────┘
  height  min: 42.1793  max: 157.145  mean: 89.7727
  intensity  min: 8454.65  max: 16573.8  mean: 13395.8
  width  min: 20.9125  max: 208.19  mean: 133.542
  (5 pts sampled)
──────────────────────────────────────────────── Iteration 6 / 10 ─────────────────────────────────────────────────
  Acquire UID  a84cad23-345e-4d04-b1bb-199c20f98c33
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             5 │    17302.2     37684.5  15.5608    18190.7  169.667 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.5608  max: 157.145  mean: 77.404
  intensity  min: 8454.65  max: 18190.7  mean: 14195
  width  min: 20.9125  max: 208.19  mean: 139.563
  (6 pts sampled)
──────────────────────────────────────────────── Iteration 7 / 10 ─────────────────────────────────────────────────
  Acquire UID  eb22ec90-ca09-4e3a-83ba-d66d84aed224
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             6 │    22657.1     40522.4  40.2347    17933.3  75.8053 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.5608  max: 157.145  mean: 72.0941
  intensity  min: 8454.65  max: 18190.7  mean: 14729
  width  min: 20.9125  max: 208.19  mean: 130.455
  (7 pts sampled)
──────────────────────────────────────────────── Iteration 8 / 10 ─────────────────────────────────────────────────
  Acquire UID  d8de51e0-233b-4602-9bfa-fe045ecb5959
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             7 │      21656     38615.9  20.0893    18318.8  36.4633 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.5608  max: 157.145  mean: 65.5935
  intensity  min: 8454.65  max: 18318.8  mean: 15177.7
  width  min: 20.9125  max: 208.19  mean: 118.706
  (8 pts sampled)
──────────────────────────────────────────────── Iteration 9 / 10 ─────────────────────────────────────────────────
  Acquire UID  c5abcefb-1f3b-4e71-8222-37ba97cb5f4c
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │             8 │    20617.3       37874  15.2716    17309.5  12.4174 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.2716  max: 157.145  mean: 60.0022
  intensity  min: 8454.65  max: 18318.8  mean: 15414.6
  width  min: 12.4174  max: 208.19  mean: 106.896
  (9 pts sampled)
──────────────────────────────────────────────── Iteration 10 / 10 ────────────────────────────────────────────────
  Acquire UID  065933bd-4121-449b-a816-c5b116c04c41
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius  height  intensity  width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━┩
│     0 │             9 │    18640.5     38158.3  16.372    18735.6  97.11 
└───────┴───────────────┴────────────┴────────────┴────────┴───────────┴───────┘
  height  min: 15.2716  max: 157.145  mean: 55.6392
  intensity  min: 8454.65  max: 18735.6  mean: 15746.7
  width  min: 12.4174  max: 208.19  mean: 105.917
  (10 pts sampled)

                           Summary Statistics                           
┏━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓
 Name        Type         Min      Max     Mean      Std  Count 
┡━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩
 kbh-radius │ param   │ 17302.2  31937.6  22587.5  4808.91 │    10 │
 kbv-radius │ param   │ 27542.8  44114.5  36651.7  4632.14 │    10 │
 height     │ outcome │ 15.2716  157.145  55.6392  48.4888 │    10 │
 intensity  │ outcome │ 8454.65  18735.6  15746.7  3364.39 │    10 │
 width      │ outcome │ 12.4174   208.19  105.917   72.752 │    10 │
└────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────

('3de7fa77-0bf3-4edf-9a37-46acba2cd653',
 '4980e741-7903-4b7b-835a-3fc73db9b7c1',
 'd4a8f09b-4a3a-4f75-9da4-0da493635284',
 '58dd6279-4ee5-4cb1-8c13-bd39e04df63e',
 'fd6d7297-d786-460b-9267-d5e3f84b1413',
 '965a0963-e0e7-4918-b86d-d3b1e3655769',
 'a84cad23-345e-4d04-b1bb-199c20f98c33',
 'eb22ec90-ca09-4e3a-83ba-d66d84aed224',
 'd8de51e0-233b-4602-9bfa-fe045ecb5959',
 'c5abcefb-1f3b-4e71-8222-37ba97cb5f4c',
 '065933bd-4121-449b-a816-c5b116c04c41')

Checking Optimization Health#

After running some iterations, it’s good practice to check how the optimization is progressing. Ax provides built-in health checks and diagnostics through compute_analyses():

_ = agent.ax_client.compute_analyses()
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:23] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 18088.035733558558), ObjectiveThreshold(width <= 185.40684198221163), ObjectiveThreshold(height <= 16.97024999382038)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:27] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 18088.035733558558), ObjectiveThreshold(width <= 185.40684198221163), ObjectiveThreshold(height <= 16.97024999382038)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:27] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 18088.035733558558), ObjectiveThreshold(width <= 185.40684198221163), ObjectiveThreshold(height <= 16.97024999382038)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:76, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     75         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 76     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     77 else:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:96, in _run_input_lines(cmd, input_lines, kwargs)
     95 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 96     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
     98     stdin_write = popen.stdin.write

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1039, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1036             self.stderr = io.TextIOWrapper(self.stderr,
   1037                     encoding=encoding, errors=errors)
-> 1039     self._execute_child(args, executable, preexec_fn, close_fds,
   1040                         pass_fds, cwd, env,
   1041                         startupinfo, creationflags, shell,
   1042                         p2cread, p2cwrite,
   1043                         c2pread, c2pwrite,
   1044                         errread, errwrite,
   1045                         restore_signals,
   1046                         gid, gids, uid, umask,
   1047                         start_new_session, process_group)
   1048 except:
   1049     # Cleanup if the child failed starting.

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1991, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1990 if err_filename is not None:
-> 1991     raise child_exception_type(errno_num, err_msg, err_filename)
   1992 else:

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:195, in AnalysisCardBase._ipython_display_(self)
    191         display(card._body_papermill())
    193     return
--> 195 display(HTML(self._repr_html_()))

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:224, in AnalysisCardBase._repr_html_(self)
    220 # require.js is not compatible with ES6 import used by plotly.js so we must
    221 # null out `define` here. This does not affect rendering.
    222 plotlyjs_script = f"<script>define = null;{get_plotlyjs()}</script>"
--> 224 return plotlyjs_script + self._to_html(depth=0)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:323, in AnalysisCardGroup._body_html(self, depth)
    320         res.append(leaves_grid)
    321         leaf_cards = []
--> 323     res.append(child._to_html(depth=depth + 1))
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:329, in AnalysisCardGroup._body_html(self, depth)
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:
    327     leaves_grid = html_grid_template.format(
    328         card_divs="".join(
--> 329             [card._to_html(depth=depth + 1) for card in leaf_cards]
    330         )
    331     )
    332     res.append(leaves_grid)
    334 return "\n".join(res)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:230, in AnalysisCardBase._to_html(self, depth)
    226 def _to_html(self, depth: int) -> str:
    227     return html_card_template.format(
    228         title_str=self.title,
    229         subtitle_str=self.subtitle,
--> 230         body_html=self._body_html(depth=depth),
    231     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/analysis/graphviz/graphviz_analysis.py:21, in GraphvizAnalysisCard._body_html(self, depth)
     17 def _body_html(self, depth: int) -> str:
     18     """
     19     Return the a HTML div with the Graphviz figure as an SVG.
     20     """
---> 21     svg = self.get_digraph().pipe(format="svg")
     23     return f"<div>{svg}</div>"

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    177     wanted = ', '.join(f'{name}={value!r}'
    178                        for name, value in deprecated.items())
    179     warnings.warn(f'The signature of {func_name} will be reduced'
    180                   f' to {supported_number} positional arg{s_}{qualification}'
    181                   f' {list(supported)}: pass {wanted} as keyword arg{s_}',
    182                   stacklevel=stacklevel,
    183                   category=category)
--> 185 return func(*args, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:161, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    159     else:
    160         return raw.decode(encoding)
--> 161 return self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/piping.py:161, in pipe_lines(engine, format, input_lines, input_encoding, renderer, formatter, neato_no_op, quiet)
    155 cmd = dot_command.command(engine, format,
    156                           renderer=renderer,
    157                           formatter=formatter,
    158                           neato_no_op=neato_no_op)
    159 kwargs = {'input_lines': (line.encode(input_encoding) for line in input_lines)}
--> 161 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    162 return proc.stdout

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79 except OSError as e:
     80     if e.errno == errno.ENOENT:
---> 81         raise ExecutableNotFound(cmd) from e
     82     raise
     84 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:76, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     75         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 76     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     77 else:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:96, in _run_input_lines(cmd, input_lines, kwargs)
     95 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 96     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
     98     stdin_write = popen.stdin.write

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1039, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1036             self.stderr = io.TextIOWrapper(self.stderr,
   1037                     encoding=encoding, errors=errors)
-> 1039     self._execute_child(args, executable, preexec_fn, close_fds,
   1040                         pass_fds, cwd, env,
   1041                         startupinfo, creationflags, shell,
   1042                         p2cread, p2cwrite,
   1043                         c2pread, c2pwrite,
   1044                         errread, errwrite,
   1045                         restore_signals,
   1046                         gid, gids, uid, umask,
   1047                         start_new_session, process_group)
   1048 except:
   1049     # Cleanup if the child failed starting.

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1991, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1990 if err_filename is not None:
-> 1991     raise child_exception_type(errno_num, err_msg, err_filename)
   1992 else:

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:224, in AnalysisCardBase._repr_html_(self)
    220 # require.js is not compatible with ES6 import used by plotly.js so we must
    221 # null out `define` here. This does not affect rendering.
    222 plotlyjs_script = f"<script>define = null;{get_plotlyjs()}</script>"
--> 224 return plotlyjs_script + self._to_html(depth=0)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:323, in AnalysisCardGroup._body_html(self, depth)
    320         res.append(leaves_grid)
    321         leaf_cards = []
--> 323     res.append(child._to_html(depth=depth + 1))
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:329, in AnalysisCardGroup._body_html(self, depth)
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:
    327     leaves_grid = html_grid_template.format(
    328         card_divs="".join(
--> 329             [card._to_html(depth=depth + 1) for card in leaf_cards]
    330         )
    331     )
    332     res.append(leaves_grid)
    334 return "\n".join(res)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:230, in AnalysisCardBase._to_html(self, depth)
    226 def _to_html(self, depth: int) -> str:
    227     return html_card_template.format(
    228         title_str=self.title,
    229         subtitle_str=self.subtitle,
--> 230         body_html=self._body_html(depth=depth),
    231     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/analysis/graphviz/graphviz_analysis.py:21, in GraphvizAnalysisCard._body_html(self, depth)
     17 def _body_html(self, depth: int) -> str:
     18     """
     19     Return the a HTML div with the Graphviz figure as an SVG.
     20     """
---> 21     svg = self.get_digraph().pipe(format="svg")
     23     return f"<div>{svg}</div>"

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    177     wanted = ', '.join(f'{name}={value!r}'
    178                        for name, value in deprecated.items())
    179     warnings.warn(f'The signature of {func_name} will be reduced'
    180                   f' to {supported_number} positional arg{s_}{qualification}'
    181                   f' {list(supported)}: pass {wanted} as keyword arg{s_}',
    182                   stacklevel=stacklevel,
    183                   category=category)
--> 185 return func(*args, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:161, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    159     else:
    160         return raw.decode(encoding)
--> 161 return self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/piping.py:161, in pipe_lines(engine, format, input_lines, input_encoding, renderer, formatter, neato_no_op, quiet)
    155 cmd = dot_command.command(engine, format,
    156                           renderer=renderer,
    157                           formatter=formatter,
    158                           neato_no_op=neato_no_op)
    159 kwargs = {'input_lines': (line.encode(input_encoding) for line in input_lines)}
--> 161 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    162 return proc.stdout

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79 except OSError as e:
     80     if e.errno == errno.ENOENT:
---> 81         raise ExecutableNotFound(cmd) from e
     82     raise
     84 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<ax.core.analysis_card.AnalysisCardGroup at 0x7fd7502af250>

This runs all applicable analyses for the current experiment state, including health checks that flag potential issues like model fit problems or exploration gaps. Review these before continuing.

Continuing the Optimization#

The optimization state is preserved, so we can simply run more iterations:

# Run remaining 20 iterations
RE(agent.optimize(20))

╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮
 Optimizer  AxOptimizer                                                                                          
 Actuators  kbv-radius, kbh-radius                                                                               
 Sensors    det                                                                                                  
 Iterations 20 more (10 completed, 30 total)                                                                     
 Run UID    78930a79-127d-4e22-9275-76c17274483a                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:29] ax.api.client: Generated new trial 10 with parameters {'kbv-radius': 37928.750018, 'kbh-radius': 19461.746838} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:29] ax.api.client: Trial 10 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:33] ax.api.client: Generated new trial 11 with parameters {'kbv-radius': 37982.653316, 'kbh-radius': 18122.120993} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:34] ax.api.client: Trial 11 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:38] ax.api.client: Generated new trial 12 with parameters {'kbv-radius': 37907.582695, 'kbh-radius': 18930.191017} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:38] ax.api.client: Trial 12 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:42] ax.api.client: Generated new trial 13 with parameters {'kbv-radius': 37998.949688, 'kbh-radius': 19947.026184} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:42] ax.api.client: Trial 13 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:48] ax.api.client: Generated new trial 14 with parameters {'kbv-radius': 38034.41096, 'kbh-radius': 15000.0} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:49] ax.api.client: Trial 14 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:11:54] ax.api.client: Generated new trial 15 with parameters {'kbv-radius': 37997.690204, 'kbh-radius': 16954.290265} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:11:54] ax.api.client: Trial 15 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:00] ax.api.client: Generated new trial 16 with parameters {'kbv-radius': 38002.983364, 'kbh-radius': 17622.956655} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:00] ax.api.client: Trial 16 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:07] ax.api.client: Generated new trial 17 with parameters {'kbv-radius': 38040.269936, 'kbh-radius': 16285.980029} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:08] ax.api.client: Trial 17 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:15] ax.api.client: Generated new trial 18 with parameters {'kbv-radius': 38166.783964, 'kbh-radius': 19134.983112} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:15] ax.api.client: Trial 18 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:22] ax.api.client: Generated new trial 19 with parameters {'kbv-radius': 37508.397328, 'kbh-radius': 18997.290584} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:22] ax.api.client: Trial 19 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:29] ax.api.client: Generated new trial 20 with parameters {'kbv-radius': 38253.218102, 'kbh-radius': 17238.104501} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:29] ax.api.client: Trial 20 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:37] ax.api.client: Generated new trial 21 with parameters {'kbv-radius': 38120.454698, 'kbh-radius': 19664.231765} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:37] ax.api.client: Trial 21 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/linear_operator/utils/cholesky.py:41: NumericalWarning: A not p.d., added jitter of 1.0e-08 to the diagonal
  warnings.warn(
[INFO 04-19 07:12:46] ax.api.client: Generated new trial 22 with parameters {'kbv-radius': 38138.470862, 'kbh-radius': 18344.384498} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:46] ax.api.client: Trial 22 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:12:55] ax.api.client: Generated new trial 23 with parameters {'kbv-radius': 38041.17327, 'kbh-radius': 20242.172021} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:12:55] ax.api.client: Trial 23 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/linear_operator/utils/cholesky.py:41: NumericalWarning: A not p.d., added jitter of 1.0e-08 to the diagonal
  warnings.warn(
[INFO 04-19 07:13:04] ax.api.client: Generated new trial 24 with parameters {'kbv-radius': 38110.599072, 'kbh-radius': 16653.433345} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:05] ax.api.client: Trial 24 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:13:13] ax.api.client: Generated new trial 25 with parameters {'kbv-radius': 37782.674075, 'kbh-radius': 22253.682151} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:13] ax.api.client: Trial 25 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:13:22] ax.api.client: Generated new trial 26 with parameters {'kbv-radius': 32836.751829, 'kbh-radius': 21683.414255} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:23] ax.api.client: Trial 26 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/linear_operator/utils/cholesky.py:41: NumericalWarning: A not p.d., added jitter of 1.0e-08 to the diagonal
  warnings.warn(
[INFO 04-19 07:13:33] ax.api.client: Generated new trial 27 with parameters {'kbv-radius': 38104.124521, 'kbh-radius': 15796.744414} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:33] ax.api.client: Trial 27 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/linear_operator/utils/cholesky.py:41: NumericalWarning: A not p.d., added jitter of 1.0e-08 to the diagonal
  warnings.warn(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/linear_operator/utils/cholesky.py:41: NumericalWarning: A not p.d., added jitter of 1.0e-08 to the diagonal
  warnings.warn(
[INFO 04-19 07:13:45] ax.api.client: Generated new trial 28 with parameters {'kbv-radius': 38096.834564, 'kbh-radius': 17896.330907} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:45] ax.api.client: Trial 28 marked COMPLETED.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:13:55] ax.api.client: Generated new trial 29 with parameters {'kbv-radius': 37374.798066, 'kbh-radius': 21247.555059} using GenerationNode MBM.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
[INFO 04-19 07:13:55] ax.api.client: Trial 29 marked COMPLETED.
──────────────────────────────────────────────── Iteration 11 / 30 ────────────────────────────────────────────────
  Acquire UID  77a32995-0a4b-43ea-8541-d08a9ac1ada9
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            10 │    19461.7     37928.8  16.9587    18654.2  51.9701 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.2716  max: 157.145  mean: 52.1228
  intensity  min: 8454.65  max: 18735.6  mean: 16011
  width  min: 12.4174  max: 208.19  mean: 101.013
  (11 pts sampled)
──────────────────────────────────────────────── Iteration 12 / 30 ────────────────────────────────────────────────
  Acquire UID  f1b567d0-36a8-4a62-adfe-37d084c791f6
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            11 │    18122.1     37982.7  15.5554    18483.5  123.678 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.2716  max: 157.145  mean: 49.0755
  intensity  min: 8454.65  max: 18735.6  mean: 16217.1
  width  min: 12.4174  max: 208.19  mean: 102.902
  (12 pts sampled)
──────────────────────────────────────────────── Iteration 13 / 30 ────────────────────────────────────────────────
  Acquire UID  ab1bec04-3a7c-4c89-930b-e0d312533743
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            12 │    18930.2     37907.6  16.8822    19236.4  81.9475 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.2716  max: 157.145  mean: 46.5991
  intensity  min: 8454.65  max: 19236.4  mean: 16449.3
  width  min: 12.4174  max: 208.19  mean: 101.29
  (13 pts sampled)
──────────────────────────────────────────────── Iteration 14 / 30 ────────────────────────────────────────────────
  Acquire UID  5aa6f696-45ab-4314-a1a9-cda38234b946
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            13 │      19947     37998.9  16.2446    17710.8  27.5282 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 15.2716  max: 157.145  mean: 44.4309
  intensity  min: 8454.65  max: 19236.4  mean: 16539.4
  width  min: 12.4174  max: 208.19  mean: 96.0212
  (14 pts sampled)
──────────────────────────────────────────────── Iteration 15 / 30 ────────────────────────────────────────────────
  Acquire UID  dc7b63bc-1807-4891-b4ab-14e0c2d86deb
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            14 │      15000     38034.4  11.8107    13118.7  217.094 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 42.2562
  intensity  min: 8454.65  max: 19236.4  mean: 16311.4
  width  min: 12.4174  max: 217.094  mean: 104.093
  (15 pts sampled)
──────────────────────────────────────────────── Iteration 16 / 30 ────────────────────────────────────────────────
  Acquire UID  4b59b73d-172e-4ca7-873b-7ee051b68eae
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            15 │    16954.3     37997.7  14.7244    18221.2  187.086 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 40.5355
  intensity  min: 8454.65  max: 19236.4  mean: 16430.7
  width  min: 12.4174  max: 217.094  mean: 109.28
  (16 pts sampled)
──────────────────────────────────────────────── Iteration 17 / 30 ────────────────────────────────────────────────
  Acquire UID  6fa0d390-35ae-4ff1-9669-a88948b6cf95
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity   width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━┩
│     0 │            16 │      17623       38003  15.6697    18514.6  153.63 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴────────┘
  height  min: 11.8107  max: 157.145  mean: 39.0728
  intensity  min: 8454.65  max: 19236.4  mean: 16553.3
  width  min: 12.4174  max: 217.094  mean: 111.889
  (17 pts sampled)
──────────────────────────────────────────────── Iteration 18 / 30 ────────────────────────────────────────────────
  Acquire UID  17c72a60-89eb-4659-96f3-aef74642159f
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius  height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            17 │      16286     38040.3  13.078    16294.2  200.373 
└───────┴───────────────┴────────────┴────────────┴────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 37.6286
  intensity  min: 8454.65  max: 19236.4  mean: 16538.9
  width  min: 12.4174  max: 217.094  mean: 116.804
  (18 pts sampled)
──────────────────────────────────────────────── Iteration 19 / 30 ────────────────────────────────────────────────
  Acquire UID  811ebdf0-d87c-4211-99ee-a64c94b2e40e
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            18 │      19135     38166.8  17.2345    18996.1  69.7656 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 36.5553
  intensity  min: 8454.65  max: 19236.4  mean: 16668.3
  width  min: 12.4174  max: 217.094  mean: 114.329
  (19 pts sampled)
──────────────────────────────────────────────── Iteration 20 / 30 ────────────────────────────────────────────────
  Acquire UID  a714211c-4201-4c2a-be7d-74159e4dfc7c
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            19 │    18997.3     37508.4  18.5451    19225.9  80.0315 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 35.6547
  intensity  min: 8454.65  max: 19236.4  mean: 16796.1
  width  min: 12.4174  max: 217.094  mean: 112.614
  (20 pts sampled)
──────────────────────────────────────────────── Iteration 21 / 30 ────────────────────────────────────────────────
  Acquire UID  3d65e3ff-5ad6-4218-ac6a-e77c44d1908a
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            20 │    17238.1     38253.2  14.9986    17926.3  170.405 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 34.6711
  intensity  min: 8454.65  max: 19236.4  mean: 16850
  width  min: 12.4174  max: 217.094  mean: 115.366
  (21 pts sampled)
──────────────────────────────────────────────── Iteration 22 / 30 ────────────────────────────────────────────────
  Acquire UID  6e653115-21ce-44f0-b835-31d7135ce071
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            21 │    19664.2     38120.5  17.5814    18861.4  43.2586 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 33.8943
  intensity  min: 8454.65  max: 19236.4  mean: 16941.4
  width  min: 12.4174  max: 217.094  mean: 112.088
  (22 pts sampled)
──────────────────────────────────────────────── Iteration 23 / 30 ────────────────────────────────────────────────
  Acquire UID  a1ac4761-647d-428e-8f4a-1d78c7526e28
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            22 │    18344.4     38138.5  16.5994    19242.5  115.118 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 33.1424
  intensity  min: 8454.65  max: 19242.5  mean: 17041.4
  width  min: 12.4174  max: 217.094  mean: 112.22
  (23 pts sampled)
──────────────────────────────────────────────── Iteration 24 / 30 ────────────────────────────────────────────────
  Acquire UID  a369d3c8-de9f-4985-b52c-2f48538145cf
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            23 │    20242.2     38041.2  15.6463    17120.7  17.4396 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 32.4134
  intensity  min: 8454.65  max: 19242.5  mean: 17044.7
  width  min: 12.4174  max: 217.094  mean: 108.271
  (24 pts sampled)
──────────────────────────────────────────────── Iteration 25 / 30 ────────────────────────────────────────────────
  Acquire UID  53a7d6bb-636d-437a-87c5-fe008c33bac0
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            24 │    16653.4     38110.6  14.1767    17394.6  194.491 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 31.6839
  intensity  min: 8454.65  max: 19242.5  mean: 17058.7
  width  min: 12.4174  max: 217.094  mean: 111.72
  (25 pts sampled)
──────────────────────────────────────────────── Iteration 26 / 30 ────────────────────────────────────────────────
  Acquire UID  0f217284-21bf-4d5c-a36c-d6ac3aa0c398
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            25 │    22253.7     37782.7  18.4885    18820.2  61.6321 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 31.1764
  intensity  min: 8454.65  max: 19242.5  mean: 17126.5
  width  min: 12.4174  max: 217.094  mean: 109.793
  (26 pts sampled)
──────────────────────────────────────────────── Iteration 27 / 30 ────────────────────────────────────────────────
  Acquire UID  e2d76e57-5236-445e-89be-d89d19aba4d3
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            26 │    21683.4     32836.8  90.7809    16274.7  33.3051 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 33.384
  intensity  min: 8454.65  max: 19242.5  mean: 17094.9
  width  min: 12.4174  max: 217.094  mean: 106.96
  (27 pts sampled)
──────────────────────────────────────────────── Iteration 28 / 30 ────────────────────────────────────────────────
  Acquire UID  8d342f26-252b-419d-9f53-73c348f75300
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            27 │    15796.7     38104.1  12.9125    15169.3  210.733 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 32.6528
  intensity  min: 8454.65  max: 19242.5  mean: 17026.2
  width  min: 12.4174  max: 217.094  mean: 110.666
  (28 pts sampled)
──────────────────────────────────────────────── Iteration 29 / 30 ────────────────────────────────────────────────
  Acquire UID  fcf83d13-2997-45e7-bf18-3aeb120c8aef
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius   height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            28 │    17896.3     38096.8  15.5149    18686.2  140.013 
└───────┴───────────────┴────────────┴────────────┴─────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 32.0619
  intensity  min: 8454.65  max: 19242.5  mean: 17083.4
  width  min: 12.4174  max: 217.094  mean: 111.678
  (29 pts sampled)
──────────────────────────────────────────────── Iteration 30 / 30 ────────────────────────────────────────────────
  Acquire UID  c5e6fc54-b308-432a-aad3-e0ce99c857e0
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┓
 Event  Suggestion ID  kbh-radius  kbv-radius  height  intensity    width 
┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━┩
│     0 │            29 │    21247.6     37374.8  18.394    17161.5  19.9828 
└───────┴───────────────┴────────────┴────────────┴────────┴───────────┴─────────┘
  height  min: 11.8107  max: 157.145  mean: 31.6063
  intensity  min: 8454.65  max: 19242.5  mean: 17086
  width  min: 12.4174  max: 217.094  mean: 108.622
  (30 pts sampled)

                           Summary Statistics                           
┏━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓
 Name        Type         Min      Max     Mean      Std  Count 
┡━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩
 kbh-radius │ param   │   15000  31937.6  19911.7  3660.54 │    30 │
 kbv-radius │ param   │ 27542.8  44114.5  37364.8  2795.94 │    30 │
 height     │ outcome │ 11.8107  157.145  31.6063  34.8521 │    30 │
 intensity  │ outcome │ 8454.65  19242.5    17086  2461.22 │    30 │
 width      │ outcome │ 12.4174  217.094  108.622  69.5046 │    30 │
└────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────

('78930a79-127d-4e22-9275-76c17274483a',
 '77a32995-0a4b-43ea-8541-d08a9ac1ada9',
 'f1b567d0-36a8-4a62-adfe-37d084c791f6',
 'ab1bec04-3a7c-4c89-930b-e0d312533743',
 '5aa6f696-45ab-4314-a1a9-cda38234b946',
 'dc7b63bc-1807-4891-b4ab-14e0c2d86deb',
 '4b59b73d-172e-4ca7-873b-7ee051b68eae',
 '6fa0d390-35ae-4ff1-9669-a88948b6cf95',
 '17c72a60-89eb-4659-96f3-aef74642159f',
 '811ebdf0-d87c-4211-99ee-a64c94b2e40e',
 'a714211c-4201-4c2a-be7d-74159e4dfc7c',
 '3d65e3ff-5ad6-4218-ac6a-e77c44d1908a',
 '6e653115-21ce-44f0-b835-31d7135ce071',
 'a1ac4761-647d-428e-8f4a-1d78c7526e28',
 'a369d3c8-de9f-4985-b52c-2f48538145cf',
 '53a7d6bb-636d-437a-87c5-fe008c33bac0',
 '0f217284-21bf-4d5c-a36c-d6ac3aa0c398',
 'e2d76e57-5236-445e-89be-d89d19aba4d3',
 '8d342f26-252b-419d-9f53-73c348f75300',
 'fcf83d13-2997-45e7-bf18-3aeb120c8aef',
 'c5e6fc54-b308-432a-aad3-e0ce99c857e0')

Understanding the Results#

After optimization, we can examine what the agent learned. Let’s run the full suite of analyses again to see how things have improved:

_ = agent.ax_client.compute_analyses()
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:13:58] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 12592.094650202525), ObjectiveThreshold(width <= 237.51604559649311), ObjectiveThreshold(height <= 20.831940017100695)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/data.py:365: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  self.full_df.groupby(self.DEDUPLICATE_BY_COLUMNS).apply(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:14:02] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 12592.094650202525), ObjectiveThreshold(width <= 237.51604559649311), ObjectiveThreshold(height <= 20.831940017100695)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:14:03] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 12592.094650202525), ObjectiveThreshold(width <= 237.51604559649311), ObjectiveThreshold(height <= 20.831940017100695)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:76, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     75         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 76     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     77 else:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:96, in _run_input_lines(cmd, input_lines, kwargs)
     95 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 96     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
     98     stdin_write = popen.stdin.write

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1039, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1036             self.stderr = io.TextIOWrapper(self.stderr,
   1037                     encoding=encoding, errors=errors)
-> 1039     self._execute_child(args, executable, preexec_fn, close_fds,
   1040                         pass_fds, cwd, env,
   1041                         startupinfo, creationflags, shell,
   1042                         p2cread, p2cwrite,
   1043                         c2pread, c2pwrite,
   1044                         errread, errwrite,
   1045                         restore_signals,
   1046                         gid, gids, uid, umask,
   1047                         start_new_session, process_group)
   1048 except:
   1049     # Cleanup if the child failed starting.

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1991, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1990 if err_filename is not None:
-> 1991     raise child_exception_type(errno_num, err_msg, err_filename)
   1992 else:

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:195, in AnalysisCardBase._ipython_display_(self)
    191         display(card._body_papermill())
    193     return
--> 195 display(HTML(self._repr_html_()))

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:224, in AnalysisCardBase._repr_html_(self)
    220 # require.js is not compatible with ES6 import used by plotly.js so we must
    221 # null out `define` here. This does not affect rendering.
    222 plotlyjs_script = f"<script>define = null;{get_plotlyjs()}</script>"
--> 224 return plotlyjs_script + self._to_html(depth=0)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:323, in AnalysisCardGroup._body_html(self, depth)
    320         res.append(leaves_grid)
    321         leaf_cards = []
--> 323     res.append(child._to_html(depth=depth + 1))
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:329, in AnalysisCardGroup._body_html(self, depth)
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:
    327     leaves_grid = html_grid_template.format(
    328         card_divs="".join(
--> 329             [card._to_html(depth=depth + 1) for card in leaf_cards]
    330         )
    331     )
    332     res.append(leaves_grid)
    334 return "\n".join(res)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:230, in AnalysisCardBase._to_html(self, depth)
    226 def _to_html(self, depth: int) -> str:
    227     return html_card_template.format(
    228         title_str=self.title,
    229         subtitle_str=self.subtitle,
--> 230         body_html=self._body_html(depth=depth),
    231     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/analysis/graphviz/graphviz_analysis.py:21, in GraphvizAnalysisCard._body_html(self, depth)
     17 def _body_html(self, depth: int) -> str:
     18     """
     19     Return the a HTML div with the Graphviz figure as an SVG.
     20     """
---> 21     svg = self.get_digraph().pipe(format="svg")
     23     return f"<div>{svg}</div>"

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    177     wanted = ', '.join(f'{name}={value!r}'
    178                        for name, value in deprecated.items())
    179     warnings.warn(f'The signature of {func_name} will be reduced'
    180                   f' to {supported_number} positional arg{s_}{qualification}'
    181                   f' {list(supported)}: pass {wanted} as keyword arg{s_}',
    182                   stacklevel=stacklevel,
    183                   category=category)
--> 185 return func(*args, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:161, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    159     else:
    160         return raw.decode(encoding)
--> 161 return self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/piping.py:161, in pipe_lines(engine, format, input_lines, input_encoding, renderer, formatter, neato_no_op, quiet)
    155 cmd = dot_command.command(engine, format,
    156                           renderer=renderer,
    157                           formatter=formatter,
    158                           neato_no_op=neato_no_op)
    159 kwargs = {'input_lines': (line.encode(input_encoding) for line in input_lines)}
--> 161 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    162 return proc.stdout

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79 except OSError as e:
     80     if e.errno == errno.ENOENT:
---> 81         raise ExecutableNotFound(cmd) from e
     82     raise
     84 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:76, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     75         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 76     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     77 else:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:96, in _run_input_lines(cmd, input_lines, kwargs)
     95 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 96     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
     98     stdin_write = popen.stdin.write

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1039, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1036             self.stderr = io.TextIOWrapper(self.stderr,
   1037                     encoding=encoding, errors=errors)
-> 1039     self._execute_child(args, executable, preexec_fn, close_fds,
   1040                         pass_fds, cwd, env,
   1041                         startupinfo, creationflags, shell,
   1042                         p2cread, p2cwrite,
   1043                         c2pread, c2pwrite,
   1044                         errread, errwrite,
   1045                         restore_signals,
   1046                         gid, gids, uid, umask,
   1047                         start_new_session, process_group)
   1048 except:
   1049     # Cleanup if the child failed starting.

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/subprocess.py:1991, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1990 if err_filename is not None:
-> 1991     raise child_exception_type(errno_num, err_msg, err_filename)
   1992 else:

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:224, in AnalysisCardBase._repr_html_(self)
    220 # require.js is not compatible with ES6 import used by plotly.js so we must
    221 # null out `define` here. This does not affect rendering.
    222 plotlyjs_script = f"<script>define = null;{get_plotlyjs()}</script>"
--> 224 return plotlyjs_script + self._to_html(depth=0)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:323, in AnalysisCardGroup._body_html(self, depth)
    320         res.append(leaves_grid)
    321         leaf_cards = []
--> 323     res.append(child._to_html(depth=depth + 1))
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:340, in AnalysisCardGroup._to_html(self, depth)
    336 def _to_html(self, depth: int) -> str:
    337     return html_group_card_template.format(
    338         title_str=self.title,
    339         subtitle_str=self.subtitle,
--> 340         body_html=self._body_html(depth=depth),
    341     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:329, in AnalysisCardGroup._body_html(self, depth)
    325 # Collect the accumulated leaves a final time to append to the result.
    326 if len(leaf_cards) > 0:
    327     leaves_grid = html_grid_template.format(
    328         card_divs="".join(
--> 329             [card._to_html(depth=depth + 1) for card in leaf_cards]
    330         )
    331     )
    332     res.append(leaves_grid)
    334 return "\n".join(res)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/core/analysis_card.py:230, in AnalysisCardBase._to_html(self, depth)
    226 def _to_html(self, depth: int) -> str:
    227     return html_card_template.format(
    228         title_str=self.title,
    229         subtitle_str=self.subtitle,
--> 230         body_html=self._body_html(depth=depth),
    231     )

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/analysis/graphviz/graphviz_analysis.py:21, in GraphvizAnalysisCard._body_html(self, depth)
     17 def _body_html(self, depth: int) -> str:
     18     """
     19     Return the a HTML div with the Graphviz figure as an SVG.
     20     """
---> 21     svg = self.get_digraph().pipe(format="svg")
     23     return f"<div>{svg}</div>"

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    177     wanted = ', '.join(f'{name}={value!r}'
    178                        for name, value in deprecated.items())
    179     warnings.warn(f'The signature of {func_name} will be reduced'
    180                   f' to {supported_number} positional arg{s_}{qualification}'
    181                   f' {list(supported)}: pass {wanted} as keyword arg{s_}',
    182                   stacklevel=stacklevel,
    183                   category=category)
--> 185 return func(*args, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/piping.py:161, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    159     else:
    160         return raw.decode(encoding)
--> 161 return self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/piping.py:161, in pipe_lines(engine, format, input_lines, input_encoding, renderer, formatter, neato_no_op, quiet)
    155 cmd = dot_command.command(engine, format,
    156                           renderer=renderer,
    157                           formatter=formatter,
    158                           neato_no_op=neato_no_op)
    159 kwargs = {'input_lines': (line.encode(input_encoding) for line in input_lines)}
--> 161 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    162 return proc.stdout

File ~/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79 except OSError as e:
     80     if e.errno == errno.ENOENT:
---> 81         raise ExecutableNotFound(cmd) from e
     82     raise
     84 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<ax.core.analysis_card.AnalysisCardGroup at 0x7fd73045ae40>

We can also get a tabular summary of the trials:

agent.ax_client.summarize()
trial_index arm_name trial_status generation_node intensity width height kbv-radius kbh-radius
0 0 0_0 COMPLETED CenterOfSearchSpace 16411.046875 149.343536 51.730312 35000.000000 25000.000000
1 1 1_0 COMPLETED Sobol 13512.050781 201.430756 42.179260 35528.516769 29308.345318
2 2 2_0 COMPLETED Sobol 12027.515625 20.912548 157.145172 27542.769965 20028.450154
3 3 3_0 COMPLETED Sobol 8454.648438 208.190277 116.764359 31476.355288 31937.575676
4 4 4_0 COMPLETED Sobol 16573.820312 87.833015 81.044258 44114.464223 18727.302644
5 5 5_0 COMPLETED MBM 18190.746094 169.666656 15.560753 37684.518752 17302.231826
6 6 6_0 COMPLETED MBM 17933.320312 75.805260 40.234680 40522.428456 22657.060851
7 7 7_0 COMPLETED MBM 18318.800781 36.463322 20.089252 38615.920550 21656.046132
8 8 8_0 COMPLETED MBM 17309.546875 12.417444 15.271626 37873.970853 20617.303811
9 9 9_0 COMPLETED MBM 18735.648438 97.109985 16.371954 38158.347400 18640.476644
10 10 10_0 COMPLETED MBM 18654.164062 51.970116 16.958710 37928.750018 19461.746838
11 11 11_0 COMPLETED MBM 18483.511719 123.677605 15.555395 37982.653316 18122.120993
12 12 12_0 COMPLETED MBM 19236.410156 81.947495 16.882217 37907.582695 18930.191017
13 13 13_0 COMPLETED MBM 17710.757812 27.528166 16.244621 37998.949688 19947.026184
14 14 14_0 COMPLETED MBM 13118.660156 217.094055 11.810706 38034.410960 15000.000000
15 15 15_0 COMPLETED MBM 18221.218750 187.085846 14.724368 37997.690204 16954.290265
16 16 16_0 COMPLETED MBM 18514.605469 153.629761 15.669703 38002.983364 17622.956655
17 17 17_0 COMPLETED MBM 16294.238281 200.373016 13.078042 38040.269936 16285.980029
18 18 18_0 COMPLETED MBM 18996.144531 69.765579 17.234526 38166.783964 19134.983112
19 19 19_0 COMPLETED MBM 19225.886719 80.031471 18.545055 37508.397328 18997.290584
20 20 20_0 COMPLETED MBM 17926.335938 170.404953 14.998608 38253.218102 17238.104501
21 21 21_0 COMPLETED MBM 18861.402344 43.258617 17.581388 38120.454698 19664.231765
22 22 22_0 COMPLETED MBM 19242.503906 115.118309 16.599400 38138.470862 18344.384498
23 23 23_0 COMPLETED MBM 17120.722656 17.439602 15.646281 38041.173270 20242.172021
24 24 24_0 COMPLETED MBM 17394.582031 194.491028 14.176724 38110.599072 16653.433345
25 25 25_0 COMPLETED MBM 18820.230469 61.632099 18.488487 37782.674075 22253.682151
26 26 26_0 COMPLETED MBM 16274.718750 33.305138 90.780884 32836.751829 21683.414255
27 27 27_0 COMPLETED MBM 15169.312500 210.733322 12.912532 38104.124521 15796.744414
28 28 28_0 COMPLETED MBM 18686.187500 140.013412 15.514874 38096.834564 17896.330907
29 29 29_0 COMPLETED MBM 17161.488281 19.982779 18.393990 37374.798066 21247.555059

Visualizing the Surrogate Model#

The plot_objective method shows how an objective varies across the DOF space, based on the surrogate model the agent built:

_ = agent.plot_objective(x_dof_name="kbh-radius", y_dof_name="kbv-radius", objective_name="intensity")
intensity (Mean) vs. kbh-radius, kbv-radius

The contour plot visualizes the predicted outcomes for intensity across a two-dimensional parameter space, with other parameters held fixed at the center of the search space. 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.

This plot reveals the landscape the optimizer explored. Peaks (for maximization) or valleys (for minimization) show where good configurations lie.

Applying the Optimal Configuration#

The Pareto frontier contains all optimal trade-off solutions. Let’s retrieve one and apply it to see the resulting beam:

optimal_parameters = next(iter(agent.ax_client.get_pareto_frontier()))[0]
optimal_parameters
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/adapter/transforms/winsorize.py:126: AxOptimizationWarning: Encountered a `MultiObjective` without objective thresholds. We will winsorize each objective separately. We strongly recommend specifying the objective thresholds when using multi-objective optimization.
  metric_signature: _get_cutoffs(
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/ax/generators/torch/botorch_moo_utils.py:268: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).
  obj_mask = torch.tensor(obj_indices, device=objective_weights.device)
[INFO 04-19 07:14:04] ax.service.utils.best_point: Using inferred objective thresholds: [ObjectiveThreshold(intensity >= 12592.094650202525), ObjectiveThreshold(width <= 237.51604559649311), ObjectiveThreshold(height <= 20.831940017100695)], as objective thresholds were not specified as part of the optimization configuration on the experiment.
{'kbv-radius': 37998.9496881064, 'kbh-radius': 19947.02618403819}

Now move the mirrors to these optimal positions and acquire an image:

from bluesky.plans import list_scan

uid = RE(list_scan(
    [det],
    kbv.radius, [optimal_parameters[kbv.radius.name]],
    kbh.radius, [optimal_parameters[kbh.radius.name]],
))
image = tiled_client[uid[0]]["primary/det_image"].read().squeeze()
plt.imshow(image)
plt.colorbar()
plt.show()

What You’ve Learned#

In this tutorial, you worked through a complete Bayesian optimization workflow:

  1. DOFs define the search space—the parameters you can control and their allowed ranges

  2. Objectives specify your goals and whether to minimize or maximize each one

  3. Evaluation functions extract meaningful metrics from experimental data

  4. The Agent coordinates everything, building a model of your system and intelligently exploring the parameter space

  5. Health checks let you diagnose optimization progress and catch issues early

These same components apply to any optimization problem: swap the simulated devices for real hardware, adjust the DOFs and objectives for your system, and write an evaluation function that extracts your metrics.

Next Steps#

See Also#