Simulation#

Client for running battery simulations using UCP protocol and PyBaMM.

For usage examples and guides, see Simulate API on docs.ionworks.com.

Simulation client for running battery simulations.

This module provides the SimulationClient for running battery simulations using the Universal Cycler Protocol (UCP) format. It supports single simulations, batch simulations with design of experiments (DOE), and PyBaMM-based modeling.

class ionworks.simulation.SimulationResult(time_series, steps, metrics)[source]#

Bases: object

Typed result returned by SimulationClient.get_result().

Parameters:
time_series: DataFrame | DataFrame#

Time-series data with one row per time point. Column names follow the platform convention (e.g. "Time [s]", "Voltage [V]"). Returns a polars DataFrame by default; a pandas DataFrame when set_dataframe_backend("pandas") is active.

steps: DataFrame | DataFrame#

Step-level summary with one row per protocol step. Returns the same DataFrame type as time_series.

metrics: dict[str, Any]#

Scalar metrics computed over the full simulation (e.g. cycle-level summaries). Not tabular; returned as a plain dict.

__init__(time_series, steps, metrics)#
Parameters:
Return type:

None

class ionworks.simulation.QuickModelConfig(*, capacity=1.0, chemistry='NMC/Graphite')[source]#

Bases: BaseModel

Quick model configuration for protocol-based simulations.

A quick model builds a system ECM from a nominal capacity and a chemistry name — it does not take a base model_id (that is what a full parameterized model is for).

Parameters:
capacity: float#
chemistry: str#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.ProtocolExperimentConfig(*, protocol, name)[source]#

Bases: BaseModel

Protocol experiment configuration.

Parameters:
protocol: str#
name: str#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.DOERow(*, type, name, min=None, max=None, count=None, values=None, mean=None, std=None)[source]#

Bases: BaseModel

Design of experiments row configuration.

Parameters:
type: str#
name: str#
min: float | None#
max: float | None#
count: int | None#
values: list[float] | None#
mean: float | None#
std: float | None#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.DesignParametersDOE(*, sampling, rows, count=None)[source]#

Bases: BaseModel

Design of experiments configuration.

Parameters:
sampling: str#
rows: list[DOERow]#
count: int | None#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.ProtocolSimulationBatchRequest(*, parameterized_model, protocol_experiment, design_parameters_doe=None, experiment_parameters=None, max_backward_jumps=None, study_id=None, project_id=None, extra_variables=None)[source]#

Bases: BaseModel

Request model for batch protocol-based simulation.

Parameters:
parameterized_model: Any#
protocol_experiment: ProtocolExperimentConfig#
design_parameters_doe: DesignParametersDOE | None#
experiment_parameters: dict[str, float] | None#
max_backward_jumps: int | None#
study_id: str | None#
project_id: str | None#
extra_variables: list[str] | None#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.SimulationResponse(*, simulation_id, job_id)[source]#

Bases: BaseModel

Response model for simulation creation.

Parameters:
  • simulation_id (str)

  • job_id (str)

simulation_id: str#
job_id: str#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ionworks.simulation.SimulationClient(client)[source]#

Bases: object

Client for running simulations.

Parameters:

client (Any)

__init__(client)[source]#

Initialize the SimulationClient.

Parameters:

client (Any) – The HTTP client instance for making API requests.

Return type:

None

protocol(config)[source]#

Create a single protocol-based simulation.

Delegates to protocol_batch() and returns the single result. Pass the same config fields as protocol_batch(), plus the single-simulation convenience field design_parameters (a flat dict[str, float]) — it is translated internally to a one-row discrete DOE.

Parameters:

config (dict[str, Any]) –

Configuration dictionary containing:

  • parameterized_model: one of
    • a quick-model dict {"capacity": <Ah>, "chemistry": <name>} (builds a system ECM; no base model_id),

    • a QuickModelConfig,

    • a full model dict {"model_id": ..., "parameters": {...}}, or

    • a parameterized-model ID string.

  • protocol_experiment: ProtocolExperimentConfig dict with protocol and name fields

  • experiment_parameters: Optional dict with initial_soc and initial_temperature

  • design_parameters: Optional dict[str, float] — design parameter overrides for this single simulation (translated to a single-row discrete DOE under the hood).

  • max_backward_jumps: Optional int

  • study_id: Optional str

  • extra_variables: Optional list[str] — extra variables to include in simulation output

Returns:

Response containing simulation_id and job_id.

Return type:

SimulationResponse

Raises:

ValueError – If the configuration is invalid, both design_parameters and design_parameters_doe are supplied, or a multi-row design_parameters_doe is supplied (use protocol_batch() for multi-simulation DOE).

protocol_batch(config)[source]#

Create multiple protocol-based simulations using DOE.

Uses a two-step flow: first parses the protocol and creates an experiment template (POST /protocols/parse-to-template), then runs the batch (POST /simulations/with-template/batch).

Parameters:

config (dict[str, Any]) –

Configuration dictionary containing:

  • parameterized_model: one of
    • a quick-model dict {"capacity": <Ah>, "chemistry": <name>} (builds a system ECM; no base model_id),

    • a QuickModelConfig,

    • a full model dict {"model_id": ..., "parameters": {...}}, or

    • a parameterized-model ID string.

  • protocol_experiment: ProtocolExperimentConfig dict with protocol and name fields

  • design_parameters_doe: DesignParametersDOE dict

  • experiment_parameters: Optional dict

  • max_backward_jumps: Optional int

  • study_id: Optional str

  • extra_variables: Optional list[str] — extra variables to include in simulation output

Returns:

List of responses, each containing simulation_id and job_id.

Return type:

list[SimulationResponse]

Raises:

ValueError – If the configuration is invalid.

list(parameterized_model_id=None, study_id=None)[source]#

List simulations filtered by parameterized model or study.

Exactly one of parameterized_model_id or study_id must be provided.

Parameters:
  • parameterized_model_id (str, optional) – Filter simulations belonging to this parameterized model.

  • study_id (str, optional) – Filter simulations assigned to this study.

Returns:

List of simulation summary objects.

Return type:

list[dict[str, Any]]

get(simulation_id)[source]#

Get a specific simulation by ID.

Parameters:

simulation_id (str) – The UUID of the simulation to retrieve.

Returns:

Simulation object with full joined data including model, experiment, and simulation_data (null if not completed).

Return type:

dict[str, Any]

get_result(simulation_id)[source]#

Get simulation data/result for a completed simulation.

Parameters:

simulation_id (str) – The UUID of the simulation.

Returns:

Typed result with time_series and steps as DataFrames and metrics as a plain dict. DataFrame type (polars or pandas) follows the active backend set via set_dataframe_backend().

Return type:

SimulationResult

Raises:

IonworksError – If the API request fails. A 404 typically means the result is not yet available (simulation still running or queued). Other status codes indicate authentication failures, server errors, or a missing simulation ID.

wait_for_completion(simulation_id, timeout=60, poll_interval=2, verbose=True, raise_on_failure=True)[source]#

Wait for simulation(s) to complete by polling until done or timeout.

Parameters:
  • simulation_id (str | list[str]) – Single simulation ID or list of simulation IDs to wait for. Can also be a SimulationResponse or list of them (the job_id will be extracted automatically for failure detection).

  • timeout (int) – Maximum time to wait in seconds (default: 60).

  • poll_interval (int) – Time between polls in seconds (default: 2).

  • verbose (bool) – Whether to print status updates (default: True).

  • raise_on_failure (bool) – Whether to raise IonworksError when a simulation’s job fails or is canceled (default: True).

Returns:

Completed simulation(s). Returns single dict if single ID provided, list of dicts if list of IDs provided. Only returns completed simulations if timeout is reached.

Return type:

dict[str, Any] | list[dict[str, Any]]

Raises:
  • TimeoutError – If timeout is reached before all simulations complete.

  • IonworksError – If a simulation fails and raise_on_failure is True.