Make IDAKLU output variables compatible with Experiments
This was initially reported as a bug (see report below) but it turns out it is not an implemented feature yet. It seems the main issue is that when a new experiment step is initialised with the previous step solution, that one is empty so the relevant variables are not available. I believe that amending the last_state so it stores the whole state vector even when output variables are used should fix this.
PyBaMM Version
develop
Python Version
3.11.6
Describe the bug
I am running a model with the IDAKLUSolver and some output_variables. These include, amongst others, the "Discharge capacity [A.h]", however PyBaMM complains that that variable is not found.
Steps to Reproduce
import pybamm
pybamm.set_logging_level("NOTICE")
model = pybamm.lithium_ion.DFN()
output_variables = ["Discharge capacity [A.h]", "Time [s]", "Current [A]", "Voltage [V]"]
solver = pybamm.IDAKLUSolver(output_variables=output_variables)
experiment = pybamm.Experiment(
[
(
"Charge at 1C until 4.2 V",
"Hold at 4.2 V until C/50",
"Rest for 1 hour",
)
]
)
sim = pybamm.Simulation(
model,
experiment=experiment,
solver=solver,
)
sol = sim.solve()
Relevant log output
Traceback (most recent call last):
File "/home/brosaplanella/PyBaMM/src/pybamm/models/base_model.py", line 808, in set_initial_conditions_from
final_state = solution[var.name]
~~~~~~~~^^^^^^^^^^
File "/home/brosaplanella/PyBaMM/src/pybamm/solvers/solution.py", line 547, in __getitem__
self.update(key)
File "/home/brosaplanella/PyBaMM/src/pybamm/solvers/solution.py", line 481, in update
raise KeyError(
KeyError: "Cannot process variable 'Discharge capacity [A.h]' as it was not part of the solve. Please re-run the solve with `output_variables` set to include this variable."
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/brosaplanella/battery_modelling/degradation-data/examples/mwe.py", line 29, in <module>
sol = sim.solve()
^^^^^^^^^^^
File "/home/brosaplanella/PyBaMM/src/pybamm/simulation.py", line 702, in solve
step_solution = solver.step(
^^^^^^^^^^^^
File "/home/brosaplanella/PyBaMM/src/pybamm/solvers/base_solver.py", line 1222, in step
_, concatenated_initial_conditions = model.set_initial_conditions_from(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/brosaplanella/PyBaMM/src/pybamm/models/base_model.py", line 810, in set_initial_conditions_from
raise pybamm.ModelError(
pybamm.expression_tree.exceptions.ModelError: To update a model from a solution, each variable in model.initial_conditions must appear in the solution with the same key as the variable name. In the solution provided, 'Cannot process variable 'Discharge capacity [A.h]' as it was not part of the solve. Please re-run the solve with `output_variables` set to include this variable.' was not found.
I think we cannot yet combine output_variables with experiment arguments (I don't see any tests that cover this use case). @pipliggins, @BradyPlanden, do you know if this might be the reason?
Yes, I noticed that too. I will edit the issue to reflect that.
As already mentioned, this is a known problem - it was discussed in the last developer meeting I believe, and in #4300. I'm happy to take this one as my next issue.
Thanks! Sorry, I checked for an existing issue for this, as I remembered talking about it, but missed the comment in #4300.
Hi i tried running your code @brosaplanella setup is wsl ubuntu, pyamm Version: 24.9.0, python 3.10.12
my output is much different?
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[177], [line 26](vscode-notebook-cell:?execution_count=177&line=26)
[10](vscode-notebook-cell:?execution_count=177&line=10) experiment = pybamm.Experiment(
[11](vscode-notebook-cell:?execution_count=177&line=11) [
[12](vscode-notebook-cell:?execution_count=177&line=12) (
(...)
[17](vscode-notebook-cell:?execution_count=177&line=17) ]
[18](vscode-notebook-cell:?execution_count=177&line=18) )
[20](vscode-notebook-cell:?execution_count=177&line=20) sim = pybamm.Simulation(
[21](vscode-notebook-cell:?execution_count=177&line=21) model,
[22](vscode-notebook-cell:?execution_count=177&line=22) experiment=experiment,
[23](vscode-notebook-cell:?execution_count=177&line=23) solver=solver,
[24](vscode-notebook-cell:?execution_count=177&line=24) )
---> [26](vscode-notebook-cell:?execution_count=177&line=26) sol = sim.solve()
ValueError: y is too short, so value with slice is smaller than expected
I have encountered similar behaviour when trying to use output variable as a passable parameter into the IDAKLU Solver in general. I'm not sure if this is a package thing but if anyone knows why it does this it would be greatly appreciated
Hi @MarkV-ADI - are you using the developer install for pybamm? If so, you'll need to re-run nox -s dev to get the IDAKLU solver to recompile. That should get you the model error from running this example, and should allow you to use output_variables outside Experiments.
Having looked into this, there seem to be 2 separate, but related, issues. They both stem from the fact that the full state vector for all time-steps is not returned when output_variables are specified for the IDAKLU solver.
- The full state vector for the final time-step is required from the end of one step to initialise the start of the next one
- The FSV for the first timestep is required to fill
Solution.first_state
1 is easily solved because we already return the final FSV from the solver to calculate events, it just needs pulling from Solution.y_event - as mentioned in the issue report.
2 looks like it has 2 possible solutions. I think first_state is only used for the calculation of summary variables? So:
A: We edit the IDAKLU solver again to return the first state vector, as well as the last SV and the subset specified in output_variables. This would add a bit of extra memory load back in which the output_variables option was supposed to reduce, but not loads.
B: Summary variables don’t get calculated when output variables are specified (as presumably only the requested subset are wanted anyway).
If I understand correctly, the last state of cycle N is identical to the first state of cycle N+1. Therefore, if we are already returning last states, we could just point the first states to them. The only that won't be caught is the initial state (i.e. first cycle first state), but that's from the initial conditions and I think we store it anyway.
Would that automatically fix the issue?
If I understand correctly, the last state of cycle N is identical to the first state of cycle N+1. Therefore, if we are already returning last states, we could just point the first states to them. The only that won't be caught is the initial state (i.e. first cycle first state), but that's from the initial conditions and I think we store it anyway.
Would that automatically fix the issue?
I think the only first state we actually use is to calculate the 'Change in x' summary variables, which would require the initial state. I thought I'd looked at the initial conditions vs first timestep and found them to be slightly different, but I'll double check. The fix I've implemented so far just issues a warning that the 'Change in x' summary variables won't be calculated, everything else works as expected.
Edit: We can use the initial conditions to populate first_state, added that to the PR