Releases: pybamm-team/PyBaMM
Releases · pybamm-team/PyBaMM
Release list
pybammsolvers 0.9.1
Patch release of pybammsolvers. The published version comes from version.py (0.9.1); the release workflow's check_version job asserts the tag, version.py, pyproject.toml, and vcpkg.json all agree.
Bug fixes
- Fixed the CMake build under conda (
CONDA_BUILD=1), where SUNDIALS, SuiteSparse, and CasADi are host dependencies rather than vendored: the.idakluroot defaults and the from-source bootstrap are skipped, the system CasADi is used instead of a pip one, and the libstdc++ ABI probe (which has no wheel to inspect and would wrongly force the legacy ABI) is now limited to the PyPI-CasADi path. (#5668) - IDAKLU debug logging and
print_statsoutput are now buffered and emitted once the OpenMP region is over, instead of calling into Python from worker threads that do not hold the GIL. Solving with several input sets again produces one trace and one statistics block per input set. (#5717) - Buffered IDAKLU diagnostics are also flushed when a solve raises, so a failed solve still emits the trace leading up to the failure. (#5717)
- IDAKLU diagnostics are emitted as the solve progresses whenever it runs on the calling thread, which is the one holding the GIL, so a long solve reports progress instead of going quiet until it returns. Only the solves handed to OpenMP worker threads are held back, and they are flushed at the end of the parallel region. (#5717)
Optimizations
- IDAKLU with
output_variablesnow writes sensitivities straight into their final NumPy layout, removing the post-solve transpose pass and the second full-size sensitivity buffer it required. (#5717) - The dense scratch vector used to scatter sparse output sensitivities is now a reused member buffer instead of being allocated per output row on every step. (#5717)
Full changelog: https://github.com/pybamm-team/PyBaMM/blob/main/CHANGELOG.md
PyBaMM 26.8.0.0
Features
- Added unstructured mesh support (
UnstructuredSubMesh, generators, and interface coupling) for arbitrary 2D/3D domains. Hexahedra must have planar faces (warped hexes raise aGeometryError), andUserSuppliedUnstructuredMeshaccepts tetrahedral, triangular, and quadrilateral cells only. (#5687) - Generalised
VectorFieldto N components and addedComponent/Normoperators for multi-dimensional vector fields. (#5686) - Removed the left sidebar from the documentation home page for a cleaner landing experience. (#5699)
Bug fixes
- IDAKLU debug logging and
print_statsoutput are now buffered and emitted once the OpenMP region is over, instead of calling into Python from worker threads that do not hold the GIL. Solving with several input sets again produces one trace and one statistics block per input set. (#5717) - Buffered IDAKLU diagnostics are also flushed when a solve raises, so a failed solve still emits the trace leading up to the failure. (#5717)
- IDAKLU diagnostics are emitted as the solve progresses whenever it runs on the calling thread, which is the one holding the GIL, so a long solve reports progress instead of going quiet until it returns. Only the solves handed to OpenMP worker threads are held back, and they are flushed at the end of the parallel region. (#5717)
ParameterValues.create_from_bpxno longer writesNoneinto the parameter set for thermal material properties (density and specific heat capacity) that a BPX file omits. Absent optional BPX fields are now dropped entirely, so building an isothermal model from a thermal-less BPX still works, and building a thermal model raises PyBaMM's usual named "parameter not found" error instead of a cryptic type error deep in the expression tree. (#5708)VectorField._from_jsonnow rebuilds all N components instead of only the first two, so a field with three or more components survives serialisation instead of silently losing its extra components (which later triggered anIndexErroronComponent). (#5703)ElectrodeSOHSolvernow passes model options through, so hysteresis OCP branches are used. (#5701)- Fixed a memory leak in
ElectrodeSOHSolver.theoretical_energy_integral, which cached a new expression tree per call. (#5695) BatchStudy.solveno longer ignores itssolverargument: previously the loop over study inputs shadowed it, so a caller-supplied solver was silently dropped. A solver fromBatchStudy(solvers=...)still takes precedence. (#5677)pybamm.citations.registernow names the citation the caller passed in when a BibTeX string fails to parse, instead of whichever entry the parser had reached. (#5677)- Deserialising a parameter set whose interpolant specification is invalid now logs a warning naming the offending parameter, instead of printing the bare exception to stdout with no indication of which parameter fell back to zero. (#5679)
- A user-specified boundary tag that is absent from a mesh file now raises
GeometryErrorinstead of degrading to a warning and a mesh with no boundary groups. (#5679) - Fixed the
pybammsolversCMake build under conda (CONDA_BUILD=1), where SUNDIALS, SuiteSparse, and CasADi are host dependencies rather than vendored: the.idakluroot defaults and the from-source bootstrap are skipped, the system CasADi is used instead of a pip one, and the libstdc++ ABI probe (which has no wheel to inspect and would wrongly force the legacy ABI) is now limited to the PyPI-CasADi path. Released aspybammsolversv0.9.1. (#5668)
Optimizations
- IDAKLU with
output_variablesnow writes sensitivities straight into their final NumPy layout, removing the post-solve transpose pass and the second full-size sensitivity buffer it required. (#5717) - The dense scratch vector used to scatter sparse output sensitivities is now a reused member buffer instead of being allocated per output row on every step. (#5717)
PyBaMM 26.7.1.0
Breaking changes
- Reverted the "voltage as a state" default back to "false", undoing the v26.7.0.0 change to "true". Promoting voltage to an algebraic state turns SPM/SPMe into DAEs and places voltage under solver error control, which caused IDAKLU error-test failures on solves of discontinuous (pulsed) current profiles at the default tolerances, and lowered voltage-output accuracy. The option remains available (
{"voltage as a state": "true"}) and is still enabled automatically for the "explicit power" and "explicit resistance" operating modes. (#5670)
Features
- Exposed the per-value parameter serialisation dispatch publicly as
pybamm.serialize_parameter_value/pybamm.deserialize_parameter_value, andconvert_parameter_values_to_jsonnow accepts anyMapping(not just aParameterValues), so a raw{name: value}mapping can be serialised without constructing a throwawayParameterValues. (#5663)
pybammsolvers 0.9.0
First pybammsolvers release from the PyBaMM monorepo, tagged in the pybammsolvers-v* namespace. The published version comes from version.py (0.9.0); the release workflow's check_version job asserts the tag, version.py, pyproject.toml, and vcpkg.json all agree.
Breaking changes
- The minimum supported NumPy version is now
2.0.0(previously unpinned). NumPy 1.x is no longer supported. (#5647)
Features
- Now ships Linux
aarch64(arm64) wheels, built onmanylinux_2_34native ARM runners. The libstdc++std::stringABI (_GLIBCXX_USE_CXX11_ABI) is detected from the linked CasADi library instead of hard-coded, resolving the unresolved-symbol failure against CasADi's C++11-ABI aarch64 wheel. (#5653) - PyBaMM and
pybammsolversnow develop in a single repository (a UV workspace underpackages/) while continuing to release independently to PyPI. Release tags are namespaced (pybamm-v*andpybammsolvers-v*). (#5512)
Bug fixes
- Fixed the Windows wheels failing to build: vcpkg's transitive reference-LAPACK/Fortran chain broke on a pruned upstream MSYS2 download (a 404). The Windows build now uses a
suitesparse-klu-only sundials port and vcpkg 2026.06.24 on awindows-2025runner. (#5650) - Fixed the source distribution bundling the SUNDIALS/SuiteSparse submodule trees (~291 MB, over PyPI's per-file limit) when built from a checkout with the submodules initialised; the sdist now excludes them. (#5623)
- Fixed the editable auto-rebuild failing to configure when the SUNDIALS/SuiteSparse submodules are absent even though the libraries were already built in
.idaklu. (#5623) - Fixed the Dependabot
uvupdate job failing to resolve the workspace (ModuleNotFoundError: No module named 'scikit_build_core'):pybammsolversnow declares a staticversioninpyproject.toml, so build-tool-less resolvers read its metadata without invoking the scikit-build-core backend.version.pyremains the single source of truth, mirrored intopyproject.tomlandvcpkg.jsonby thesync-pybammsolvers-versionpre-commit hook. (#5655)
Full changelog: https://github.com/pybamm-team/PyBaMM/blob/main/CHANGELOG.md
PyBaMM 26.7.0.0
Breaking changes
- The minimum supported NumPy version is now
2.0.0for bothpybammandpybammsolvers(previously unpinned). NumPy 1.x is no longer supported. (#5647) - The "voltage as a state" model option now defaults to "true": voltage is solved as an algebraic state, making standard models DAEs. Reading
Voltage [V]from a solution is now an O(1) state lookup instead of a post-solve expression evaluation (up to 73% faster end-to-end for dense output; 8-24% faster experiment cycling across SPM/SPMe/DFN; up to 48% faster with in-solveroutput_variables=["Voltage [V]"]). The defaultIDAKLUSolver,CasadiSolver(all modes), andJaxSolver(method="BDF")handle DAEs; ODE-only solvers (ScipySolver,JaxSolver(method="RK45")) require{"voltage as a state": "false", "surface form": "false"}for SPM/SPMe, which remains a supported configuration. Known trade-off: continuous solves of rapidly alternating current profiles (e.g. interpolant drive cycles with more than ~25 current reversals in one solve) can be slower, up to ~2x for SPM in the worst measured case; the legacy configuration above restores previous performance for these workloads. Experiment-driven cycling is unaffected. (#5573) CasadiSolver,ScipySolver, andCasadiAlgebraicSolverare deprecated; useIDAKLUSolver(orNonlinearSolverfor algebraic systems) instead. It is now the default for every model. (#5624)
Features
pybammsolversnow ships Linuxaarch64(arm64) wheels, built onmanylinux_2_34native ARM runners. The libstdc++std::stringABI (_GLIBCXX_USE_CXX11_ABI) is now detected from the linked CasADi library instead of hard-coded, resolving the unresolved-symbol failure against CasADi's C++11-ABI aarch64 wheel. (#5653)- Added
skip_surface_form_checkoption toEISSimulationto bypass the surface form validation. (#5632) - Added ability to export pybamm.Simulation with experiments to DiffSL format (#5557)
- PyBaMM and
pybammsolversnow develop in a single repository — a UV workspace underpackages/— while continuing to release independently to PyPI. Release tags are namespaced (pybamm-v*andpybammsolvers-v*), and PyBaMM's CI now tests against the in-repo solver on every platform. The publishedpybammpackage and its dependency onpybammsolversare unchanged for users. SeeRELEASE.mdfor the release model. (#5512) - Legacy BPX v0.x files/objects now load again:
bpxitself detects and converts them to the v1.x schema on a best-effort basis (with aUserWarning), soParameterValues.create_from_bpx/create_from_bpx_objno longer raise aValidationError. PyBaMM officially supportsbpx>=1. (#5574) create_from_bpx/create_from_bpx_objnow also accept BPX files that omitStatefields (or the wholeStatesection): the ambient/initial temperatures default to the reference temperature and the initial electrolyte concentration to 1000 mol.m-3 (logged), while opt-in fields (initial hysteresis state, heat transfer coefficient) are left for the model to default. (#5574)
Bug fixes
- Fixed
ParameterValues.to_json(andSerialiseof parameter values) raisingTypeError: ... got multiple values for argumentoncreate_from_bpxoutputs, whose functional parameters arefunctools.partialobjects with keyword-bound arguments (e.g. constant diffusivity, tabular OCPs, exchange-current density). The serialiser now only creates symbols for a partial's remaining required arguments, leaving bound and defaulted arguments in place. (#5641) - Fixed the Dependabot
uvupdate job failing to resolve the workspace (ModuleNotFoundError: No module named 'scikit_build_core'):pybammsolversnow declares a staticversioninpyproject.toml, so build-tool-less resolvers read its metadata without invoking the scikit-build-core backend.version.pyremains the single source of truth, mirrored intopyproject.tomlandvcpkg.jsonby a newsync-pybammsolvers-versionpre-commit hook. (#5655) - Fixed the
pybammsolversWindows wheels failing to build: vcpkg's transitive reference-LAPACK/Fortran toolchain chain broke on a pruned upstream MSYS2 download (a 404). The Windows build now avoids that chain, using asuitesparse-klu-only sundials port and vcpkg 2026.06.24 on awindows-2025runner. (#5650) - Fixed the deprecated
"<X> electrode diffusivity [m2.s-1]"alias silently overriding the current"<X> particle diffusivity [m2.s-1]": the current name now takes precedence inParameterValues(instead of being overwritten by the deprecated alias), and a warning is raised when both are set, so setting or fittingparticle diffusivityis no longer a silent no-op. The deprecated key is retained for backward compatibility, andcreate_from_bpxnow emits only the currentparticle diffusivityname. (#5642) - Fixed the
pybammsolverssource distribution bundling the SUNDIALS/SuiteSparse submodule trees (~291 MB, over PyPI's per-file limit) when built from a checkout with the submodules initialised; the sdist now excludes them. (#5623) - Fixed the
pybammsolverseditable auto-rebuild failing to configure when the SUNDIALS/SuiteSparse submodules are absent even though the libraries were already built in.idaklu; the from-source bootstrap (and its submodule requirement) is now skipped once the libraries exist. (#5623) - Fixed the Read the Docs documentation build, which broke once
pybammsolversbecame a workspace member with no published wheel during the release: RTD now fetches the SUNDIALS/SuiteSparse submodules and installsgfortran/libopenblasso the solver builds from source. Link checking was also restructured so transient external-link failures no longer block builds: Sphinxlinkcheckis advisory, and the CIlycheecheck runs offline on PRs with a weekly external sweep that files a tracking issue. (#5659)
v26.6.2.0
Features
create_from_bpx/create_from_bpx_objnow apply a BPXStateInitial state-of-chargeviaset_initial_state(supporting blended electrodes and validated to lie in[0, 1]) instead of ignoring it. (#5616)- The parameter
"Contact resistance [Ohm]"can now be a function of the volume-averaged cell temperature (in addition to a constant), and works with all thermal options. The accompanying documentation now clarifies that this represents a lumped series resistance rather than a true contact resistance (BPX#130); the name is retained to avoid a breaking change. (#5604)
Bug fixes
- Fixed BPX import leaving interpolated-table OCP hysteresis branches (
OCP (lithiation) [V],OCP (delithiation) [V]) as raw data tuples instead of usable expression-tree objects. RemainingFloatFunctionTableplaceholders are now converted generically, so new BPX table parameters no longer need a hand-maintained conversion list. (#5610) RegulariseSqrtAndPowerno longer regularises state-independent bases, fixing corrupted small rate constants in exchange-current density functions. (#5600)- Fixed
Serialise.load_custom_modelleaving a loaded lithium-ion model's cachedparambuilt from default options instead of the restored ones, so a model loaded with non-default options (e.g. composite"particle phases") had parameters inconsistent with its options. (#5599) - Fixed
BatteryModelOptionsletting two invalid MSMR option sets pass validation and then crash during parameter construction withinvalid literal for int() with base 10: 'none'; both now raise a clearOptionError. The all-or-nothing MSMR check now detects MSMR inside a per-electrode tuple (e.g."open-circuit potential": ("MSMR", "single")), and an MSMR model must set"number of MSMR reactions"to a positive integer rather than the default"none". (#5599) - Fixed
Serialise.serialise_custom_modelnot recording a custom model's discretisation recipe (geometry,var_pts,submesh_types,spatial_methods), so a custom model reloaded via theBaseModelfallback (when its defining package is unavailable) was no longer discretisable. (#5609)
v26.6.1.1
v26.6.1.0
Features
- The "voltage as a state" option is now registered centrally in
BaseBatteryModeland supports all operating modes. SPM/SPMe promote "surface form" to "algebraic" automatically when a particle-size distribution is used (previously an error) as well as for non-default kinetics.CasadiSolverintegrator failures on DAE models solved without algebraic initial-condition perturbation now include an actionable hint. (#5572)
Bug fixes
- Fixed CasADi conversion of a differentiated
Interpolant, which returned the original function. (#5583) - Fixed the "explicit power" and "explicit resistance" operating modes, which failed to build with a
ModelError. These modes now default "voltage as a state" to "true", which breaks the circular dependency between current and voltage (I = P/V), and raise a clearOptionErrorif it is explicitly disabled. (#5572) - Fixed
latexify()crashing with aNotImplementedErrorfor models whose boundary conditions containboundary_gradientnodes (e.g. DFN with{"surface form": "algebraic"}). (#5572) - Fixed unified experiment crash when the ambient-temperature parameter value is a
pybamm.Scalar. (#5587) - Unified experiment
calculate_sensitivitiesno longer leaks internal control inputs into the parameter Jacobian. (#5587) - Corrected the overflow-clamp threshold in the lithium-ion OCP asymptote helper so the softplus and its linear continuation match exactly. (#5588)
- Fixed unified experiment building redundant control branches and a dense switching-control Jacobian. (#5589)
v26.6.0.0
Breaking changes
- Electrode electronic conductivity supplied as a function must now accept
(stoichiometry, temperature). A constant value is unaffected, but a conductivity function previously written asf(temperature)must be updated tof(stoichiometry, temperature); supplying a temperature-only function now raises a clear error pointing at the new signature. (#5556)
Features
- Electrode electronic conductivity can now be specified as a function of stoichiometry (in addition to temperature) for all lithium-ion and sodium-ion models. (#5556)
- Unified PyBaMM serialisation onto a single safe-or-loud encode/decode kernel. Serialisation now either round-trips or raises
SerialisationError, never silently dropping a field, across the expression tree, discretised models, meshes, solvers, experiments and parameter values. There is one canonical on-disk format, and files saved by older PyBaMM versions continue to load via backward-compatible readers. Note thatsave_model(model, mesh=...)now raises for meshes containing submeshes that cannot round-trip (those without a_from_jsonhook, e.g.Exponential1DSubMesh); previously the save succeeded but the mesh could not be reloaded. Derived caches such asArray.entries_stringare no longer stored on disk and are recomputed from the stored entries on load, so a stale value in a legacy file is replaced by the recomputed one. (#5560, #5561)
Bug fixes
convert_symbol_from_jsonis strict again: raw strings, lists, and dicts without a$type/typetag raiseSerialisationError(restoring pre-kernel validation) instead of being returned unchanged. Constructor-style legacy nodes ({"type": ..., "children": [...]}withoutname/domains) keep decoding via the class constructor, as the pre-kernel reader did. Decoding a node missing a key its codec requires now raises a descriptiveSerialisationErrorinstead of a bareKeyError, andSerialisationErroris importable aspybamm.SerialisationError. (#5567)- Fixed legacy geometry deserialisation over-stripping the
symbol_key prefix as a character set, which raisedKeyErrorfor variable names composed of those characters (e.g. the current-collector variabley). (#5561) - Fixed unified experiment mode using excessive memory and time for experiments with many cycles. (#5554)
- Fixed unified experiment mode inlining every step's equations; switching now dispatches via a
casadi.Function.conditionalswitch. (#5562)
Optimizations
- Fixed two O(N²) slowdowns in long experiment/ageing simulations where
Solution.__add__/copyre-did whole-accumulation work on every step append: time-series validation now re-checks only the joined boundary, andSolution.observableis computed lazily. (#5550) - Experiment/ageing accumulation now folds per-cycle solutions in a single O(N) pass via
Solution.from_sub_solutions, removing the residual O(N²) list concatenation in repeatedSolution.__add__, and fixes an aliasing bug where__add__mutated the left operand's sensitivities. (#5551)
v26.5.0
Breaking changes
Simulation.solvenow always clearsSimulation.solutionbefore solving, so a failed solve leaves it asNonerather than retaining the previous result. (#5528)
Bug fixes
- Fixed
Simulation.solveretaining the prior solution alongside the new one during repeated solves. (#5528) IDAKLUSolverno longer caches redundant serialised function bytes, reducing memory and pickle size. (#5528)
Features
- Default
summary_variablesnow include per-phase LAM%, capacity, total lithium, SEI loss, SEI-on-cracks loss, and lithium plating loss for composite electrodes; aggregate per-electrode entries are unchanged. (#5516) - Added a
store_first_lastkwarg to solvers. WhenTrue, only the first and last sample of each integration window (one experiment step inSimulation.solve, or the full[t_eval[0], t_eval[-1]]window insolve) are stored. Composes withoutput_variablesfor memory-light ageing simulations whose post-processing only reads per-step first/last values. Has effect on solvers that support intra-solve interpolation (IDAKLUSolver); other solvers warn and no-op. Note: with this flag set, intra-step interpolation falls back to linear across the whole step, so it is not appropriate when post-processing queries an intra-step time. (#5499) - Added
NonlinearSolveras the default nonlinear solver, which replacesCasadiAlgebraicSolver.IDAKLUSolvernow computes the initial conditions in C++ by default. (#5459)