Skip to content

QOL code to building evaluation functions for more simply framed optimizations? #300

@MTakahashi-KWH

Description

@MTakahashi-KWH

Premise

A subset of Bluesky RunEngine optimization streams should be well-structured within the event model (i.e. data lives directly in event documents) and acquisition plans (default_acquire). Because of this, we can provide reusable default implementations for evaluation-function data handling using common stream/data-store patterns. The goal is to providing utility to avoid "reinventing" the wheel every time they want to do a simple opt without taking on strict internal API guarantees around data handling.

I've been experimenting with decorators to separate data handling from explicit per sample data processing, also enabling code separation between:

  • run-to-run configuration changes
  • system/setup-level configuration

For simple or tightly integrated systems, this could make fast-start optimization workflows much cleaner.

Example

dofs = [
    RangeDOF(actuator=motor1, bounds=(-3, 3), parameter_type="float"),
    RangeDOF(actuator=motor2, bounds=(-3, 3), parameter_type="float"),
    RangeDOF(actuator=motor3, bounds=(-3, 3), parameter_type="float"),
    RangeDOF(actuator=motor4, bounds=(-3, 3), parameter_type="float"),
]
objectives = [
    Objective(name="beam_peak", minimize=False),
]
readables = [det]

//////////////////////////// new:

@tiled_link(tiled_client,channels=[det])
def cost(measures):
    evaluation = 5*np.exp(-.1*measures[det.name])+.1
    return {"beam_peak" : evaluation}

or 

\\ exists as a proof of concept to decouple Tiled as core data store and feasibly use another within a conv func
stream_store = OptimizationCache()
RE.subscribe(stream_store)

@direct_link(stream_store=stream_store)
def cost(measures):
    evaluation = 5*np.exp(-.1*measures[det.name])+.1
    return {"beam_peak" : evaluation}

//////////////////////////////


agent = Agent(
    sensors=readables,
    dofs=dofs,
    objectives=objectives,
    evaluation_function=cost.linked,
    name="simple-experiment",
    description="A simple experiment optimizing the beam peak intensity",
)
RE(agent.optimize(iterations=4,n_points=3))

Note:

The Eval-function-wrapper branch contains the current prototype. I'll be adding examples and comments over the next few days.

Its a novel and narrow use case, but TBH, this is more of a bet on future optimizations will likely focus more on "too high degree to optimize by hand" rather than "novel data processing, novel target results" when coming to beam-line optimizations. The core API still supports both, but this approach aims to make common/simple optimization workflows easier to learn and compose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions