Repository navigation
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5804 +/- ##
=======================================
Coverage 98.00% 98.00%
=======================================
Files 346 346
Lines 35259 35280 +21
=======================================
+ Hits 34554 34575 +21
Misses 705 705 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
thanks @mleot, can you also check if this still works with serialising the interpolant (packages/pybamm/src/pybamm/expression_tree/operations/serialise.py:105), and diffsl conversion of the interpolant (packages/pybamm/src/pybamm/expression_tree/operations/diffsl.py:1280)?
The heat of mixing takes dU/dc, so it failed with any tabulated OCP or entropic change (pybamm-team#5798, pybamm-team#5799). Cubic: scipy's `BSpline.derivative()` keeps a coefficient array longer than the spline's basis (52 coefficients for 49 basis functions from 50 points) and ignores the tail. `_cubic_to_casadi` passed the whole array, which evaluates, but CasADi's own derivative of the spline, which the solver's Jacobian needs, rejects it: "reshape: number of elements must remain the same". Pass only the basis coefficients. Values are unchanged. Linear: `interp1d` has no `.derivative()`, so `.diff` raised. Build the derivative as the equivalent degree-1 spline differentiated once, and convert it to CasADi as a lookup of each interval's slope, as the pchip conversion looks up its coefficients. Higher derivatives are zero. Tests: CasADi's Jacobian of a differentiated interpolant must match the second derivative (the pybamm-team#5582 tests compared values only); linear derivatives are the interval slopes, at knots and when extrapolating; and the heat of mixing with a 201-point OCP table matches the analytic OCP to 1e-2 (linear), 1e-3 (pchip) and 1e-4 (cubic) for SPM and DFN. Nine unit and four integration cases fail without the fix. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…source ExpressionFunctionParameter.to_source wrote the Interpolant constructor without _num_derivatives, so the source evaluated the interpolant itself rather than its derivative. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
interp1d interpolates the table values, so the export silently gave the interpolant itself instead of its derivative. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8bcae57 to
3ddb73a
Compare
|
Thanks @martinjrobins, good call on both of these. For serialisation, the JSON round trip was already fine, but DiffSL was silently wrong too. I also rebased onto main. Brady's #5955 changed the CasADi interpolants to find which interval a point is in by binary search, since the old shortcut could pick the wrong interval right at a knot, so I updated the new linear derivative to do the same. I think it's ready for another look when you get the chance. |
Description
Fixes #5798
Fixes #5799
A differentiated 1D
Interpolantnow works in the solvers for every interpolator. Theheat of mixing differentiates the OCP, so
"heat of mixing": "true"failed with anytabulated OCP or entropic change: a
"cubic"table crashed at solve time and a"linear"one (the default interpolator) at build time.Ai2020as shipped hit thecubic case.
Cubic (#5798). scipy's
BSpline.derivative()keeps a coefficient array longer thanthe spline's basis (52 coefficients for 49 basis functions, from 50 points) and ignores
the tail.
_cubic_to_casadipassed the whole array. CasADi evaluates that, but its ownderivative of the spline, which the solver's Jacobian needs, rejects it:
The #5582 tests compare values only, so they passed. Only the basis coefficients are
now passed; values are unchanged.
Linear (#5799).
interp1dhas no.derivative(), so.diffraisedAttributeError. The derivative is now the equivalent degree-1 spline differentiatedonce (the slope of the interval containing the point, right-continuous at knots, the end
intervals' slope when extrapolating), converted to CasADi as a slope lookup in the same
way as the pchip conversion looks up its coefficients. Higher derivatives are zero.
Unchanged: every interpolant value and derivative that worked before is
bit-identical in CasADi inside the data range; undifferentiated linear interpolants
still use
interp1dandinterpn_linear.With a 201-point table of Chen2020's graphite OCP, the heat of mixing now matches the
analytic OCP's to 1e-3 (linear), 1e-4 (pchip) and 3e-6 (cubic), for SPM and DFN.
Not addressed here: a cubic
Interpolant's CasADi conversion is zero outside itsdata range (scipy extrapolates), for values as well as derivatives. That predates this
PR and will get its own issue.
Type of change
Bug fix: an entry under
## Bug fixesinCHANGELOG.md.Important checks:
No style issues:
nox -s pre-commit(every hook passes on the branch diff)All tests pass:
nox -s tests(locally 4558 unit, 515 integration and 63pybammsolverstests pass on this branch)The documentation builds:
nox -s doctests(not run; no docs changed)Code is commented for hard-to-understand areas
Tests added that prove fix is effective or that feature works:
for linear, cubic and pchip on uniform and non-uniform grids
when extrapolating, for vector data, and its second derivative is zero
OCP for SPM and DFN
Nine unit and four integration cases fail without the fix.
🤖 Generated with Claude Code