Skip to main content
The ionworks Python package lets you run simulations and submit parameterization pipelines programmatically. For installation and authentication, see the Python API client page. To save, validate, parse, or convert the protocols you run here, see the Protocol API page.

Running simulations

Use client.simulation to run simulations. A simulation requires a parameterized model and a protocol in UCP format.

Single simulation

You can also pass experiment parameters and design parameters:
design_parameters is a single-simulation convenience field on protocol(). Pass a flat dict of parameter overrides, each a number or a table for a function-valued parameter. Use it when you want to vary one or more design parameters for a single run without writing out the full DOE schema.
In protocol(), design_parameters and design_parameters_doe are mutually exclusive, and any DOE you supply must resolve to exactly one simulation. Passing both, or a DOE that would expand to multiple simulations, raises ValueError — use protocol_batch for multi-simulation sweeps instead.
For a model with hysteresis, experiment_parameters also accepts "Initial hysteresis state": the cell’s hysteresis history at the start of the run, from -1 (after a discharge) through 0 (average) to 1 (after a charge). It is rejected for a model without hysteresis.

Function-valued parameters

A parameter that is a function, such as electrolyte conductivity, can be overridden with a lookup table of x and y values. The table replaces the function with an interpolant in its first input, and the other inputs are ignored: a table of conductivity against concentration replaces a function of concentration and temperature.
x must be strictly increasing, with at least two points and one y per x. interpolator defaults to "linear". Tables work in protocol() and in the conditions of protocol_batch(). To run a protocol you have already saved, pass protocol_id in place of protocol_experiment — exactly one of the two. project_id is then optional and defaults to the saved protocol’s own project:
Config keys are checked before anything is sent. A misspelt or misplaced key raises a ValueError naming it and listing the valid top-level keys, rather than being ignored.

Running at an operating limit

Pass operating_limit to run the protocol at the limit of one of its inputs, instead of at a given value. The limit is found by bisection and reported in the simulation’s metrics, and the stored results are the run at the limit. For peak power, the protocol’s pulse step reads input["Power [W]"]; earlier steps set the state it starts from:
peak_power also takes voltage_limit (defaults to the protocol’s own safety limit, else the model’s cut-off), direction ("Discharge" or "Charge") and bounds (defaults to 1/100 to 100 times the cell’s 1C power). For any other input, give the range to search, what to optimize, and the bounds the run must stay within. The longest cruise that still stays above 3.0 V:
The typed forms are iw.api.PeakPowerSpec and iw.api.OperatingLimitSpec (with LimitObjective and LimitConstraint).
The bounds must bracket the limit: one feasible, the other not. When both are feasible, metrics["Operating limit status"] is "beyond bounds" and the run is at the bound with the better objective; when neither is, the simulation fails with a configuration error. A value given for the searched input in experiment_parameters is ignored.

Waiting for results

Use wait_for_completion to poll until the simulation finishes. The method detects failed and canceled jobs immediately rather than waiting for the timeout.
When a simulation fails or is canceled, the IonworksError it raises has error_code "JOB_FAILED", and its data["detail"] carries the failure’s job_error_code and job_error to branch on; see Failed jobs. Set raise_on_failure=False to get the result dict instead of raising an exception when a simulation fails:

Batch simulations with design of experiments

Run multiple simulations across a parameter sweep using protocol_batch:
Supported DOE row types: Sampling strategies: grid (all combinations), random, latin_hypercube.

Explicit list of runs

When the runs are not a sampled design, list them with conditions instead of design_parameters_doe. Each condition is one simulation with its own experiment_parameters and design_parameters; nothing is crossed. A top-level experiment_parameters is a shared default that each condition can override. conditions and design_parameters_doe cannot be combined.

Checking many simulations at once

get_statuses returns the status of many simulations in one request, which is cheaper than calling get() per id. Unknown ids are omitted from the result.

Retrieving simulation data

list() scopes by parameterized_model_id or study_id (not both), and protocol_id narrows either to one saved protocol (or scopes by protocol alone), so all runs of one model on one protocol are a single request. state keeps only queued, running, completed or failed runs, and summary=True leaves out each run’s metrics. With limit or offset, list() returns a page whose .total counts every match. Each run carries protocol_id and protocol_name.
You don’t need to check for an existing run before starting one. Submitting a simulation identical to an existing one (same model, protocol, inputs, design and options), finished or still running, returns that run with already_existed=True instead of starting a new one.
get_result returns a typed SimulationResult dataclass with three fields: To read only the step summary, get_steps skips the time series, which is far larger:
It returns the same frame as result.steps, and raises a 404 until the run has completed. time_series and steps are returned as polars DataFrames by default. Call set_dataframe_backend("pandas") once at session start to receive pandas DataFrames instead.
Discharge capacity [A.h] and Charge capacity [A.h] in time_series reset to 0 at each step boundary. Use "Step count" to join time_series to steps, or accumulate per-step end values if you need a continuous cumulative capacity trace.

Deleting a simulation

Running PyBaMM simulations

import ionworks.pybamm as pybamm is PyBaMM with Simulation.solve running on Ionworks. Each solve is an ordinary simulation in your project, and returns a RemoteSolution you read like a pybamm.Solution:
A remote solve needs initial_soc and the same pybamm version Ionworks runs. Set IONWORKS_PYBAMM_LOCAL=1 to solve locally instead. See the ionworks.pybamm reference for batches, client.simulation.submit and what is supported.

Running pipelines

Pipelines have moved to their own page. See the Pipelines API how-to for submitting pipelines, polling them, reading results, and managing submissions.

Managing studies

Use client.study to create, list, update, and delete studies. Studies are scoped to a project. All client.study.* methods accept project_id as an optional keyword argument. When omitted, they use the default project configured on the client (or resolved from IONWORKS_PROJECT_ID). Pass project_id= explicitly to override on a per-call basis.

Listing studies

Supported filters: name, name_exact, order_by, order.

Getting a study

Creating a study

Updating a study

Assigning simulations and measurements

Deleting a study

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.

Next steps

Simulations

Learn about running simulations in Ionworks Studio.

Protocol API

Save, validate, parse, and convert protocols with client.protocol.

Protocol reference

Full reference for the Universal Cycler Protocol format.

Uploading data

Upload and manage cell data via the Python API.

Build API

List and retrieve models and parameterized models.