Exemple #1
0
    def test_function_of_one_variable(self):
        a = pybamm.Symbol("a")
        funca = pybamm.Function(test_function, a)
        self.assertEqual(funca.name, "function (test_function)")
        self.assertEqual(str(funca), "test_function(a)")
        self.assertEqual(funca.children[0].name, a.name)

        b = pybamm.Scalar(1)
        sina = pybamm.Function(np.sin, b)
        self.assertEqual(sina.evaluate(), np.sin(1))
        self.assertEqual(sina.name, "function ({})".format(np.sin.__name__))

        c = pybamm.Vector(np.linspace(0, 1))
        cosb = pybamm.Function(np.cos, c)
        np.testing.assert_array_equal(cosb.evaluate(), np.cos(c.evaluate()))

        var = pybamm.StateVector(slice(0, 100))
        y = np.linspace(0, 1, 100)[:, np.newaxis]
        logvar = pybamm.Function(np.log1p, var)
        np.testing.assert_array_equal(logvar.evaluate(y=y), np.log1p(y))

        # use known_evals
        np.testing.assert_array_equal(
            logvar.evaluate(y=y, known_evals={})[0], np.log1p(y)
        )
 def test_special_functions(self):
     a = pybamm.Array(np.array([1, 2, 3, 4, 5]))
     self.assert_casadi_equal(pybamm.max(a).to_casadi(),
                              casadi.MX(5),
                              evalf=True)
     self.assert_casadi_equal(pybamm.min(a).to_casadi(),
                              casadi.MX(1),
                              evalf=True)
     b = pybamm.Array(np.array([-2]))
     c = pybamm.Array(np.array([3]))
     self.assert_casadi_equal(pybamm.Function(np.abs, b).to_casadi(),
                              casadi.MX(2),
                              evalf=True)
     self.assert_casadi_equal(pybamm.Function(np.abs, c).to_casadi(),
                              casadi.MX(3),
                              evalf=True)
     for np_fun in [
             np.sqrt,
             np.tanh,
             np.cosh,
             np.sinh,
             np.exp,
             np.log,
             np.sign,
             np.sin,
             np.cos,
             np.arccosh,
             np.arcsinh,
     ]:
         self.assert_casadi_equal(pybamm.Function(np_fun, c).to_casadi(),
                                  casadi.MX(np_fun(3)),
                                  evalf=True)
Exemple #3
0
    def test_diff(self):
        a = pybamm.StateVector(slice(0, 1))
        b = pybamm.StateVector(slice(1, 2))
        y = np.array([5])
        func = pybamm.Function(test_function, a)
        self.assertEqual(func.diff(a).evaluate(y=y), 2)
        self.assertEqual(func.diff(func).evaluate(), 1)
        func = pybamm.sin(a)
        self.assertEqual(func.evaluate(y=y), np.sin(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.cos(a.evaluate(y=y)))
        func = pybamm.exp(a)
        self.assertEqual(func.evaluate(y=y), np.exp(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.exp(a.evaluate(y=y)))

        # multiple variables
        func = pybamm.Function(test_multi_var_function, 4 * a, 3 * a)
        self.assertEqual(func.diff(a).evaluate(y=y), 7)
        func = pybamm.Function(test_multi_var_function, 4 * a, 3 * b)
        self.assertEqual(func.diff(a).evaluate(y=np.array([5, 6])), 4)
        self.assertEqual(func.diff(b).evaluate(y=np.array([5, 6])), 3)
        func = pybamm.Function(test_multi_var_function_cube, 4 * a, 3 * b)
        self.assertEqual(func.diff(a).evaluate(y=np.array([5, 6])), 4)
        self.assertEqual(
            func.diff(b).evaluate(y=np.array([5, 6])), 3 * 3 * (3 * 6) ** 2
        )

        # exceptions
        func = pybamm.Function(
            test_multi_var_function_cube, 4 * a, 3 * b, derivative="derivative"
        )
        with self.assertRaises(ValueError):
            func.diff(a)
 def test_special_functions(self):
     a = pybamm.Array(np.array([1, 2, 3, 4, 5]))
     self.assertEqual(pybamm.max(a).to_casadi(), casadi.SX(5))
     self.assertEqual(pybamm.min(a).to_casadi(), casadi.SX(1))
     b = pybamm.Array(np.array([-2]))
     c = pybamm.Array(np.array([3]))
     self.assertEqual(pybamm.Function(np.abs, b).to_casadi(), casadi.SX(2))
     self.assertEqual(pybamm.Function(np.abs, c).to_casadi(), casadi.SX(3))
Exemple #5
0
    def test_number_input(self):
        # with numbers
        log = pybamm.Function(np.log, 10)
        self.assertIsInstance(log.children[0], pybamm.Scalar)
        self.assertEqual(log.evaluate(), np.log(10))

        summ = pybamm.Function(test_multi_var_function, 1, 2)
        self.assertIsInstance(summ.children[0], pybamm.Scalar)
        self.assertIsInstance(summ.children[1], pybamm.Scalar)
        self.assertEqual(summ.evaluate(), 3)
    def test_convert_differentiated_function(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)

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

        f = pybamm.Function(myfunction, a, b).diff(a)
        self.assert_casadi_equal(f.to_casadi(), casadi.MX(1), evalf=True)
        f = pybamm.Function(myfunction, a, b).diff(b)
        self.assert_casadi_equal(f.to_casadi(), casadi.MX(3), evalf=True)
    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 #8
0
    def _function_simplify(self, simplified_children):
        """
        Simplifies the function.

        Inputs
        ------
        simplified_children: : list
            A list of simplified children of the function

        Returns
        -------
         :: pybamm.Scalar() if no children
         :: pybamm.Function if there are children
        """
        if self.takes_no_params is True:
            # If self.function() takes no parameters then we can always simplify it
            return pybamm.Scalar(self.function())
        elif isinstance(self.function, pybamm.GetConstantCurrent):
            # If self.function() is a constant current then simplify to scalar
            return pybamm.Scalar(self.function.parameters_eval["Current [A]"])
        else:
            return pybamm.Function(
                self.function,
                *simplified_children,
                name=self.name,
                derivative=self.derivative,
                differentiated_function=self.differentiated_function
            )
Exemple #9
0
 def _function_diff(self, children, idx):
     """
     Derivative with respect to child number 'idx'.
     See :meth:`pybamm.Symbol._diff()`.
     """
     # Store differentiated function, needed in case we want to convert to CasADi
     if self.derivative == "autograd":
         return Function(
             autograd.elementwise_grad(self.function, idx),
             *children,
             differentiated_function=self.function
         )
     elif self.derivative == "derivative":
         if len(children) > 1:
             raise ValueError(
                 """
                 differentiation using '.derivative()' not implemented for functions
                 with more than one child
                 """
             )
         else:
             # keep using "derivative" as derivative
             return pybamm.Function(
                 self.function.derivative(),
                 *children,
                 derivative="derivative",
                 differentiated_function=self.function
             )
Exemple #10
0
 def test_special_functions(self):
     a = pybamm.Array(np.array([1, 2, 3, 4, 5]))
     self.assert_casadi_equal(pybamm.max(a).to_casadi(),
                              casadi.MX(5),
                              evalf=True)
     self.assert_casadi_equal(pybamm.min(a).to_casadi(),
                              casadi.MX(1),
                              evalf=True)
     b = pybamm.Array(np.array([-2]))
     c = pybamm.Array(np.array([3]))
     self.assert_casadi_equal(pybamm.Function(np.abs, b).to_casadi(),
                              casadi.MX(2),
                              evalf=True)
     self.assert_casadi_equal(pybamm.Function(np.abs, c).to_casadi(),
                              casadi.MX(3),
                              evalf=True)
    def get_interp_fun(variable_name, domain):
        """
        Create a :class:`pybamm.Function` object using the variable, to allow
        plotting with :class:`'pybamm.QuickPlot'` (interpolate in space to match
        edges, and then create function to interpolate in time)
        """
        variable = comsol_variables[variable_name]
        if domain == ["negative electrode"]:
            comsol_x = comsol_variables["x_n"]
        elif domain == ["separator"]:
            comsol_x = comsol_variables["x_s"]
        elif domain == ["positive electrode"]:
            comsol_x = comsol_variables["x_p"]
        elif domain == whole_cell:
            comsol_x = comsol_variables["x"]
        # Make sure to use dimensional space
        pybamm_x = mesh.combine_submeshes(*domain)[0].nodes * L_x
        variable = interp.interp1d(comsol_x,
                                   variable,
                                   axis=0,
                                   kind=interp_kind)(pybamm_x)

        def myinterp(t):
            return interp.interp1d(comsol_t, variable,
                                   kind=interp_kind)(t)[:, np.newaxis]

        # Make sure to use dimensional time
        fun = pybamm.Function(myinterp,
                              pybamm.t * tau,
                              name=variable_name + "_comsol")
        fun.domain = domain
        return fun
def get_interp_fun(variable_name, domain):
    """
    Create a :class:`pybamm.Function` object using the variable, to allow plotting with
    :class:`pybamm.QuickPlot` (interpolate in space to match edges, and then create
    function to interpolate in time)
    """
    variable = comsol_variables[variable_name]
    if domain == ["negative electrode"]:
        comsol_x = comsol_variables["x_n"]
    elif domain == ["positive electrode"]:
        comsol_x = comsol_variables["x_p"]
    elif domain == whole_cell:
        comsol_x = comsol_variables["x"]
    # Make sure to use dimensional space
    pybamm_x = mesh.combine_submeshes(*domain)[0].nodes * L_x
    variable = interp.interp1d(comsol_x, variable, axis=0)(pybamm_x)

    def myinterp(t):
        try:
            return interp.interp1d(comsol_t,
                                   variable,
                                   fill_value="extrapolate",
                                   bounds_error=False)(t)[:, np.newaxis]
        except ValueError as err:
            raise ValueError(
                """Failed to interpolate '{}' with time range [{}, {}] at time {}.
                Original error: {}""".format(variable_name, comsol_t[0],
                                             comsol_t[-1], t, err))

    # Make sure to use dimensional time
    fun = pybamm.Function(myinterp, pybamm.t, name=variable_name + "_comsol")
    fun.domain = domain
    fun.mesh = mesh.combine_submeshes(*domain)
    fun.secondary_mesh = None
    return fun
    def _set_dimensional_parameters(self):
        "Defines the dimensional parameters"

        self.I_typ = pybamm.Parameter("Typical current [A]")
        self.Q = pybamm.Parameter("Cell capacity [A.h]")
        self.C_rate = pybamm.AbsoluteValue(self.I_typ / self.Q)
        self.n_electrodes_parallel = pybamm.Parameter(
            "Number of electrodes connected in parallel to make a cell")
        self.n_cells = pybamm.Parameter(
            "Number of cells connected in series to make a battery")
        self.i_typ = pybamm.Function(
            np.abs, self.I_typ / (self.n_electrodes_parallel * self.geo.A_cc))
        self.voltage_low_cut_dimensional = pybamm.Parameter(
            "Lower voltage cut-off [V]")
        self.voltage_high_cut_dimensional = pybamm.Parameter(
            "Upper voltage cut-off [V]")

        # Current as a function of *dimensional* time. The below is overwritten in
        # lithium_ion_parameters.py and lead_acid_parameters.py to use the correct
        # timescale used for non-dimensionalisation. For a base model, the user may
        # provide the typical timescale as a parameter.
        self.timescale = pybamm.Parameter("Typical timescale [s]")
        self.dimensional_current_with_time = pybamm.FunctionParameter(
            "Current function [A]", {"Time[s]": pybamm.t * self.timescale})
        self.dimensional_current_density_with_time = (
            self.dimensional_current_with_time /
            (self.n_electrodes_parallel * self.geo.A_cc))
Exemple #14
0
    def test_with_autograd(self):
        a = pybamm.StateVector(slice(0, 1))
        y = np.array([5])
        func = pybamm.Function(test_function, a)
        self.assertEqual(func.diff(a).evaluate(y=y), 2)
        self.assertEqual(func.diff(func).evaluate(), 1)
        func = pybamm.Function(auto_np.sin, a)
        self.assertEqual(func.evaluate(y=y), np.sin(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.cos(a.evaluate(y=y)))
        func = pybamm.Function(auto_np.exp, a)
        self.assertEqual(func.evaluate(y=y), np.exp(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.exp(a.evaluate(y=y)))

        # multiple variables
        func = pybamm.Function(test_multi_var_function, 4 * a, 3 * a)
        self.assertEqual(func.diff(a).evaluate(y=y), 7)
Exemple #15
0
 def test_function_unnamed(self):
     t = np.linspace(0, 1)
     entries = 2 * t
     interpfun = interp1d(t, entries)
     fun = pybamm.Function(interpfun, pybamm.t)
     self.assertEqual(
         fun.name, "function (<class 'scipy.interpolate.interpolate.interp1d'>)"
     )
Exemple #16
0
    def test_functions(self):
        y = pybamm.StateVector(slice(0, 4))
        u = pybamm.StateVector(slice(0, 2))
        v = pybamm.StateVector(slice(2, 4))
        const = pybamm.Scalar(1)

        y0 = np.array([1.0, 2.0, 3.0, 4.0])

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

        func = pybamm.cos(v)
        jacobian = np.array([[0, 0, -np.sin(3), 0], [0, 0, 0, -np.sin(4)]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.sin(3 * u * v)
        jacobian = np.array(
            [
                [9 * np.cos(9), 0, 3 * np.cos(9), 0],
                [0, 12 * np.cos(24), 0, 6 * np.cos(24)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.cos(5 * pybamm.exp(u + v))
        jacobian = np.array(
            [
                [
                    -5 * np.exp(4) * np.sin(5 * np.exp(4)),
                    0,
                    -5 * np.exp(4) * np.sin(5 * np.exp(4)),
                    0,
                ],
                [
                    0,
                    -5 * np.exp(6) * np.sin(5 * np.exp(6)),
                    0,
                    -5 * np.exp(6) * np.sin(5 * np.exp(6)),
                ],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        # when child evaluates to number
        func = pybamm.Sin(const)
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(0, dfunc_dy)

        # several children
        func = pybamm.Function(test_multi_var_function, 2 * y, 3 * y)
        jacobian = np.diag(5 * np.ones(4))
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())
    def test_convert_differentiated_function(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)

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

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

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

        f = pybamm.Function(myfunction, a, b).diff(a)
        self.assertEqual(f.to_casadi(), casadi.SX(1))
        f = pybamm.Function(myfunction, a, b).diff(b)
        self.assertEqual(f.to_casadi(), casadi.SX(3))
Exemple #18
0
    def test_function_of_multiple_variables(self):
        a = pybamm.Variable("a")
        b = pybamm.Parameter("b")
        func = pybamm.Function(test_multi_var_function, a, b)
        self.assertEqual(func.name, "function (test_multi_var_function)")
        self.assertEqual(func.children[0].name, a.name)
        self.assertEqual(func.children[1].name, b.name)

        # test eval and diff
        a = pybamm.StateVector(slice(0, 1))
        b = pybamm.StateVector(slice(1, 2))
        y = np.array([5, 2])
        func = pybamm.Function(test_multi_var_function, a, b)

        self.assertEqual(func.evaluate(y=y), 7)
        self.assertEqual(func.diff(a).evaluate(y=y), 1)
        self.assertEqual(func.diff(b).evaluate(y=y), 1)
        self.assertEqual(func.diff(func).evaluate(), 1)
Exemple #19
0
 def _diff(self, children):
     """ See :meth:`pybamm.Symbol._diff()`. """
     if self.derivative == "autograd":
         return Function(autograd.elementwise_grad(self.function),
                         *children)
     elif self.derivative == "derivative":
         # keep using "derivative" as derivative
         return pybamm.Function(self.function.derivative(),
                                *children,
                                derivative="derivative")
Exemple #20
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))
Exemple #21
0
    def test_functions(self):
        y = pybamm.StateVector(slice(0, 8))
        u = pybamm.StateVector(slice(0, 2), slice(4, 6))
        v = pybamm.StateVector(slice(2, 4), slice(6, 8))

        y0 = np.arange(1, 9)
        const = pybamm.Scalar(1)

        func = pybamm.sin(u)
        jacobian = np.array(
            [
                [np.cos(1), 0, 0, 0, 0, 0, 0, 0],
                [0, np.cos(2), 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, np.cos(5), 0, 0, 0],
                [0, 0, 0, 0, 0, np.cos(6), 0, 0],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.cos(v)
        jacobian = np.array(
            [
                [0, 0, -np.sin(3), 0, 0, 0, 0, 0],
                [0, 0, 0, -np.sin(4), 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, -np.sin(7), 0],
                [0, 0, 0, 0, 0, 0, 0, -np.sin(8)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.sin(3 * u * v)
        jacobian = np.array(
            [
                [9 * np.cos(9), 0, 3 * np.cos(9), 0, 0, 0, 0, 0],
                [0, 12 * np.cos(24), 0, 6 * np.cos(24), 0, 0, 0, 0],
                [0, 0, 0, 0, 21 * np.cos(105), 0, 15 * np.cos(105), 0],
                [0, 0, 0, 0, 0, 24 * np.cos(144), 0, 18 * np.cos(144)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        # when child evaluates to number
        func = pybamm.sin(const)
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(0, dfunc_dy)

        # several children
        func = pybamm.Function(test_multi_var_function, 2 * y, 3 * y)
        jacobian = np.diag(5 * np.ones(8))
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())
    def _set_input_current(self):
        """Set the input current"""

        self.dimensional_current_with_time = pybamm.FunctionParameter(
            "Current function [A]", {"Time [s]": pybamm.t * self.timescale})
        self.dimensional_current_density_with_time = (
            self.dimensional_current_with_time /
            (self.n_electrodes_parallel * self.geo.A_cc))
        self.current_with_time = (self.dimensional_current_with_time /
                                  self.I_typ *
                                  pybamm.Function(np.sign, self.I_typ))
    def test_multi_var_function_with_parameters(self):
        def D(a, b):
            return a * np.exp(b)

        parameter_values = pybamm.ParameterValues({"a": 3, "b": 0})
        a = pybamm.Parameter("a")
        b = pybamm.Parameter("b")
        func = pybamm.Function(D, a, b)

        processed_func = parameter_values.process_symbol(func)
        self.assertIsInstance(processed_func, pybamm.Function)
        self.assertEqual(processed_func.evaluate(), 3)
Exemple #24
0
    def test_symbol_new_copy(self):
        a = pybamm.Parameter("a")
        b = pybamm.Parameter("b")
        v_n = pybamm.Variable("v", "negative electrode")
        x_n = pybamm.standard_spatial_vars.x_n
        v_s = pybamm.Variable("v", "separator")
        vec = pybamm.Vector([1, 2, 3, 4, 5])
        mat = pybamm.Matrix([[1, 2], [3, 4]])
        mesh = get_mesh_for_testing()

        for symbol in [
                a + b,
                a - b,
                a * b,
                a / b,
                a**b,
                -a,
                abs(a),
                pybamm.Function(np.sin, a),
                pybamm.FunctionParameter("function", {"a": a}),
                pybamm.grad(v_n),
                pybamm.div(pybamm.grad(v_n)),
                pybamm.upwind(v_n),
                pybamm.IndefiniteIntegral(v_n, x_n),
                pybamm.BackwardIndefiniteIntegral(v_n, x_n),
                pybamm.BoundaryValue(v_n, "right"),
                pybamm.BoundaryGradient(v_n, "right"),
                pybamm.PrimaryBroadcast(a, "domain"),
                pybamm.SecondaryBroadcast(v_n, "current collector"),
                pybamm.FullBroadcast(a, "domain",
                                     {"secondary": "other domain"}),
                pybamm.concatenation(v_n, v_s),
                pybamm.NumpyConcatenation(a, b, v_s),
                pybamm.DomainConcatenation([v_n, v_s], mesh),
                pybamm.Parameter("param"),
                pybamm.InputParameter("param"),
                pybamm.StateVector(slice(0, 56)),
                pybamm.Matrix(np.ones((50, 40))),
                pybamm.SpatialVariable("x", ["negative electrode"]),
                pybamm.t,
                pybamm.Index(vec, 1),
                pybamm.NotConstant(a),
                pybamm.ExternalVariable(
                    "external variable",
                    20,
                    domain="test",
                    auxiliary_domains={"secondary": "test2"},
                ),
                pybamm.minimum(a, b),
                pybamm.maximum(a, b),
                pybamm.SparseStack(mat, mat),
        ]:
            self.assertEqual(symbol.id, symbol.new_copy().id)
    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.SX(0))
        self.assertEqual(d.to_casadi(), casadi.SX(2))

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

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

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

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

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

        # addition
        self.assertEqual((a + b).to_casadi(), casadi.SX(1))
        # subtraction
        self.assertEqual((c - d).to_casadi(), casadi.SX(-3))
        # multiplication
        self.assertEqual((c * d).to_casadi(), casadi.SX(-2))
        # power
        self.assertEqual((c**d).to_casadi(), casadi.SX(1))
        # division
        self.assertEqual((b / d).to_casadi(), casadi.SX(1 / 2))
Exemple #26
0
    def _function_new_copy(self, children):
        """Returns a new copy of the function.

        Inputs
        ------
        children : : list
            A list of the children of the function

        Returns
        -------
            : :pybamm.Function
            A new copy of the function
        """
        return pybamm.Function(self.function,
                               *children,
                               name=self.name,
                               derivative=self.derivative)
Exemple #27
0
    def test_symbol_new_copy(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)
        v_n = pybamm.Variable("v", "negative electrode")
        x_n = pybamm.standard_spatial_vars.x_n
        v_s = pybamm.Variable("v", "separator")
        vec = pybamm.Vector(np.array([1, 2, 3, 4, 5]))
        mesh = get_mesh_for_testing()

        for symbol in [
                a + b,
                a - b,
                a * b,
                a / b,
                a**b,
                -a,
                abs(a),
                pybamm.Function(np.sin, a),
                pybamm.FunctionParameter("function", {"a": a}),
                pybamm.grad(v_n),
                pybamm.div(pybamm.grad(v_n)),
                pybamm.Integral(a, pybamm.t),
                pybamm.IndefiniteIntegral(v_n, x_n),
                pybamm.BackwardIndefiniteIntegral(v_n, x_n),
                pybamm.BoundaryValue(v_n, "right"),
                pybamm.BoundaryGradient(v_n, "right"),
                pybamm.PrimaryBroadcast(a, "domain"),
                pybamm.SecondaryBroadcast(v_n, "current collector"),
                pybamm.FullBroadcast(a, "domain",
                                     {"secondary": "other domain"}),
                pybamm.Concatenation(v_n, v_s),
                pybamm.NumpyConcatenation(a, b, v_s),
                pybamm.DomainConcatenation([v_n, v_s], mesh),
                pybamm.Parameter("param"),
                pybamm.InputParameter("param"),
                pybamm.StateVector(slice(0, 56)),
                pybamm.Matrix(np.ones((50, 40))),
                pybamm.SpatialVariable("x", ["negative electrode"]),
                pybamm.t,
                pybamm.Index(vec, 1),
        ]:
            self.assertEqual(symbol.id, symbol.new_copy().id)
Exemple #28
0
    def _function_new_copy(self, children):
        """Returns a new copy of the function.

        Inputs
        ------
        children : : list
            A list of the children of the function

        Returns
        -------
            : :pybamm.Function
            A new copy of the function
        """
        return pybamm.simplify_if_constant(
            pybamm.Function(
                self.function,
                *children,
                name=self.name,
                derivative=self.derivative,
                differentiated_function=self.differentiated_function), )
    def get_interp_fun_curr_coll(variable_name):
        """
        Interpolate in space to plotting nodes, and then create function to interpolate
        in time that can be called for plotting at any t.
        """

        comsol_z = comsol_variables[variable_name + "_z"]
        variable = comsol_variables[variable_name]
        variable = interp.interp1d(comsol_z, variable, axis=0, kind=interp_kind)(
            z_interp
        )

        def myinterp(t):
            return interp.interp1d(comsol_t, variable, kind=interp_kind)(t)[
                :, np.newaxis
            ]

        # Make sure to use dimensional time
        fun = pybamm.Function(myinterp, pybamm.t * tau, name=variable_name + "_comsol")
        fun.domain = "current collector"
        return fun
Exemple #30
0
    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)