You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(basic_dfn.py, lines 230-233 at 258fdc8), with a purely diffusive flux N_e. That form is equivalent to the conservative cation balance only when t_plus is constant. With t_plus = t_plus(c_e) the conservative form is
and expanding the divergence gives the BasicDFN form plus an extra -i_e * d(t_plus)/dx / F, which BasicDFN omits. Integrating the BasicDFN equation together with the particle equations over the cell gives
dN/dt = -A * integral( t_plus(c_e) * a_j / F ) dx
which is not zero when t_plus varies in x. The modular Full electrolyte submodel keeps t_plus * i_e / F inside the flux (full_diffusion.py, lines 72-76 and 99), which is why the full DFN conserves lithium with the same parameters. #2666 / #2758 fixed exactly this for the modular submodel in 2023; the Basic* models were not part of that change.
Observed (ORegan2022, which has a concentration-dependent t_plus; negative particle diffusivity 3.3e-14; the protocol from #5700; initial SOC 0.45; 20 cells per x-domain, 20 radial shells; IDAKLUSolver(rtol=atol=1e-8)):
Case
max abs(N - N0) / N0
BasicDFN, variable t_plus
2.44e-2
BasicDFN, t_plus fixed at its initial value
1.9e-14
DFN(), same parameters
1.4e-14
The drift is insensitive to tolerance and mesh: max abs(N - N0) is 6.518e-3 mol at 20/20 for rtol=atol=1e-6, 1e-8 and 1e-10, 6.516e-3 mol at 40/40 and 6.5155e-3 mol at 80/80 (1e-10). Time-integration error is not the explanation, and refinement does not remove it.
The measured change in N matches the time integral of -A * integral(t_plus * a_j / F) dx from the solution to 1.2e-6 mol out of 6.5e-3 mol (5 s trapezoid).
Because the constant-t_plus case conserves to round-off with the same node-evaluated source term, this is separate from the finite-volume source-term discretisation question raised in [Bug]: Half-cell and custom models do not conserve lithium #5700. It is a property of the reduced equation, not of how a_j is evaluated on nodes, and a boundary-condition change alone does not remove it (PR Flux boundary conditions in 1D finite volume #5524 leaves the BasicDFN time series byte-identical to main; the model declares no "Flux" boundary condition).
The same reduced form appears in BasicDFN2D (basic_dfn_2d.py line 302), BasicDFNHalfCell (basic_dfn_half_cell.py line 197) and BasicDFNComposite (basic_dfn_composite.py line 323) at 258fdc8. The BasicDFN2D drift @SarahRo reported in #5700 is consistent with this. I have only measured the 1D BasicDFN.
Two reasonable resolutions, and the current state is neither:
State in the Basic* docstrings that they assume a constant t_plus, and warn or raise when a function is supplied. The current docstring cites Marquis 2019 and says nothing about t_plus, and ORegan2022 is accepted silently.
Steps to Reproduce
Run against main 258fdc8; the two lines under "Relevant log output" are what it printed.
importpybammexperiment=pybamm.Experiment([
"Rest for 10 minutes (5 seconds period)",
"Discharge at 1C for 20 minutes (5 seconds period)",
"Rest for 10 minutes (5 seconds period)",
"Charge at 1C for 20 minutes (5 seconds period)",
"Rest for 20 minutes (5 seconds period)",
])
forconstant_t_plusin [False, True]:
model=pybamm.lithium_ion.BasicDFN()
pv=pybamm.ParameterValues("ORegan2022")
pv["Negative particle diffusivity [m2.s-1]"] =3.3e-14ifconstant_t_plus:
pv["Cation transference number"] =pv["Cation transference number"](
pv["Initial concentration in electrolyte [mol.m-3]"], pv["Ambient temperature [K]"]
)
# lithium per unit area, mol/m2 (BasicDFN has no built-in "Total lithium [mol]")n=0fordom, epsin [("Negative", "Negative electrode porosity"),
("Separator", "Separator porosity"),
("Positive", "Positive electrode porosity")]:
thick="Separator thickness [m]"ifdom=="Separator"elsef"{dom} electrode thickness [m]"n+=pybamm.x_average(model.variables[f"{dom} electrolyte concentration [mol.m-3]"]
*pybamm.Parameter(eps)) *pybamm.Parameter(thick)
fordomin ["Negative", "Positive"]:
n+=pybamm.x_average(pybamm.Parameter(f"{dom} electrode active material volume fraction")
*pybamm.r_average(model.variables[f"{dom} particle concentration [mol.m-3]"])) \
*pybamm.Parameter(f"{dom} electrode thickness [m]")
model.variables["Lithium per area [mol.m-2]"] =nsim=pybamm.Simulation(model, parameter_values=pv, experiment=experiment,
solver=pybamm.IDAKLUSolver(rtol=1e-8, atol=1e-8),
var_pts={"x_n": 20, "x_s": 20, "x_p": 20, "r_n": 20, "r_p": 20})
sol=sim.solve(initial_soc=0.45)
li=sol["Lithium per area [mol.m-2]"].entriesprint(f"constant t+ = {constant_t_plus}: max |N - N0| / N0 = {abs(li-li[0]).max() /li[0]:.3e}")
PyBaMM Version
main at
258fdc8(2026-09-05); also reproduced on v26.4.1 (d9e5afb) and the PR #5524 head (719763b)Python Version
3.12.13
Describe the bug
Split out from #5700 at @NicolaCourtier's suggestion.
BasicDFNwrites the electrolyte balance as(
basic_dfn.py, lines 230-233 at258fdc8), with a purely diffusive fluxN_e. That form is equivalent to the conservative cation balance only whent_plusis constant. Witht_plus = t_plus(c_e)the conservative form isand expanding the divergence gives the
BasicDFNform plus an extra-i_e * d(t_plus)/dx / F, whichBasicDFNomits. Integrating theBasicDFNequation together with the particle equations over the cell giveswhich is not zero when
t_plusvaries in x. The modularFullelectrolyte submodel keepst_plus * i_e / Finside the flux (full_diffusion.py, lines 72-76 and 99), which is why the fullDFNconserves lithium with the same parameters. #2666 / #2758 fixed exactly this for the modular submodel in 2023; theBasic*models were not part of that change.Observed (ORegan2022, which has a concentration-dependent
t_plus; negative particle diffusivity 3.3e-14; the protocol from #5700; initial SOC 0.45; 20 cells per x-domain, 20 radial shells;IDAKLUSolver(rtol=atol=1e-8)):BasicDFN, variablet_plusBasicDFN,t_plusfixed at its initial valueDFN(), same parameters-A * integral(t_plus * a_j / F) dxfrom the solution to 1.2e-6 mol out of 6.5e-3 mol (5 s trapezoid).t_pluscase conserves to round-off with the same node-evaluated source term, this is separate from the finite-volume source-term discretisation question raised in [Bug]: Half-cell and custom models do not conserve lithium #5700. It is a property of the reduced equation, not of howa_jis evaluated on nodes, and a boundary-condition change alone does not remove it (PR Flux boundary conditions in 1D finite volume #5524 leaves theBasicDFNtime series byte-identical to main; the model declares no"Flux"boundary condition).The same reduced form appears in
BasicDFN2D(basic_dfn_2d.pyline 302),BasicDFNHalfCell(basic_dfn_half_cell.pyline 197) andBasicDFNComposite(basic_dfn_composite.pyline 323) at258fdc8. TheBasicDFN2Ddrift @SarahRo reported in #5700 is consistent with this. I have only measured the 1DBasicDFN.Two reasonable resolutions, and the current state is neither:
t_plus * i_e / FinsideN_ein theBasic*models, asfull_diffusion.pydoes. Electrolyte concentration not conserved if surface form is algebraic #2551 records thatdiv(t_plus * i_e)once hit a concatenation problem in one configuration; I have not tested whether that applies here.Basic*docstrings that they assume a constantt_plus, and warn or raise when a function is supplied. The current docstring cites Marquis 2019 and says nothing aboutt_plus, andORegan2022is accepted silently.Steps to Reproduce
Run against main
258fdc8; the two lines under "Relevant log output" are what it printed.The refinement table and the comparison with
DFN()come from a direct finite-volume sum over cell volumes rather thanx_average; code and per-run outputs are in the package linked from #5700 (https://github.com/repowazdogz-droid/pybamm-5700-lithium-inventory, commitadaa877).Relevant log output