def test_definite_integral_vector(self): mesh = get_2p1d_mesh_for_testing(include_particles=False) spatial_methods = { "macroscale": pybamm.FiniteVolume(), "current collector": pybamm.ScikitFiniteElement(), } disc = pybamm.Discretisation(mesh, spatial_methods) var = pybamm.Variable("var", domain="current collector") disc.set_variable_slices([var]) # row (default) vec = pybamm.DefiniteIntegralVector(var) vec_disc = disc.process_symbol(vec) self.assertEqual(vec_disc.shape[0], 1) self.assertEqual(vec_disc.shape[1], mesh["current collector"].npts) # column vec = pybamm.DefiniteIntegralVector(var, vector_type="column") vec_disc = disc.process_symbol(vec) self.assertEqual(vec_disc.shape[0], mesh["current collector"].npts) self.assertEqual(vec_disc.shape[1], 1)
def test_definite_integral_vector(self): mesh = get_mesh_for_testing() spatial_methods = { "macroscale": pybamm.FiniteVolume(), "negative particle": pybamm.FiniteVolume(), "positive particle": pybamm.FiniteVolume(), } disc = pybamm.Discretisation(mesh, spatial_methods) var = pybamm.Variable("var", domain="negative electrode") disc.set_variable_slices([var]) # row (default) vec = pybamm.DefiniteIntegralVector(var) vec_disc = disc.process_symbol(vec) self.assertEqual(vec_disc.shape[0], 1) self.assertEqual(vec_disc.shape[1], mesh["negative electrode"][0].npts) # column vec = pybamm.DefiniteIntegralVector(var, vector_type="column") vec_disc = disc.process_symbol(vec) self.assertEqual(vec_disc.shape[0], mesh["negative electrode"][0].npts) self.assertEqual(vec_disc.shape[1], 1)
def test_pure_neumann_poisson(self): # grad^2 u = 1, du/dz = 1 at z = 1, du/dn = 0 elsewhere, u has zero average u = pybamm.Variable("u", domain="current collector") c = pybamm.Variable("c") # lagrange multiplier y = pybamm.SpatialVariable("y", ["current collector"]) z = pybamm.SpatialVariable("z", ["current collector"]) model = pybamm.BaseModel() # 0*c hack otherwise gives KeyError model.algebraic = { u: pybamm.laplacian(u) - pybamm.source(1, u) + c * pybamm.DefiniteIntegralVector(u, vector_type="column"), c: pybamm.Integral(u, [y, z]) + 0 * c, } model.initial_conditions = {u: pybamm.Scalar(0), c: pybamm.Scalar(0)} # set boundary conditions ("negative tab" = bottom of unit square, # "positive tab" = top of unit square, elsewhere normal derivative is zero) model.boundary_conditions = { u: { "negative tab": (0, "Neumann"), "positive tab": (1, "Neumann") } } model.variables = {"c": c, "u": u} # create discretisation mesh = get_unit_2p1D_mesh_for_testing(ypts=32, zpts=32, include_particles=False) spatial_methods = { "macroscale": pybamm.FiniteVolume(), "current collector": pybamm.ScikitFiniteElement(), } disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) # solve model solver = pybamm.AlgebraicSolver() solution = solver.solve(model) z = mesh["current collector"].coordinates[1, :][:, np.newaxis] u_exact = z**2 / 2 - 1 / 6 np.testing.assert_array_almost_equal(solution.y[:-1], u_exact, decimal=1)
def __init__(self): super().__init__() self.name = "Effective resistance in current collector model" self.param = pybamm.standard_parameters_lithium_ion # Get useful parameters param = self.param l_cn = param.l_cn l_cp = param.l_cp l_y = param.l_y sigma_cn_dbl_prime = param.sigma_cn_dbl_prime sigma_cp_dbl_prime = param.sigma_cp_dbl_prime alpha_prime = param.alpha_prime # Set model variables var = pybamm.standard_spatial_vars psi = pybamm.Variable("Current collector potential weighted sum", ["current collector"]) W = pybamm.Variable( "Perturbation to current collector potential difference", ["current collector"], ) c_psi = pybamm.Variable("Lagrange multiplier for variable `psi`") c_W = pybamm.Variable("Lagrange multiplier for variable `W`") self.variables = { "Current collector potential weighted sum": psi, "Perturbation to current collector potential difference": W, "Lagrange multiplier for variable `psi`": c_psi, "Lagrange multiplier for variable `W`": c_W, } # Algebraic equations (enforce zero mean constraint through Lagrange multiplier) # 0*LagrangeMultiplier hack otherwise gives KeyError self.algebraic = { psi: pybamm.laplacian(psi) + c_psi * pybamm.DefiniteIntegralVector(psi, vector_type="column"), W: pybamm.laplacian(W) - pybamm.source(1, W) + c_W * pybamm.DefiniteIntegralVector(W, vector_type="column"), c_psi: pybamm.Integral(psi, [var.y, var.z]) + 0 * c_psi, c_W: pybamm.Integral(W, [var.y, var.z]) + 0 * c_W, } # Boundary conditons psi_neg_tab_bc = l_cn psi_pos_tab_bc = -l_cp W_neg_tab_bc = l_y / (alpha_prime * sigma_cn_dbl_prime) W_pos_tab_bc = l_y / (alpha_prime * sigma_cp_dbl_prime) self.boundary_conditions = { psi: { "negative tab": (psi_neg_tab_bc, "Neumann"), "positive tab": (psi_pos_tab_bc, "Neumann"), }, W: { "negative tab": (W_neg_tab_bc, "Neumann"), "positive tab": (W_pos_tab_bc, "Neumann"), }, } # "Initial conditions" provides initial guess for solver # TODO: better guess than zero? self.initial_conditions = { psi: pybamm.Scalar(0), W: pybamm.Scalar(0), c_psi: pybamm.Scalar(0), c_W: pybamm.Scalar(0), } # Define effective current collector resistance psi_neg_tab = pybamm.BoundaryValue(psi, "negative tab") psi_pos_tab = pybamm.BoundaryValue(psi, "positive tab") W_neg_tab = pybamm.BoundaryValue(W, "negative tab") W_pos_tab = pybamm.BoundaryValue(W, "positive tab") R_cc = ((alpha_prime / l_y) * (sigma_cn_dbl_prime * l_cn * W_pos_tab + sigma_cp_dbl_prime * l_cp * W_neg_tab) - (psi_pos_tab - psi_neg_tab)) / (sigma_cn_dbl_prime * l_cn + sigma_cp_dbl_prime * l_cp) R_cc_dim = R_cc * param.potential_scale / param.I_typ self.variables.update({ "Current collector potential weighted sum (negative tab)": psi_neg_tab, "Current collector potential weighted sum (positive tab)": psi_pos_tab, "Perturbation to c.c. potential difference (negative tab)": W_neg_tab, "Perturbation to c.c. potential difference (positive tab)": W_pos_tab, "Effective current collector resistance": R_cc, "Effective current collector resistance [Ohm]": R_cc_dim, })
def __init__(self): super().__init__() self.name = "Effective resistance in current collector model (2D)" self.param = pybamm.standard_parameters_lithium_ion # Get necessary parameters param = self.param l_cn = param.l_cn l_cp = param.l_cp l_tab_p = param.l_tab_p A_tab_p = l_cp * l_tab_p sigma_cn_dbl_prime = param.sigma_cn_dbl_prime sigma_cp_dbl_prime = param.sigma_cp_dbl_prime delta = param.delta # Set model variables -- we solve a auxilliary problem in each current collector # then relate this to the potentials and resistances later f_n = pybamm.Variable("Unit solution in negative current collector", domain="current collector") f_p = pybamm.Variable("Unit solution in positive current collector", domain="current collector") # Governing equations -- we impose that the average of f_p is zero # by introducing a Lagrange multiplier c = pybamm.Variable("Lagrange multiplier") self.algebraic = { f_n: pybamm.laplacian(f_n) + pybamm.source(1, f_n), c: pybamm.laplacian(f_p) - pybamm.source(1, f_p) + c * pybamm.DefiniteIntegralVector(f_p, vector_type="column"), f_p: pybamm.yz_average(f_p) + 0 * c, } # Boundary conditons pos_tab_bc = l_cp / A_tab_p self.boundary_conditions = { f_n: { "negative tab": (0, "Dirichlet"), "positive tab": (0, "Neumann") }, f_p: { "negative tab": (0, "Neumann"), "positive tab": (pos_tab_bc, "Neumann"), }, } # "Initial conditions" provides initial guess for solver self.initial_conditions = { f_n: pybamm.Scalar(0), f_p: pybamm.Scalar(0), c: pybamm.Scalar(0), } # Define effective current collector resistance R_cc_n = delta * pybamm.yz_average(f_n) / (l_cn * sigma_cn_dbl_prime) R_cc_p = (delta * pybamm.BoundaryIntegral(f_p, "positive tab") / (l_cp * sigma_cp_dbl_prime)) R_cc = R_cc_n + R_cc_p R_scale = param.potential_scale / param.I_typ self.variables = { "Unit solution in negative current collector": f_n, "Unit solution in positive current collector": f_p, "Effective current collector resistance": R_cc, "Effective current collector resistance [Ohm]": R_cc * R_scale, "Effective negative current collector resistance": R_cc_n, "Effective negative current collector resistance [Ohm]": R_cc_n * R_scale, "Effective positive current collector resistance": R_cc_p, "Effective positive current collector resistance [Ohm]": R_cc_p * R_scale, } # Add spatial variables var = pybamm.standard_spatial_vars L_y = pybamm.geometric_parameters.L_y L_z = pybamm.geometric_parameters.L_z self.variables.update({ "y": var.y, "y [m]": var.y * L_y, "z": var.z, "z [m]": var.z * L_z }) pybamm.citations.register("timms2020")