Skip to main content
PyBaMM provides several solvers suited to different use cases. All solvers accept a common set of tolerance parameters and are interchangeable — you pass a solver instance to pybamm.Simulation.

Solver overview

CasadiSolver

The recommended general-purpose solver. Uses CasADi for JIT-compiled, efficient integration. Supports DAEs, events, and multiple operating modes.

IDAKLUSolver

High-performance solver using SUNDIALS IDA with the KLU sparse direct solver. The fastest option for most PyBaMM models, especially in experiment mode or when solving many steps.

ScipySolver

Wraps scipy.integrate.solve_ivp. Easy to use and well-understood, but does not support DAEs or sensitivity analysis. Good for ODE-only models and debugging.

JaxSolver

JAX-compiled solver, enabling JIT compilation and automatic differentiation. Requires Python ≥ 3.11 and is not available on Intel macOS.

CasadiSolver

The default solver for most models. It compiles the model to a CasADi function and integrates using the CVODES/IDA integrators inside CasADi.
solver = pybamm.CasadiSolver()

Modes

The mode parameter controls the integration strategy:
ModeDescriptionWhen to use
"safe" (default)Step-and-check in global steps of size dt_max, looking for eventsFull charge/discharge simulations
"fast"Direct integration without event detectionDrive cycles or simulations where no events should be triggered
"fast with events"Direct integration, then retrospectively check for eventsExperimental
"safe without grid"Step-by-step without pre-computing the time gridExperimental; can be faster in some cases
# Fast mode for drive cycles
solver = pybamm.CasadiSolver(mode="fast")

# Safe mode with custom step size
solver = pybamm.CasadiSolver(mode="safe", dt_max=60)  # 60 s max step

Key options

solver = pybamm.CasadiSolver(
    mode="safe",
    rtol=1e-6,                         # relative tolerance (default: 1e-6)
    atol=1e-6,                         # absolute tolerance (default: 1e-6)
    root_method="casadi",               # method for finding DAE initial conditions
    root_tol=1e-6,                     # root-finding tolerance
    max_step_decrease_count=5,         # max step size reductions before error
    dt_max=600,                        # max step size in "safe" mode [s]
    on_extrapolation="error",          # "error", "warn", or "ignore"
    return_solution_if_failed_early=False,
    extra_options_setup={"max_num_steps": 10000},  # passed to CasADi integrator
)

IDAKLUSolver

The fastest solver for PyBaMM models. Uses the SUNDIALS IDA time integrator with the KLU sparse linear solver, called via the pybammsolvers package.
solver = pybamm.IDAKLUSolver()

Key options

solver = pybamm.IDAKLUSolver(
    rtol=1e-4,          # relative tolerance (default: 1e-4)
    atol=1e-6,          # absolute tolerance (default: 1e-6)
    root_method="casadi",
    on_extrapolation="warn",
    output_variables=[  # pre-specify variables to avoid computing the full state
        "Battery voltage [V]",
        "Current [A]",
    ],
)

output_variables for speed

When you only need a small set of outputs, specifying output_variables avoids computing and storing the full state vector:
solver = pybamm.IDAKLUSolver(
    output_variables=[
        "Battery voltage [V]",
        "Discharge capacity [A.h]",
        "Cell temperature [K]",
    ]
)
sim = pybamm.Simulation(model, solver=solver)
sol = sim.solve([0, 3600])

Parallel solving

IDAKLUSolver can solve multiple input sets in parallel using OpenMP threads:
solver = pybamm.IDAKLUSolver(
    options={"num_threads": 4, "num_solvers": 4}
)

# Solve with a list of input dicts in parallel
input_list = [
    {"Current function [A]": 1.0},
    {"Current function [A]": 2.0},
    {"Current function [A]": 5.0},
]
sol = sim.solve([0, 3600], inputs=input_list)

ScipySolver

Wraps scipy.integrate.solve_ivp. Only supports ODE models (no algebraic equations), so it cannot solve DFN or SPMe without modification.
solver = pybamm.ScipySolver(
    method="BDF",           # default; other scipy methods also work
    rtol=1e-6,
    atol=1e-6,
    on_extrapolation="warn",
)
ScipySolver does not support sensitivity analysis and cannot solve DAE systems. It is best suited to ODE-only models or for quick debugging.

JaxSolver

A JAX-based solver that enables JIT compilation and compatibility with JAX’s automatic differentiation.
solver = pybamm.JaxSolver(
    method="BDF",   # "BDF" (default) or "RK45"
    rtol=1e-6,
    atol=1e-6,
)
The model must be built with JAX format:
model = pybamm.lithium_ion.SPM()
model.convert_to_format = "jax"

sim = pybamm.Simulation(model, solver=pybamm.JaxSolver())
JAX solver requirements:
  • Python ≥ 3.11
  • Not available on Intel macOS
  • Install with: pip install pybamm[jax]
  • Does not support models with termination events
  • Requires model.convert_to_format = "jax"

Passing a solver to Simulation

model = pybamm.lithium_ion.DFN()

# Use CasadiSolver in fast mode
solver = pybamm.CasadiSolver(mode="fast", rtol=1e-6, atol=1e-6)
sim = pybamm.Simulation(model, solver=solver)
sol = sim.solve([0, 3600])
You can also override the solver at solve time:
sol = sim.solve([0, 3600], solver=pybamm.IDAKLUSolver())

Choosing a solver

ScenarioRecommended solver
General-purpose charge/dischargeCasadiSolver(mode="safe")
Drive cycle (no events expected)CasadiSolver(mode="fast")
Maximum performance / experiment cyclingIDAKLUSolver()
Only need a few output variablesIDAKLUSolver(output_variables=[...])
ODE-only model, quick debuggingScipySolver()
JAX ecosystem / AD through solveJaxSolver()

Adjusting tolerances

All solvers accept rtol (relative) and atol (absolute) tolerance parameters. Tighter tolerances improve accuracy at the cost of speed:
# Default tolerances (1e-6 / 1e-6) for most solvers
solver = pybamm.CasadiSolver(rtol=1e-6, atol=1e-6)

# Tighter tolerances for more accurate results
solver = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8)

# IDAKLU defaults to rtol=1e-4 (looser but faster)
solver = pybamm.IDAKLUSolver(rtol=1e-4, atol=1e-6)
For degradation studies requiring many cycles, start with IDAKLUSolver and loosen tolerances (rtol=1e-4) for speed. For a single precise discharge, use CasadiSolver with default tolerances.

Build docs developers (and LLMs) love