Beispiel #1
0
    def test_absolute(self):
        a = pybamm.Symbol("a")
        absa = pybamm.AbsoluteValue(a)
        self.assertEqual(absa.name, "abs")
        self.assertEqual(absa.children[0].name, a.name)

        b = pybamm.Scalar(-4)
        absb = pybamm.AbsoluteValue(b)
        self.assertEqual(absb.evaluate(), 4)

        # Test broadcast gets switched
        broad_a = pybamm.PrimaryBroadcast(a, "test")
        abs_broad = abs(broad_a)
        self.assertEqual(abs_broad.id,
                         pybamm.PrimaryBroadcast(absa, "test").id)

        broad_a = pybamm.FullBroadcast(a, "test", "test2")
        abs_broad = abs(broad_a)
        self.assertEqual(abs_broad.id,
                         pybamm.FullBroadcast(absa, "test", "test2").id)

        # Test recursion
        broad_a = pybamm.PrimaryBroadcast(pybamm.PrimaryBroadcast(a, "test"),
                                          "test2")
        abs_broad = abs(broad_a)
        self.assertEqual(
            abs_broad.id,
            pybamm.PrimaryBroadcast(pybamm.PrimaryBroadcast(absa, "test"),
                                    "test2").id,
        )
Beispiel #2
0
    def test_absolute(self):
        a = pybamm.Symbol("a")
        absa = pybamm.AbsoluteValue(a)
        self.assertEqual(absa.name, "abs")
        self.assertEqual(absa.children[0].name, a.name)

        b = pybamm.Scalar(-4)
        absb = pybamm.AbsoluteValue(b)
        self.assertEqual(absb.evaluate(), 4)
    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))
Beispiel #4
0
    def test_to_equation(self):
        a = pybamm.Symbol("a", domain="negative particle")
        b = pybamm.Symbol("b", domain="current collector")
        c = pybamm.Symbol("c", domain="test")

        # Test print_name
        pybamm.Floor.print_name = "test"
        self.assertEqual(pybamm.Floor(-2.5).to_equation(), sympy.symbols("test"))

        # Test Negate
        self.assertEqual(pybamm.Negate(4).to_equation(), -4.0)

        # Test AbsoluteValue
        self.assertEqual(pybamm.AbsoluteValue(-4).to_equation(), 4.0)

        # Test Gradient
        self.assertEqual(pybamm.Gradient(a).to_equation(), sympy_Gradient("a"))

        # Test Divergence
        self.assertEqual(
            pybamm.Divergence(pybamm.Gradient(a)).to_equation(),
            sympy_Divergence(sympy_Gradient(a)),
        )

        # Test BoundaryValue
        self.assertEqual(
            pybamm.BoundaryValue(a, "right").to_equation(), sympy.symbols("a^{surf}")
        )
        self.assertEqual(
            pybamm.BoundaryValue(b, "positive tab").to_equation(), sympy.symbols(str(b))
        )
        self.assertEqual(
            pybamm.BoundaryValue(c, "left").to_equation(), sympy.symbols("c^{left}")
        )
Beispiel #5
0
 def __abs__(self):
     """return an :class:`AbsoluteValue` object, or a smooth approximation"""
     k = pybamm.settings.abs_smoothing
     # Return exact approximation if that is the setting or the outcome is a constant
     # (i.e. no need for smoothing)
     if k == "exact" or is_constant(self):
         out = pybamm.AbsoluteValue(self)
     else:
         out = pybamm.smooth_absolute_value(self, k)
     return pybamm.simplify_if_constant(out, keep_domains=True)
Beispiel #6
0
    def test_unary_operator(self):
        a = pybamm.Symbol("a", domain=["test"])
        un = pybamm.UnaryOperator("unary test", a)
        self.assertEqual(un.children[0].name, a.name)
        self.assertEqual(un.domain, a.domain)

        # with number
        a = pybamm.InputParameter("a")
        absval = pybamm.AbsoluteValue(-a)
        self.assertEqual(absval.evaluate(inputs={"a": 10}), 10)
        self.assertEqual(absval.evaluate(inputs={"a": 10}, known_evals={})[0], 10)
Beispiel #7
0
    def test_unary_operator(self):
        a = pybamm.Symbol("a", domain=["test"])
        un = pybamm.UnaryOperator("unary test", a)
        self.assertEqual(un.children[0].name, a.name)
        self.assertEqual(un.domain, a.domain)

        # with number
        absval = pybamm.AbsoluteValue(-10)
        self.assertEqual(absval.evaluate(), 10)

        log = pybamm.log(10)
        self.assertEqual(log.evaluate(), np.log(10))
Beispiel #8
0
    def test_nonlinear(self):
        y = pybamm.StateVector(slice(0, 4))
        u = pybamm.StateVector(slice(0, 2))
        v = pybamm.StateVector(slice(2, 4))

        y0 = np.array([1, 2, 3, 4])

        func = v**2
        jacobian = np.array([[0, 0, 6, 0], [0, 0, 0, 8]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

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

        func = v**v
        jacobian = [[0, 0, 27 * (1 + np.log(3)), 0],
                    [0, 0, 0, 256 * (1 + np.log(4))]]
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_almost_equal(jacobian, dfunc_dy.toarray())

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

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

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

        func = u / v
        jacobian = np.array([[1 / 3, 0, -1 / 9, 0], [0, 1 / 4, 0, -1 / 8]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

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

        func = pybamm.AbsoluteValue(v)
        with self.assertRaises(pybamm.UndefinedOperationError):
            func.jac(y)
Beispiel #9
0
    def test_smooth_absolute_value(self):
        # Test that smooth absolute value is used when the setting is changed
        a = pybamm.Symbol("a")
        pybamm.settings.abs_smoothing = 10
        self.assertEqual(str(abs(a)), str(pybamm.smooth_absolute_value(a, 10)))

        # But exact absolute value should still be used for constants
        a = pybamm.Parameter("a")
        self.assertEqual(str(abs(a)), str(pybamm.AbsoluteValue(a)))
        a = -1
        self.assertEqual(str(abs(a)), "1")

        # Change setting back for other tests
        pybamm.settings.abs_smoothing = "exact"
Beispiel #10
0
    def get_fundamental_variables(self):
        param = self.param
        # Current is a variable
        i_cell = pybamm.Variable("Total current density")

        # Update derived variables
        I = i_cell * pybamm.AbsoluteValue(param.I_typ)
        i_cell_dim = I / (param.n_electrodes_parallel * param.A_cc)

        variables = {
            "Total current density": i_cell,
            "Total current density [A.m-2]": i_cell_dim,
            "Current [A]": I,
            "C-rate": I / param.Q,
        }

        # Add discharge capacity variable
        variables.update(super().get_fundamental_variables())

        return variables
Beispiel #11
0
 def __abs__(self):
     """return an :class:`AbsoluteValue` object, or a smooth approximation."""
     if isinstance(self, pybamm.AbsoluteValue):
         # No need to apply abs a second time
         return self
     elif isinstance(self, pybamm.Broadcast):
         # Move absolute value inside the broadcast
         # Apply recursively
         abs_self_not_broad = pybamm.simplify_if_constant(
             abs(self.orphans[0]))
         return self._unary_new_copy(abs_self_not_broad)
     else:
         k = pybamm.settings.abs_smoothing
         # Return exact approximation if that is the setting or the outcome is a
         # constant (i.e. no need for smoothing)
         if k == "exact" or is_constant(self):
             out = pybamm.AbsoluteValue(self)
         else:
             out = pybamm.smooth_absolute_value(self, k)
         return pybamm.simplify_if_constant(out)
Beispiel #12
0
 def __abs__(self):
     """return an :class:`AbsoluteValue` object"""
     return pybamm.simplify_if_constant(pybamm.AbsoluteValue(self),
                                        keep_domains=True)
Beispiel #13
0
 def __abs__(self):
     """return an :class:`AbsoluteValue` object"""
     return pybamm.AbsoluteValue(self)