Make LAM/crack degradation submodels well-posed under 1+1D current collectors (#5296) - #5543
Open
gaoflow wants to merge 1 commit into
Open
Make LAM/crack degradation submodels well-posed under 1+1D current collectors (#5296)#5543gaoflow wants to merge 1 commit into
gaoflow wants to merge 1 commit into
Conversation
gaoflow
force-pushed
the
fix/lam-lli-yz-average-dimensionality-1
branch
2 times, most recently
from
June 9, 2026 11:09
1c34da3 to
d67aaec
Compare
gaoflow
force-pushed
the
fix/lam-lli-yz-average-dimensionality-1
branch
from
June 12, 2026 15:22
d67aaec to
5f32880
Compare
…llectors (pybamm-team#5296) Fixes pybamm-team#5296. Discretising any `lithium_ion` model with `"dimensionality": 1` plus the degradation stack (`"loss of active material": "stress-driven"`, `"particle mechanics": "swelling and cracking"`, etc.) failed with:: ModelError: rhs and initial conditions must have the same shape after discretisation but rhs.shape = (10, 1) and initial_conditions.shape = (1, 1) for variable 'Loss of lithium due to loss of active material in negative electrode [mol]'. Two independent shape gaps were responsible, both activated only when the current-collector mesh has more than one node. 1. `submodels/active_material/loss_active_material.py:192` — the LAM loss-of-lithium accumulator is declared as a scalar (`pybamm.Variable(...)` with no domain, IC `pybamm.Scalar(0)`). Its rhs was `-V * pybamm.x_average(c_s_rav * deps_solid_dt)` which averages through the cell thickness but keeps the current-collector axis, so the rhs shape was `(z_n, 1)` while the IC was `(1, 1)`. The fix wraps the existing `x_average` in `pybamm.yz_average`, collapsing to a scalar on 1-D current collectors (the identity operation) and to a true scalar on 1+1D and 2+1D current collectors. Total lithium loss is preserved because `V = L * A_cc` already carries `L_y * L_z`. 2. `submodels/particle_mechanics/crack_propagation.py:175` — for DFN (`x_average is False`) the crack-length state is declared `pybamm.Variable(..., domain="<dom> electrode", auxiliary_domains={"secondary": "current collector"})`, but its IC was `pybamm.PrimaryBroadcast(l_cr_0, "<dom> electrode")` which only broadcasts across the electrode mesh. Under `"dimensionality": 1` the rhs is `(x_n, z_n)` while the IC is `(x_n, 1)`. Switching to `pybamm.FullBroadcast(l_cr_0, "<dom> electrode", "current collector")` makes the IC span both axes; `FullBroadcast` is the identity on a 0-D current collector, so no existing model changes shape. Verified end-to-end against the exact reproducer from the issue (SPMe + OKane2022 + dimensionality=1 + full degradation stack) and the equivalent DFN/SPM configurations, all of which now build, discretise and solve. The 0-D model fleet (SPM/SPMe/DFN on OKane2022 with stress- driven LAM and cracking) produces `Loss of lithium due to LAM` totals indistinguishable from main within solver tolerance. The 637-test lithium-ion unit suite passes (+4 new regression tests). Regression coverage is in `tests/unit/test_models/test_full_battery_models/test_lithium_ion/test_lam_lli_dimensionality_5296.py` and pins (a) the issue reproducer for SPMe and DFN, (b) a direct rhs-vs-IC shape guard after `Discretisation`, and (c) the 0-D non-regression.
gaoflow
force-pushed
the
fix/lam-lli-yz-average-dimensionality-1
branch
from
June 18, 2026 22:20
5f32880 to
4fb5a7e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #5296.
Discretising any
lithium_ionmodel with"dimensionality": 1plus the degradation stack ("loss of active material": "stress-driven","particle mechanics": "swelling and cracking", …) fails withTwo independent shape gaps are responsible, both activated only when the current-collector mesh has more than one node.
Root cause
(a)
submodels/active_material/loss_active_material.py:192— the LAM loss-of-lithium accumulator is declared as a scalar (pybamm.Variable(...)with no domain, ICpybamm.Scalar(0)). Its rhs wasx_averageaverages through the cell thickness but keeps the current-collector axis. For"dimensionality": 1the rhs is(z_n, 1)while the IC is(1, 1).(b)
submodels/particle_mechanics/crack_propagation.py:175— for DFN (x_average is False) the crack-length state is declaredbut its IC was
pybamm.PrimaryBroadcast(l_cr_0, "<dom> electrode"), which only broadcasts across the electrode mesh. Under"dimensionality": 1the rhs is(x_n, z_n)while the IC is(x_n, 1). PyBaMM's discretisation check raises:The SPMe reproducer in the issue hits (a) first; DFN with the same options additionally hits (b).
Fix
Two surgical changes.
loss_active_material.py:192wrap the existingx_averageinpybamm.yz_averageso the rhs collapses to a scalar in 1+1D and 2+1D current collectors.yz_averageis the identity on 0-D current collectors, so 0-D models are unaffected. Total lithium loss is preserved becauseV = L * A_ccalready carriesL_y * L_z(seeinterface/lithium_plating/base_plating.py:87andinterface/sei/base_sei.py:132for the same pattern on plating and SEI accumulators).crack_propagation.py:175replacePrimaryBroadcast(l_cr_0, "<dom> electrode")withFullBroadcast(l_cr_0, "<dom> electrode", "current collector")so the IC spans both the electrode and the current-collector mesh.FullBroadcastis the identity on 0-D current collectors.Reproducer
Exact options from the issue (only the
Simulation.solvet_evalwas shortened to[0, 600]to keep CI fast):Verification
Loss of lithium due to loss of active material in negative electrode [mol]evolves to ~3.0e-7 mol after 600 s.LLI_LAM_n[-1]matches SPMe within solver tolerance: ~3.0e-7 mol).main(~3.0e-7 mol after 600 s).pytest tests/unit/test_models/test_full_battery_models/test_lithium_ion/— 637 passed, 12 skipped (+4 new regression tests).ruff check+ruff format --checkclean.Regression test
New
tests/unit/test_models/test_full_battery_models/test_lithium_ion/test_lam_lli_dimensionality_5296.pypins four guards:dimensionality=1+ full degradation stack discretises and solves (locks fix (a)).Discretisationevery LAM-LLI variable's rhs must match its IC shape (catches future regressions in either direction).dimensionality=1+ full degradation stack discretises and solves (locks fix (b)).Checklist