def _current_collector_heating(self, variables): "Compute Ohmic heating in current collectors" # TODO: implement grad in 0D to return a scalar zero # TODO: implement grad_squared in other spatial methods so that the if # statement can be removed # In the limit of infinitely large current collector conductivity (i.e. # 0D current collectors), the Ohmic heating in the current collectors is # zero if self.cc_dimension == 0: Q_s_cn = pybamm.Scalar(0) Q_s_cp = pybamm.Scalar(0) # Otherwise we compute the Ohmic heating for 1 or 2D current collectors elif self.cc_dimension in [1, 2]: phi_s_cn = variables["Negative current collector potential"] phi_s_cp = variables["Positive current collector potential"] if self.cc_dimension == 1: Q_s_cn = self.param.sigma_cn_prime * pybamm.inner( pybamm.grad(phi_s_cn), pybamm.grad(phi_s_cn)) Q_s_cp = self.param.sigma_cp_prime * pybamm.inner( pybamm.grad(phi_s_cp), pybamm.grad(phi_s_cp)) elif self.cc_dimension == 2: # Inner not implemented in 2D -- have to call grad_squared directly Q_s_cn = self.param.sigma_cn_prime * pybamm.grad_squared( phi_s_cn) Q_s_cp = self.param.sigma_cp_prime * pybamm.grad_squared( phi_s_cp) return Q_s_cn, Q_s_cp
def _current_collector_heating(self, variables): """Returns the heat source terms in the 2D current collector""" phi_s_cn = variables["Negative current collector potential"] phi_s_cp = variables["Positive current collector potential"] Q_s_cn = self.param.sigma_cn_prime * pybamm.grad_squared(phi_s_cn) Q_s_cp = self.param.sigma_cp_prime * pybamm.grad_squared(phi_s_cp) return Q_s_cn, Q_s_cp
def _current_collector_heating(self, variables): """Returns the heat source terms in the 2D current collector""" phi_s_cn = variables["Negative current collector potential"] phi_s_cp = variables["Positive current collector potential"] # Note: grad not implemented in 2D weak form, but can compute grad squared # directly Q_s_cn = self.param.sigma_cn_prime * pybamm.grad_squared(phi_s_cn) Q_s_cp = self.param.sigma_cp_prime * pybamm.grad_squared(phi_s_cp) return Q_s_cn, Q_s_cp
def test_gradient(self): 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) # test gradient of 5*y + 6*z var = pybamm.Variable("var", domain="current collector") disc.set_variable_slices([var]) y = mesh["current collector"].coordinates[0, :] z = mesh["current collector"].coordinates[1, :] gradient = pybamm.grad(var) grad_disc = disc.process_symbol(gradient) grad_disc_y, grad_disc_z = grad_disc.children np.testing.assert_array_almost_equal( grad_disc_y.evaluate(None, 5 * y + 6 * z), 5 * np.ones_like(y)[:, np.newaxis], ) np.testing.assert_array_almost_equal( grad_disc_z.evaluate(None, 5 * y + 6 * z), 6 * np.ones_like(z)[:, np.newaxis], ) # check grad_squared positive eqn = pybamm.grad_squared(var) eqn_disc = disc.process_symbol(eqn) ans = eqn_disc.evaluate(None, 3 * y ** 2) np.testing.assert_array_less(0, ans)
def test_discretise_equations(self): # get mesh mesh = get_2p1d_mesh_for_testing() spatial_methods = { "macroscale": pybamm.FiniteVolume, "current collector": pybamm.ScikitFiniteElement, } disc = pybamm.Discretisation(mesh, spatial_methods) # discretise some equations var = pybamm.Variable("var", domain="current collector") y = pybamm.SpatialVariable("y", ["current collector"]) z = pybamm.SpatialVariable("z", ["current collector"]) disc.set_variable_slices([var]) y_test = np.ones(mesh["current collector"][0].npts) unit_source = pybamm.Broadcast(1, "current collector") disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Neumann"), "positive tab": (pybamm.Scalar(0), "Neumann"), } } for eqn in [ pybamm.laplacian(var), pybamm.source(unit_source, var), pybamm.laplacian(var) - pybamm.source(unit_source, var), pybamm.source(var, var), pybamm.laplacian(var) - pybamm.source(2 * var, var), pybamm.laplacian(var) - pybamm.source(unit_source**2 + 1 / var, var), pybamm.Integral(var, [y, z]) - 1, pybamm.source(var, var, boundary=True), pybamm.laplacian(var) - pybamm.source(unit_source, var, boundary=True), pybamm.laplacian(var) - pybamm.source(unit_source**2 + 1 / var, var, boundary=True), pybamm.grad_squared(var), ]: # Check that equation can be evaluated in each case # Dirichlet disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Dirichlet"), "positive tab": (pybamm.Scalar(1), "Dirichlet"), } } eqn_disc = disc.process_symbol(eqn) eqn_disc.evaluate(None, y_test) # Neumann disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Neumann"), "positive tab": (pybamm.Scalar(1), "Neumann"), } } eqn_disc = disc.process_symbol(eqn) eqn_disc.evaluate(None, y_test) # One of each disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Neumann"), "positive tab": (pybamm.Scalar(1), "Dirichlet"), } } eqn_disc = disc.process_symbol(eqn) eqn_disc.evaluate(None, y_test) # One of each disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Dirichlet"), "positive tab": (pybamm.Scalar(1), "Neumann"), } } eqn_disc = disc.process_symbol(eqn) eqn_disc.evaluate(None, y_test) # check ValueError raised for non Dirichlet or Neumann BCs eqn = pybamm.laplacian(var) - pybamm.source(unit_source, var) disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Dirichlet"), "positive tab": (pybamm.Scalar(1), "Other BC"), } } with self.assertRaises(ValueError): eqn_disc = disc.process_symbol(eqn) disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Other BC"), "positive tab": (pybamm.Scalar(1), "Neumann"), } } with self.assertRaises(ValueError): eqn_disc = disc.process_symbol(eqn) # raise ModelError if no BCs provided new_var = pybamm.Variable("new_var", domain="current collector") disc.set_variable_slices([new_var]) eqn = pybamm.laplacian(new_var) with self.assertRaises(pybamm.ModelError): eqn_disc = disc.process_symbol(eqn) # check GeometryError if using scikit-fem not in y or z x = pybamm.SpatialVariable("x", ["current collector"]) with self.assertRaises(pybamm.GeometryError): disc.process_symbol(x)