Skip to content

feat(rust): evaluate rust models through compiled evaluators - #5960

Open
BradyPlanden wants to merge 1 commit into
stack/04-to-rust-loweringfrom
stack/05-rust-generic-evaluators
Open

BradyPlanden wants to merge 1 commit into
stack/04-to-rust-loweringfrom
stack/05-rust-generic-evaluators

Conversation

@BradyPlanden

Copy link
Copy Markdown
Member

Description

Makes "rust" a valid convert_to_format. A rust model's rhs, algebraic, Jacobian, event and initial-condition functions are compiled to Rust and evaluated by ScipySolver, AlgebraicSolver and EIS. The default stays "casadi".

  • Compilation:
    • BaseSolver.process compiles each function into a CompiledFunction on its own ExprGraph. Inputs are registered in stacking order at their widths (rust_graph_with_inputs).
    • RustEvaluator wraps the compiled function with CasADi's (t, y, inputs) calling convention. It has four roles: the value, the Jacobian (a scipy CSC built on first use), a Jacobian-vector product, and jacp, with one column per sensitivity parameter.
  • Inputs:
    • stack_inputs gains convert_to_format="casadi", and returns a flat numpy array for rust models. Every caller passes the model's format (EIS, inside its rust branch, passes "rust"), and a one-argument call behaves as in v26.10.0.
    • Input-dependent discontinuity times and Modulo periods are evaluated through the model's own compiled functions, with the inputs stacked in its format, as its residual is.
    • An input whose number of values differs from its parameter's width raises pybamm.SolverError naming the input. So does a vector-width input that only a variable reads and that has no value, which before raised a bare ValueError from Rust.
  • Root method: a CasADi root method converts a rust model to CasADi with a warning, as it does any model not in CasADi form; feat(rust): solve rust models with IDAKLUSolver #5962 keeps rust models on rust.
  • Other solvers:
    • IDAKLUSolver, CasadiSolver and CasadiAlgebraicSolver convert rust models to CasADi, with a warning; feat(rust): solve rust models with IDAKLUSolver #5962 adds IDAKLU's Rust path.
    • EIS evaluates the model's Jacobian through Rust. Its output Jacobian is still built with CasADi.
  • Default-path edits: the ScipySolver event wrapper returns np.asarray(...).item(), and EIS calls .sparse() only on CasADi Jacobians, so a python or jax model's Jacobian goes to csc_matrix as it is.
  • Unused here: validate_rust_sensitivity_widths is added in this PR, and feat(rust): solve rust models with IDAKLUSolver #5962 calls it.

Not supported in this PR:

  • return_jacp_stacked raises SolverError, before anything is lowered or compiled.
  • Consistent initialisation's root solve, in NonlinearSolver, still builds its residual with CasADi, so no DAE solver keeps a rust model until feat(rust): solve rust models with IDAKLUSolver #5962.
  • ScipySolver sensitivities raise NotImplementedError, as on main.

Type of change

New feature, under ## Features in CHANGELOG.md.

Key checklist

  • No style issues: pre-commit run
  • Unit tests pass (N), as do the integration tests (N)
  • Tests added: 28 Python test functions.
    • Evaluator parity: each RustEvaluator role against CasADi on a toy DAE (rtol 1e-12, atol 1e-14), including events, initial conditions and a rectangular Jacobian.
    • Plumbing:
      • stack_inputs for rust models, and called with one argument;
      • the input-width SolverError at widths 1 and 3, and for a missing vector input;
      • return_jacp_stacked rejected before lowering;
      • dense-matrix products (TestDenseMatrixToRust) and the conftest_rust fixtures from feat(rust): lower expression trees with Symbol.to_rust #5959, with rust_backend added here;
      • pickled evaluators.
    • ScipySolver: a solve with inputs and an event, on casadi and rust; a rust model with an input-dependent switch time against the exact solution; numpy inputs reaching the evaluators.
    • Solver parity:
      • AlgebraicSolver on rust against casadi (rtol 1e-8);
      • SPM impedance on rust against casadi (rtol 1e-6).
    • Conversion and serialisation: the CasADi solvers convert and solve a rust model; the default root method keeps the rust format; "rust" round-trips through serialisation.
Rust execution engine stack: proposal #5667, showcase #5732

Each PR is one commit on the one above it.

# PR Adds
0 #5954 Function.create_copy keeps the function's class
0b #5955 CasADi's RegPower and uniform-grid interpolant lookups match evaluate
1 #5956 pybamm-core: expression graph, typed IR, interpreters, forward-mode AD
2 #5957 pybamm-core: CompiledModel, coloured Jacobians, the C ABI
3 #5958 pybamm.rust bindings, built into the pybamm wheel
4 #5959 Symbol.to_rust
5 #5960 convert_to_format = "rust" for ScipySolver, AlgebraicSolver and EIS ← this PR
6 #5961 pybammsolvers: IDAKLU over the C ABI
7 #5962 IDAKLUSolver on rust models
8 #5963 variables and sensitivities read in Rust
9 #5964 pybamm-core: diffsol DAE solver
10 #5965 pybamm.DiffsolSolver
11 #5966 "rust" as the default convert_to_format

@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.08197% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.18%. Comparing base (595db2e) to head (d158fdb).

Files with missing lines Patch % Lines
packages/pybamm/src/pybamm/solvers/base_solver.py 91.80% 5 Missing ⚠️
...ges/pybamm/src/pybamm/simulation/eis_simulation.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@                      Coverage Diff                      @@
##           stack/04-to-rust-lowering    #5960      +/-   ##
=============================================================
- Coverage                      98.18%   98.18%   -0.01%     
=============================================================
  Files                            351      353       +2     
  Lines                          36399    36505     +106     
=============================================================
+ Hits                           35738    35841     +103     
- Misses                           661      664       +3     

☔ View full report in Codecov by Harness.
📢 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.

@BradyPlanden
BradyPlanden force-pushed the stack/05-rust-generic-evaluators branch from db04e34 to 45bbd36 Compare October 28, 2026 09:55
@BradyPlanden
BradyPlanden force-pushed the stack/05-rust-generic-evaluators branch 2 times, most recently from 67e6c0a to 3e4986e Compare October 28, 2026 15:28
@BradyPlanden
BradyPlanden force-pushed the stack/05-rust-generic-evaluators branch from 3e4986e to b408f4d Compare October 29, 2026 08:01
@BradyPlanden
BradyPlanden marked this pull request as ready for review October 29, 2026 08:55
@BradyPlanden
BradyPlanden requested a review from a team as a code owner October 29, 2026 08:55
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

ProjectPyBaMM
Branchstack/05-rust-generic-evaluators
Testbedbare-metal

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

🐰 View full continuous benchmarking report in Bencher

"rust" is a valid convert_to_format; BaseSolver.process builds
RustEvaluators; ScipySolver, AlgebraicSolver and EIS run on them.
@BradyPlanden
BradyPlanden force-pushed the stack/05-rust-generic-evaluators branch from b408f4d to d158fdb Compare October 29, 2026 17:26

This branch has not been deployed

No deployments
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.

1 participant