def test_adding_2D_external_variable_fail(self): model = pybamm.BaseModel() a = pybamm.Variable( "a", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) b1 = pybamm.Variable( "b", domain="negative electrode", auxiliary_domains={"secondary": "current collector"}, ) b2 = pybamm.Variable( "b", domain="separator", auxiliary_domains={"secondary": "current collector"}, ) b = pybamm.Concatenation(b1, b2) model.rhs = {a: a * b} model.initial_conditions = {a: 0} model.external_variables = [b] model.variables = {"b": b} disc = get_1p1d_discretisation_for_testing() with self.assertRaisesRegex( NotImplementedError, "Cannot create 2D external variable" ): disc.process_model(model)
def test_concatenations(self): y = np.linspace(0, 1, 10)[:, np.newaxis] a = pybamm.Vector(y) b = pybamm.Scalar(16) c = pybamm.Scalar(3) conc = pybamm.NumpyConcatenation(a, b, c) self.assert_casadi_equal(conc.to_casadi(), casadi.MX(conc.evaluate()), evalf=True) # Domain concatenation mesh = get_mesh_for_testing() a_dom = ["negative electrode"] b_dom = ["separator"] a = 2 * pybamm.Vector(np.ones_like(mesh[a_dom[0]].nodes), domain=a_dom) b = pybamm.Vector(np.ones_like(mesh[b_dom[0]].nodes), domain=b_dom) conc = pybamm.DomainConcatenation([b, a], mesh) self.assert_casadi_equal(conc.to_casadi(), casadi.MX(conc.evaluate()), evalf=True) # 2d disc = get_1p1d_discretisation_for_testing() a = pybamm.Variable("a", domain=a_dom) b = pybamm.Variable("b", domain=b_dom) conc = pybamm.Concatenation(a, b) disc.set_variable_slices([conc]) expr = disc.process_symbol(conc) y = casadi.SX.sym("y", expr.size) x = expr.to_casadi(None, y) f = casadi.Function("f", [x], [x]) y_eval = np.linspace(0, 1, expr.size) self.assert_casadi_equal(f(y_eval), casadi.SX(expr.evaluate(y=y_eval)))
def test_jac_of_domain_concatenation(self): # create mesh disc = get_1p1d_discretisation_for_testing() mesh = disc.mesh y = pybamm.StateVector(slice(0, 1500)) # Jacobian of a DomainConcatenation of constants is a zero matrix of the # appropriate size a_dom = ["negative electrode"] b_dom = ["separator"] c_dom = ["positive electrode"] cc_npts = mesh["current collector"][0].npts curr_coll_vector = pybamm.Vector(np.ones(cc_npts), domain="current collector") a = 2 * pybamm.PrimaryBroadcast(curr_coll_vector, a_dom) b = pybamm.PrimaryBroadcast(curr_coll_vector, b_dom) c = 3 * pybamm.PrimaryBroadcast(curr_coll_vector, c_dom) conc = pybamm.Concatenation(a, b, c) disc.set_variable_slices([conc]) conc_disc = disc.process_symbol(conc) jac = conc_disc.jac(y).evaluate().toarray() np.testing.assert_array_equal(jac, np.zeros((1500, 1500))) # Jacobian of a DomainConcatenation of StateVectors a = pybamm.Variable("a", domain=a_dom) b = pybamm.Variable("b", domain=b_dom) c = pybamm.Variable("c", domain=c_dom) conc = pybamm.Concatenation(a, b, c) disc.set_variable_slices([conc]) conc_disc = disc.process_symbol(conc) y0 = np.ones(1500) jac = conc_disc.jac(y).evaluate(y=y0).toarray() np.testing.assert_array_equal(jac, np.eye(1500))
def test_concatenation_2D(self): disc = get_1p1d_discretisation_for_testing(zpts=3) a = pybamm.Variable("a", domain=["negative electrode"]) b = pybamm.Variable("b", domain=["separator"]) c = pybamm.Variable("c", domain=["positive electrode"]) conc = pybamm.Concatenation(a, b, c) disc.set_variable_slices([conc]) self.assertEqual( disc.y_slices[a.id], [slice(0, 40), slice(100, 140), slice(200, 240)]) self.assertEqual( disc.y_slices[b.id], [slice(40, 65), slice(140, 165), slice(240, 265)]) self.assertEqual( disc.y_slices[c.id], [slice(65, 100), slice(165, 200), slice(265, 300)]) expr = disc.process_symbol(conc) self.assertIsInstance(expr, pybamm.DomainConcatenation) # Evaulate y = np.linspace(0, 1, 300) self.assertEqual(expr.children[0].evaluate(0, y).shape, (120, 1)) self.assertEqual(expr.children[1].evaluate(0, y).shape, (75, 1)) self.assertEqual(expr.children[2].evaluate(0, y).shape, (105, 1)) np.testing.assert_equal(expr.evaluate(0, y), y[:, np.newaxis])
def test_domain_concatenation_2D(self): disc = get_1p1d_discretisation_for_testing() a_dom = ["negative electrode"] b_dom = ["separator"] a = pybamm.Variable("a", domain=a_dom) b = pybamm.Variable("b", domain=b_dom) conc = pybamm.concatenation(2 * a, 3 * b) disc.set_variable_slices([a, b]) expr = disc.process_symbol(conc) self.assertIsInstance(expr, pybamm.DomainConcatenation) y = np.empty((expr._size, 1)) for i in range(len(y)): y[i] = i constant_symbols = OrderedDict() variable_symbols = OrderedDict() pybamm.find_symbols(expr, constant_symbols, variable_symbols) self.assertEqual(len(constant_symbols), 0) evaluator = pybamm.EvaluatorPython(expr) result = evaluator.evaluate(y=y) np.testing.assert_allclose(result, expr.evaluate(y=y)) # check that concatenating a single domain is consistent expr = disc.process_symbol(pybamm.Concatenation(a)) evaluator = pybamm.EvaluatorPython(expr) result = evaluator.evaluate(y=y) np.testing.assert_allclose(result, expr.evaluate(y=y))
def test_processed_variable_2D_x_z(self): var = pybamm.Variable( "var", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) x = pybamm.SpatialVariable( "x", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_1p1d_discretisation_for_testing() disc.set_variable_slices([var]) z_sol = disc.process_symbol(z).entries[:, 0] x_sol = disc.process_symbol(x).entries[:, 0] # Keep only the first iteration of entries x_sol = x_sol[:len(x_sol) // len(z_sol)] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(z_sol))[:, np.newaxis] * np.linspace( 0, 5) var_casadi = to_casadi(var_sol, y_sol) processed_var = pybamm.ProcessedVariable( [var_sol], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal( processed_var.entries, np.reshape( y_sol, [len(x_sol), len(z_sol), len(t_sol)]), ) # On edges x_s_edge = pybamm.Matrix( np.tile(disc.mesh["separator"].edges, len(z_sol)), domain="separator", auxiliary_domains={"secondary": "current collector"}, ) x_s_edge.mesh = disc.mesh["separator"] x_s_edge.secondary_mesh = disc.mesh["current collector"] x_s_casadi = to_casadi(x_s_edge, y_sol) processed_x_s_edge = pybamm.ProcessedVariable( [x_s_edge], [x_s_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal( x_s_edge.entries.flatten(), processed_x_s_edge.entries[:, :, 0].T.flatten())
def test_broadcast_2D(self): # broadcast in 2D --> Outer symbol var = pybamm.Variable("var", ["current collector"]) disc = get_1p1d_discretisation_for_testing() mesh = disc.mesh broad = pybamm.Broadcast(var, "separator", broadcast_type="primary") disc.set_variable_slices([var]) broad_disc = disc.process_symbol(broad) self.assertIsInstance(broad_disc, pybamm.Outer) self.assertIsInstance(broad_disc.children[0], pybamm.StateVector) self.assertIsInstance(broad_disc.children[1], pybamm.Vector) self.assertEqual( broad_disc.shape, (mesh["separator"][0].npts * mesh["current collector"][0].npts, 1), )
def test_outer(self): var = pybamm.Variable("var", ["current collector"]) x = pybamm.SpatialVariable("x_s", ["separator"]) # create discretisation disc = get_1p1d_discretisation_for_testing() mesh = disc.mesh # process Outer variable disc.set_variable_slices([var]) outer = pybamm.outer(var, x) outer_disc = disc.process_symbol(outer) self.assertIsInstance(outer_disc, pybamm.Outer) self.assertIsInstance(outer_disc.children[0], pybamm.StateVector) self.assertIsInstance(outer_disc.children[1], pybamm.Vector) self.assertEqual( outer_disc.shape, (mesh["separator"][0].npts * mesh["current collector"][0].npts, 1), )
def test_processed_variable_3D_x_z(self): var = pybamm.Variable( "var", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_1p1d_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] z_sol = disc.process_symbol(z).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(z_sol))[:, np.newaxis] * np.linspace( 0, 5) processed_var = pybamm.ProcessedVariable(var_sol, t_sol, y_sol, mesh=disc.mesh) np.testing.assert_array_equal( processed_var.entries, np.reshape( y_sol, [len(x_sol), len(z_sol), len(t_sol)]), ) # On edges x_s_edge = pybamm.Matrix( np.repeat(disc.mesh["separator"][0].edges, len(z_sol)), domain="separator", auxiliary_domains={"secondary": "current collector"}, ) processed_x_s_edge = pybamm.ProcessedVariable(x_s_edge, t_sol, y_sol, disc.mesh) np.testing.assert_array_equal( x_s_edge.entries[:, 0], processed_x_s_edge.entries[:, :, 0].reshape(-1, 1)[:, 0], )
def test_broadcast_2D(self): # broadcast in 2D --> MatrixMultiplication var = pybamm.Variable("var", ["current collector"]) disc = get_1p1d_discretisation_for_testing() mesh = disc.mesh broad = pybamm.PrimaryBroadcast(var, "separator") disc.set_variable_slices([var]) broad_disc = disc.process_symbol(broad) self.assertIsInstance(broad_disc, pybamm.MatrixMultiplication) self.assertIsInstance(broad_disc.children[0], pybamm.Matrix) self.assertIsInstance(broad_disc.children[1], pybamm.StateVector) self.assertEqual( broad_disc.shape, (mesh["separator"][0].npts * mesh["current collector"][0].npts, 1), ) y_test = np.linspace(0, 1, mesh["current collector"][0].npts) np.testing.assert_array_equal( broad_disc.evaluate(y=y_test), np.outer(y_test, np.ones(mesh["separator"][0].npts)).reshape(-1, 1), ) # test broadcast to edges broad_to_edges = pybamm.PrimaryBroadcastToEdges(var, "separator") broad_to_edges_disc = disc.process_symbol(broad_to_edges) self.assertIsInstance(broad_to_edges_disc, pybamm.MatrixMultiplication) self.assertIsInstance(broad_to_edges_disc.children[0], pybamm.Matrix) self.assertIsInstance(broad_to_edges_disc.children[1], pybamm.StateVector) self.assertEqual( broad_to_edges_disc.shape, ((mesh["separator"][0].npts + 1) * mesh["current collector"][0].npts, 1), ) y_test = np.linspace(0, 1, mesh["current collector"][0].npts) np.testing.assert_array_equal( broad_to_edges_disc.evaluate(y=y_test), np.outer(y_test, np.ones(mesh["separator"][0].npts + 1)).reshape(-1, 1), )
def test_1D_different_domains(self): # Negative electrode domain var = pybamm.Variable("var", domain=["negative electrode"]) x = pybamm.SpatialVariable("x", domain=["negative electrode"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = [0] y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5 sol = pybamm.Solution(t_sol, y_sol) pybamm.ProcessedSymbolicVariable(var_sol, sol) # Particle domain var = pybamm.Variable("var", domain=["negative particle"]) r = pybamm.SpatialVariable("r", domain=["negative particle"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = [0] y_sol = np.ones_like(r_sol)[:, np.newaxis] * 5 sol = pybamm.Solution(t_sol, y_sol) pybamm.ProcessedSymbolicVariable(var_sol, sol) # Current collector domain var = pybamm.Variable("var", domain=["current collector"]) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_1p1d_discretisation_for_testing() disc.set_variable_slices([var]) z_sol = disc.process_symbol(z).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = [0] y_sol = np.ones_like(z_sol)[:, np.newaxis] * 5 sol = pybamm.Solution(t_sol, y_sol) pybamm.ProcessedSymbolicVariable(var_sol, sol) # Other domain var = pybamm.Variable("var", domain=["line"]) x = pybamm.SpatialVariable("x", domain=["line"]) geometry = pybamm.Geometry( {"line": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} ) submesh_types = {"line": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)} var_pts = {x: 10} mesh = pybamm.Mesh(geometry, submesh_types, var_pts) disc = pybamm.Discretisation(mesh, {"line": pybamm.FiniteVolume()}) disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = [0] y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5 sol = pybamm.Solution(t_sol, y_sol) pybamm.ProcessedSymbolicVariable(var_sol, sol) # 2D fails var = pybamm.Variable( "var", domain=["negative particle"], auxiliary_domains={"secondary": "negative electrode"}, ) r = pybamm.SpatialVariable( "r", domain=["negative particle"], auxiliary_domains={"secondary": "negative electrode"}, ) disc = tests.get_p2d_discretisation_for_testing() disc.set_variable_slices([var]) r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = [0] y_sol = np.ones_like(r_sol)[:, np.newaxis] * 5 sol = pybamm.Solution(t_sol, y_sol) with self.assertRaisesRegex(NotImplementedError, "Shape not recognized"): pybamm.ProcessedSymbolicVariable(var_sol, sol)