Ejemplo n.º 1
0
    def test_outer(self):
        # Outer class
        v = pybamm.Vector(np.ones(5), domain="current collector")
        w = pybamm.Vector(2 * np.ones(3), domain="test")
        outer = pybamm.Outer(v, w)
        np.testing.assert_array_equal(outer.evaluate(), 2 * np.ones((15, 1)))
        self.assertEqual(outer.domain, w.domain)
        self.assertEqual(
            str(outer),
            "outer(Column vector of length 5, Column vector of length 3)")

        # outer function
        # if there is no domain clash, normal multiplication is retured
        u = pybamm.Vector(np.linspace(0, 1, 5))
        outer = pybamm.outer(u, v)
        self.assertIsInstance(outer, pybamm.Multiplication)
        np.testing.assert_array_equal(outer.evaluate(), u.evaluate())
        # otherwise, Outer class is returned
        outer_fun = pybamm.outer(v, w)
        outer_class = pybamm.Outer(v, w)
        self.assertEqual(outer_fun.id, outer_class.id)

        # failures
        y = pybamm.StateVector(slice(10))
        with self.assertRaisesRegex(
                TypeError,
                "right child must only contain SpatialVariable and scalars"):
            pybamm.Outer(v, y)
        with self.assertRaises(NotImplementedError):
            outer_fun.diff(None)
Ejemplo n.º 2
0
 def test_simplify_outer(self):
     v = pybamm.Vector(np.ones(5), domain="current collector")
     w = pybamm.Vector(2 * np.ones(3), domain="test")
     outer_simp = pybamm.Outer(v, w).simplify()
     self.assertIsInstance(outer_simp, pybamm.Vector)
     np.testing.assert_array_equal(outer_simp.evaluate(), 2 * np.ones(
         (15, 1)))
Ejemplo n.º 3
0
def outer(left, right):
    """
    Return outer product of two symbols. If the symbols have the same domain, the outer
    product is just a multiplication. If they have different domains, make a copy of the
    left child with same domain as right child, and then take outer product.
    """
    try:
        return left * right
    except pybamm.DomainError:
        return pybamm.Outer(left, right)
Ejemplo n.º 4
0
    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"]
        a_npts = mesh[a_dom[0]][0].npts
        b_npts = mesh[b_dom[0]][0].npts
        c_npts = mesh[c_dom[0]][0].npts
        cc_npts = mesh["current collector"][0].npts
        curr_coll_vector = pybamm.Vector(np.ones(cc_npts),
                                         domain="current collector")
        a = 2 * pybamm.Outer(curr_coll_vector,
                             pybamm.Vector(np.ones(a_npts), domain=a_dom))
        b = pybamm.Outer(curr_coll_vector,
                         pybamm.Vector(np.ones(b_npts), domain=b_dom))
        c = 3 * pybamm.Outer(curr_coll_vector,
                             pybamm.Vector(np.ones(c_npts), domain=c_dom))

        conc = pybamm.DomainConcatenation([a, b, c], mesh)
        jac = conc.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))
Ejemplo n.º 5
0
    def test_simplify_divide_outer(self):
        u = pybamm.Scalar(1)
        v = pybamm.StateVector(slice(0, 5), domain="current collector")
        outer = pybamm.Outer(v, u)

        exp1 = pybamm.Division(pybamm.Division(outer, u), u)
        self.assertIsInstance(exp1.simplify(), pybamm.Outer)

        exp2 = pybamm.Division(pybamm.Division(outer, 2 * u), u)
        self.assertIsInstance(exp2.simplify(), pybamm.Multiplication)

        exp3 = pybamm.Division(pybamm.Division(outer, u), 2 * u)
        self.assertIsInstance(exp3.simplify(), pybamm.Multiplication)

        exp4 = pybamm.Division(pybamm.Division(outer, 2 * u), 2 * u)
        self.assertIsInstance(exp4.simplify(), pybamm.Multiplication)
Ejemplo n.º 6
0
    def test_convert_array_symbols(self):
        # Arrays
        a = np.array([1, 2, 3, 4, 5])
        pybamm_a = pybamm.Array(a)
        self.assertTrue(casadi.is_equal(pybamm_a.to_casadi(), casadi.SX(a)))

        casadi_t = casadi.SX.sym("t")
        casadi_y = casadi.SX.sym("y", 10)

        pybamm_t = pybamm.Time()
        pybamm_y = pybamm.StateVector(slice(0, 10))

        # Time
        self.assertEqual(pybamm_t.to_casadi(casadi_t, casadi_y), casadi_t)

        # State Vector
        self.assertTrue(
            casadi.is_equal(pybamm_y.to_casadi(casadi_t, casadi_y), casadi_y))

        # outer product
        outer = pybamm.Outer(pybamm_a, pybamm_a)
        self.assertTrue(
            casadi.is_equal(outer.to_casadi(), casadi.SX(outer.evaluate())))
Ejemplo n.º 7
0
    def broadcast(self, symbol, domain, auxiliary_domains, broadcast_type):
        """
        Broadcast symbol to a specified domain.

        Parameters
        ----------
        symbol : :class:`pybamm.Symbol`
            The symbol to be broadcasted
        domain : iterable of strings
            The domain to broadcast to
        broadcast_type : str
            The type of broadcast, either: 'primary' or 'full'

        Returns
        -------
        broadcasted_symbol: class: `pybamm.Symbol`
            The discretised symbol of the correct size for the spatial method
        """

        primary_pts_for_broadcast = sum(
            self.mesh[dom][0].npts_for_broadcast for dom in domain
        )

        full_pts_for_broadcast = sum(
            subdom.npts_for_broadcast for dom in domain for subdom in self.mesh[dom]
        )

        if broadcast_type == "primary":
            out = pybamm.Outer(
                symbol, pybamm.Vector(np.ones(primary_pts_for_broadcast), domain=domain)
            )

        elif broadcast_type == "full":
            out = symbol * pybamm.Vector(np.ones(full_pts_for_broadcast), domain=domain)

        out.auxiliary_domains = auxiliary_domains
        return out
Ejemplo n.º 8
0
    def test_process_symbol(self):
        parameter_values = pybamm.ParameterValues({"a": 1, "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, 1)

        # process binary operation
        b = pybamm.Parameter("b")
        add = a + b
        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.Scalar)
        self.assertEqual(processed_add.children[0].value, 1)
        self.assertEqual(processed_add.children[1].value, 2)

        scal = pybamm.Scalar(34)
        mul = a * scal
        processed_mul = parameter_values.process_symbol(mul)
        self.assertIsInstance(processed_mul, pybamm.Multiplication)
        self.assertIsInstance(processed_mul.children[0], pybamm.Scalar)
        self.assertIsInstance(processed_mul.children[1], pybamm.Scalar)
        self.assertEqual(processed_mul.children[0].value, 1)
        self.assertEqual(processed_mul.children[1].value, 34)

        # 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, 1)
        self.assertEqual(processed_integ.integration_variable[0].id, x.id)

        # process unary operation
        grad = pybamm.Gradient(a)
        processed_grad = parameter_values.process_symbol(grad)
        self.assertIsInstance(processed_grad, pybamm.Gradient)
        self.assertIsInstance(processed_grad.children[0], pybamm.Scalar)
        self.assertEqual(processed_grad.children[0].value, 1)

        # 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, 1)

        # 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, 1)
        self.assertEqual(processed_x.id, x.id)

        # process broadcast
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        broad = pybamm.Broadcast(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(), np.array([1]))

        # process concatenation
        conc = pybamm.Concatenation(pybamm.Vector(np.ones(10)),
                                    pybamm.Vector(2 * np.ones(15)))
        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, 1)
        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)))

        # process outer
        c = pybamm.Parameter("c", domain="current collector")
        outer = pybamm.Outer(c, b)
        processed_outer = parameter_values.process_symbol(outer)
        self.assertIsInstance(processed_outer, pybamm.Outer)

        # not implemented
        sym = pybamm.Symbol("sym")
        with self.assertRaises(NotImplementedError):
            parameter_values.process_symbol(sym)
Ejemplo n.º 9
0
 def _binary_simplify(self, left, right):
     """ See :meth:`pybamm.BinaryOperator.simplify()`. """
     # Make sure left child keeps same domain
     left.domain = self.left.domain
     return pybamm.Outer(left, right)
Ejemplo n.º 10
0
    def test_linear(self):
        y = pybamm.StateVector(slice(0, 4))
        u = pybamm.StateVector(slice(0, 2))
        v = pybamm.StateVector(slice(2, 4))

        y0 = np.ones(4)

        func = u
        jacobian = np.array([[1, 0, 0, 0], [0, 1, 0, 0]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = -v
        jacobian = np.array([[0, 0, -1, 0], [0, 0, 0, -1]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = 3 * u + 4 * v
        jacobian = np.array([[3, 0, 4, 0], [0, 3, 0, 4]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = 7 * u - v * 9
        jacobian = np.array([[7, 0, -9, 0], [0, 7, 0, -9]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        A = pybamm.Matrix(2 * eye(2))
        func = A @ u
        jacobian = np.array([[2, 0, 0, 0], [0, 2, 0, 0]])
        dfunc_dy = func.jac(y).simplify().evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = u @ pybamm.StateVector(slice(0, 1))
        with self.assertRaises(NotImplementedError):
            func.jac(y)

        # when differentiating by independent part of the state vector
        jacobian = np.array([[0, 0], [0, 0]])
        du_dv = u.jac(v).evaluate().toarray()
        np.testing.assert_array_equal(du_dv, jacobian)

        # test Jacobian of Outer (must set domain to be 'current collector')
        u.domain = ["current collector"]
        func = pybamm.Outer(u, pybamm.Scalar(4))
        jacobian = np.array([[4, 0, 0, 0], [0, 4, 0, 0]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.Outer(u, pybamm.Vector(np.array([1, 2, 3])))
        jacobian = np.array([
            [1, 0, 0, 0],
            [2, 0, 0, 0],
            [3, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 2, 0, 0],
            [0, 3, 0, 0],
        ])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        # test jac of outer if left evaluates to number
        func = pybamm.Outer(pybamm.Scalar(1), pybamm.Scalar(4))
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(0, dfunc_dy.toarray())
Ejemplo n.º 11
0
 def _binary_simplify(self, left, right):
     """ See :meth:`pybamm.BinaryOperator._binary_simplify()`. """
     return pybamm.Outer(left, right)
Ejemplo n.º 12
0
    def test_evaluator_python(self):
        a = pybamm.StateVector(slice(0, 1))
        b = pybamm.StateVector(slice(1, 2))

        y_tests = [np.array([[2], [3]]), np.array([[1], [3]])]
        t_tests = [1, 2]

        # test a * b
        expr = a * b
        evaluator = pybamm.EvaluatorPython(expr)
        result = evaluator.evaluate(t=None, y=np.array([[2], [3]]))
        self.assertEqual(result, 6)
        result = evaluator.evaluate(t=None, y=np.array([[1], [3]]))
        self.assertEqual(result, 3)

        # test function(a*b)
        expr = pybamm.Function(test_function, a * b)
        evaluator = pybamm.EvaluatorPython(expr)
        result = evaluator.evaluate(t=None, y=np.array([[2], [3]]))
        self.assertEqual(result, 12)

        # test a constant expression
        expr = pybamm.Scalar(2) * pybamm.Scalar(3)
        evaluator = pybamm.EvaluatorPython(expr)
        result = evaluator.evaluate()
        self.assertEqual(result, 6)

        # test a larger expression
        expr = a * b + b + a**2 / b + 2 * a + b / 2 + 4
        evaluator = pybamm.EvaluatorPython(expr)
        for y in y_tests:
            result = evaluator.evaluate(t=None, y=y)
            self.assertEqual(result, expr.evaluate(t=None, y=y))

        # test something with time
        expr = a * pybamm.t
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y)
            self.assertEqual(result, expr.evaluate(t=t, y=y))

        # test something with a matrix multiplication
        A = pybamm.Matrix(np.array([[1, 2], [3, 4]]))
        expr = A @ pybamm.StateVector(slice(0, 2))
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y)
            np.testing.assert_allclose(result, expr.evaluate(t=t, y=y))

        # test something with an index
        expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0)
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y)
            self.assertEqual(result, expr.evaluate(t=t, y=y))

        # test something with a sparse matrix multiplication
        A = pybamm.Matrix(np.array([[1, 2], [3, 4]]))
        B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]])))
        C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]])))
        expr = A @ B @ C @ pybamm.StateVector(slice(0, 2))
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y)
            np.testing.assert_allclose(result, expr.evaluate(t=t, y=y))

        # test numpy concatenation
        a = pybamm.Vector(np.array([[1], [2]]))
        b = pybamm.Vector(np.array([[3]]))
        expr = pybamm.NumpyConcatenation(a, b)
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y)
            np.testing.assert_allclose(result, expr.evaluate(t=t, y=y))

        # test sparse stack
        A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]])))
        B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]])))
        expr = pybamm.SparseStack(A, B)
        evaluator = pybamm.EvaluatorPython(expr)
        for t, y in zip(t_tests, y_tests):
            result = evaluator.evaluate(t=t, y=y).toarray()
            np.testing.assert_allclose(result,
                                       expr.evaluate(t=t, y=y).toarray())

        # test Outer
        v = pybamm.Vector(np.ones(5), domain="current collector")
        w = pybamm.Vector(2 * np.ones(3), domain="test")
        expr = pybamm.Outer(v, w)
        evaluator = pybamm.EvaluatorPython(expr)
        result = evaluator.evaluate()
        np.testing.assert_allclose(result, expr.evaluate())

        # test Inner
        v = pybamm.Vector(np.ones(5), domain="test")
        w = pybamm.Vector(2 * np.ones(5), domain="test")
        expr = pybamm.Inner(v, w)
        evaluator = pybamm.EvaluatorPython(expr)
        result = evaluator.evaluate()
        np.testing.assert_allclose(result, expr.evaluate())