def test_convert_scalar_symbols(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)
        c = pybamm.Scalar(-1)
        d = pybamm.Scalar(2)
        e = pybamm.Scalar(3)
        g = pybamm.Scalar(3.3)

        self.assertEqual(a.to_casadi(), casadi.MX(0))
        self.assertEqual(d.to_casadi(), casadi.MX(2))

        # negate
        self.assertEqual((-b).to_casadi(), casadi.MX(-1))
        # absolute value
        self.assertEqual(abs(c).to_casadi(), casadi.MX(1))
        # floor
        self.assertEqual(pybamm.Floor(g).to_casadi(), casadi.MX(3))
        # ceiling
        self.assertEqual(pybamm.Ceiling(g).to_casadi(), casadi.MX(4))

        # function
        def square_plus_one(x):
            return x**2 + 1

        f = pybamm.Function(square_plus_one, b)
        self.assertEqual(f.to_casadi(), 2)

        def myfunction(x, y):
            return x + y

        f = pybamm.Function(myfunction, b, d)
        self.assertEqual(f.to_casadi(), casadi.MX(3))

        # use classes to avoid simplification
        # addition
        self.assertEqual((pybamm.Addition(a, b)).to_casadi(), casadi.MX(1))
        # subtraction
        self.assertEqual(pybamm.Subtraction(c, d).to_casadi(), casadi.MX(-3))
        # multiplication
        self.assertEqual(
            pybamm.Multiplication(c, d).to_casadi(), casadi.MX(-2))
        # power
        self.assertEqual(pybamm.Power(c, d).to_casadi(), casadi.MX(1))
        # division
        self.assertEqual(pybamm.Division(b, d).to_casadi(), casadi.MX(1 / 2))

        # modulo
        self.assertEqual(pybamm.Modulo(e, d).to_casadi(), casadi.MX(1))

        # minimum and maximum
        self.assertEqual(pybamm.Minimum(a, b).to_casadi(), casadi.MX(0))
        self.assertEqual(pybamm.Maximum(a, b).to_casadi(), casadi.MX(1))
Exemple #2
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)
Exemple #3
0
    def test_convert_scalar_symbols(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)
        c = pybamm.Scalar(-1)
        d = pybamm.Scalar(2)

        self.assertEqual(a.to_casadi(), casadi.MX(0))
        self.assertEqual(d.to_casadi(), casadi.MX(2))

        # negate
        self.assertEqual((-b).to_casadi(), casadi.MX(-1))
        # absolute value
        self.assertEqual(abs(c).to_casadi(), casadi.MX(1))

        # function
        def sin(x):
            return np.sin(x)

        f = pybamm.Function(sin, b)
        self.assertEqual(f.to_casadi(), casadi.MX(np.sin(1)))

        def myfunction(x, y):
            return x + y

        f = pybamm.Function(myfunction, b, d)
        self.assertEqual(f.to_casadi(), casadi.MX(3))

        # use classes to avoid simplification
        # addition
        self.assertEqual((pybamm.Addition(a, b)).to_casadi(), casadi.MX(1))
        # subtraction
        self.assertEqual(pybamm.Subtraction(c, d).to_casadi(), casadi.MX(-3))
        # multiplication
        self.assertEqual(
            pybamm.Multiplication(c, d).to_casadi(), casadi.MX(-2))
        # power
        self.assertEqual(pybamm.Power(c, d).to_casadi(), casadi.MX(1))
        # division
        self.assertEqual(pybamm.Division(b, d).to_casadi(), casadi.MX(1 / 2))

        # minimum and maximum
        self.assertEqual(pybamm.Minimum(a, b).to_casadi(), casadi.MX(0))
        self.assertEqual(pybamm.Maximum(a, b).to_casadi(), casadi.MX(1))
    def test_to_equation(self):
        # Test print_name
        pybamm.Addition.print_name = "test"
        self.assertEqual(pybamm.Addition(1, 2).to_equation(), sympy.symbols("test"))

        # Test Power
        self.assertEqual(pybamm.Power(7, 2).to_equation(), 49)

        # Test Division
        self.assertEqual(pybamm.Division(10, 2).to_equation(), 5)

        # Test Matrix Multiplication
        arr1 = pybamm.Array([[1, 0], [0, 1]])
        arr2 = pybamm.Array([[4, 1], [2, 2]])
        self.assertEqual(
            pybamm.MatrixMultiplication(arr1, arr2).to_equation(),
            sympy.Matrix([[4.0, 1.0], [2.0, 2.0]]),
        )

        # Test EqualHeaviside
        self.assertEqual(pybamm.EqualHeaviside(1, 0).to_equation(), False)

        # Test NotEqualHeaviside
        self.assertEqual(pybamm.NotEqualHeaviside(2, 4).to_equation(), True)
Exemple #5
0
 def __rtruediv__(self, other):
     """return a :class:`Division` object"""
     return pybamm.simplify_if_constant(pybamm.Division(other, self),
                                        keep_domains=True)
Exemple #6
0
 def __rtruediv__(self, other):
     """return a :class:`Division` object"""
     if isinstance(other, (Symbol, numbers.Number)):
         return pybamm.Division(other, self)
     else:
         raise NotImplementedError
Exemple #7
0
def simplified_division(left, right):
    left, right = simplify_elementwise_binary_broadcasts(left, right)

    # Check for Concatenations and Broadcasts
    out = simplified_binary_broadcast_concatenation(left, right,
                                                    simplified_division)
    if out is not None:
        return out

    # zero divided by anything returns zero (being careful about shape)
    if pybamm.is_scalar_zero(left):
        return pybamm.zeros_like(right)

    # matrix zero divided by anything returns matrix zero (i.e. itself)
    if pybamm.is_matrix_zero(left):
        return pybamm.zeros_like(pybamm.Division(left, right))

    # anything divided by zero raises error
    if pybamm.is_scalar_zero(right):
        raise ZeroDivisionError

    # anything divided by one is itself
    if pybamm.is_scalar_one(right):
        return left

    # a symbol divided by itself is 1s of the same shape
    if left.id == right.id:
        return pybamm.ones_like(left)

    # anything multiplied by a matrix one returns itself if
    # - the shapes are the same
    # - both left and right evaluate on edges, or both evaluate on nodes, in all
    # dimensions
    # (and possibly more generally, but not implemented here)
    try:
        if left.shape_for_testing == right.shape_for_testing and all(
                left.evaluates_on_edges(dim) == right.evaluates_on_edges(dim)
                for dim in ["primary", "secondary", "tertiary"]):
            if pybamm.is_matrix_one(right):
                return left
            # also check for negative one
            if pybamm.is_matrix_minus_one(right):
                return -left

    except NotImplementedError:
        pass

    # Return constant if both sides are constant
    if left.is_constant() and right.is_constant():
        return pybamm.simplify_if_constant(pybamm.Division(left, right))

    # Simplify (B @ c) / a to (B / a) @ c if (B / a) is constant
    # This is a common construction that appears from discretisation of averages
    elif isinstance(left, MatrixMultiplication) and right.is_constant():
        l_left, l_right = left.orphans
        new_left = l_left / right
        if new_left.is_constant():
            # be careful about domains to avoid weird errors
            new_left.clear_domains()
            new_division = new_left @ l_right
            # Keep the domain of the old left
            new_division.copy_domains(left)
            return new_division

    if isinstance(left, Multiplication):
        # Simplify (a * b) / c to (a / c) * b if (a / c) is constant
        if left.left.is_constant():
            l_left, l_right = left.orphans
            new_left = l_left / right
            if new_left.is_constant():
                return new_left * l_right
        # Simplify (a * b) / c to a * (b / c) if (b / c) is constant
        elif left.right.is_constant():
            l_left, l_right = left.orphans
            new_right = l_right / right
            if new_right.is_constant():
                return l_left * new_right

    # Negation simplifications
    elif isinstance(left, pybamm.Negate) and right.is_constant():
        # Simplify (-a) / b to a / (-b) if (-b) is constant
        return left.orphans[0] / (-right)
    elif isinstance(right, pybamm.Negate) and left.is_constant():
        # Simplify a / (-b) to (-a) / b if (-a) is constant
        return (-left) / right.orphans[0]

    return pybamm.simplify_if_constant(pybamm.Division(left, right))