def test_variable_init(self): a = pybamm.VariableDot("a'") self.assertEqual(a.name, "a'") self.assertEqual(a.domain, []) a = pybamm.VariableDot("a", domain=["test"]) self.assertEqual(a.domain[0], "test") self.assertRaises(TypeError, pybamm.Variable("a", domain="test"))
def test_variable_id(self): a1 = pybamm.VariableDot("a", domain=["negative electrode"]) a2 = pybamm.VariableDot("a", domain=["negative electrode"]) self.assertEqual(a1.id, a2.id) a3 = pybamm.VariableDot("b", domain=["negative electrode"]) a4 = pybamm.VariableDot("a", domain=["positive electrode"]) self.assertNotEqual(a1.id, a3.id) self.assertNotEqual(a1.id, a4.id)
def test_variable_diff(self): a = pybamm.VariableDot("a") b = pybamm.Variable("b") self.assertIsInstance(a.diff(a), pybamm.Scalar) self.assertEqual(a.diff(a).evaluate(), 1) self.assertIsInstance(a.diff(b), pybamm.Scalar) self.assertEqual(a.diff(b).evaluate(), 0)
def diff(self, variable): if variable.id == self.id: return pybamm.Scalar(1) elif variable.id == pybamm.t.id: return pybamm.VariableDot( self.name + "'", domain=self.domain, auxiliary_domains=self.auxiliary_domains, ) else: return pybamm.Scalar(0)
def test_symbol_simplify(self): a = pybamm.Scalar(0, domain="domain") b = pybamm.Scalar(1) c = pybamm.Parameter("c") d = pybamm.Scalar(-1) e = pybamm.Scalar(2) g = pybamm.Variable("g") gdot = pybamm.VariableDot("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": b}) self.assertIsInstance((f).simplify(), pybamm.FunctionParameter) self.assertEqual((f).simplify().children[0].id, b.id) f = pybamm.FunctionParameter("function", {"a": a, "b": 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", domain="domain") grad_v = pybamm.grad(v) self.assertIsInstance(grad_v.simplify(), pybamm.Gradient) # Divergence div_b = pybamm.div(pybamm.PrimaryBroadcastToEdges(b, "domain")) self.assertIsInstance(div_b.simplify(), pybamm.PrimaryBroadcast) self.assertEqual(div_b.simplify().child.child.evaluate(), 0) self.assertIsInstance((pybamm.div(pybamm.grad(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 * b).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 2.0) self.assertIsInstance(expr.children[1], pybamm.Variable) expr = (e * gdot * b).simplify() self.assertIsInstance(expr, pybamm.Multiplication) self.assertIsInstance(expr.children[0], pybamm.Scalar) self.assertEqual(expr.children[0].evaluate(), 2.0) self.assertIsInstance(expr.children[1], pybamm.VariableDot) 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)
def test_process_symbol_base(self): # create discretisation mesh = get_mesh_for_testing() spatial_methods = { "macroscale": pybamm.SpatialMethod(), "negative particle": pybamm.SpatialMethod(), "positive particle": pybamm.SpatialMethod(), "current collector": pybamm.SpatialMethod(), } disc = pybamm.Discretisation(mesh, spatial_methods) # variable var = pybamm.Variable("var") var_vec = pybamm.Variable("var vec", domain=["negative electrode"]) disc.y_slices = {var.id: [slice(53)], var_vec.id: [slice(53, 93)]} var_disc = disc.process_symbol(var) self.assertIsInstance(var_disc, pybamm.StateVector) self.assertEqual(var_disc.y_slices[0], disc.y_slices[var.id][0]) # variable dot var_dot = pybamm.VariableDot("var'") var_dot_disc = disc.process_symbol(var_dot) self.assertIsInstance(var_dot_disc, pybamm.StateVectorDot) self.assertEqual(var_dot_disc.y_slices[0], disc.y_slices[var.id][0]) # scalar scal = pybamm.Scalar(5) scal_disc = disc.process_symbol(scal) self.assertIsInstance(scal_disc, pybamm.Scalar) self.assertEqual(scal_disc.value, scal.value) # vector vec = pybamm.Vector(np.array([1, 2, 3, 4])) vec_disc = disc.process_symbol(vec) self.assertIsInstance(vec_disc, pybamm.Vector) np.testing.assert_array_equal(vec_disc.entries, vec.entries) # matrix mat = pybamm.Matrix(np.array([[1, 2, 3, 4], [5, 6, 7, 8]])) mat_disc = disc.process_symbol(mat) self.assertIsInstance(mat_disc, pybamm.Matrix) np.testing.assert_array_equal(mat_disc.entries, mat.entries) # binary operator bin = var + scal bin_disc = disc.process_symbol(bin) self.assertIsInstance(bin_disc, pybamm.Addition) self.assertIsInstance(bin_disc.children[0], pybamm.StateVector) self.assertIsInstance(bin_disc.children[1], pybamm.Scalar) bin2 = scal + var bin2_disc = disc.process_symbol(bin2) self.assertIsInstance(bin2_disc, pybamm.Addition) self.assertIsInstance(bin2_disc.children[0], pybamm.Scalar) self.assertIsInstance(bin2_disc.children[1], pybamm.StateVector) # non-spatial unary operator un1 = -var un1_disc = disc.process_symbol(un1) self.assertIsInstance(un1_disc, pybamm.Negate) self.assertIsInstance(un1_disc.children[0], pybamm.StateVector) un2 = abs(var) un2_disc = disc.process_symbol(un2) self.assertIsInstance(un2_disc, pybamm.AbsoluteValue) self.assertIsInstance(un2_disc.children[0], pybamm.StateVector) # function of one variable def myfun(x): return np.exp(x) func = pybamm.Function(myfun, var) func_disc = disc.process_symbol(func) self.assertIsInstance(func_disc, pybamm.Function) self.assertIsInstance(func_disc.children[0], pybamm.StateVector) func = pybamm.Function(myfun, scal) func_disc = disc.process_symbol(func) self.assertIsInstance(func_disc, pybamm.Function) self.assertIsInstance(func_disc.children[0], pybamm.Scalar) # function of multiple variables def myfun(x, y): return np.exp(x) * y func = pybamm.Function(myfun, var, scal) func_disc = disc.process_symbol(func) self.assertIsInstance(func_disc, pybamm.Function) self.assertIsInstance(func_disc.children[0], pybamm.StateVector) self.assertIsInstance(func_disc.children[1], pybamm.Scalar) # boundary value bv_left = pybamm.BoundaryValue(var_vec, "left") bv_left_disc = disc.process_symbol(bv_left) self.assertIsInstance(bv_left_disc, pybamm.MatrixMultiplication) self.assertIsInstance(bv_left_disc.left, pybamm.Matrix) self.assertIsInstance(bv_left_disc.right, pybamm.StateVector) bv_right = pybamm.BoundaryValue(var_vec, "left") bv_right_disc = disc.process_symbol(bv_right) self.assertIsInstance(bv_right_disc, pybamm.MatrixMultiplication) self.assertIsInstance(bv_right_disc.left, pybamm.Matrix) self.assertIsInstance(bv_right_disc.right, pybamm.StateVector) # not implemented sym = pybamm.Symbol("sym") with self.assertRaises(NotImplementedError): disc.process_symbol(sym)