Skip to content

Single model for experiment#5422

Open
martinjrobins wants to merge 34 commits intomainfrom
single-model-for-experiment
Open

Single model for experiment#5422
martinjrobins wants to merge 34 commits intomainfrom
single-model-for-experiment

Conversation

@martinjrobins
Copy link
Contributor

@martinjrobins martinjrobins commented Mar 21, 2026

Description

fixes #5407

This PR adds a unified experiment-model path that reuses one processed model and one solver across compatible experiment steps, instead of building one model per step.

The unified path combines per-step control and termination behavior into shared experiment-wide expressions, and switches the active step through solve-time one-hot inputs.

For step weights $w_i$, step control residuals $g_i(x)$, and step-local termination aggregates $h_i(x)$, the unified model uses:

$$ \sum_i w_i g_i(x) = 0 $$

and

$$ \sum_i w_i h_i(x) = 0 $$

where exactly one $w_i$ is active for each solve step.
UPDATE: the sum over one-hot weights has been replaced by a conditional expression over a single "step index" input, see discussion below

Examples of the control residuals include:

$$ g_i(x) = \begin{cases} I - I_{\mathrm{set}} & \text{current step} \\ V - V_{\mathrm{set}} & \text{voltage step} \\ VI - P_{\mathrm{set}} & \text{power step} \\ V - R_{\mathrm{set}} I & \text{resistance step} \end{cases} $$

For steps with multiple terminations $f_{ij}(x)$, the step-local aggregate is formed as a nested minimum so that any active termination can stop the step:

$$ h_i(x) = \min_j f_{ij}(x) $$

The legacy per-step build remains available, and Simulation now supports:

  • experiment_model_mode="unified"
  • experiment_model_mode="legacy" (default)

Unsupported cases raise clearly in unified mode.

Benchmarks

Benchmark script:

  • scripts/benchmark_unified_experiment.py

Scenarios:

  • event_driven_cccv
    • Charge at C/3 until 4.1 V
    • Hold at 4.1 V until C/20
  • mixed_control
    • Discharge at C/20 for 20 minutes
    • Charge at 1 A for 10 minutes
    • Hold at 4.1 V for 10 minutes
    • Discharge at 2 W for 10 minutes
    • Discharge at 4 Ohm for 10 minutes
  • start_time_padding
    • Current(1, duration=20 minutes, start_time=2023-01-01 08:00:00)
    • Rest(duration=20 minutes, start_time=2023-01-01 09:00:00)

Models:

  • SPM
  • DFN

The script was run on both this branch and main. main legacy timings were effectively the same as this branch’s legacy timings, so the comparison is consistent.

Current branch results

Model Scenario Legacy Total (s) Unified Total (s) Unified / Legacy
SPM event_driven_cccv 0.335 0.314 0.94x
SPM mixed_control 0.481 0.155 0.32x
SPM start_time_padding 0.244 0.105 0.43x
DFN event_driven_cccv 0.616 0.438 0.71x
DFN mixed_control 1.165 0.320 0.27x
DFN start_time_padding 0.736 0.295 0.40x

main legacy comparison

Model Scenario This branch legacy (s) main legacy (s)
SPM event_driven_cccv 0.335 0.334
SPM mixed_control 0.481 0.488
SPM start_time_padding 0.244 0.241
DFN event_driven_cccv 0.616 0.618
DFN mixed_control 1.165 1.181
DFN start_time_padding 0.736 0.738

On this machine, the unified path is faster in all benchmarked cases, with the largest gains in mixed-control and start-time experiments.

@martinjrobins martinjrobins requested a review from a team as a code owner March 21, 2026 21:08
@martinjrobins martinjrobins requested review from Copilot and removed request for a team March 21, 2026 21:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a unified experiment model pathway that reuses a single processed/built model (and solver) across compatible experiment steps, switching the “active” step via one-hot, solve-time inputs. It keeps the legacy per-step build available, with experiment_model_mode controlling selection and fallback behavior.

Changes:

  • Added experiment_model_mode={"auto","unified","legacy"} (with "per-step" alias) to Simulation, plus unified-model construction, step-weight inputs, and unified termination decoding.
  • Extended experiment step APIs to expose symbolic helpers for control residuals and combined termination expressions, enabling experiment-wide weighted expressions.
  • Added extensive unit coverage and a benchmark script comparing unified vs legacy experiment performance.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/pybamm/simulation.py Core unified experiment-model build path, one-hot inputs, solver/model reuse, termination decoding, and mode selection/fallback logic
src/pybamm/experiment/step/base_step.py Adds termination-expression helpers and refactors control-submodel wiring for reuse by unified experiments
src/pybamm/experiment/step/steps.py Adds get_control_residual implementations for implicit steps and custom-step support constraints
src/pybamm/experiment/step/step_termination.py Refactors terminations to expose event name + symbolic expression, retaining get_event construction
src/pybamm/models/submodels/external_circuit/function_control_external_circuit.py Updates resistance control residual form and adds ExperimentFunctionControl for weighted control residuals
src/pybamm/models/submodels/external_circuit/__init__.py Exposes ExperimentFunctionControl in the external circuit submodule exports
tests/unit/test_experiments/test_simulation_with_experiment.py Adds/updates tests validating unified vs legacy behavior, fallback/rejection cases, and result equivalence
tests/unit/test_experiments/test_experiment_steps.py Tests new symbolic helper methods for terminations and control residuals
scripts/benchmark_unified_experiment.py New benchmark driver for unified vs legacy experiment execution
CHANGELOG.md Documents the new unified experiment-model path feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Mar 21, 2026

Codecov Report

❌ Patch coverage is 99.37759% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.31%. Comparing base (fc13f30) to head (f31d8e7).

Files with missing lines Patch % Lines
src/pybamm/simulation.py 99.19% 2 Missing ⚠️
src/pybamm/expression_tree/conditional.py 98.87% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5422      +/-   ##
==========================================
+ Coverage   98.24%   98.31%   +0.06%     
==========================================
  Files         330      331       +1     
  Lines       30072    30471     +399     
==========================================
+ Hits        29544    29957     +413     
+ Misses        528      514      -14     

☔ 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.

@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Copy link
Member

@MarcBerliner MarcBerliner left a comment

Choose a reason for hiding this comment

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

Thanks Martin, the build time improvements are a nice win. I left some comments on a few areas I think we should sort out before this is ready to merge

@martinjrobins
Copy link
Contributor Author

Raw medians

Model Scenario Mode Solves Build (s) Solve 1 (s) Solve 2 (s) Solve 3 (s) Solve Total (s) Total (s) Termination
SPM event_driven_cccv legacy 3 0.104 0.223 0.008 0.008 0.240 0.343 event: C-rate cut-off [experiment]
SPM event_driven_cccv unified 3 0.059 0.252 0.015 0.014 0.281 0.342 event: C-rate cut-off [experiment]
SPM mixed_control legacy 3 0.264 0.215 0.010 0.009 0.234 0.498 final time
SPM mixed_control unified 3 0.061 0.087 0.015 0.015 0.117 0.178 final time
SPM start_time_padding legacy 3 0.147 0.094 0.004 0.004 0.103 0.249 final time
SPM start_time_padding unified 3 0.057 0.049 0.007 0.007 0.063 0.120 final time
SPM input_parameter_repeated_solves legacy 3 0.267 0.218 0.011 0.012 0.242 0.509 final time
SPM input_parameter_repeated_solves unified 3 0.061 0.088 0.018 0.019 0.125 0.187 final time
SPMe event_driven_cccv legacy 3 0.231 0.354 0.018 0.018 0.389 0.619 event: C-rate cut-off [experiment]
SPMe event_driven_cccv unified 3 0.127 0.380 0.033 0.033 0.446 0.573 event: C-rate cut-off [experiment]
SPMe mixed_control legacy 3 0.659 0.544 0.029 0.029 0.603 1.257 final time
SPMe mixed_control unified 3 0.130 0.206 0.045 0.045 0.296 0.426 final time
SPMe start_time_padding legacy 3 0.306 0.172 0.007 0.007 0.187 0.495 final time
SPMe start_time_padding unified 3 0.124 0.089 0.012 0.012 0.113 0.236 final time
SPMe input_parameter_repeated_solves legacy 3 0.663 0.557 0.036 0.035 0.627 1.290 final time
SPMe input_parameter_repeated_solves unified 3 0.129 0.210 0.054 0.054 0.318 0.448 final time
DFN event_driven_cccv legacy 3 0.259 0.356 0.028 0.027 0.412 0.671 event: C-rate cut-off [experiment]
DFN event_driven_cccv unified 3 0.139 0.300 0.036 0.035 0.371 0.510 event: C-rate cut-off [experiment]
DFN mixed_control legacy 3 0.707 0.515 0.054 0.054 0.620 1.328 final time
DFN mixed_control unified 3 0.141 0.181 0.065 0.065 0.313 0.453 final time
DFN start_time_padding legacy 3 0.396 0.337 0.042 0.041 0.420 0.820 final time
DFN start_time_padding unified 3 0.139 0.161 0.044 0.044 0.249 0.388 final time
DFN input_parameter_repeated_solves legacy 3 0.707 0.515 0.067 0.072 0.656 1.360 final time
DFN input_parameter_repeated_solves unified 3 0.140 0.182 0.080 0.091 0.353 0.495 final time

Unified vs legacy

Model Scenario Legacy Total (s) Unified Total (s) Unified / Legacy
SPM event_driven_cccv 0.343 0.342 1.00x
SPM mixed_control 0.498 0.178 0.36x
SPM start_time_padding 0.249 0.120 0.48x
SPM input_parameter_repeated_solves 0.509 0.187 0.37x
SPMe event_driven_cccv 0.619 0.573 0.92x
SPMe mixed_control 1.257 0.426 0.34x
SPMe start_time_padding 0.495 0.236 0.48x
SPMe input_parameter_repeated_solves 1.290 0.448 0.35x
DFN event_driven_cccv 0.671 0.510 0.76x
DFN mixed_control 1.328 0.453 0.34x
DFN start_time_padding 0.820 0.388 0.47x
DFN input_parameter_repeated_solves 1.360 0.495 0.36x

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.

feat: experimental steps use the same model

3 participants