Skip to content

[Bug]: Joining solutions with and without sensitivities returns another solve's sensitivities #5845

Open

Description

@BradyPlanden

PyBaMM Version

main at 445ba33. Also reproduces with #5794 applied.

Python Version

3.14

Describe the bug

Joining a solution solved without sensitivities to one solved with them gives wrong or unreadable sensitivities:

  • first_state or last_state silently returns the other solve's sensitivities.
  • Reading any variable's sensitivities raises.

Solution.__add__ and Solution.from_sub_solutions only extend _all_sensitivities with segments that have sensitivities. first_state, last_state and _merge_sensitivities then assume the first sensitivity block belongs to all_ts[0] and the last to all_ts[-1].

solver.step and Simulation never build such a join: stepping with sensitivities from a solution without them raises. So this only happens when solutions are added by hand. It was raised in review of #5794 (comment).

Expected: the join raises, or the joined solution has no sensitivities. One option is for __add__ and from_sub_solutions to reject a join whose segments have different sensitivity_names, or to drop the sensitivities.

Steps to Reproduce

import numpy as np
import pybamm

model = pybamm.BaseModel()
u = pybamm.Variable("u")
a = pybamm.InputParameter("a")
model.rhs = {u: a}
model.initial_conditions = {u: a}
model.variables = {"u": u}
solver = pybamm.IDAKLUSolver()


def solve(t_interp, calculate_sensitivities):
    return solver.solve(
        model,
        [t_interp[0], t_interp[-1]],
        t_interp=np.array(t_interp),
        inputs={"a": 1.0},
        calculate_sensitivities=calculate_sensitivities,
    )


# Each solve restarts from u = a, so du/da = 1 + (t - t0)
early = [0, 0.5, 1]  # du/da = 1, 1.5, 2
late = [1, 2, 3]  # du/da = 1, 2, 3

joined = solve(early, False) + solve(late, True)
print("first_state:", joined.first_state.sensitivities["a"].ravel())

joined = solve(early, True) + solve(late, False)
print("last_state:", joined.last_state.sensitivities["a"].ravel())
joined["u"].sensitivities

On main:

  • first_state is the later solve's sensitivity at t = 3, although the earlier solve has none.
  • last_state is the earlier solve's sensitivity at t = 1, although the later solve has none.

With #5794, first_state returns [2.] instead, the later solve's value at t = 2.

Relevant log output

first_state: [3.]
last_state: [2.]
Traceback (most recent call last):
  ...
ValueError: zip() argument 5 is shorter than arguments 1-4

Activity

  1. Readyrel commented on Oct 8, 2026

    @Readyrel

    Hi, I'd like to work on this issue.

    I would allow joining solutions with and without sensitivities, discarding the sensitivity information from the resulting solution, and also emitting a warning that the sensitivity data has been discarded.

    Would this approach be acceptable?

    Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions