Skip to main content
The ionworks-api Python package provides a sub-client for running and managing optimizations programmatically. For installation and authentication, see the Python API client page.

Running an optimization

from ionworks import Ionworks

# Reads IONWORKS_API_KEY and IONWORKS_PROJECT_ID from the environment.
# project_id is auto-injected into payloads that don't specify it.
client = Ionworks()

optimization = client.optimization.run({
    "name": "Electrode thickness optimization",
    "parameterized_model_id": "your-parameterized-model-id",
    "protocol_experiment": {
        "protocol": "...",
        "name": "1C Discharge",
    },
    "design_parameters": {
        "Positive electrode thickness [m]": {
            "bounds": [50e-6, 100e-6],
        },
    },
    "objectives": {
        "Discharge capacity [A.h]": {"type": "maximize"},
    },
})

print(f"Optimization ID: {optimization.id}")
print(f"Job ID: {optimization.job_id}")

Waiting for completion

result = client.optimization.wait_for_completion(
    "your-optimization-id",
    timeout=600,        # seconds (default: 600)
    poll_interval=3,    # seconds between polls (default: 3)
    verbose=True,       # print status updates (default: True)
)
Set raise_on_failure=False to get the result dict instead of raising an exception when an optimization fails.

Listing optimizations

# List optimizations in the default project
# (set IONWORKS_PROJECT_ID or pass project_id= to Ionworks(...))
optimizations = client.optimization.list()

# Override the project for a single call
optimizations = client.optimization.list(project_id="other-project-id")

# Paginate results
optimizations = client.optimization.list(limit=10, offset=0)
When project_id is omitted, client.optimization.run and .list use the default project configured on the Ionworks client.

Getting an optimization

Returns the optimization record along with its associated job status.
result = client.optimization.get("your-optimization-id")
print(result["optimization"])
print(result["job"])

Updating an optimization

optimization = client.optimization.update("your-optimization-id", {
    "name": "Electrode optimization v2",
    "description": "Updated bounds",
})

Inspecting the parameter trace

Design optimizations and data fits log the optimizer’s per-iteration progress to the job’s metadata. This is the same data that powers the parameter and cost-convergence plots in Studio. Use client.job.get_parameter_trace to pull it down as a list of dicts (one per saved iteration, oldest first):
trace = client.job.get_parameter_trace(optimization.job_id)

for entry in trace:
    print(entry["inputs_unscaled"], entry["cost"], entry["best_cost"])
Each entry contains:
KeyDescription
costObjective value at this iteration.
best_costBest (lowest) objective value seen up to this iteration.
inputsScaled parameter values at this iteration.
inputs_unscaledUnscaled (physical) parameter values, keyed by parameter name. Use these for parameter traces.
multistart_job_idIndex of the multistart this entry belongs to, when applicable.
outputs / best_outputsModel outputs at this iteration. Present for design-objective runs.
Saves are throttled (roughly every 100 iterations or every 5 seconds), so the trace is a sampled subset of the optimizer’s evaluations rather than every single one. The list is empty when live progress updates were disabled for the run, and there is no per-iteration wall-clock timing.

Canceling an optimization

result = client.optimization.cancel("your-optimization-id")
You can find the ID for any resource from the Ionworks Studio web app. The ID is displayed in the URL when you navigate to a resource’s detail page.