def test_delta_function(self): a = pybamm.Symbol("a") delta_a = pybamm.DeltaFunction(a, "right", "some domain") self.assertEqual(delta_a.side, "right") self.assertEqual(delta_a.child.id, a.id) self.assertFalse(delta_a.evaluates_on_edges()) with self.assertRaisesRegex(pybamm.DomainError, "Delta function domain cannot be None"): delta_a = pybamm.DeltaFunction(a, "right", None)
def test_delta_function(self): a = pybamm.Symbol("a") delta_a = pybamm.DeltaFunction(a, "right", "some domain") self.assertEqual(delta_a.side, "right") self.assertEqual(delta_a.child.id, a.id) self.assertEqual(delta_a.domain, ["some domain"]) self.assertFalse(delta_a.evaluates_on_edges("primary")) a = pybamm.Symbol("a", domain="some domain") delta_a = pybamm.DeltaFunction(a, "left", "another domain") self.assertEqual(delta_a.side, "left") self.assertEqual(delta_a.domain, ["another domain"]) self.assertEqual(delta_a.auxiliary_domains, {"secondary": ["some domain"]}) with self.assertRaisesRegex(pybamm.DomainError, "Delta function domain cannot be None"): delta_a = pybamm.DeltaFunction(a, "right", None)
def test_delta_function(self): mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) var = pybamm.Variable("var") delta_fn_left = pybamm.DeltaFunction(var, "left", "negative electrode") delta_fn_right = pybamm.DeltaFunction(var, "right", "negative electrode") disc.set_variable_slices([var]) delta_fn_left_disc = disc.process_symbol(delta_fn_left) delta_fn_right_disc = disc.process_symbol(delta_fn_right) # Basic shape and type tests y = np.ones_like(mesh["negative electrode"][0].nodes[:, np.newaxis]) # Left self.assertEqual(delta_fn_left_disc.domain, delta_fn_left.domain) self.assertEqual(delta_fn_left_disc.auxiliary_domains, delta_fn_left.auxiliary_domains) self.assertIsInstance(delta_fn_left_disc, pybamm.Multiplication) self.assertIsInstance(delta_fn_left_disc.left, pybamm.Matrix) np.testing.assert_array_equal( delta_fn_left_disc.left.evaluate()[:, 1:], 0) self.assertEqual(delta_fn_left_disc.shape, y.shape) # Right self.assertEqual(delta_fn_right_disc.domain, delta_fn_right.domain) self.assertEqual(delta_fn_right_disc.auxiliary_domains, delta_fn_right.auxiliary_domains) self.assertIsInstance(delta_fn_right_disc, pybamm.Multiplication) self.assertIsInstance(delta_fn_right_disc.left, pybamm.Matrix) np.testing.assert_array_equal( delta_fn_right_disc.left.evaluate()[:, :-1], 0) self.assertEqual(delta_fn_right_disc.shape, y.shape) # Value tests # Delta function should integrate to the same thing as variable var_disc = disc.process_symbol(var) x = pybamm.standard_spatial_vars.x_n delta_fn_int_disc = disc.process_symbol( pybamm.Integral(delta_fn_left, x)) np.testing.assert_array_equal( var_disc.evaluate(y=y) * mesh["negative electrode"][0].edges[-1], np.sum(delta_fn_int_disc.evaluate(y=y)), )
def test_process_symbol(self): parameter_values = pybamm.ParameterValues({"a": 4, "b": 2, "c": 3}) # process parameter a = pybamm.Parameter("a") processed_a = parameter_values.process_symbol(a) self.assertIsInstance(processed_a, pybamm.Scalar) self.assertEqual(processed_a.value, 4) # process binary operation var = pybamm.Variable("var") add = a + var processed_add = parameter_values.process_symbol(add) self.assertIsInstance(processed_add, pybamm.Addition) self.assertIsInstance(processed_add.children[0], pybamm.Scalar) self.assertIsInstance(processed_add.children[1], pybamm.Variable) self.assertEqual(processed_add.children[0].value, 4) b = pybamm.Parameter("b") add = a + b processed_add = parameter_values.process_symbol(add) self.assertIsInstance(processed_add, pybamm.Scalar) self.assertEqual(processed_add.value, 6) scal = pybamm.Scalar(34) mul = a * scal processed_mul = parameter_values.process_symbol(mul) self.assertIsInstance(processed_mul, pybamm.Scalar) self.assertEqual(processed_mul.value, 136) # process integral aa = pybamm.Parameter("a", domain=["negative electrode"]) x = pybamm.SpatialVariable("x", domain=["negative electrode"]) integ = pybamm.Integral(aa, x) processed_integ = parameter_values.process_symbol(integ) self.assertIsInstance(processed_integ, pybamm.Integral) self.assertIsInstance(processed_integ.children[0], pybamm.Scalar) self.assertEqual(processed_integ.children[0].value, 4) self.assertEqual(processed_integ.integration_variable[0].id, x.id) # process unary operation v = pybamm.Variable("v", domain="test") grad = pybamm.Gradient(v) processed_grad = parameter_values.process_symbol(grad) self.assertIsInstance(processed_grad, pybamm.Gradient) self.assertIsInstance(processed_grad.children[0], pybamm.Variable) # process delta function aa = pybamm.Parameter("a") delta_aa = pybamm.DeltaFunction(aa, "left", "some domain") processed_delta_aa = parameter_values.process_symbol(delta_aa) self.assertIsInstance(processed_delta_aa, pybamm.DeltaFunction) self.assertEqual(processed_delta_aa.side, "left") processed_a = processed_delta_aa.children[0] self.assertIsInstance(processed_a, pybamm.Scalar) self.assertEqual(processed_a.value, 4) # process boundary operator (test for BoundaryValue) aa = pybamm.Parameter("a", domain=["negative electrode"]) x = pybamm.SpatialVariable("x", domain=["negative electrode"]) boundary_op = pybamm.BoundaryValue(aa * x, "left") processed_boundary_op = parameter_values.process_symbol(boundary_op) self.assertIsInstance(processed_boundary_op, pybamm.BoundaryOperator) processed_a = processed_boundary_op.children[0].children[0] processed_x = processed_boundary_op.children[0].children[1] self.assertIsInstance(processed_a, pybamm.Scalar) self.assertEqual(processed_a.value, 4) self.assertEqual(processed_x.id, x.id) # process broadcast whole_cell = ["negative electrode", "separator", "positive electrode"] broad = pybamm.PrimaryBroadcast(a, whole_cell) processed_broad = parameter_values.process_symbol(broad) self.assertIsInstance(processed_broad, pybamm.Broadcast) self.assertEqual(processed_broad.domain, whole_cell) self.assertIsInstance(processed_broad.children[0], pybamm.Scalar) self.assertEqual(processed_broad.children[0].evaluate(), 4) # process concatenation conc = pybamm.concatenation( pybamm.Vector(np.ones(10), domain="test"), pybamm.Vector(2 * np.ones(15), domain="test 2"), ) processed_conc = parameter_values.process_symbol(conc) self.assertIsInstance(processed_conc.children[0], pybamm.Vector) self.assertIsInstance(processed_conc.children[1], pybamm.Vector) np.testing.assert_array_equal(processed_conc.children[0].entries, 1) np.testing.assert_array_equal(processed_conc.children[1].entries, 2) # process domain concatenation c_e_n = pybamm.Variable("c_e_n", ["negative electrode"]) c_e_s = pybamm.Variable("c_e_p", ["separator"]) test_mesh = shared.get_mesh_for_testing() dom_con = pybamm.DomainConcatenation([a * c_e_n, b * c_e_s], test_mesh) processed_dom_con = parameter_values.process_symbol(dom_con) a_proc = processed_dom_con.children[0].children[0] b_proc = processed_dom_con.children[1].children[0] self.assertIsInstance(a_proc, pybamm.Scalar) self.assertIsInstance(b_proc, pybamm.Scalar) self.assertEqual(a_proc.value, 4) self.assertEqual(b_proc.value, 2) # process variable c = pybamm.Variable("c") processed_c = parameter_values.process_symbol(c) self.assertIsInstance(processed_c, pybamm.Variable) self.assertEqual(processed_c.name, "c") # process scalar d = pybamm.Scalar(14) processed_d = parameter_values.process_symbol(d) self.assertIsInstance(processed_d, pybamm.Scalar) self.assertEqual(processed_d.value, 14) # process array types e = pybamm.Vector(np.ones(4)) processed_e = parameter_values.process_symbol(e) self.assertIsInstance(processed_e, pybamm.Vector) np.testing.assert_array_equal(processed_e.evaluate(), np.ones((4, 1))) f = pybamm.Matrix(np.ones((5, 6))) processed_f = parameter_values.process_symbol(f) self.assertIsInstance(processed_f, pybamm.Matrix) np.testing.assert_array_equal(processed_f.evaluate(), np.ones((5, 6))) # process statevector g = pybamm.StateVector(slice(0, 10)) processed_g = parameter_values.process_symbol(g) self.assertIsInstance(processed_g, pybamm.StateVector) np.testing.assert_array_equal( processed_g.evaluate(y=np.ones(10)), np.ones((10, 1)) ) # not implemented sym = pybamm.Symbol("sym") with self.assertRaises(NotImplementedError): parameter_values.process_symbol(sym) # not found with self.assertRaises(KeyError): x = pybamm.Parameter("x") parameter_values.process_symbol(x)
def test_delta_function(self): a = pybamm.Symbol("a") delta_a = pybamm.DeltaFunction(a, "right", "some domain") self.assertEqual(delta_a.side, "right") self.assertEqual(delta_a.child.id, a.id) self.assertFalse(delta_a.evaluates_on_edges())
def test_symbol_simplify(self): a = pybamm.Scalar(0) b = pybamm.Scalar(1) c = pybamm.Parameter("c") d = pybamm.Scalar(-1) e = pybamm.Scalar(2) g = pybamm.Variable("g") # negate self.assertIsInstance((-a).simplify(), pybamm.Scalar) self.assertEqual((-a).simplify().evaluate(), 0) self.assertIsInstance((-b).simplify(), pybamm.Scalar) self.assertEqual((-b).simplify().evaluate(), -1) # absolute value self.assertIsInstance((abs(a)).simplify(), pybamm.Scalar) self.assertEqual((abs(a)).simplify().evaluate(), 0) self.assertIsInstance((abs(d)).simplify(), pybamm.Scalar) self.assertEqual((abs(d)).simplify().evaluate(), 1) # function def sin(x): return math.sin(x) f = pybamm.Function(sin, b) self.assertIsInstance((f).simplify(), pybamm.Scalar) self.assertEqual((f).simplify().evaluate(), math.sin(1)) def myfunction(x, y): return x * y f = pybamm.Function(myfunction, a, b) self.assertIsInstance((f).simplify(), pybamm.Scalar) self.assertEqual((f).simplify().evaluate(), 0) # FunctionParameter f = pybamm.FunctionParameter("function", b) self.assertIsInstance((f).simplify(), pybamm.FunctionParameter) self.assertEqual((f).simplify().children[0].id, b.id) f = pybamm.FunctionParameter("function", a, b) self.assertIsInstance((f).simplify(), pybamm.FunctionParameter) self.assertEqual((f).simplify().children[0].id, a.id) self.assertEqual((f).simplify().children[1].id, b.id) # Gradient self.assertIsInstance((pybamm.grad(a)).simplify(), pybamm.Scalar) self.assertEqual((pybamm.grad(a)).simplify().evaluate(), 0) v = pybamm.Variable("v") self.assertIsInstance((pybamm.grad(v)).simplify(), pybamm.Gradient) # Divergence self.assertIsInstance((pybamm.div(a)).simplify(), pybamm.Scalar) self.assertEqual((pybamm.div(a)).simplify().evaluate(), 0) self.assertIsInstance((pybamm.div(v)).simplify(), pybamm.Divergence) # Integral self.assertIsInstance( (pybamm.Integral(a, pybamm.t)).simplify(), pybamm.Integral ) # BoundaryValue v_neg = pybamm.Variable("v", domain=["negative electrode"]) self.assertIsInstance( (pybamm.boundary_value(v_neg, "right")).simplify(), pybamm.BoundaryValue ) # Delta function self.assertIsInstance( (pybamm.DeltaFunction(v_neg, "right", "domain")).simplify(), pybamm.DeltaFunction, ) # addition self.assertIsInstance((a + b).simplify(), pybamm.Scalar) self.assertEqual((a + b).simplify().evaluate(), 1) self.assertIsInstance((b + b).simplify(), pybamm.Scalar) self.assertEqual((b + b).simplify().evaluate(), 2) self.assertIsInstance((b + a).simplify(), pybamm.Scalar) self.assertEqual((b + a).simplify().evaluate(), 1) # subtraction self.assertIsInstance((a - b).simplify(), pybamm.Scalar) self.assertEqual((a - b).simplify().evaluate(), -1) self.assertIsInstance((b - b).simplify(), pybamm.Scalar) self.assertEqual((b - b).simplify().evaluate(), 0) self.assertIsInstance((b - a).simplify(), pybamm.Scalar) self.assertEqual((b - a).simplify().evaluate(), 1) # addition and subtraction with matrix zero v = pybamm.Vector(np.zeros((10, 1))) self.assertIsInstance((b + v).simplify(), pybamm.Array) np.testing.assert_array_equal((b + v).simplify().evaluate(), np.ones((10, 1))) self.assertIsInstance((v + b).simplify(), pybamm.Array) np.testing.assert_array_equal((v + b).simplify().evaluate(), np.ones((10, 1))) self.assertIsInstance((b - v).simplify(), pybamm.Array) np.testing.assert_array_equal((b - v).simplify().evaluate(), np.ones((10, 1))) self.assertIsInstance((v - b).simplify(), pybamm.Array) np.testing.assert_array_equal((v - b).simplify().evaluate(), -np.ones((10, 1))) # multiplication self.assertIsInstance((a * b).simplify(), pybamm.Scalar) self.assertEqual((a * b).simplify().evaluate(), 0) self.assertIsInstance((b * a).simplify(), pybamm.Scalar) self.assertEqual((b * a).simplify().evaluate(), 0) self.assertIsInstance((b * b).simplify(), pybamm.Scalar) self.assertEqual((b * b).simplify().evaluate(), 1) self.assertIsInstance((a * a).simplify(), pybamm.Scalar) self.assertEqual((a * a).simplify().evaluate(), 0) # test when other node is a parameter self.assertIsInstance((a + c).simplify(), pybamm.Parameter) self.assertIsInstance((c + a).simplify(), pybamm.Parameter) self.assertIsInstance((c + b).simplify(), pybamm.Addition) self.assertIsInstance((b + c).simplify(), pybamm.Addition) self.assertIsInstance((a * c).simplify(), pybamm.Scalar) self.assertEqual((a * c).simplify().evaluate(), 0) self.assertIsInstance((c * a).simplify(), pybamm.Scalar) self.assertEqual((c * a).simplify().evaluate(), 0) self.assertIsInstance((b * c).simplify(), pybamm.Parameter) self.assertIsInstance((e * c).simplify(), pybamm.Multiplication) expr = (e * (e * c)).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (e / (e * c)).simplify() self.assertIsInstance(expr, pybamm.Division) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 1.0) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (e * (e / c)).simplify() self.assertIsInstance(expr, pybamm.Division) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 4.0) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (e * (c / e)).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 1.0) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = ((e * c) * (c / e)).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 1.0) self.assertIsInstance(expr.children[1], pybamm.Multiplication) self.assertIsInstance(expr.children[1].children[0], pybamm.Parameter) self.assertIsInstance(expr.children[1].children[1], pybamm.Parameter) expr = (e + (e + c)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 4.0) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (e + (e - c)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 4.0) self.assertIsInstance(expr.children[1], pybamm.Negate) self.assertIsInstance(expr.children[1].children[0], pybamm.Parameter) expr = (e + (g - c)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 2.0) self.assertIsInstance(expr.children[1], pybamm.Subtraction) self.assertIsInstance(expr.children[1].children[0], pybamm.Variable) self.assertIsInstance(expr.children[1].children[1], pybamm.Parameter) expr = ((2 + c) + (c + 2)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 4.0) self.assertIsInstance(expr.children[1], pybamm.Multiplication) self.assertIsInstance(expr.children[1].children[0], pybamm.Scalar) self.assertEqual(expr.children[1].children[0].evaluate(), 2) self.assertIsInstance(expr.children[1].children[1], pybamm.Parameter) expr = ((-1 + c) - (c + 1) + (c - 1)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), -3.0) # check these don't simplify self.assertIsInstance((c * e).simplify(), pybamm.Multiplication) self.assertIsInstance((e / c).simplify(), pybamm.Division) self.assertIsInstance((c).simplify(), pybamm.Parameter) c1 = pybamm.Parameter("c1") self.assertIsInstance((c1 * c).simplify(), pybamm.Multiplication) # should simplify division to multiply self.assertIsInstance((c / e).simplify(), pybamm.Multiplication) self.assertIsInstance((c / b).simplify(), pybamm.Parameter) self.assertIsInstance((c * b).simplify(), pybamm.Parameter) # negation with parameter self.assertIsInstance((-c).simplify(), pybamm.Negate) self.assertIsInstance((a + b + a).simplify(), pybamm.Scalar) self.assertEqual((a + b + a).simplify().evaluate(), 1) self.assertIsInstance((b + a + a).simplify(), pybamm.Scalar) self.assertEqual((b + a + a).simplify().evaluate(), 1) self.assertIsInstance((a * b * b).simplify(), pybamm.Scalar) self.assertEqual((a * b * b).simplify().evaluate(), 0) self.assertIsInstance((b * a * b).simplify(), pybamm.Scalar) self.assertEqual((b * a * b).simplify().evaluate(), 0) # power simplification self.assertIsInstance((c ** a).simplify(), pybamm.Scalar) self.assertEqual((c ** a).simplify().evaluate(), 1) self.assertIsInstance((a ** c).simplify(), pybamm.Scalar) self.assertEqual((a ** c).simplify().evaluate(), 0) d = pybamm.Scalar(2) self.assertIsInstance((c ** d).simplify(), pybamm.Power) # division self.assertIsInstance((a / b).simplify(), pybamm.Scalar) self.assertEqual((a / b).simplify().evaluate(), 0) self.assertIsInstance((b / a).simplify(), pybamm.Scalar) self.assertEqual((b / a).simplify().evaluate(), np.inf) self.assertIsInstance((a / a).simplify(), pybamm.Scalar) self.assertTrue(np.isnan((a / a).simplify().evaluate())) self.assertIsInstance((b / b).simplify(), pybamm.Scalar) self.assertEqual((b / b).simplify().evaluate(), 1) # not implemented for Symbol sym = pybamm.Symbol("sym") with self.assertRaises(NotImplementedError): sym.simplify() # A + A = 2A (#323) a = pybamm.Parameter("A") expr = (a + a).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 2) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (a + a + a + a).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 4) self.assertIsInstance(expr.children[1], pybamm.Parameter) expr = (a - a + a - a + a + a).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 2) self.assertIsInstance(expr.children[1], pybamm.Parameter) # A - A = 0 (#323) expr = (a - a).simplify() self.assertIsInstance(expr, pybamm.Scalar) self.assertEqual(expr.evaluate(), 0) # B - (A+A) = B - 2*A (#323) expr = (b - (a + a)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.right, pybamm.Negate) self.assertIsInstance(expr.right.child, pybamm.Multiplication) self.assertEqual(expr.right.child.left.id, pybamm.Scalar(2).id) self.assertEqual(expr.right.child.right.id, a.id) # B - (1*A + 2*A) = B - 3*A (#323) expr = (b - (1 * a + 2 * a)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.right, pybamm.Negate) self.assertIsInstance(expr.right.child, pybamm.Multiplication) self.assertEqual(expr.right.child.left.id, pybamm.Scalar(3).id) self.assertEqual(expr.right.child.right.id, a.id) # B - (A + C) = B - (A + C) (not B - (A - C)) expr = (b - (a + c)).simplify() self.assertIsInstance(expr, pybamm.Addition) self.assertIsInstance(expr.right, pybamm.Subtraction) self.assertEqual(expr.right.left.id, (-a).id) self.assertEqual(expr.right.right.id, c.id)