Skip to content

fix: include SEI film resistive loss in irreversible heating - #5841

Open
shaurya20335 wants to merge 9 commits into
pybamm-team:mainfrom
shaurya20335:fix-sei-film-heating
Open

shaurya20335 wants to merge 9 commits into
pybamm-team:mainfrom
shaurya20335:fix-sei-film-heating

Conversation

@shaurya20335

@shaurya20335 shaurya20335 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #5820.

With "SEI film resistance" set to "distributed" or "average", BaseKinetics adds the film drop eta_sei = -j * L_sei * R_sei to the reaction overpotential, so eta_r = delta_phi - U + eta_sei. This lowers the terminal voltage, but BaseThermal computed irreversible heating as a_j * eta_r, which leaves the film drop out. The energy lost across the film therefore never appeared in Total heating [W] or in the cell temperature.

Irreversible heating now uses a_j * (eta_r - eta_sei), the full departure of delta_phi from the open-circuit potential, for both electrodes, every particle phase, and the planar lithium metal electrode in half cells. eta_sei is read from the existing "... SEI film overpotential [V]" variables, which are zero when the film resistance is off, so nothing changes for models without it.

Energy check (OKane2022, 5 A for 1800 s, lumped thermal with the temperature held at ambient by a large heat transfer coefficient, 50 nm film, extra quantities relative to "SEI film resistance": "none"):

model film resistance extra electrical loss extra heat on main extra heat with this PR
SPM distributed 133.94 J 0.00 J 133.94 J
SPMe distributed 133.94 J 0.00 J 133.94 J
SPMe average 133.94 J 0.00 J 133.94 J
DFN distributed 137.36 J 1.35 J 137.56 J
SPMe half cell (Xu2019, 1C, 1200 s) distributed 0.4853 J 0.0000 J 0.4853 J

In the DFN the film also changes the current distribution, which shifts the other heat terms slightly (the 1.35 J on main and the 0.2 J residual with this PR).

With a particle-size distribution (MPM, or SPMe and DFN with "particle size": "distribution"), eta_sei has a particle-size domain. It is now size-averaged in BaseInterface._get_standard_sei_film_overpotential_variables, as eta_r already is, so these models build with a thermal model. There the balance closes to 0.16% for MPM and 0.7% for DFN with a size distribution; models without a distribution are unchanged by the size average.

Side reactions (SEI growth, plating) carry their own share of the interfacial current through the film. Their heat is not included in BaseThermal today, so I have left that out of scope here.

Type of change

Bug fix, with an entry under ## Bug fixes in CHANGELOG.md.

Important checks:

  • No style issues: ruff 0.16.10 format and check, and comment-slop, pass on the changed files
  • Tests added that prove fix is effective: TestThermal.test_sei_film_heating (integration) checks that the extra heat equals the extra electrical loss for SPMe (distributed and average), DFN, MPM and an SPMe half cell. The non-MPM cases fail on main; the MPM case fails without the size average, with the DomainError from the review.
  • All tests pass: the full unit suite (4,848 passed, 89 skipped) and the doctests (71 passed) pass locally on macOS with Python 3.12, as do the lithium-ion unit tests, the submodel unit tests and the thermal and MPM integration tests (724 passed). I am relying on CI for the rest of the integration tests, the notebooks and example scripts, and the other platforms.
  • The documentation builds: not run locally, no docs changes
  • Code is commented for hard-to-understand areas

With "SEI film resistance" on, the voltage drop across the film is added to the
reaction overpotential eta_r, which lowers the terminal voltage. The thermal
model computed irreversible heating as a*j*eta_r, so the energy lost across the
film never appeared in "Total heating [W]" or the cell temperature.

Use a*j*(eta_r - eta_sei), i.e. the full departure from the open-circuit
potential, for both electrodes, every particle phase, and the planar lithium
metal electrode. Add an energy-balance test: at fixed temperature, the extra
heat from switching on the film resistance equals the extra electrical loss.

Fixes pybamm-team#5820

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shaurya20335
shaurya20335 requested a review from a team as a code owner October 5, 2026 01:54
shaurya20335 and others added 4 commits October 4, 2026 21:54
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@rtimms rtimms left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the physics and signs check out: forward and inverse kinetics both give eta_r − eta_sei = delta_phi − U, and I confirmed the energy balance for composite (DFN, Chen2020_composite), half-cell and SPM inverse-kinetics paths.

One regression to fix before merge: with "particle size": "distribution" (MPM, or DFN with that option), a non-isothermal model and "SEI film resistance": "distributed", building the model now raises DomainError: children must have same or empty domains, not ['positive particle size'] and ['positive electrode']. eta_sei keeps its particle-size domain there. Size-averaging it in BaseInterface._get_standard_sei_film_overpotential_variables, as _get_standard_overpotential_variables already does for eta_r, fixes it:

if eta_sei.domain and eta_sei.domain[0].endswith("particle size"):
    eta_sei = pybamm.size_average(eta_sei)

Could you add an MPM case to test_sei_film_heating too? Minor: the "which eta_r excludes" comment reads oddly, since eta_r contains eta_sei. Maybe "eta_r is the kinetic overpotential net of the film drop".

Side-reaction heat (SEI growth, plating) will follow in a separate PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shaurya20335

Copy link
Copy Markdown
Contributor Author

Thanks for checking the signs and the energy balance across all those paths, @rtimms. I have pushed the changes:

  1. eta_sei is now size-averaged in BaseInterface._get_standard_sei_film_overpotential_variables, as you suggested. MPM, and DFN with "particle size": "distribution", now build and solve with a lumped thermal model and "SEI film resistance": "distributed".
  2. test_sei_film_heating has an MPM case. Without the size average it fails with the DomainError you saw.
  3. The comment now reads "eta_r is the kinetic overpotential net of the film drop, so eta_r - eta_sei adds the resistive loss in the SEI film".

The regression was a bit wider than the MPM case: it also hit SPMe and DFN with a size distribution, and isothermal models with "calculate heat source for isothermal models": "true". The size average fixes all of them. Models without a size distribution give bit-identical results before and after this change. With the fix, the energy balance closes to 0.16% for MPM and 0.7% for DFN with a size distribution.

Side note, not touched here: "SEI film resistance": "average" with a particle-size distribution (SPMe or DFN) fails to build on main too, with a DomainError at eta_r += eta_sei in base_kinetics.py.

@rtimms

rtimms commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Thanks, all three changes look good. I checked this together with #5892 and #5875: every size-distribution model builds (SPMe, DFN and MPM, with no, average or distributed film, constant or growing SEI). With #5892's fix, the energy balance also closes for the "average" film with a size distribution (extra heat vs extra electrical loss: 0.13% for SPMe, 0.01% for DFN).

Heads-up on #5818, which deprecates relying on options set from other options (the test suite turns that warning into an error): test_sei_film_heating will then fail, because "SEI film resistance": "distributed" sets "total interfacial current density as a state": "true" by default. Whichever of this PR and #5818 merges second needs to pass that option explicitly in the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shaurya20335

Copy link
Copy Markdown
Contributor Author

Thanks for checking it together with #5892 and #5875, @rtimms. I have already made test_sei_film_heating pass "total interfacial current density as a state" explicitly ("true" for the distributed film, "false" otherwise), so it should work whichever order this and #5818 merge in.

@rtimms

rtimms commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

@shaurya20335 heads-up on how this fits with #5875. #5875 was built on top of this PR, so its base_interface.py size-average and the eta_r - eta_sei changes in base_thermal.py are the same lines as here. I merged both onto main and they combine without conflicts.

Plan: this lands first, then I'll rebase #5875 on it so that PR only adds the side-reaction heat (SEI growth and lithium plating) on top. Nothing to change here for that. Please merge main to clear the CHANGELOG.md conflict, and keep your entry under # [Unreleased].

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SEI film resistance loss is not included in heat generation

2 participants