def test_div(self): # divergence of scalar symbol should fail a = pybamm.Symbol("a") with self.assertRaisesRegex( pybamm.DomainError, "Cannot take divergence of 'a' since its domain is empty", ): pybamm.Divergence(a) # divergence of variable evaluating on edges should fail a = pybamm.PrimaryBroadcast(pybamm.Scalar(1), "test") with self.assertRaisesRegex(TypeError, "evaluate on edges"): pybamm.Divergence(a) # divergence of broadcast should return broadcasted zero a = pybamm.PrimaryBroadcastToEdges(pybamm.Variable("a"), "test domain") div = pybamm.div(a) self.assertIsInstance(div, pybamm.PrimaryBroadcast) self.assertIsInstance(div.child, pybamm.PrimaryBroadcast) self.assertIsInstance(div.child.child, pybamm.Scalar) self.assertEqual(div.child.child.value, 0) # otherwise divergence should work a = pybamm.Symbol("a", domain="test domain") div = pybamm.Divergence(pybamm.Gradient(a)) self.assertEqual(div.domain, a.domain) # check div commutes with negation a = pybamm.Symbol("a", domain="test domain") div = pybamm.div(-pybamm.Gradient(a)) self.assertEqual(div.id, (-pybamm.Divergence(pybamm.Gradient(a))).id)
def get_fundamental_variables(self): # Electrolyte pressure p_n = pybamm.Variable( "Negative electrode pressure", domain="negative electrode", auxiliary_domains={"secondary": "current collector"}, ) p_p = pybamm.Variable( "Positive electrode pressure", domain="positive electrode", auxiliary_domains={"secondary": "current collector"}, ) variables = self._get_standard_neg_pos_pressure_variables(p_n, p_p) # TODO: add permeability and viscosity, and other terms v_mass_n = -pybamm.grad(p_n) v_mass_p = -pybamm.grad(p_p) v_box_n = v_mass_n v_box_p = v_mass_p variables.update( self._get_standard_neg_pos_velocity_variables(v_box_n, v_box_p)) div_v_box_n = pybamm.div(v_box_n) div_v_box_p = pybamm.div(v_box_p) variables.update( self._get_standard_neg_pos_acceleration_variables( div_v_box_n, div_v_box_p)) return variables
def test_exceptions(self): c_n = pybamm.Variable("c", domain=["negative electrode"]) N_n = pybamm.grad(c_n) c_s = pybamm.Variable("c", domain=["separator"]) N_s = pybamm.grad(c_s) model = pybamm.BaseModel() model.rhs = {c_n: pybamm.div(N_n), c_s: pybamm.div(N_s)} model.initial_conditions = {c_n: pybamm.Scalar(3), c_s: pybamm.Scalar(1)} model.boundary_conditions = { c_n: {"left": (0, "Neumann"), "right": (0, "Neumann")}, c_s: {"left": (0, "Neumann"), "right": (0, "Neumann")}, } disc = get_discretisation_for_testing() # check raises error if different sized key and output var model.variables = {c_n.name: c_s} with self.assertRaisesRegex(pybamm.ModelError, "variable and its eqn"): disc.process_model(model) # check doesn't raise if concatenation model.variables = {c_n.name: pybamm.Concatenation(c_n, c_s)} disc.process_model(model, inplace=False) # check doesn't raise if broadcast model.variables = { c_n.name: pybamm.PrimaryBroadcast( pybamm.InputParameter("a"), ["negative electrode"] ) } disc.process_model(model)
def set_rhs(self, variables): c, N, _ = self._unpack(variables) if self.domain == "Negative": self.rhs = {c: -(1 / self.param.C_n) * pybamm.div(N)} elif self.domain == "Positive": self.rhs = {c: -(1 / self.param.C_p) * pybamm.div(N)}
def set_rhs(self, variables): c_s = variables[self.domain + " particle concentration"] N_s = variables[self.domain + " particle flux"] R = variables[self.domain + " particle radius"] if self.domain == "Negative": self.rhs = {c_s: -(1 / (R**2 * self.param.C_n)) * pybamm.div(N_s)} elif self.domain == "Positive": self.rhs = {c_s: -(1 / (R**2 * self.param.C_p)) * pybamm.div(N_s)}
def set_rhs(self, variables): c_s_xav = variables["X-averaged " + self.domain.lower() + " particle concentration"] N_s_xav = variables["X-averaged " + self.domain.lower() + " particle flux"] if self.domain == "Negative": self.rhs = {c_s_xav: -(1 / self.param.C_n) * pybamm.div(N_s_xav)} elif self.domain == "Positive": self.rhs = {c_s_xav: -(1 / self.param.C_p) * pybamm.div(N_s_xav)}
def test_has_spatial_derivatives(self): var = pybamm.Variable("var", domain="test") grad_eqn = pybamm.grad(var) div_eqn = pybamm.div(pybamm.standard_spatial_vars.x_edge) grad_div_eqn = pybamm.div(grad_eqn) algebraic_eqn = 2 * var + 3 self.assertTrue(grad_eqn.has_symbol_of_classes(pybamm.Gradient)) self.assertFalse(grad_eqn.has_symbol_of_classes(pybamm.Divergence)) self.assertFalse(div_eqn.has_symbol_of_classes(pybamm.Gradient)) self.assertTrue(div_eqn.has_symbol_of_classes(pybamm.Divergence)) self.assertTrue(grad_div_eqn.has_symbol_of_classes(pybamm.Gradient)) self.assertTrue(grad_div_eqn.has_symbol_of_classes(pybamm.Divergence)) self.assertFalse(algebraic_eqn.has_symbol_of_classes(pybamm.Gradient)) self.assertFalse(algebraic_eqn.has_symbol_of_classes(pybamm.Divergence))
def set_algebraic(self, variables): p_n = variables["Negative electrode pressure"] p_p = variables["Positive electrode pressure"] j_n = variables["Negative electrode interfacial current density"] j_p = variables["Positive electrode interfacial current density"] v_box_n = variables["Negative electrode volume-averaged velocity"] v_box_p = variables["Positive electrode volume-averaged velocity"] # Problems in the x-direction for p_n and p_p self.algebraic = { p_n: pybamm.div(v_box_n) - self.param.beta_n * j_n, p_p: pybamm.div(v_box_p) - self.param.beta_p * j_p, }
def test_check_well_posedness_initial_boundary_conditions(self): # Well-posed model - Dirichlet whole_cell = ["negative electrode", "separator", "positive electrode"] model = pybamm.BaseModel() c = pybamm.Variable("c", domain=whole_cell) model.rhs = {c: 5 * pybamm.div(pybamm.grad(c)) - 1} model.initial_conditions = {c: 1} model.boundary_conditions = { c: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") } } model.check_well_posedness() # Well-posed model - Neumann model.boundary_conditions = { c: { "left": (0, "Neumann"), "right": (0, "Neumann") } } model.check_well_posedness() # Model with bad initial conditions (expect assertion error) d = pybamm.Variable("d", domain=whole_cell) model.initial_conditions = {d: 3} with self.assertRaisesRegex(pybamm.ModelError, "initial condition"): model.check_well_posedness() # Algebraic well-posed model whole_cell = ["negative electrode", "separator", "positive electrode"] model = pybamm.BaseModel() model.algebraic = {c: 5 * pybamm.div(pybamm.grad(c)) - 1} model.boundary_conditions = { c: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") } } model.check_well_posedness() model.boundary_conditions = { c: { "left": (0, "Neumann"), "right": (0, "Neumann") } } model.check_well_posedness()
def test_process_model_not_inplace(self): # concatenation of variables as the key c = pybamm.Variable("c", domain=["negative electrode"]) N = pybamm.grad(c) model = pybamm.BaseModel() model.rhs = {c: pybamm.div(N)} model.initial_conditions = {c: pybamm.Scalar(3)} model.boundary_conditions = { c: {"left": (0, "Neumann"), "right": (0, "Neumann")} } model.check_well_posedness() # create discretisation disc = get_discretisation_for_testing() mesh = disc.mesh submesh = mesh["negative electrode"] discretised_model = disc.process_model(model, inplace=False) y0 = discretised_model.concatenated_initial_conditions.evaluate() np.testing.assert_array_equal( y0, 3 * np.ones_like(submesh.nodes[:, np.newaxis]) ) # grad and div are identity operators here np.testing.assert_array_equal( y0, discretised_model.concatenated_rhs.evaluate(None, y0) ) discretised_model.check_well_posedness()
def test_mass_matrix_shape(self): """ Test mass matrix shape """ # one equation whole_cell = ["negative electrode", "separator", "positive electrode"] c = pybamm.Variable("c", domain=whole_cell) N = pybamm.grad(c) model = pybamm.BaseModel() model.rhs = {c: pybamm.div(N)} model.initial_conditions = {c: pybamm.Scalar(0)} model.boundary_conditions = { c: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") } } model.variables = {"c": c, "N": N} # create discretisation mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) combined_submesh = mesh.combine_submeshes(*whole_cell) disc.process_model(model) # mass matrix mass = np.eye(combined_submesh[0].npts) np.testing.assert_array_equal(mass, model.mass_matrix.entries.toarray())
def set_rhs(self, variables): "Composite reaction-diffusion with source terms from leading order" param = self.param eps_0 = separator_and_positive_only(variables["Leading-order porosity"]) deps_0_dt = separator_and_positive_only( variables["Leading-order porosity change"] ) c_ox = variables["Separator and positive electrode oxygen concentration"] N_ox = variables["Oxygen flux"].orphans[1] if self.extended is False: pos_reactions = sum( reaction["Positive"]["s_ox"] * variables["Leading-order " + reaction["Positive"]["aj"].lower()] for reaction in self.reactions.values() ) else: pos_reactions = sum( reaction["Positive"]["s_ox"] * variables[reaction["Positive"]["aj"]] for reaction in self.reactions.values() ) sep_reactions = pybamm.FullBroadcast(0, "separator", "current collector") source_terms_0 = ( pybamm.Concatenation(sep_reactions, pos_reactions) / param.gamma_e ) self.rhs = { c_ox: (1 / eps_0) * (-pybamm.div(N_ox) / param.C_e + source_terms_0 - c_ox * deps_0_dt) }
def test_p2d_mass_matrix_shape(self): """ Test mass matrix shape in the pseudo 2-dimensional case """ c = pybamm.Variable("c", domain=["negative particle"]) N = pybamm.grad(c) model = pybamm.BaseModel() model.rhs = {c: pybamm.div(N)} model.initial_conditions = {c: pybamm.Scalar(0)} model.boundary_conditions = { c: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") } } model.variables = {"c": c, "N": N} mesh = get_p2d_mesh_for_testing() spatial_methods = {"negative particle": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) prim_pts = mesh["negative particle"][0].npts sec_pts = len(mesh["negative particle"]) mass_local = eye(prim_pts) mass = kron(eye(sec_pts), mass_local) np.testing.assert_array_equal(mass.toarray(), model.mass_matrix.entries.toarray())
def set_rhs(self, variables): "Composite reaction-diffusion with source terms from leading order" param = self.param eps_0 = variables["Leading-order porosity"] deps_0_dt = variables["Leading-order porosity change"] c_e = variables["Electrolyte concentration"] N_e = variables["Electrolyte flux"] if self.extended is False: sum_s_j = variables[ "Leading-order sum of electrolyte reaction source terms" ] elif self.extended == "distributed": sum_s_j = variables["Sum of electrolyte reaction source terms"] elif self.extended == "average": sum_s_j_n_av = variables[ "Sum of x-averaged negative electrode electrolyte reaction source terms" ] sum_s_j_p_av = variables[ "Sum of x-averaged positive electrode electrolyte reaction source terms" ] sum_s_j = pybamm.Concatenation( pybamm.PrimaryBroadcast(sum_s_j_n_av, "negative electrode"), pybamm.FullBroadcast(0, "separator", "current collector"), pybamm.PrimaryBroadcast(sum_s_j_p_av, "positive electrode"), ) source_terms = sum_s_j / self.param.gamma_e self.rhs = { c_e: (1 / eps_0) * (-pybamm.div(N_e) / param.C_e + source_terms - c_e * deps_0_dt) }
def test_grad_div_broadcast(self): # create mesh and discretisation spatial_methods = {"macroscale": pybamm.FiniteVolume()} mesh = get_mesh_for_testing() disc = pybamm.Discretisation(mesh, spatial_methods) a = pybamm.PrimaryBroadcast(1, "negative electrode") grad_a = disc.process_symbol(pybamm.grad(a)) np.testing.assert_array_equal(grad_a.evaluate(), 0) a_edge = pybamm.PrimaryBroadcastToEdges(1, "negative electrode") div_a = disc.process_symbol(pybamm.div(a_edge)) np.testing.assert_array_equal(div_a.evaluate(), 0) div_grad_a = disc.process_symbol(pybamm.div(pybamm.grad(a))) np.testing.assert_array_equal(div_grad_a.evaluate(), 0)
def test_new_copy(self): model = pybamm.BaseModel(name="a model") whole_cell = ["negative electrode", "separator", "positive electrode"] c = pybamm.Variable("c", domain=whole_cell) d = pybamm.Variable("d", domain=whole_cell) model.rhs = {c: 5 * pybamm.div(pybamm.grad(d)) - 1, d: -c} model.initial_conditions = {c: 1, d: 2} model.boundary_conditions = { c: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") }, d: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") }, } model.use_jacobian = False model.use_simplify = False model.convert_to_format = "python" new_model = model.new_copy() self.assertEqual(new_model.name, model.name) self.assertEqual(new_model.use_jacobian, model.use_jacobian) self.assertEqual(new_model.use_simplify, model.use_simplify) self.assertEqual(new_model.convert_to_format, model.convert_to_format) self.assertEqual(new_model.timescale, model.timescale)
def set_rhs(self, variables): param = self.param eps = variables["Porosity"] deps_dt = variables["Porosity change"] c_e = variables["Electrolyte concentration"] N_e = variables["Electrolyte flux"] # i_e = variables["Electrolyte current density"] # source_term = ((param.s - param.t_plus) / param.gamma_e) * pybamm.div(i_e) # source_term = pybamm.div(i_e) / param.gamma_e # lithium-ion source_terms = sum( pybamm.Concatenation( reaction["Negative"]["s"] * variables[reaction["Negative"]["aj"]], pybamm.FullBroadcast(0, "separator", "current collector"), reaction["Positive"]["s"] * variables[reaction["Positive"]["aj"]], ) / param.gamma_e for reaction in self.reactions.values()) self.rhs = { c_e: (1 / eps) * (-pybamm.div(N_e) / param.C_e + source_terms - c_e * deps_dt) }
def set_rhs(self, variables): "Composite reaction-diffusion with source terms from leading order" param = self.param eps_0 = separator_and_positive_only( variables["Leading-order porosity"]) deps_0_dt = separator_and_positive_only( variables["Leading-order porosity change"]) c_ox = variables[ "Separator and positive electrode oxygen concentration"] N_ox = variables["Oxygen flux"].orphans[1] if self.extended is False: j_ox_0 = variables[ "Leading-order positive electrode oxygen interfacial current density"] pos_reactions = param.s_ox_Ox * j_ox_0 else: j_ox_0 = variables[ "Positive electrode oxygen interfacial current density"] pos_reactions = param.s_ox_Ox * j_ox_0 sep_reactions = pybamm.FullBroadcast(0, "separator", "current collector") source_terms_0 = (pybamm.Concatenation(sep_reactions, pos_reactions) / param.gamma_e) self.rhs = { c_ox: (1 / eps_0) * (-pybamm.div(N_ox) / param.C_e + source_terms_0 - c_ox * deps_0_dt) }
def set_rhs(self, variables): T = variables["Cell temperature"] T_n = variables["Negative electrode temperature"] T_s = variables["Separator temperature"] T_p = variables["Positive electrode temperature"] Q = variables["Total heating"] # Define volumetric heat capacity rho_k = pybamm.concatenation( self.param.rho_n(T_n), self.param.rho_s(T_s), self.param.rho_p(T_p), ) # Devine thermal conductivity lambda_k = pybamm.concatenation( self.param.lambda_n(T_n), self.param.lambda_s(T_s), self.param.lambda_p(T_p), ) # Fourier's law for heat flux q = -lambda_k * pybamm.grad(T) # N.B only y-z surface cooling is implemented for this model self.rhs = { T: (-pybamm.div(q) / self.param.delta**2 + self.param.B * Q) / (self.param.C_th * rho_k) }
def test_adding_1D_external_variable(self): model = pybamm.BaseModel() a = pybamm.Variable("a", domain=["test"]) b = pybamm.Variable("b", domain=["test"]) model.rhs = {a: a * b} model.boundary_conditions = { a: { "left": (0, "Dirichlet"), "right": (0, "Dirichlet") } } model.initial_conditions = {a: 0} model.external_variables = [b] model.variables = { "a": a, "b": b, "c": a * b, "grad b": pybamm.grad(b), "div grad b": pybamm.div(pybamm.grad(b)), } x = pybamm.SpatialVariable("x", domain="test", coord_sys="cartesian") geometry = { "test": { "primary": { x: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) } } } } submesh_types = {"test": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)} var_pts = {x: 10} mesh = pybamm.Mesh(geometry, submesh_types, var_pts) spatial_methods = {"test": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) self.assertEqual(disc.y_slices[a.id][0], slice(0, 10, None)) self.assertEqual(model.y_slices[a][0], slice(0, 10, None)) b_test = np.ones((10, 1)) np.testing.assert_array_equal( model.variables["b"].evaluate(inputs={"b": b_test}), b_test) # check that b is added to the boundary conditions model.bcs[b.id]["left"] model.bcs[b.id]["right"] # check that grad and div(grad ) produce the correct shapes self.assertEqual(model.variables["b"].shape_for_testing, (10, 1)) self.assertEqual(model.variables["grad b"].shape_for_testing, (11, 1)) self.assertEqual(model.variables["div grad b"].shape_for_testing, (10, 1))
def set_rhs(self, variables): param = self.param eps_s = variables["Separator porosity"] eps_p = variables["Positive electrode porosity"] eps = pybamm.concatenation(eps_s, eps_p) deps_dt_s = variables["Separator porosity change"] deps_dt_p = variables["Positive electrode porosity change"] deps_dt = pybamm.concatenation(deps_dt_s, deps_dt_p) c_ox = variables["Separator and positive electrode oxygen concentration"] N_ox = variables["Oxygen flux"].orphans[1] j_ox = variables["Positive electrode oxygen interfacial current density"] source_terms = pybamm.concatenation( pybamm.FullBroadcast(0, "separator", "current collector"), param.s_ox_Ox * j_ox, ) self.rhs = { c_ox: (1 / eps) * (-pybamm.div(N_ox) / param.C_e + source_terms - c_ox * deps_dt) }
def test_grad_div_with_bcs_on_tab(self): # 2d macroscale mesh = get_1p1d_mesh_for_testing() spatial_methods = { "macroscale": pybamm.FiniteVolume(), "negative particle": pybamm.FiniteVolume(), "positive particle": pybamm.FiniteVolume(), "current collector": pybamm.FiniteVolume(), } disc = pybamm.Discretisation(mesh, spatial_methods) y_test = np.ones(mesh["current collector"][0].npts) # var var = pybamm.Variable("var", domain="current collector") disc.set_variable_slices([var]) # grad grad_eqn = pybamm.grad(var) # div N = pybamm.grad(var) div_eqn = pybamm.div(N) # bcs (on each tab) boundary_conditions = { var.id: { "negative tab": (pybamm.Scalar(1), "Dirichlet"), "positive tab": (pybamm.Scalar(0), "Neumann"), } } disc.bcs = boundary_conditions grad_eqn_disc = disc.process_symbol(grad_eqn) grad_eqn_disc.evaluate(None, y_test) div_eqn_disc = disc.process_symbol(div_eqn) div_eqn_disc.evaluate(None, y_test) # bcs (one pos, one not tab) boundary_conditions = { var.id: { "no tab": (pybamm.Scalar(1), "Dirichlet"), "positive tab": (pybamm.Scalar(0), "Dirichlet"), } } disc.bcs = boundary_conditions grad_eqn_disc = disc.process_symbol(grad_eqn) grad_eqn_disc.evaluate(None, y_test) div_eqn_disc = disc.process_symbol(div_eqn) div_eqn_disc.evaluate(None, y_test) # bcs (one neg, one not tab) boundary_conditions = { var.id: { "negative tab": (pybamm.Scalar(1), "Neumann"), "no tab": (pybamm.Scalar(0), "Neumann"), } } disc.bcs = boundary_conditions grad_eqn_disc = disc.process_symbol(grad_eqn) grad_eqn_disc.evaluate(None, y_test) div_eqn_disc = disc.process_symbol(div_eqn) div_eqn_disc.evaluate(None, y_test)
def set_algebraic(self, variables): phi_e = variables["Electrolyte potential"] i_e = variables["Electrolyte current density"] # Variable summing all of the interfacial current densities sum_j = variables["Sum of interfacial current densities"] self.algebraic = {phi_e: pybamm.div(i_e) - sum_j}
def set_algebraic(self, variables): phi_s = variables[self.domain + " electrode potential"] i_s = variables[self.domain + " electrode current density"] sum_j = sum(variables[reaction[self.domain]["aj"]] for reaction in self.reactions.values()) self.algebraic[phi_s] = pybamm.div(i_s) + sum_j
def set_algebraic(self, variables): p = variables["Electrolyte pressure"] j = variables["Interfacial current density"] v_box = variables["Volume-averaged velocity"] dVbox_dz = variables["Vertical volume-averaged acceleration"] self.algebraic = { p: pybamm.div(v_box) + dVbox_dz - self.param.beta * j }
def set_rhs(self, variables): T = variables["Cell temperature"] q = variables["Heat flux"] Q = variables["Total heating"] self.rhs = { T: (-pybamm.div(q) / self.param.delta**2 + self.param.B * Q) / (self.param.C_th * self.param.rho_k) }
def test_grad_div_shapes_mixed_domain(self): """ Test grad and div with Dirichlet boundary conditions (applied by grad on var) """ # create discretisation mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.SpectralVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) # grad var = pybamm.Variable("var", domain=["negative electrode", "separator"]) grad_eqn = pybamm.grad(var) boundary_conditions = { var.id: { "left": (pybamm.Scalar(1), "Dirichlet"), "right": (pybamm.Scalar(1), "Dirichlet"), } } disc.bcs = boundary_conditions disc.set_variable_slices([var]) grad_eqn_disc = disc.process_symbol(grad_eqn) combined_submesh = mesh.combine_submeshes("negative electrode", "separator") constant_y = np.ones_like(combined_submesh.nodes[:, np.newaxis]) np.testing.assert_array_almost_equal( grad_eqn_disc.evaluate(None, constant_y), np.zeros_like(combined_submesh.edges[:, np.newaxis]), ) # div: test on linear y (should have laplacian zero) so change bcs linear_y = combined_submesh.nodes N = pybamm.grad(var) div_eqn = pybamm.div(N) boundary_conditions = { var.id: { "left": (pybamm.Scalar(0), "Dirichlet"), "right": (pybamm.Scalar(combined_submesh.edges[-1]), "Dirichlet"), } } disc.bcs = boundary_conditions grad_eqn_disc = disc.process_symbol(grad_eqn) np.testing.assert_array_almost_equal( grad_eqn_disc.evaluate(None, linear_y), np.ones_like(combined_submesh.edges[:, np.newaxis]), ) div_eqn_disc = disc.process_symbol(div_eqn) np.testing.assert_array_almost_equal( div_eqn_disc.evaluate(None, linear_y), np.zeros_like(combined_submesh.nodes[:, np.newaxis]), )
def set_algebraic(self, variables): if self.domain == "Separator": return delta_phi = variables[self.domain + " electrode surface potential difference"] i_e = variables[self.domain + " electrolyte current density"] sum_j = sum(variables[reaction[self.domain]["aj"]] for reaction in self.reactions.values()) self.algebraic[delta_phi] = pybamm.div(i_e) - sum_j
def set_algebraic(self, variables): phi_s = variables[self.domain + " electrode potential"] i_s = variables[self.domain + " electrode current density"] # Variable summing all of the interfacial current densities sum_j = variables["Sum of " + self.domain.lower() + " electrode interfacial current densities"] self.algebraic[phi_s] = pybamm.div(i_s) + sum_j
def test_discretise_spatial_operator(self): # create discretisation whole_cell = ["negative electrode", "separator", "positive electrode"] var = pybamm.Variable("var", domain=whole_cell) disc = get_discretisation_for_testing() mesh = disc.mesh variables = [var] disc.set_variable_slices(variables) # Simple expressions for eqn in [pybamm.grad(var), pybamm.div(var)]: eqn_disc = disc.process_symbol(eqn) self.assertIsInstance(eqn_disc, pybamm.MatrixMultiplication) self.assertIsInstance(eqn_disc.children[0], pybamm.Matrix) self.assertIsInstance(eqn_disc.children[1], pybamm.StateVector) combined_submesh = mesh.combine_submeshes(*whole_cell) y = combined_submesh[0].nodes**2 var_disc = disc.process_symbol(var) # grad and var are identity operators here (for testing purposes) np.testing.assert_array_equal(eqn_disc.evaluate(None, y), var_disc.evaluate(None, y)) # More complex expressions for eqn in [var * pybamm.grad(var), var * pybamm.div(var)]: eqn_disc = disc.process_symbol(eqn) self.assertIsInstance(eqn_disc, pybamm.Multiplication) self.assertIsInstance(eqn_disc.children[0], pybamm.StateVector) self.assertIsInstance(eqn_disc.children[1], pybamm.MatrixMultiplication) self.assertIsInstance(eqn_disc.children[1].children[0], pybamm.Matrix) self.assertIsInstance(eqn_disc.children[1].children[1], pybamm.StateVector) y = combined_submesh[0].nodes**2 var_disc = disc.process_symbol(var) # grad and var are identity operators here (for testing purposes) np.testing.assert_array_equal(eqn_disc.evaluate(None, y), var_disc.evaluate(None, y)**2)