|
| 1 | +import pybamm |
| 2 | +import numpy as np |
| 3 | +import matplotlib.pyplot as plt |
| 4 | + |
| 5 | +pybamm.set_logging_level("INFO") |
| 6 | + |
| 7 | +# load model |
| 8 | +options = { |
| 9 | + "current collector": "potential pair", |
| 10 | + "dimensionality": 2, |
| 11 | + "thermal": "x-lumped", |
| 12 | + # The below option replaces the PDEs in the particles with ODEs under the |
| 13 | + # assumption of fast diffusion (so that the concentration is uniform within |
| 14 | + # each particle). This will speed up the simulation and is an OK assumption |
| 15 | + # for a lot of cases. Uncomment it to switch it on/off. |
| 16 | + "particle": "fast diffusion", |
| 17 | +} |
| 18 | +model = pybamm.lithium_ion.SPM(options) |
| 19 | + |
| 20 | +# parameters can be updated here |
| 21 | +param = model.default_parameter_values |
| 22 | + |
| 23 | +# set mesh points |
| 24 | +var = pybamm.standard_spatial_vars |
| 25 | +var_pts = { |
| 26 | + var.x_n: 10, |
| 27 | + var.x_s: 10, |
| 28 | + var.x_p: 10, |
| 29 | + var.r_n: 10, |
| 30 | + var.r_p: 10, |
| 31 | + var.y: 10, |
| 32 | + var.z: 10, |
| 33 | +} |
| 34 | + |
| 35 | +# solver |
| 36 | +# casadi fast mode is pretty quick, but doesn't support events out of the box |
| 37 | +solver = pybamm.CasadiSolver(atol=1e-6, rtol=1e-3, root_tol=1e-3, mode="fast") |
| 38 | +# KLU is sometimes better for bigger problems and supports events |
| 39 | +# solver = pybamm.IDAKLUSolver(atol=1e-6, rtol=1e-3, root_tol=1e-3, root_method="hybr") |
| 40 | +# KLU performs better if you convert the final model to a python function |
| 41 | +if isinstance(solver, pybamm.IDAKLUSolver): |
| 42 | + model.convert_to_format = "python" |
| 43 | + |
| 44 | +# simulation object |
| 45 | +simulation = pybamm.Simulation( |
| 46 | + model, parameter_values=param, var_pts=var_pts, solver=solver |
| 47 | +) |
| 48 | + |
| 49 | +# build simulation |
| 50 | +# by default pybamm performs some checks on the discretised model. this can |
| 51 | +# be a little slow for bigger problems, so you can turn if off. if you start to |
| 52 | +# get obscure errors when you change things, set this to True and the error should |
| 53 | +# get caught sooner and give a more informative message |
| 54 | +simulation.build(check_model=False) |
| 55 | + |
| 56 | +# solve simulation |
| 57 | +t_eval = np.linspace(0, 3600, 100) # time in seconds |
| 58 | +simulation.solve(t_eval=t_eval) |
| 59 | +solution = simulation.solution |
| 60 | + |
| 61 | +# plotting |
| 62 | +# TO DO: 2+1D automated plotting |
| 63 | + |
| 64 | +# post-process variables |
| 65 | +phi_s_cn = solution["Negative current collector potential [V]"] |
| 66 | +phi_s_cp = solution["Positive current collector potential [V]"] |
| 67 | +I = solution["Current collector current density [A.m-2]"] |
| 68 | +T = solution["X-averaged cell temperature [K]"] |
| 69 | + |
| 70 | +# get y and z points for plotting (these are non-dimensional) |
| 71 | +l_y = phi_s_cp.y_sol[-1] |
| 72 | +l_z = phi_s_cp.z_sol[-1] |
| 73 | +y_plot = np.linspace(0, l_y, 21) |
| 74 | +z_plot = np.linspace(0, l_z, 21) |
| 75 | + |
| 76 | +# Can multiply by L_z to get dimensional y and z. Note that both y and z are |
| 77 | +# scaled with L_z |
| 78 | +L_z = param.evaluate(pybamm.standard_parameters_lithium_ion.L_z) |
| 79 | +y_plot_dim = np.linspace(0, l_y, 21) * L_z |
| 80 | +z_plot_dim = np.linspace(0, l_z, 21) * L_z |
| 81 | + |
| 82 | + |
| 83 | +# define plotting function |
| 84 | +def plot(time_in_seconds): |
| 85 | + fig, ax = plt.subplots(figsize=(15, 8)) |
| 86 | + plt.tight_layout() |
| 87 | + plt.subplots_adjust(left=-0.1) |
| 88 | + |
| 89 | + # get non-dim time |
| 90 | + tau = param.evaluate(pybamm.standard_parameters_lithium_ion.tau_discharge) |
| 91 | + t_non_dim = time_in_seconds / tau |
| 92 | + |
| 93 | + # negative current collector potential |
| 94 | + plt.subplot(221) |
| 95 | + phi_s_cn_plot = plt.pcolormesh( |
| 96 | + y_plot_dim, |
| 97 | + z_plot_dim, |
| 98 | + np.transpose( |
| 99 | + phi_s_cn(y=y_plot, z=z_plot, t=t_non_dim) |
| 100 | + ), # accepts non-dim values |
| 101 | + shading="gouraud", |
| 102 | + ) |
| 103 | + plt.axis([0, l_y * L_z, 0, l_z * L_z]) |
| 104 | + plt.xlabel(r"$y$ [m]") |
| 105 | + plt.ylabel(r"$z$ [m]") |
| 106 | + plt.title(r"$\phi_{s,cn}$ [V]") |
| 107 | + plt.set_cmap("cividis") |
| 108 | + plt.colorbar(phi_s_cn_plot) |
| 109 | + |
| 110 | + # positive current collector potential |
| 111 | + plt.subplot(222) |
| 112 | + phi_s_cp_plot = plt.pcolormesh( |
| 113 | + y_plot_dim, |
| 114 | + z_plot_dim, |
| 115 | + np.transpose( |
| 116 | + phi_s_cp(y=y_plot, z=z_plot, t=t_non_dim) |
| 117 | + ), # accepts non-dim values |
| 118 | + shading="gouraud", |
| 119 | + ) |
| 120 | + plt.axis([0, l_y * L_z, 0, l_z * L_z]) |
| 121 | + plt.xlabel(r"$y$ [m]") |
| 122 | + plt.ylabel(r"$z$ [m]") |
| 123 | + plt.title(r"$\phi_{s,cp}$ [V]") |
| 124 | + plt.set_cmap("viridis") |
| 125 | + plt.colorbar(phi_s_cp_plot) |
| 126 | + |
| 127 | + # through-cell current |
| 128 | + plt.subplot(223) |
| 129 | + I_plot = plt.pcolormesh( |
| 130 | + y_plot_dim, |
| 131 | + z_plot_dim, |
| 132 | + np.transpose(I(y=y_plot, z=z_plot, t=t_non_dim)), # accepts non-dim values |
| 133 | + shading="gouraud", |
| 134 | + ) |
| 135 | + plt.axis([0, l_y * L_z, 0, l_z * L_z]) |
| 136 | + plt.xlabel(r"$y$ [m]") |
| 137 | + plt.ylabel(r"$z$ [m]") |
| 138 | + plt.title(r"$I$ [A.m-2]") |
| 139 | + plt.set_cmap("plasma") |
| 140 | + plt.colorbar(I_plot) |
| 141 | + # temperature |
| 142 | + plt.subplot(224) |
| 143 | + T_plot = plt.pcolormesh( |
| 144 | + y_plot_dim, |
| 145 | + z_plot_dim, |
| 146 | + np.transpose(T(y=y_plot, z=z_plot, t=t_non_dim)), # accepts non-dim values |
| 147 | + shading="gouraud", |
| 148 | + ) |
| 149 | + plt.axis([0, l_y * L_z, 0, l_z * L_z]) |
| 150 | + plt.xlabel(r"$y$ [m]") |
| 151 | + plt.ylabel(r"$z$ [m]") |
| 152 | + plt.title(r"$T$ [K]") |
| 153 | + plt.set_cmap("inferno") |
| 154 | + plt.colorbar(T_plot) |
| 155 | + |
| 156 | + plt.subplots_adjust( |
| 157 | + top=0.92, bottom=0.15, left=0.10, right=0.9, hspace=0.5, wspace=0.5 |
| 158 | + ) |
| 159 | + plt.show() |
| 160 | + |
| 161 | + |
| 162 | +# call plot |
| 163 | +plot(1000) |
0 commit comments