Skip to content

Conversation

@MarcBerliner
Copy link
Member

@MarcBerliner MarcBerliner commented Dec 5, 2025

Description

Adds preliminary ability to lazily evaluate custom pybamm expressions after solving the simulation. E.g.,

import pybamm

sim = pybamm.Simulation(pybamm.lithium_ion.SPM())

sol = sim.solve([0, 1000])

soc = pybamm.Variable("Discharge capacity [A.h]") / pybamm.Parameter("Nominal cell capacity [A.h]")

sol.observe(soc)
# <pybamm.solvers.processed_variable.ProcessedVariable0D at 0x104606c90>

This currently only supports 0D variables. It's not straightforward to support variables with meshes because only their discretized version is available at solution time. To support lazy observation of general variables (including the non-state variables), we would need to ensure that the original, non-discretized model.variables is not replaced with a discretized version.

Type of change

Please add a line in the relevant section of CHANGELOG.md to document the change (include PR #)

Important checks:

Please confirm the following before marking the PR as ready for review:

  • No style issues: nox -s pre-commit
  • All tests pass: nox -s tests
  • The documentation builds: nox -s doctests
  • Code is commented for hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

agriyakhetarpal and others added 30 commits November 13, 2025 09:12
* Fix typo in concentration description in notebook

* Add CHANGELOG.md entry for typo fix

* Remove unneccesary changelog entry

Co-authored-by: Agriya Khetarpal <[email protected]>

---------

Co-authored-by: Agriya Khetarpal <[email protected]>
* fix `InputParameter` serialisation

* Update CHANGELOG.md
…-fix

Don't be too strict with func_args longer than symbol.children
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* feat: add`silence_sundial_warnings` solver option

* refactor: `silence_sundials_warnings` -> `silence_sundials_errors`
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* raise `SolverError` at failure to init sundials

* Update simulation.py

* Update idaklu_solver.py

* reuse `pybammsolvers` error messages

* Update test_idaklu_solver.py

* bump `pybammsolvers`

* Update CHANGELOG.md

* Update CHANGELOG.md

Update CHANGELOG.md
@@ -0,0 +1,248 @@
import pybamm
Copy link
Member Author

@MarcBerliner MarcBerliner Dec 5, 2025

Choose a reason for hiding this comment

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

@MarcBerliner MarcBerliner changed the title Observe 0D custom variables post-solving Observe 0D custom variables after solving Dec 5, 2025
@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 93.23308% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.69%. Comparing base (df53205) to head (9844e0e).

Files with missing lines Patch % Lines
src/pybamm/expression_tree/operations/serialise.py 68.75% 10 Missing ⚠️
...bamm/expression_tree/operations/replace_symbols.py 95.04% 5 Missing ⚠️
src/pybamm/expression_tree/symbol.py 50.00% 1 Missing ⚠️
src/pybamm/models/base_model.py 92.30% 1 Missing ⚠️
src/pybamm/solvers/solution.py 98.87% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #5308      +/-   ##
===========================================
- Coverage    98.77%   98.69%   -0.09%     
===========================================
  Files          321      322       +1     
  Lines        27746    27947     +201     
===========================================
+ Hits         27406    27582     +176     
- Misses         340      365      +25     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MarcBerliner MarcBerliner marked this pull request as ready for review December 5, 2025 22:19
@MarcBerliner MarcBerliner requested a review from a team as a code owner December 5, 2025 22:19
Copy link
Member

@valentinsulzer valentinsulzer left a comment

Choose a reason for hiding this comment

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

I don't like the idea of adding the parameter values as an argument to the model, could we find a different way of doing this, e.g.

  1. pass parameter values to solution
  2. create a "parameterized model" type which is model + parameter values (as created by the simulation) and pass that to the solution in the all_models argument

2 is my preferred solution but it is a bigger change

Comment on lines +438 to +444
"parameter_values": (
Serialise._serialise_parameter_values(
getattr(model, "_parameter_values", None)
)
if getattr(model, "_parameter_values", None) is not None
else None
),
Copy link
Member

Choose a reason for hiding this comment

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

I don't think adding parameter values as an attribute to the model is the right pattern, I could see this causing some bugs. It would be better to have a "parameterized model" object which is model + parameter values.

Copy link
Member

Choose a reason for hiding this comment

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

Is this just here so we can access parameter values when processing a variable in observe? In that case could the parameter values be an optional argument of Solution instead (and throw an error in observe if not provided)?

return d

@staticmethod
def _serialise_parameter_values(
Copy link
Member

Choose a reason for hiding this comment

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

why not use ParameterValues.to_json() ?

@MarcBerliner
Copy link
Member Author

I don't like the idea of adding the parameter values as an argument to the model, could we find a different way of doing this, e.g.

1. pass parameter values to solution

2. create a "parameterized model" type which is model + parameter values (as created by the simulation) and pass that to the solution in the all_models argument

2 is my preferred solution but it is a bigger change

@valentinsulzer the reason I attached parameter_values to the model is because I believe this is the only way to make it work with the solver.solve(built_model, t_eval, ...) interface, since the parameter values are inaccessible after the model is built. We could streamline this if we chose to only make it available via the Simulation solve interface

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.

10 participants