Repository navigation
refactor: read solution variables through per-model observer caches - #5786
Conversation
b51c7e3 to
d5324bd
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5786 +/- ##
==========================================
+ Coverage 98.09% 98.11% +0.01%
==========================================
Files 346 348 +2
Lines 35407 35610 +203
==========================================
+ Hits 34733 34939 +206
+ Misses 674 671 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
48c7baa to
a97b0be
Compare
a97b0be to
a5afbe0
Compare
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
a5afbe0 to
1bdfb89
Compare
|
| Project | PyBaMM |
| Branch | a4/observation-seam |
| Testbed | bare-metal |
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
1bdfb89 to
01f0a91
Compare
01f0a91 to
405fe19
Compare
405fe19 to
3e30544
Compare
rtimms
left a comment
There was a problem hiding this comment.
The refactor matches the code it replaces as far as I can trace: build_variable against _update_variable, CasadiObserver against the old observe/sensitivity paths, and OutputAssembly.attach against the old IDAKLU loop. Caching time integrals per model is safe because ProcessedVariableTimeIntegral holds only model-level data. The deprecation shim and old-pickle loading are tested. Two minor points inline.
3e30544 to
dfc15bc
Compare
dfc15bc to
cb4ea47
Compare
A Solution reads variables through one ObservationBackend and a ProcessedVariable through one VariableObserver (CasADi only); OutputAssembly owns the output_variables layout and keys its sensitivities by sensitivity parameter. Solution carries its backend in an _observation slot, which a solution pickled before it existed loads as CASADI_OBSERVATION.
A Solution carried an observation backend, the module-level CASADI_OBSERVATION, which first_state, last_state, +, from_sub_solutions and copy sliced and joined. The backend held no state, so every slice and join returned it unchanged, while the CasADi leaves it compiled were cached on each model. A Solution now holds no observation state. build_variable reads each segment through its own model's ObserverCache, which replaces model._variables_casadi and keeps its rules: keyed by variable name, copied by new_copy, and skipping time integrals. A model pickled before the cache existed builds one on first read. ObservationBackend, CasadiObservation, CASADI_OBSERVATION and join_observations are removed with their tests.
ObserverCache skipped time integrals: it cached only the CasADi leaf, so a hit lost the integral and would have read its integrand. Every read of a time integral therefore converted it again for each segment, 20 times for a 20-step experiment, and again for every solve of the model. The cache now keeps a leaf with the expression it evaluates and its time integral. The integral's analysis depends only on its expression, and nothing changes it after conversion, so solutions of one model can share it. Reading an ExplicitTimeIntegral from a 20-step experiment drops from 1.9 ms to 0.6 ms on first read and from 1.5 ms to 0.01 ms on later solves of the model, with identical values.
Each changelog entry is now one line, leaving the detail to the PR, and the performance entry moves from Features to Optimizations. Eight two-line comments become one line, and four that restated the code they moved with are removed. VariableObserver holds its leaves rather than owning them: the model's ObserverCache shares them.
The solver returns no rows for such a variable, so its payload is (n_t, 0). Covers it as the only output and alongside a regular one.
cb4ea47 to
2d1f76d
Compare
Description
Reading a variable back from a
Solutionwas spread acrossSolution,ProcessedVariableandIDAKLUSolver, each re-deriving the same facts. This gathers it into two modules, with identical values:solvers/variable_observer.py:VariableObserverandCasadiObserver, moved fromProcessedVariable. An observer serialises its CasADi functions and selects its segments once, so a repeatsolution["Voltage [V]"](t)on an SPMe discharge is about 40% faster.solvers/observation.py:build_variable, which reads each segment through its own model'sObserverCache(replacingmodel._variables_casadi), andOutputAssembly, moved fromIDAKLUSolver. ASolutionholds no observation state.ProcessedVariable'sbase_variables_casadiis deprecated, and solutions pickled by earlier versions still load. The Rust path (#5732) will add a second reader tobuild_variable.Type of change
Add an entry under
# [Unreleased]in CHANGELOG.md, in one of## Breaking changes,## Deprecated,## Features, or## Bug fixes(include PR number; breaking and deprecation entries need a one-line migration note). Internal-only PRs — refactor, docs, CI, tests — can skip this. See RELEASE.md for the full policy.Important checks:
Please confirm the following before marking the PR as ready for review:
nox -s pre-commitnox -s testsnox -s doctests