Making the most of PyBaMM outputs
There is a large overlap between this exercise and PyBaMM Tutorial notebook 6, so we recommended you read both.
Getting a solution object
After solving a simulation, there are two says of accessing the solution:
import pybamm sim = pybamm.Simulation() sol = sim.solve()
when calling the solve
command and
sol = sim.solution
Accessing solution variables
if sim
has already been solved. There are many things you can do with PyBaMM solutions. A common one is to plot the solution variables, which we saw in Lesson 1.
You might also want to access the solution variables directly. For example, to get the terminal voltage at the end of the simulation, you can use:
sol["Terminal voltage [V]"]
This returns a pybamm.ProcessedVariable
, which can be used to calculate the value of that variable at an array of times:
import numpy as np times = np.linespace(0, 3600, 100) terminal_voltage = sol["Terminal voltage [V]"](times)
Here we use numpy to create an array of 100 times between 0 and 3600 seconds,
and then use the ProcessedVariable
to calculate the terminal voltage at those
times. We can then directly plot the terminal voltage against time using
matplotlib
import matplotlib.pyplot as plt plt.plot(times, terminal_voltage) plt.xlabel("Time [s]") plt.ylabel("Terminal voltage [V]") plt.show()
The solution object contains the entire solution of your simulation which is calculated a set of timepoint chosen by the solver. You can access the timepoints using
sol.t
It is often useful to know these times, as you don't have to guess the
resolution needed to plot a smooth or complete solution (e.g. if the solution is
changing rapidly in one time period, and slowly in another). If you want to get
the associated values of a variable at these times, you can use the entries
attribute of the ProcessedVariable
:
terminal_voltage = sol["Terminal voltage [V]"].entries
Solution times
Run a simulation using an experiment of your choice. Using matplotlib, plot a variable of your choice against the times used by the solver. Add points to the plot to show where the solver has calculated the solution.
Saving solutions
It is often useful to save the solution to disk, so you can load it later on for
processing or plotting. For example, you can save the entire solution to a
.pkl
file and load it later.
path = "/mnt/c/Users/YourUsername/" sol.save(path + "my_pybamm_solution.pkl")
If you're a Windows Subsystem for Linux (WSL) user like me, you can read and write to your Windows drives (instead of the Linux partition) by putting /mnt/
before the letter denoting the drive. Anyway...
sol2 = pybamm.load(path + "my_pybamm_solution.pkl")
PyBaMM has a lot of variables, so these .pkl
files are huge! So why bother?
You can run another PyBaMM model, with the final results of the saved solution as the initial conditions for the next, by using
model.set_initial_conditions_from(sol2)
, as shown in this exampleYou can do the same post-processing on a solution loaded from disk as you can on a "fresh" solution.
If saving the entire solution would take up too much space, you can use save_data
to only save the variables you need:
sol.save_data( path + "tIV.pkl", ["Time [s]", "Current [A]", "Voltage [V]"] ) sol.save_data( path + "tIV.csv", ["Time [s]", "Current [A]", "Voltage [V]"], to_format="csv" )
When to save what?
Can you think of three situations where you would save the entire solution, and three where you would only save selected variables?
To help you think, have a look at this example from my own research:
model = pybamm.lithium_ion.DFN() param = pybamm.ParameterValues("ORegan2022") exp = pybamm.Experiment( [ "Rest for 60 seconds (0.1 second period)", "Discharge at 5 A for 144 seconds or until 2.5 V (0.1 second period)", "Rest for 1 hour (1 second period)," ] * 25 ) sim = pybamm.Simulation(model, parameter_values=param, experiment=exp) sol = sim.solve() path = "/mnt/c/Users/sokane/pybamm_data/" sol.save_data( path + "tIVQ.csv", ["Time [s]", "Current [A]", "Voltage [V]", "Discharge capacity [A.h]"], to_format="csv" )
What does this code do?
What does the above code do? What do you think the intended application was?