Note

This notebook is already available in your BattMo installation. In Matlab, run

open tutorial_8_simulate_a_multilayer_pouch_cell_live

Tutorial 8 - Simulate a Multilayer Pouch Cell

Introduction

In this tutorial, we simulate a multilayer pouch cell. We use the same material property as in the other tutorials

[1]:
jsonstruct_material = parseBattmoJson('Examples/jsondatafiles/sample_input.json');

Next, we load and parse a json file where we have chosen some parameters for the multilayer pouch domain. Note that all the parameters are described in a json schema, see Geometry.schema.json, even if the simplest way to proceed is to start with an example, in this case given by geometryMultiLayerPouch.json.

[2]:
jsonfilename = 'Examples/JsonDataFiles/geometryMultiLayerPouch.json';
jsonstruct_geometry = parseBattmoJson(jsonfilename);

We use FlatJsonViewer.m to flatten the json structure and print it to screen. We can see that, in this example, we use 5 layers and two different lengths for the tabs (height value). At the moment, the two tabs share the same width. Implementing a separate width for each tab would require to modify the grid generator for this geometry. It is more a developper work but is definitely not out of reach.

[3]:
fjv = flattenJsonStruct(jsonstruct_geometry)
[3]:
                     parameter name                       parameter value
    ________________________________________________    ___________________
    {'Geometry.case'                               }    {'multiLayerPouch'}
    {'Geometry.nLayers'                            }    {[              5]}
    {'Geometry.width'                              }    {[         0.1000]}
    {'Geometry.length'                             }    {[         0.1000]}
    {'Geometry.tab.width'                          }    {[         0.0500]}
    {'Geometry.tab.Nx'                             }    {[              3]}
    {'Geometry.tab.NegativeElectrode.length'       }    {[         0.0400]}
    {'Geometry.tab.NegativeElectrode.Ny'           }    {[              2]}
    {'Geometry.tab.PositiveElectrode.length'       }    {[         0.0200]}
    {'Geometry.tab.PositiveElectrode.Ny'           }    {[              2]}
    {'Geometry.Electrolyte.Nx'                     }    {[              2]}
    {'Geometry.Electrolyte.Ny'                     }    {[              4]}
    {'include_current_collectors'                  }    {[              1]}
    {'NegativeElectrode.Coating.thickness'         }    {[     1.0000e-04]}
    {'NegativeElectrode.Coating.N'                 }    {[              3]}
    {'NegativeElectrode.CurrentCollector.thickness'}    {[     1.0000e-05]}
    {'NegativeElectrode.CurrentCollector.N'        }    {[              2]}
    {'PositiveElectrode.Coating.thickness'         }    {[     8.0000e-05]}
    {'PositiveElectrode.Coating.N'                 }    {[              3]}
    {'PositiveElectrode.CurrentCollector.thickness'}    {[     1.0000e-05]}
    {'PositiveElectrode.CurrentCollector.N'        }    {[              2]}
    {'Separator.thickness'                         }    {[     5.0000e-05]}
    {'Separator.N'                                 }    {[              3]}
fjv =
  FlatJsonViewer with properties:
       flatjson: {23x2 cell}
    columnnames: {'parameter name'  'parameter value'}
[4]:
fjv.print();
[4]:
                     parameter name                       parameter value
    ________________________________________________    ___________________
    {'Geometry.case'                               }    {'multiLayerPouch'}
    {'Geometry.nLayers'                            }    {[              5]}
    {'Geometry.width'                              }    {[         0.1000]}
    {'Geometry.length'                             }    {[         0.1000]}
    {'Geometry.tab.width'                          }    {[         0.0500]}
    {'Geometry.tab.Nx'                             }    {[              3]}
    {'Geometry.tab.NegativeElectrode.length'       }    {[         0.0400]}
    {'Geometry.tab.NegativeElectrode.Ny'           }    {[              2]}
    {'Geometry.tab.PositiveElectrode.length'       }    {[         0.0200]}
    {'Geometry.tab.PositiveElectrode.Ny'           }    {[              2]}
    {'Geometry.Electrolyte.Nx'                     }    {[              2]}
    {'Geometry.Electrolyte.Ny'                     }    {[              4]}
    {'include_current_collectors'                  }    {[              1]}
    {'NegativeElectrode.Coating.thickness'         }    {[     1.0000e-04]}
    {'NegativeElectrode.Coating.N'                 }    {[              3]}
    {'NegativeElectrode.CurrentCollector.thickness'}    {[     1.0000e-05]}
    {'NegativeElectrode.CurrentCollector.N'        }    {[              2]}
    {'PositiveElectrode.Coating.thickness'         }    {[     8.0000e-05]}
    {'PositiveElectrode.Coating.N'                 }    {[              3]}
    {'PositiveElectrode.CurrentCollector.thickness'}    {[     1.0000e-05]}
    {'PositiveElectrode.CurrentCollector.N'        }    {[              2]}
    {'Separator.thickness'                         }    {[     5.0000e-05]}
    {'Separator.N'                                 }    {[              3]}

We load and parse the control protocol

[5]:
jsonfilename = fullfile('Examples', 'jsondatafiles', 'cc_discharge_control.json');
jsonstruct_control = parseBattmoJson(jsonfilename);

We load and parse the simulation settings. This is optional. Typically, reasonable choices are made by default.

[6]:
jsonfilename = fullfile('Examples', 'jsondatafiles', 'simulation_parameters.json');
jsonstruct_simparams = parseBattmoJson(jsonfilename);

Now, we can merge these parameter definitions into a single parameter set to obtain a jsonstruct that has all the input needed by the simulator.

[7]:
jsonstruct = mergeJsonStructs({jsonstruct_geometry , ...
    jsonstruct_material , ...
    jsonstruct_control  , ...
    jsonstruct_simparams}, 'warn', false);

Setup the model for inspection

When we run the simulation using function runBatteryJson.m, the model is setup. In the case where we want to setup the model for inspection, prior to simulation, we can use the function setupModelFromJson.m

[8]:
model = setupModelFromJson(jsonstruct);

We use the plotBatteryGrid.m function to show the grid

[9]:
plotBatteryGrid(model)
[9]:
ans =
  Figure (13) with properties:
      Number: 13
        Name: ''
       Color: [1 1 1]
    Position: [1411 753 618 463]
       Units: 'pixels'
  Use GET to show all properties
[10]:
% make the axis tight and set the camera viewing angle
axis tight
view(45,45)
[10]:
figure_0.png

Run the simulation

[11]:
output = runBatteryJson(jsonstruct);

Visualize the Results

extract the time and voltage quantities

[12]:
states = output.states;

time    = cellfun(@(state) state.time, states);
voltage = cellfun(@(state) state.('Control').E, states);

We plot the discharge curves together in a new figure

[13]:
figure();
plot((time/hour), voltage, '-', 'linewidth', 3)
xlabel('Time  /  h')
ylabel('Cell Voltage  /  V')
title('Voltage');
[13]:
figure_1.png

For a given time step, we plot the concentration on the grid.

[14]:
% Set the timestep we want to visualize
timestep = 20;

% get the state of the simulation at the given timestep
state = states{timestep};

% create a new figure
figure()

% plot the surface concentration of lithium in the negative electrode active material
plotCellData(model.NegativeElectrode.Coating.grid, state.NegativeElectrode.Coating.ActiveMaterial.SolidDiffusion.cSurface/(mol/litre))

% plot the surface concentration of lithium in the positive electrode active material
plotCellData(model.PositiveElectrode.Coating.grid, state.PositiveElectrode.Coating.ActiveMaterial.SolidDiffusion.cSurface/(mol/litre))

title('Active Material Surface Lithium Concentration  /  mol \cdot L^{-1}');
% add a colorbar
colorbar()
view(45,45)
[14]:
figure_2.png