Skip to content

PyBattMo examples

This page provides a few examples of running simulations and calibrations with PyBattMo. For more detailed examples, please refer to the BattMo.jl documentation, as all functionalities are shared between the two.

Important tip: run the examples within a notebook or using cells in VSCode to make use of the high performance of Julia. Julia compiles the functions and objects that you use when you first run a code. Because of this, the second time you run the same code it is super fast! But to make use of this, you need to have a kernel that keeps running in between code executions. Therefore, it does work with jupytor notebooks.

Run a simulation

python
from battmo import *
import plotly.express as px
import pandas as pd
import numpy as np

# Load parameter sets
cell_parameters = load_cell_parameters(from_default_set="chen_2020")
cycling_protocol = load_cycling_protocol(from_default_set="cc_discharge")

# Have a quick look into what kind of cell we're dealing with
quick_cell_check(cell_parameters)

# Setup model and simulation
model = LithiumIonBattery()
sim = Simulation(model, cell_parameters, cycling_protocol)
output = solve(sim)

# Have a look into which output quantities are available
print_info(output)

# Plotting using Plotly
df = to_pandas(output.time_series)
fig = px.line(df, x="Time", y="Voltage", title="Voltage curve")
fig.show()

Run a 3D simulation

python
from battmo import *

# Load parameter sets and settings
cell_parameters = load_cell_parameters(from_default_set="chen_2020")
cycling_protocol = load_cycling_protocol(from_default_set="cc_discharge")
model_settings = load_model_settings(from_default_set="p4d_cylindrical")
simulation_settings = load_simulation_settings(from_default_set="p4d_cylindrical")

# We adjust the parameters so that the simulation in this example is not too long
cell_parameters["Cell"]["OuterRadius"]                                   = 0.004
cell_parameters["NegativeElectrode"]["CurrentCollector"]["TabFractions"] = [0.5]
cell_parameters["PositiveElectrode"]["CurrentCollector"]["TabFractions"] = [0.5]
cell_parameters["NegativeElectrode"]["CurrentCollector"]["TabWidth"]     = 0.002
cell_parameters["PositiveElectrode"]["CurrentCollector"]["TabWidth"]     = 0.002
simulation_settings["AngularGridPoints"]

# Setup model and simulation
model = LithiumIonBattery(model_settings=model_settings)
sim = Simulation(model, cell_parameters, cycling_protocol, simulation_settings=simulation_settings)
output = solve(sim)

# Plot interative 3D results
plot_interactive_3d(output)

Calibrate a cell parameter set to experimental data

python
# The purpose of this example is to show how you can use the BattMo calibration api and therefore only shows a simple calibration procedure using only one experimental voltage curve is shown. A more complete example can be found among the BattMo.jl examples.

import pandas as pd
from battmo import *
import numpy as np
import plotly.express as px
import os

# Load experimental data
battmo_base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
exdata = os.path.join(battmo_base, "examples", "example_data")

df_05 = pd.read_csv(os.path.join(exdata, "Xu_2015_voltageCurve_05C.csv"), names=["Time", "Voltage"])

# ## Load cell parameters and cycling protocol
cell_parameters = load_cell_parameters(from_default_set="xu_2015")
cycling_protocol = load_cycling_protocol(from_default_set="cc_discharge")

cycling_protocol["LowerVoltageLimit"] = 2.25
cycling_protocol["DRate"] = 0.5

# ## Create model and simulation object
model = LithiumIonBattery()
sim = Simulation(model, cell_parameters, cycling_protocol)
output0 = solve(sim)

# Extract t-V data
df_sim = to_pandas(output.time_series)

# Plot
fig = px.line(df_sim, x="Time", y="Voltage", title="Voltage curve")
# Add experimental data as another trace
fig.add_scatter(x=df_05["Time"], y=df_05["Voltage"], mode="markers", name="Experimental 0.5C")
fig.show()

# Set up the first calibration
cal = VoltageCalibration(np.array(df_05["Time"]), np.array(df_05["Voltage"]), sim)

#  Free some parameters to calibrate
free_calibration_parameter(
    cal,
    ["NegativeElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"],
    lower_bound=0.0,
    upper_bound=1.0,
)
free_calibration_parameter(
    cal,
    ["PositiveElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"],
    lower_bound=0.0,
    upper_bound=1.0,
)

free_calibration_parameter(
    cal,
    ["NegativeElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC0"],
    lower_bound=0.0,
    upper_bound=1.0,
)
free_calibration_parameter(
    cal,
    ["PositiveElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC0"],
    lower_bound=0.0,
    upper_bound=1.0,
)

free_calibration_parameter(
    cal,
    ["NegativeElectrode", "ActiveMaterial", "MaximumConcentration"],
    lower_bound=10000.0,
    upper_bound=1e5,
)
free_calibration_parameter(
    cal,
    ["PositiveElectrode", "ActiveMaterial", "MaximumConcentration"],
    lower_bound=10000.0,
    upper_bound=1e5,
)

# print an overview of the calibration object
print_info(cal)

# Solve the calibration problem
solve(cal)

# Retrieve the calibrated parameters and print an overview of the calibration
cell_parameters_calibrated = cal.calibrated_cell_parameters
print_calibration_overview(cal)

# Run a simulation using the calibrated cell parameters
sim_calibrated = Simulation(model, cell_parameters_calibrated, cycling_protocol)
output_calibrated = solve(sim_calibrated)

# ## Extract t-V data
time_series_cal = output_calibrated.time_series

df_sim_cal = to_pandas(time_series_cal)

# Plot
fig = px.line(df_sim, x="Time", y="Voltage", title="Voltage curve")
fig.data[0].name = "Base Simulation"
# Add experimental data as another trace
fig.add_scatter(x=df_05["Time"], y=df_05["Voltage"], mode="markers", name="Experimental 0.5C")
fig.add_scatter(x=df_sim_cal["Time"], y=df_sim_cal["Voltage"], mode="lines", name="Calibrated")
fig.show()

Headless UI

python
from battmo import *

simulation_input = load_full_simulation_input(from_default_set="chen_2020")

output = run_simulation(simulation_input)

plot_dashboard(output, plot_type="contour")

User defined input function

This short example shows how a user defined python function, describing an input parameter, can be exposed to BattMo.

python
from battmo import *

def negative_electrode_ocp(c, T, refT, cmax):
    ocp = get_1d_interpolator(x, ocp)
    return ocp(c / cmax)

# Expose function to battmo
expose_to_battmo(negative_electrode_ocp)