Gradient-based parameter calibration of a lithium-ion battery model
This example demonstrates how to calibrate a lithium-ion battery against data model using BattMo.jl. The example uses a two-step calibration process:
We first calibrate the model against a 0.5C discharge curve (adjusting stoichiometric coefficients and maximum concentration in the active material)
We then calibrate the model against a 2.0C discharge curve (adjusting reaction rate constants and diffusion coefficients in the active material)
Finally, we compare the results of the calibrated model against the experimental data for discharge rates of 0.5C, 1.0C, and 2.0C.
Load packages and set up helper functions
using BattMo, Jutul
using CSV
using DataFrames
using GLMakie
function get_tV(x)
t = [state[:Control][:Controller].time for state in x[:states]]
V = [state[:Control][:Phi][1] for state in x[:states]]
return (t, V)
end
function get_tV(x::DataFrame)
return (x[:, 1], x[:, 2])
end
get_tV (generic function with 2 methods)
Load the experimental data and set up a base case
battmo_base = normpath(joinpath(pathof(BattMo) |> splitdir |> first, ".."))
exdata = joinpath(battmo_base, "examples", "example_data")
df_05 = CSV.read(joinpath(exdata, "Xu_2015_voltageCurve_05C.csv"), DataFrame)
df_1 = CSV.read(joinpath(exdata, "Xu_2015_voltageCurve_1C.csv"), DataFrame)
df_2 = CSV.read(joinpath(exdata, "Xu_2015_voltageCurve_2C.csv"), DataFrame)
dfs = [df_05, df_1, df_2]
cell_parameters = load_cell_parameters(; from_default_set = "Xu2015")
cycling_protocol = load_cycling_protocol(; from_default_set = "CCDischarge")
cycling_protocol["LowerVoltageLimit"] = 2.25
model_setup = LithiumIonBattery()
cycling_protocol["DRate"] = 0.5
sim = Simulation(model_setup, cell_parameters, cycling_protocol)
output0 = solve(sim)
t0, V0 = get_tV(output0)
t_exp_05, V_exp_05 = get_tV(df_05)
t_exp_1, V_exp_1 = get_tV(df_1)
fig = Figure()
ax = Axis(fig[1, 1], title = "CRate = 0.5", xlabel = "Time / s", ylabel = "Voltage / V")
lines!(ax, t0, V0, label = "Base case")
lines!(ax, t_exp_05, V_exp_05, label = "Experimental data")
axislegend(position = :lb)
fig
Set up the first calibration
We select the following parameters to calibrate:
"StoichiometricCoefficientAtSOC100" at both electrodes
"StoichiometricCoefficientAtSOC0" at both electrodes
"MaximumConcentration" of both electrodes
We also set bounds for these parameters to ensure they remain physically meaningful and possible to simulate. The objective function is the sum of squares:
We print the setup as a table to give the user the opportunity to review the setup before calibration starts.
vc05 = VoltageCalibration(t_exp_05, V_exp_05, sim)
free_calibration_parameter!(vc05,
["NegativeElectrode","ActiveMaterial", "StoichiometricCoefficientAtSOC100"];
lower_bound = 0.0, upper_bound = 1.0)
free_calibration_parameter!(vc05,
["PositiveElectrode","ActiveMaterial", "StoichiometricCoefficientAtSOC100"];
lower_bound = 0.0, upper_bound = 1.0)
VoltageCalibration([357.76627218934914, 715.9763313609469, 1074.1863905325445, 1432.396449704142, 1790.6065088757396, 2148.816568047337, 2507.0266272189347, 2877.5887573964496, 3223.44674556213, 3594.0088757396447, 3952.2189349112427, 4310.42899408284, 4668.639053254437, 5026.8491124260345, 5385.059171597633, 5743.2692307692305, 6101.479289940828, 6472.041420118343, 6817.899408284024, 7188.461538461537], [3.2943262673632967, 3.2638600156322126, 3.2518999695748874, 3.2446281622882482, 3.246486083133996, 3.245753135185418, 3.246253934281757, 3.2472569925301102, 3.2356583102522136, 3.2351808720466657, 3.2359284205519883, 3.237169467875278, 3.227800290612279, 3.2273140920726844, 3.2184384136276525, 3.217458716270091, 3.1992065602836877, 3.177878797019038, 2.8807910485472883, 2.179051790010771], Simulation(BattMo.run_battery, LithiumIonBattery("Setup object for a P2D lithium-ion model", {
"RampUp" => "Sinusoidal"
"Metadata" => {
"Description" => "Default model settings for a P2D simulation including a current ramp up, excluding current collectors and SEI effects."
"Title" => "P2D"
}
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => "P2D"
}, true), {
"Electrolyte" => {
"TransferenceNumber" => 0.2594
"Description" => "1.5 mol/l LiPF6 dissolved in a mixture of ethylene carbonate (EC): dimethyl carbonate (DMC) (1:1)"
"DiffusionCoefficient" => "8.794*10^(-11)*(c/1000)^2 - 3.972*10^(-10)*(c/1000) + 4.862*10^(-10)"
"IonicConductivity" => "0.1297*(c/1000)^3 - 2.51*(c/1000)^(1.5) + 3.329*(c/1000)"
"Density" => 1210
"ChargeNumber" => 1
"Concentration" => 1500.0
}
"Cell" => {
"ElectrodeGeometricSurfaceArea" => 0.007035
"NominalCapacity" => 16.5
"ElectrodeWidth" => 0.067
"ElectrodeLength" => 0.105
"Name" => "LP2770120"
"Case" => "Pouch"
"NominalVoltage" => 3.2
}
"Metadata" => {
"Description" => "Parameter set of a commercial Type LP2770120 prismatic LiFePO4/graphite cell, for an electrochemical pseudo-two-dimensional (P2D) model."
"Source" => "https://doi.org/10.1016/j.energy.2014.11.073"
"Models" => {
"CurrentCollectors" => "Generic"
"RampUp" => "Sinusoidal"
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => Any["P2D", "P4D Pouch"]
}
"Title" => "Xu2015"
}
"PositiveElectrode" => {
"ActiveMaterial" => {
"ActivationEnergyOfDiffusion" => 20000
"NumberOfElectronsTransfered" => 1
"StoichiometricCoefficientAtSOC0" => 0.999
"OpenCircuitPotential" => {
"FilePath" => "function_parameters_Xu2015.jl"
"FunctionName" => "open_circuit_potential_lfp_Xu_2015"
}
"ReactionRateConstant" => 3.626e-11
"MassFraction" => 1.0
"StoichiometricCoefficientAtSOC100" => 0.14778
"ActivationEnergyOfReaction" => 4000
"MaximumConcentration" => 26390
"VolumetricSurfaceArea" => 1.87826e6
"Description" => "LiFePO4"
"DiffusionCoefficient" => 1.25e-15
"ParticleRadius" => 1.15e-6
"Density" => 1500
"ElectronicConductivity" => 0.01
"ChargeTransferCoefficient" => 0.5
}
"ElectrodeCoating" => {
"BruggemanCoefficient" => 1.5
"EffectiveDensity" => 1080
"Thickness" => 9.2e-5
}
"Binder" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1100.0
"ElectronicConductivity" => 100.0
}
"CurrentCollector" => {
"Description" => "Aluminum"
"TabLength" => 0.01
"Density" => 2700
"ElectronicConductivity" => 3.83e7
"Thickness" => 1.6e-5
"TabWidth" => 0.015
}
"ConductiveAdditive" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1950.0
"ElectronicConductivity" => 100.0
}
}
"Separator" => {
"Density" => 779
"BruggemanCoefficient" => 1.5
"Thickness" => 2.0e-5
"Porosity" => 0.4
}
"NegativeElectrode" => {
"ActiveMaterial" => {
"ActivationEnergyOfDiffusion" => 4000
"NumberOfElectronsTransfered" => 1
"StoichiometricCoefficientAtSOC0" => 0.001
"OpenCircuitPotential" => {
"FilePath" => "function_parameters_Xu2015.jl"
"FunctionName" => "open_circuit_potential_graphite_Xu_2015"
}
"ReactionRateConstant" => 1.764e-11
"MassFraction" => 1.0
"StoichiometricCoefficientAtSOC100" => 0.51873811
"ActivationEnergyOfReaction" => 4000
"MaximumConcentration" => 31540
"VolumetricSurfaceArea" => 142373
"Description" => "Graphite"
"DiffusionCoefficient" => 3.9e-14
"ParticleRadius" => 1.475e-5
"Density" => 2660
"ElectronicConductivity" => 215.0
"ChargeTransferCoefficient" => 0.5
}
"ElectrodeCoating" => {
"BruggemanCoefficient" => 1.5
"EffectiveDensity" => 1862
"Thickness" => 5.9e-5
}
"Binder" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1100.0
"ElectronicConductivity" => 100.0
}
"CurrentCollector" => {
"Description" => "Copper"
"TabLength" => 0.01
"Density" => 8900
"ElectronicConductivity" => 6.33e7
"Thickness" => 9.0e-6
"TabWidth" => 0.015
}
"ConductiveAdditive" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1950.0
"ElectronicConductivity" => 100.0
}
}
}, {
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"InitialTemperature" => 298.15
"Metadata" => {
"Description" => "Parameter set for a constant current discharging protocol."
"Title" => "CCDischarge"
}
"DRate" => 0.5
"LowerVoltageLimit" => 2.25
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1
}, {
"Grid" => Any[]
"GridResolution" => {
"PositiveElectrodeCoating" => 10
"Separator" => 3
"NegativeElectrodeActiveMaterial" => 5
"PositiveElectrodeCurrentCollectorTabLength" => 3
"NegativeElectrodeCoating" => 10
"NegativeElectrodeCurrentCollector" => 2
"ElectrodeLength" => 10
"NegativeElectrodeCurrentCollectorTabLength" => 3
"PositiveElectrodeCurrentCollector" => 2
"PositiveElectrodeCurrentCollectorTabWidth" => 3
"ElectrodeWidth" => 10
"PositiveElectrodeActiveMaterial" => 5
"NegativeElectrodeCurrentCollectorTabWidth" => 3
}
"TimeStepDuration" => 50
"RampUpTime" => 10
"RampUpSteps" => 5
}, true), {
["NegativeElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"] => (v0 = 0.51873811, vmin = 0.0, vmax = 1.0)
["PositiveElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"] => (v0 = 0.14778, vmin = 0.0, vmax = 1.0)
}, missing, missing)
"StoichiometricCoefficientAtSOC0" at both electrodes
free_calibration_parameter!(vc05,
["NegativeElectrode","ActiveMaterial", "StoichiometricCoefficientAtSOC0"];
lower_bound = 0.0, upper_bound = 1.0)
free_calibration_parameter!(vc05,
["PositiveElectrode","ActiveMaterial", "StoichiometricCoefficientAtSOC0"];
lower_bound = 0.0, upper_bound = 1.0)
VoltageCalibration([357.76627218934914, 715.9763313609469, 1074.1863905325445, 1432.396449704142, 1790.6065088757396, 2148.816568047337, 2507.0266272189347, 2877.5887573964496, 3223.44674556213, 3594.0088757396447, 3952.2189349112427, 4310.42899408284, 4668.639053254437, 5026.8491124260345, 5385.059171597633, 5743.2692307692305, 6101.479289940828, 6472.041420118343, 6817.899408284024, 7188.461538461537], [3.2943262673632967, 3.2638600156322126, 3.2518999695748874, 3.2446281622882482, 3.246486083133996, 3.245753135185418, 3.246253934281757, 3.2472569925301102, 3.2356583102522136, 3.2351808720466657, 3.2359284205519883, 3.237169467875278, 3.227800290612279, 3.2273140920726844, 3.2184384136276525, 3.217458716270091, 3.1992065602836877, 3.177878797019038, 2.8807910485472883, 2.179051790010771], Simulation(BattMo.run_battery, LithiumIonBattery("Setup object for a P2D lithium-ion model", {
"RampUp" => "Sinusoidal"
"Metadata" => {
"Description" => "Default model settings for a P2D simulation including a current ramp up, excluding current collectors and SEI effects."
"Title" => "P2D"
}
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => "P2D"
}, true), {
"Electrolyte" => {
"TransferenceNumber" => 0.2594
"Description" => "1.5 mol/l LiPF6 dissolved in a mixture of ethylene carbonate (EC): dimethyl carbonate (DMC) (1:1)"
"DiffusionCoefficient" => "8.794*10^(-11)*(c/1000)^2 - 3.972*10^(-10)*(c/1000) + 4.862*10^(-10)"
"IonicConductivity" => "0.1297*(c/1000)^3 - 2.51*(c/1000)^(1.5) + 3.329*(c/1000)"
"Density" => 1210
"ChargeNumber" => 1
"Concentration" => 1500.0
}
"Cell" => {
"ElectrodeGeometricSurfaceArea" => 0.007035
"NominalCapacity" => 16.5
"ElectrodeWidth" => 0.067
"ElectrodeLength" => 0.105
"Name" => "LP2770120"
"Case" => "Pouch"
"NominalVoltage" => 3.2
}
"Metadata" => {
"Description" => "Parameter set of a commercial Type LP2770120 prismatic LiFePO4/graphite cell, for an electrochemical pseudo-two-dimensional (P2D) model."
"Source" => "https://doi.org/10.1016/j.energy.2014.11.073"
"Models" => {
"CurrentCollectors" => "Generic"
"RampUp" => "Sinusoidal"
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => Any["P2D", "P4D Pouch"]
}
"Title" => "Xu2015"
}
"PositiveElectrode" => {
"ActiveMaterial" => {
"ActivationEnergyOfDiffusion" => 20000
"NumberOfElectronsTransfered" => 1
"StoichiometricCoefficientAtSOC0" => 0.999
"OpenCircuitPotential" => {
"FilePath" => "function_parameters_Xu2015.jl"
"FunctionName" => "open_circuit_potential_lfp_Xu_2015"
}
"ReactionRateConstant" => 3.626e-11
"MassFraction" => 1.0
"StoichiometricCoefficientAtSOC100" => 0.14778
"ActivationEnergyOfReaction" => 4000
"MaximumConcentration" => 26390
"VolumetricSurfaceArea" => 1.87826e6
"Description" => "LiFePO4"
"DiffusionCoefficient" => 1.25e-15
"ParticleRadius" => 1.15e-6
"Density" => 1500
"ElectronicConductivity" => 0.01
"ChargeTransferCoefficient" => 0.5
}
"ElectrodeCoating" => {
"BruggemanCoefficient" => 1.5
"EffectiveDensity" => 1080
"Thickness" => 9.2e-5
}
"Binder" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1100.0
"ElectronicConductivity" => 100.0
}
"CurrentCollector" => {
"Description" => "Aluminum"
"TabLength" => 0.01
"Density" => 2700
"ElectronicConductivity" => 3.83e7
"Thickness" => 1.6e-5
"TabWidth" => 0.015
}
"ConductiveAdditive" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1950.0
"ElectronicConductivity" => 100.0
}
}
"Separator" => {
"Density" => 779
"BruggemanCoefficient" => 1.5
"Thickness" => 2.0e-5
"Porosity" => 0.4
}
"NegativeElectrode" => {
"ActiveMaterial" => {
"ActivationEnergyOfDiffusion" => 4000
"NumberOfElectronsTransfered" => 1
"StoichiometricCoefficientAtSOC0" => 0.001
"OpenCircuitPotential" => {
"FilePath" => "function_parameters_Xu2015.jl"
"FunctionName" => "open_circuit_potential_graphite_Xu_2015"
}
"ReactionRateConstant" => 1.764e-11
"MassFraction" => 1.0
"StoichiometricCoefficientAtSOC100" => 0.51873811
"ActivationEnergyOfReaction" => 4000
"MaximumConcentration" => 31540
"VolumetricSurfaceArea" => 142373
"Description" => "Graphite"
"DiffusionCoefficient" => 3.9e-14
"ParticleRadius" => 1.475e-5
"Density" => 2660
"ElectronicConductivity" => 215.0
"ChargeTransferCoefficient" => 0.5
}
"ElectrodeCoating" => {
"BruggemanCoefficient" => 1.5
"EffectiveDensity" => 1862
"Thickness" => 5.9e-5
}
"Binder" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1100.0
"ElectronicConductivity" => 100.0
}
"CurrentCollector" => {
"Description" => "Copper"
"TabLength" => 0.01
"Density" => 8900
"ElectronicConductivity" => 6.33e7
"Thickness" => 9.0e-6
"TabWidth" => 0.015
}
"ConductiveAdditive" => {
"Description" => "Unknown"
"MassFraction" => 0.0
"Density" => 1950.0
"ElectronicConductivity" => 100.0
}
}
}, {
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"InitialTemperature" => 298.15
"Metadata" => {
"Description" => "Parameter set for a constant current discharging protocol."
"Title" => "CCDischarge"
}
"DRate" => 0.5
"LowerVoltageLimit" => 2.25
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1
}, {
"Grid" => Any[]
"GridResolution" => {
"PositiveElectrodeCoating" => 10
"Separator" => 3
"NegativeElectrodeActiveMaterial" => 5
"PositiveElectrodeCurrentCollectorTabLength" => 3
"NegativeElectrodeCoating" => 10
"NegativeElectrodeCurrentCollector" => 2
"ElectrodeLength" => 10
"NegativeElectrodeCurrentCollectorTabLength" => 3
"PositiveElectrodeCurrentCollector" => 2
"PositiveElectrodeCurrentCollectorTabWidth" => 3
"ElectrodeWidth" => 10
"PositiveElectrodeActiveMaterial" => 5
"NegativeElectrodeCurrentCollectorTabWidth" => 3
}
"TimeStepDuration" => 50
"RampUpTime" => 10
"RampUpSteps" => 5
}, true), {
["PositiveElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC0"] => (v0 = 0.999, vmin = 0.0, vmax = 1.0)
["NegativeElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"] => (v0 = 0.51873811, vmin = 0.0, vmax = 1.0)
["PositiveElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC100"] => (v0 = 0.14778, vmin = 0.0, vmax = 1.0)
["NegativeElectrode", "ActiveMaterial", "StoichiometricCoefficientAtSOC0"] => (v0 = 0.001, vmin = 0.0, vmax = 1.0)
}, missing, missing)
"MaximumConcentration" of both electrodes
free_calibration_parameter!(vc05,
["NegativeElectrode","ActiveMaterial", "MaximumConcentration"];
lower_bound = 10000.0, upper_bound = 1e5)
free_calibration_parameter!(vc05,
["PositiveElectrode","ActiveMaterial", "MaximumConcentration"];
lower_bound = 10000.0, upper_bound = 1e5)
print_calibration_overview(vc05)
NegativeElectrode: Active calibration parameters
┌──────────────────────────────────────────────────┬───────────────┬────────────────────┐
│ Name │ Initial value │ Bounds │
├──────────────────────────────────────────────────┼───────────────┼────────────────────┤
│ ActiveMaterial.MaximumConcentration │ 31540 │ 10000.0 - 100000.0 │
│ ActiveMaterial.StoichiometricCoefficientAtSOC100 │ 0.518738 │ 0.0 - 1.0 │
│ ActiveMaterial.StoichiometricCoefficientAtSOC0 │ 0.001 │ 0.0 - 1.0 │
└──────────────────────────────────────────────────┴───────────────┴────────────────────┘
PositiveElectrode: Active calibration parameters
┌──────────────────────────────────────────────────┬───────────────┬────────────────────┐
│ Name │ Initial value │ Bounds │
├──────────────────────────────────────────────────┼───────────────┼────────────────────┤
│ ActiveMaterial.MaximumConcentration │ 26390 │ 10000.0 - 100000.0 │
│ ActiveMaterial.StoichiometricCoefficientAtSOC0 │ 0.999 │ 0.0 - 1.0 │
│ ActiveMaterial.StoichiometricCoefficientAtSOC100 │ 0.14778 │ 0.0 - 1.0 │
└──────────────────────────────────────────────────┴───────────────┴────────────────────┘
Solve the first calibration problem
The calibration is performed by solving the optimization problem. This makes use of the adjoint method implemented in Jutul.jl and the LBFGS algorithm.
solve(vc05);
cell_parameters_calibrated = vc05.calibrated_cell_parameters;
print_calibration_overview(vc05)
Calibration: Starting calibration of 6 parameters.
It: 0 | val: 3.915e-02 | ls-its: NaN | pgrad: 6.453e+00
It: 1 | val: 1.832e-02 | ls-its: 1 | pgrad: 6.452e+00
It: 2 | val: 4.589e-03 | ls-its: 4 | pgrad: 1.080e+00
It: 3 | val: 4.552e-03 | ls-its: 2 | pgrad: 1.263e-01
It: 4 | val: 4.549e-03 | ls-its: 1 | pgrad: 1.968e-02
It: 5 | val: 4.542e-03 | ls-its: 1 | pgrad: 1.907e-02
It: 6 | val: 4.524e-03 | ls-its: 1 | pgrad: 2.536e-02
It: 7 | val: 4.467e-03 | ls-its: 1 | pgrad: 6.518e-02
It: 8 | val: 3.936e-03 | ls-its: 3 | pgrad: 1.336e-01
LBFGS: Line search unable to succeed in 5 iterations ...
LBFGS: Hessian not updated during iteration 9
It: 9 | val: 3.868e-03 | ls-its: 5 | pgrad: 4.307e-01
LBFGS: Line search unable to succeed in 5 iterations ...
LBFGS: Hessian not updated during iteration 10
It: 10 | val: 3.868e-03 | ls-its: 5 | pgrad: 5.391e-01
Calibration: Calibration finished in 166.273224087 seconds.
NegativeElectrode: Active calibration parameters
┌──────────────────────────────────────────────────┬───────────────┬────────────────────┬─────────────────┬──────────┐
│ Name │ Initial value │ Bounds │ Optimized value │ Change │
├──────────────────────────────────────────────────┼───────────────┼────────────────────┼─────────────────┼──────────┤
│ ActiveMaterial.MaximumConcentration │ 31540 │ 10000.0 - 100000.0 │ 21898.1 │ -30.57% │
│ ActiveMaterial.StoichiometricCoefficientAtSOC100 │ 0.518738 │ 0.0 - 1.0 │ 0.53213 │ 2.58% │
│ ActiveMaterial.StoichiometricCoefficientAtSOC0 │ 0.001 │ 0.0 - 1.0 │ 0.0246662 │ 2366.62% │
└──────────────────────────────────────────────────┴───────────────┴────────────────────┴─────────────────┴──────────┘
PositiveElectrode: Active calibration parameters
┌──────────────────────────────────────────────────┬───────────────┬────────────────────┬─────────────────┬─────────┐
│ Name │ Initial value │ Bounds │ Optimized value │ Change │
├──────────────────────────────────────────────────┼───────────────┼────────────────────┼─────────────────┼─────────┤
│ ActiveMaterial.MaximumConcentration │ 26390 │ 10000.0 - 100000.0 │ 29626.9 │ 12.27% │
│ ActiveMaterial.StoichiometricCoefficientAtSOC0 │ 0.999 │ 0.0 - 1.0 │ 0.998812 │ -0.02% │
│ ActiveMaterial.StoichiometricCoefficientAtSOC100 │ 0.14778 │ 0.0 - 1.0 │ 0.129126 │ -12.62% │
└──────────────────────────────────────────────────┴───────────────┴────────────────────┴─────────────────┴─────────┘
Compare the results of the calibration against the experimental data
We can now compare the results of the calibrated model against the experimental data for the 0.5C discharge curve.
sim_opt = Simulation(model_setup, cell_parameters_calibrated, cycling_protocol)
output_opt = solve(sim_opt);
t_opt, V_opt = get_tV(output_opt)
fig = Figure()
ax = Axis(fig[1, 1], title = "CRate = 0.5")
lines!(ax, t0, V0, label = "BattMo initial")
lines!(ax, t_exp_05, V_exp_05, label = "Experimental data")
lines!(ax, t_opt, V_opt, label = "BattMo calibrated", linestyle = :dash)
axislegend(position = :lb)
fig
Set up the second calibration
The second calibration is performed against the 2.0C discharge curve. In the same manner as for the first discharge curve, we set up a set of parameters to calibrate against experimental data. The parameters are:
The reaction rate constant of both electrodes
The diffusion coefficient of both electrodes
The calibration this time around starts from the parameters calibrated in the first step, so we use the cell_parameters_calibrated
from the first solve
call when defining the new object:
t_exp_2, V_exp_2 = get_tV(df_2)
cycling_protocol2 = deepcopy(cycling_protocol)
cycling_protocol2["DRate"] = 2.0
sim2 = Simulation(model_setup, cell_parameters_calibrated, cycling_protocol2)
output2 = solve(sim2);
t2, V2 = get_tV(output2)
sim2_0 = Simulation(model_setup, cell_parameters, cycling_protocol2)
output2_0 = solve(sim2_0);
t2_0, V2_0 = get_tV(output2_0)
vc2 = VoltageCalibration(t_exp_2, V_exp_2, sim2)
free_calibration_parameter!(vc2,
["NegativeElectrode","ActiveMaterial", "ReactionRateConstant"];
lower_bound = 1e-16, upper_bound = 1e-10)
free_calibration_parameter!(vc2,
["PositiveElectrode","ActiveMaterial", "ReactionRateConstant"];
lower_bound = 1e-16, upper_bound = 1e-10)
free_calibration_parameter!(vc2,
["NegativeElectrode","ActiveMaterial", "DiffusionCoefficient"];
lower_bound = 1e-16, upper_bound = 1e-12)
free_calibration_parameter!(vc2,
["PositiveElectrode","ActiveMaterial", "DiffusionCoefficient"];
lower_bound = 1e-16, upper_bound = 1e-12)
print_calibration_overview(vc2)
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 33 minutes, 0.0002274 nanoseconds as 44 report steps
╭────────────────┬──────────┬──────────────┬──────────╮
│ Iteration type │ Avg/step │ Avg/ministep │ Total │
│ │ 34 steps │ 35 ministeps │ (wasted) │
├────────────────┼──────────┼──────────────┼──────────┤
│ Newton │ 3.47059 │ 3.37143 │ 118 (3) │
│ Linearization │ 4.47059 │ 4.34286 │ 152 (3) │
│ Linear solver │ 3.44118 │ 3.34286 │ 117 (2) │
│ Precond apply │ 0.0 │ 0.0 │ 0 (0) │
╰────────────────┴──────────┴──────────────┴──────────╯
╭───────────────┬────────┬────────────┬──────────╮
│ Timing type │ Each │ Relative │ Total │
│ │ ms │ Percentage │ ms │
├───────────────┼────────┼────────────┼──────────┤
│ Properties │ 0.2708 │ 9.92 % │ 31.9527 │
│ Equations │ 0.5893 │ 27.82 % │ 89.5783 │
│ Assembly │ 0.0762 │ 3.60 % │ 11.5839 │
│ Linear solve │ 0.6866 │ 25.16 % │ 81.0148 │
│ Linear setup │ 0.0000 │ 0.00 % │ 0.0000 │
│ Precond apply │ 0.0000 │ 0.00 % │ 0.0000 │
│ Update │ 0.0537 │ 1.97 % │ 6.3421 │
│ Convergence │ 0.0730 │ 3.45 % │ 11.0928 │
│ Input/Output │ 0.0266 │ 0.29 % │ 0.9313 │
│ Other │ 0.7581 │ 27.79 % │ 89.4590 │
├───────────────┼────────┼────────────┼──────────┤
│ Total │ 2.7284 │ 100.00 % │ 321.9550 │
╰───────────────┴────────┴────────────┴──────────╯
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 33 minutes, 0.0002274 nanoseconds as 44 report steps
╭────────────────┬──────────┬──────────────┬──────────╮
│ Iteration type │ Avg/step │ Avg/ministep │ Total │
│ │ 32 steps │ 33 ministeps │ (wasted) │
├────────────────┼──────────┼──────────────┼──────────┤
│ Newton │ 3.8125 │ 3.69697 │ 122 (3) │
│ Linearization │ 4.8125 │ 4.66667 │ 154 (3) │
│ Linear solver │ 3.78125 │ 3.66667 │ 121 (2) │
│ Precond apply │ 0.0 │ 0.0 │ 0 (0) │
╰────────────────┴──────────┴──────────────┴──────────╯
╭───────────────┬────────┬────────────┬──────────╮
│ Timing type │ Each │ Relative │ Total │
│ │ ms │ Percentage │ ms │
├───────────────┼────────┼────────────┼──────────┤
│ Properties │ 0.6914 │ 34.82 % │ 84.3463 │
│ Equations │ 0.6000 │ 38.14 % │ 92.3950 │
│ Assembly │ 0.0726 │ 4.62 % │ 11.1854 │
│ Linear solve │ 0.1677 │ 8.45 % │ 20.4652 │
│ Linear setup │ 0.0000 │ 0.00 % │ 0.0000 │
│ Precond apply │ 0.0000 │ 0.00 % │ 0.0000 │
│ Update │ 0.0530 │ 2.67 % │ 6.4639 │
│ Convergence │ 0.0719 │ 4.57 % │ 11.0768 │
│ Input/Output │ 0.0253 │ 0.34 % │ 0.8337 │
│ Other │ 0.1270 │ 6.40 % │ 15.4973 │
├───────────────┼────────┼────────────┼──────────┤
│ Total │ 1.9858 │ 100.00 % │ 242.2637 │
╰───────────────┴────────┴────────────┴──────────╯
NegativeElectrode: Active calibration parameters
┌─────────────────────────────────────┬───────────────┬───────────────────┐
│ Name │ Initial value │ Bounds │
├─────────────────────────────────────┼───────────────┼───────────────────┤
│ ActiveMaterial.DiffusionCoefficient │ 3.9e-14 │ 1.0e-16 - 1.0e-12 │
│ ActiveMaterial.ReactionRateConstant │ 1.764e-11 │ 1.0e-16 - 1.0e-10 │
└─────────────────────────────────────┴───────────────┴───────────────────┘
PositiveElectrode: Active calibration parameters
┌─────────────────────────────────────┬───────────────┬───────────────────┐
│ Name │ Initial value │ Bounds │
├─────────────────────────────────────┼───────────────┼───────────────────┤
│ ActiveMaterial.ReactionRateConstant │ 3.626e-11 │ 1.0e-16 - 1.0e-10 │
│ ActiveMaterial.DiffusionCoefficient │ 1.25e-15 │ 1.0e-16 - 1.0e-12 │
└─────────────────────────────────────┴───────────────┴───────────────────┘
Solve the second calibration problem
cell_parameters_calibrated2, = solve(vc2);
print_calibration_overview(vc2)
Calibration: Starting calibration of 4 parameters.
It: 0 | val: 6.237e-02 | ls-its: NaN | pgrad: 3.880e+01
Warning: Resetting 'm' to number of parameters: m = 4
It: 1 | val: 3.461e-03 | ls-its: 1 | pgrad: 3.880e+01
It: 2 | val: 2.393e-03 | ls-its: 2 | pgrad: 4.804e-01
It: 3 | val: 2.229e-03 | ls-its: 3 | pgrad: 2.962e-01
It: 4 | val: 1.700e-03 | ls-its: 1 | pgrad: 1.484e-01
It: 5 | val: 1.475e-03 | ls-its: 3 | pgrad: 9.660e-02
It: 6 | val: 1.395e-03 | ls-its: 2 | pgrad: 3.615e-02
It: 7 | val: 1.389e-03 | ls-its: 4 | pgrad: 1.185e-02
It: 8 | val: 1.078e-03 | ls-its: 2 | pgrad: 4.263e-02
It: 9 | val: 7.746e-04 | ls-its: 1 | pgrad: 8.629e-03
LBFGS: Line search unable to succeed in 5 iterations ...
It: 10 | val: 7.723e-04 | ls-its: 5 | pgrad: 5.025e-02
LBFGS: Line search unable to succeed in 5 iterations ...
It: 11 | val: 7.709e-04 | ls-its: 5 | pgrad: 5.357e-02
It: 12 | val: 7.264e-04 | ls-its: 2 | pgrad: 5.381e-02
It: 13 | val: 7.145e-04 | ls-its: 1 | pgrad: 1.853e-03
It: 14 | val: 7.136e-04 | ls-its: 2 | pgrad: 6.939e-03
Calibration: Calibration finished in 63.347707259 seconds.
NegativeElectrode: Active calibration parameters
┌─────────────────────────────────────┬───────────────┬───────────────────┬─────────────────┬─────────┐
│ Name │ Initial value │ Bounds │ Optimized value │ Change │
├─────────────────────────────────────┼───────────────┼───────────────────┼─────────────────┼─────────┤
│ ActiveMaterial.DiffusionCoefficient │ 3.9e-14 │ 1.0e-16 - 1.0e-12 │ 1.21952e-13 │ 212.7% │
│ ActiveMaterial.ReactionRateConstant │ 1.764e-11 │ 1.0e-16 - 1.0e-10 │ 9.14306e-12 │ -48.17% │
└─────────────────────────────────────┴───────────────┴───────────────────┴─────────────────┴─────────┘
PositiveElectrode: Active calibration parameters
┌─────────────────────────────────────┬───────────────┬───────────────────┬─────────────────┬──────────┐
│ Name │ Initial value │ Bounds │ Optimized value │ Change │
├─────────────────────────────────────┼───────────────┼───────────────────┼─────────────────┼──────────┤
│ ActiveMaterial.ReactionRateConstant │ 3.626e-11 │ 1.0e-16 - 1.0e-10 │ 3.55176e-11 │ -2.05% │
│ ActiveMaterial.DiffusionCoefficient │ 1.25e-15 │ 1.0e-16 - 1.0e-12 │ 4.17914e-14 │ 3243.31% │
└─────────────────────────────────────┴───────────────┴───────────────────┴─────────────────┴──────────┘
Compare the results of the second calibration against the experimental data
We can now compare the results of the calibrated model against the experimental data for the 2.0C discharge curve. We compare three simulations against the experimental data:
The initial simulation with the original parameters.
The simulation with the parameters calibrated against the 0.5C discharge curve.
The simulation with the parameters calibrated against the 0.5C and 2.0C discharge curves.
sim_c2 = Simulation(model_setup, cell_parameters_calibrated2, cycling_protocol2)
output2_c = solve(sim_c2, accept_invalid = false);
t2_c = [state[:Control][:Controller].time for state in output2_c[:states]]
V2_c = [state[:Control][:Phi][1] for state in output2_c[:states]]
fig = Figure()
ax = Axis(fig[1, 1], title = "CRate = 2.0")
lines!(ax, t2_0, V2_0, label = "BattMo.jl")
lines!(ax, t2, V2, label = "BattMo.jl (after CRate=0.5 calibration)")
lines!(ax, t_exp_2, V_exp_2, label = "Experimental data")
lines!(ax, t2_c, V2_c, label = "BattMo.jl (after CRate=0.5 + Crate=2.0 calibration)", linestyle = :dash)
axislegend(position = :lb)
fig
Compare the results of the calibrated model against the experimental data
We can now compare the results of the calibrated model against the experimental data for the 0.5C, 1.0C, and 2.0C discharge curves.
Note that we did not calibrate the model for the 1.0C discharge curve, but we still obtain a good fit.
CRates = [0.5, 1.0, 2.0]
outputs_base = []
outputs_calibrated = []
for CRate in CRates
cycling_protocol["DRate"] = CRate
simuc = Simulation(model_setup, cell_parameters, cycling_protocol)
output = solve(simuc, info_level = -1)
push!(outputs_base, (CRate = CRate, output = output))
simc = Simulation(model_setup, cell_parameters_calibrated2, cycling_protocol)
output_c = solve(simc, info_level = -1)
push!(outputs_calibrated, (CRate = CRate, output = output_c))
end
colors = Makie.wong_colors()
fig = Figure(size = (1200, 600))
ax = Axis(fig[1, 1], ylabel = "Voltage / V", xlabel = "Time / s", title = "Discharge curve")
for (i, data) in enumerate(outputs_base)
t_i, V_i = get_tV(data.output)
lines!(ax, t_i, V_i, label = "Simulation (initial) $(round(data.CRate, digits = 2))", color = colors[i])
end
for (i, data) in enumerate(outputs_calibrated)
t_i, V_i = get_tV(data.output)
lines!(ax, t_i, V_i, label = "Simulation (calibrated) $(round(data.CRate, digits = 2))", color = colors[i], linestyle = :dash)
end
for (i, df) in enumerate(dfs)
t_i, V_i = get_tV(df)
label = "Experimental $(round(CRates[i], digits = 2))"
lines!(ax, t_i, V_i, linestyle = :dot, label = label, color = colors[i])
end
fig[1, 2] = Legend(fig, ax, "C rate", framevisible = false)
fig
Example on GitHub
If you would like to run this example yourself, it can be downloaded from the BattMo.jl GitHub repository as a script.
This page was generated using Literate.jl.