Usage
Getting Started
The most simple way of using the library is to interact with the Cell Simulation Interface, CSI object:
>>> from cideMOD import CSI, DEFAULTS
>>> csi = CSI('params.json', DEFAULTS.SIMULATION_OPTIONS.value,
test_plan = DEFAULTS.TEST_PLAN.value)
>>> csi.run_test_plan()
Specify Model Options
The model options can be specified through the
get_model_options
method. For example:
>>> from cideMOD import CSI, DEFAULTS, get_model_options
>>> options = get_model_options(model='P2D', solve_thermal=False, SEI_model='solvent_diffusion')
>>> csi = CSI('params.json', options, test_plan=DEFAULTS.TEST_PLAN.value)
>>> csi.run_test_plan()
Cell Parameters
Cell properties and material parameters are specified in a single
json file or optionally a Python dictionary can be used as
well. Several examples of different cell datasets are
given under the data folder. The json file must contain
different mandatory objects:
- Structure:
The
"structure"entry determines the configuration of the cell. It is a list containing the tags of the different subdomains in order. The easiest configuration would be["a","s","c"]corresponding to a cell composed of an anode, separator and cathode. A cell composed of two units could have this other structure["ncc","a","s","c","pcc","c","s","a","ncc"]. All the subdomains specified in the “structure” entry must have its own entry defined in the following points.
- Current collectors:
There is a distinction between the
"positive_current_collector"and"negative_current_ollector", as they often have different properties. These keywords must contain geometry properties and conductivity. If the thermal model is used, thermal properties should be specified as well.
- Electrodes:
There is a distinction between the
"positive_electrode"and"negative_electrode", as they have different properties. These keywords must contain information about geometry, porosity, and conductivity. If the thermal model is used, thermal properties should be specified as well. Additionally, electrodes should contain a list of the active materials that it contains.- Active materials:
Each electrode can have one or more active materials. These are specified as dictionaries with the electrochemical properties that they have.
- Separator:
The
"separator"keyword must contain geometry and porosity properties. If the thermal model is used, thermal properties should be specified as well.
- Electrolyte:
The
"electrolyte"keyword must contain the electrochemical properties such as diffusivity, conductivity, transference number and activity parameter. If the thermal model is used, thermal properties should be specified as well.
In the data folder, there are several examples of such parameter files. This is an example of them:
{
"specific_heat": {"unit": "J/kg K", "notes": "assumed uniform heat capacity across cell", "value": 1080.0, "effective": true, "correction":"bruggeman"}
},
"positive_electrode": {
"name": "LiCoO2",
"thickness": {"unit": "m", "value": 68.0e-06},
"height": {"unit": "m", "value": 51e-3},
"width": {"unit": "m", "value": 47e-3},
"area": {"unit": "m^2", "value": 0.002397},
"porosity": {"unit": "-", "value": 0.32},
"bruggeman": {"unit": "-", "value": 1.83},
"electronic_conductivity": {"unit": "S/m", "value": 10, "effective": false, "correction":"bruggeman"},
"thermal_conductivity": {"unit": "W/mK", "value": 1.58, "effective": true, "correction":"bruggeman"},
"specific_heat": {"unit": "J/kg K", "notes": "assumed", "value": 1080.0, "effective": true, "correction":"bruggeman"},
"density": {"unit": "kg/m3", "notes": "assumed","value": 2000},
"active_materials":
[
{
"volume_fraction": {"unit": "-", "value": 0.62},
"particle_radius": {"unit": "m", "value": 3.0e-06},
"stoichiometry1": {"unit": "-", "value": 0.435},
"stoichiometry0": {"unit": "-", "value": 0.9651},
"kinetic_constant": {"unit": "m^2.5/mol^0.5 s", "value": 1e-11},
"alpha": {"unit": "-", "value": 0.5},
"maximum_concentration": {"unit": "mol/m3", "value": 49943.0},
"diffusion_constant": {"unit": "m^2/s", "value": 5.387e-15, "arrhenius": {"activationEnergy": 5000, "referenceTemperature":298.15}},
"OCP": {
"unit": ["-", "V"],
"type": "spline",
"spline_type": "Akima1D",
"source": "file",
"value": "OCPs/OCV_LCO_Rieger.txt"
},
"partial_molar_volume": {"unit": "m^3/mol", "value": -0.728e-6},
"young_modulus": {"unit": "Pa", "value": 375e+9},
"poisson_ratio": {"unit": "-", "value": 0.2}
}
]
},
"positive_current_collector": {
"name": "Al",
"thickness": {"unit": "m", "value": 15e-06},
"area": {"unit": "m^2", "value": 0.002397},
"density": {"unit": "kg/m3", "notes": "taken from literature","value": 2700},
"specific_heat": {"unit": "J/kg K", "notes": "taken from literature", "value": 900.0},
"thermal_conductivity": {"unit": "W/mK", "value": 205},
"electronic_conductivity": {"unit": "S/m", "value": 3.77e7}
},
"electrolyte": {
"name": "LiPF6",
"diffusion_constant": {
"unit": "m^2/s",
"value": "pow(10,-0.22*0.001*c_e-8.43-54/(temp-229-5*0.001*c_e))",
"_value": 6e-12, "effective": false, "correction":"bruggeman"
},
"ionic_conductivity": {
"unit": "S/m",
"value": "c_e*0.0001*pow(-10.5+0.074*temp-6.96*pow(10,-5)*pow(temp,2)+0.688*0.001*c_e-0.0178*0.001*c_e*temp+2.8*pow(10,-8)*c_e*pow(temp,2)+0.494*pow(0.001*c_e,2)-8.86*pow(10,-4)*pow(0.001*c_e,2)*temp,2)",
"_value": 0.7, "effective": false, "correction":"bruggeman"
},
"transference_number": {"unit": "-", "value": 0.38},
"activity_dependence": {
"unit":"-",
"note": "This is the (dln(f)/dln(c_e)+1) term in the potential equation",
"value":"(0.601-0.24*pow(1e-3*c_e,0.5)+0.982*(1-0.0052*(temp-T_0))*pow(1e-3*c_e,3/2))/(1-t_p)",
"_value": 1
},
"initial_concentration": {"unit": "mol/m3", "value": 1000}
},
"structure": ["ncc","a","s","c","pcc"],
"references": {
"1": "Ai (2020)",
"2": "Rieger (2016)"
},
"results": {
"0.5C": {
"voltage":{
"source":"file",
"value":"reference_data/V_0.5C_Rieger.txt",
"unit": "V"
},
"temperatureRise":
{
"source":"file",
"value":"reference_data/T_0.5C_Rieger.txt",
"unit": "ºC"
},
"thicknessChange":
{
"source":"file",
"value":"reference_data/thick_0.5C_Rieger.txt",
"unit": "micrometers"
}
},
"1C": {
"voltage":{
"source":"file",
"value":"reference_data/V_1C_Rieger.txt",
"unit": "V"
},
"temperatureRise":
{
"source":"file",
"value":"reference_data/T_1C_Rieger.txt",
"unit": "ºC"
},
"thicknessChange":
{
"source":"file",
"value":"reference_data/thick_1C_Rieger.txt",
"unit": "micrometers"
}
},
"2C": {
"voltage":{
"source":"file",
"value":"reference_data/V_2C_Rieger.txt",
"unit": "V"
},
"temperatureRise":
{
"source":"file",
"value":"reference_data/T_2C_Rieger.txt",
"unit": "ºC"
},
"thicknessChange":
{
"source":"file",
"value":"reference_data/thick_2C_Rieger.txt",
"unit": "micrometers"
}
}
}
}
Note
Consider that several parameters as OCP, diffusivities and conductivities can be specified as a function or an array of points.
Test Plan
When using the CSI
interface to simulate cell behavior, it is necesary to specify a test
plan. This can be specified as a json or created programatically as
python dictionaries or using cideMOD’s
Input
and Trigger
classes. An example of a test plan built in the code with the different
building blocks can be found in the Use Cases
section.
Finer control
If you want to have more control over the inner details of the model,
you can directly interact with the Problem object, as is the
main responsible of assembling the models and running the simulation.
An example of a simple discharge with this approach is given in the
main.py file under the examples folder:
from cideMOD import (
CellParser,
ErrorCheck,
Problem,
SolverCrashed,
Trigger,
get_model_options,
)
case = "Ai_2020"
data_path = f"data/data_{case}"
params = "params.json"
model_options = get_model_options(model='P2D', save_path=f"{case}_discharge", overwrite=False)
cell = CellParser(params, data_path, model_options)
problem = Problem(cell, model_options)
problem.set_cell_state(SoC=1, T_ini=273 + 25, T_ext=273 + 25)
problem.setup()
C_rate = -1
I_app = C_rate * cell.ref_capacity
t_f = 3600 / abs(C_rate) * 1.25
v_min = Trigger(3, "v")
status = problem.solve(
min_step=10, i_app=I_app, t_f=t_f, store_delay=10, adaptive=False, triggers=[v_min]
)
err = ErrorCheck(problem, status)
if isinstance(status, SolverCrashed):
raise status.args[0]
In the folder examples/notebooks you can find several examples configuring cideMOD simulations from a beggining to an advance level.
Outputs
There are two kind of outputs available. For each simulation, the library saves results to a folder on the fly in case of internal variables, and at the end of the time-loop in the case of global variables.
- Internal variables:
These are the problem variables, or any derived value that has different values for each point in the cell geometry. These are automatically defined in the code, and written in the XDMF Format. The parameter
store_delaycan be modified to a negative value to suppress this output, or to a positive value to specify the frequency (in timesteps) at which the results are saved to the disk.
- Global variables:
These are overall cell figures (for example; cell voltage, current, maximum temperature, etc…), that are calculated and saved as a list of values over time internally in the memory. When the time iterations are finished, they are saved to disk as text files.