Example #1
0
    def test_process_inline_function_parameters(self):
        def D(c):
            return c**2

        parameter_values = pybamm.ParameterValues({"Diffusivity": D})

        a = pybamm.InputParameter("a")
        func = pybamm.FunctionParameter("Diffusivity", {"a": a})

        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(inputs={"a": 3}), 9)

        # process differentiated function parameter
        diff_func = func.diff(a)
        processed_diff_func = parameter_values.process_symbol(diff_func)
        self.assertEqual(processed_diff_func.evaluate(inputs={"a": 3}), 6)
Example #2
0
    def test_multi_var_function_parameter(self):
        def D(a, b):
            return a * pybamm.exp(b)

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

        a = pybamm.Parameter("a")
        b = pybamm.Parameter("b")
        func = pybamm.FunctionParameter("Diffusivity", {"a": a, "b": b})

        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(), 3)
 def a_p_of_x(self, x):
     """
     Dimensionless surface area per unit volume distribution in x. The surface
     area per unit volume distribution is defined so that the actual surface
     area per unit volume as a function of x is given by a*a_of_x (so that
     a_of_x = 1 gives uniform surface area per unit volume in x).
     """
     if self.options["particle shape"] == "spherical":
         # Currently the active material volume fraction is a scalar, so the
         # distribution of surface are per unit volume is simply the reciprocal
         # of the particle radius distribution
         return 1 / self.R_p_of_x(x)
     elif self.options["particle shape"] == "user":
         inputs = {"Through-cell distance (x_p) [m]": x}
         return pybamm.FunctionParameter(
             "Positive surface area per unit volume distribution in x",
             inputs)
Example #4
0
    def test_set_input_names(self):

        var = pybamm.Variable("var")
        func = pybamm.FunctionParameter("a", {"var": var})

        new_input_names = ["first", "second"]
        func.input_names = new_input_names

        self.assertEqual(func.input_names, new_input_names)

        with self.assertRaises(TypeError):
            new_input_names = {"wrong": "input type"}
            func.input_names = new_input_names

        with self.assertRaises(TypeError):
            new_input_names = [var]
            func.input_names = new_input_names
Example #5
0
    def test_read_parameters(self):
        # Read parameters from different parts of the model
        model = pybamm.BaseModel()
        a = pybamm.Parameter("a")
        b = pybamm.InputParameter("b", "test")
        c = pybamm.Parameter("c")
        d = pybamm.Parameter("d")
        e = pybamm.Parameter("e")
        f = pybamm.InputParameter("f")
        g = pybamm.Parameter("g")
        h = pybamm.Parameter("h")
        i = pybamm.InputParameter("i")

        u = pybamm.Variable("u")
        v = pybamm.Variable("v")
        model.rhs = {u: -u * a}
        model.algebraic = {v: v - b}
        model.initial_conditions = {u: c, v: d}
        model.events = [pybamm.Event("u=e", u - e)]
        model.variables = {"v+f+i": v + f + i}
        model.boundary_conditions = {
            u: {
                "left": (g, "Dirichlet"),
                "right": (0, "Neumann")
            },
            v: {
                "left": (0, "Dirichlet"),
                "right": (h, "Neumann")
            },
        }

        self.assertEqual(
            set([x.name for x in model.parameters]),
            set([x.name for x in [a, b, c, d, e, f, g, h, i]]),
        )
        self.assertTrue(
            all(
                isinstance(x, (pybamm.Parameter, pybamm.InputParameter))
                for x in model.parameters))

        model.variables = {
            "v+f+i":
            v + pybamm.FunctionParameter("f", {"Time [s]": pybamm.t}) + i
        }
        model.print_parameter_info()
Example #6
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([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.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),
        ]:
            self.assertEqual(symbol.id, symbol.new_copy().id)
    def test_process_interpolant(self):
        x = np.linspace(0, 10)[:, np.newaxis]
        data = np.hstack([x, 2 * x])
        parameter_values = pybamm.ParameterValues({
            "a":
            3.01,
            "Diffusivity": ("times two", data)
        })

        a = pybamm.Parameter("a")
        func = pybamm.FunctionParameter("Diffusivity", a)

        processed_func = parameter_values.process_symbol(func)
        self.assertIsInstance(processed_func, pybamm.Interpolant)
        self.assertEqual(processed_func.evaluate(), 6.02)

        # process differentiated function parameter
        diff_func = func.diff(a)
        processed_diff_func = parameter_values.process_symbol(diff_func)
        self.assertEqual(processed_diff_func.evaluate(), 2)
Example #8
0
    def test_shape_and_size_for_testing(self):
        scal = pybamm.Scalar(1)
        self.assertEqual(scal.shape_for_testing, scal.shape)
        self.assertEqual(scal.size_for_testing, scal.size)

        state = pybamm.StateVector(slice(10, 25))
        self.assertEqual(state.shape_for_testing, state.shape)

        param = pybamm.Parameter("a")
        self.assertEqual(param.shape_for_testing, ())

        func = pybamm.FunctionParameter("func", {"state": state})
        self.assertEqual(func.shape_for_testing, state.shape_for_testing)

        concat = pybamm.Concatenation()
        self.assertEqual(concat.shape_for_testing, (0,))
        concat = pybamm.Concatenation(state, state)
        self.assertEqual(concat.shape_for_testing, (30, 1))
        self.assertEqual(concat.size_for_testing, 30)

        var = pybamm.Variable("var", domain="negative electrode")
        broadcast = pybamm.PrimaryBroadcast(0, "negative electrode")
        self.assertEqual(var.shape_for_testing, broadcast.shape_for_testing)
        self.assertEqual(
            (var + broadcast).shape_for_testing, broadcast.shape_for_testing
        )

        var = pybamm.Variable("var", domain=["random domain", "other domain"])
        broadcast = pybamm.PrimaryBroadcast(0, ["random domain", "other domain"])
        self.assertEqual(var.shape_for_testing, broadcast.shape_for_testing)
        self.assertEqual(
            (var + broadcast).shape_for_testing, broadcast.shape_for_testing
        )

        sym = pybamm.Symbol("sym")
        with self.assertRaises(NotImplementedError):
            sym.shape_for_testing
def electrolyte_diffusivity_Ecker2015(c_e, T):
    """
    Diffusivity of LiPF6 in EC:DMC as a function of ion concentration [1, 2, 3].

    References
    ----------
    .. [1] Ecker, Madeleine, et al. "Parameterization of a physico-chemical model of
    a lithium-ion battery i. determination of parameters." Journal of the
    Electrochemical Society 162.9 (2015): A1836-A1848.
    .. [2] Ecker, Madeleine, et al. "Parameterization of a physico-chemical model of
    a lithium-ion battery ii. model validation." Journal of The Electrochemical
    Society 162.9 (2015): A1849-A1857.
    .. [3] Richardson, Giles, et. al. "Generalised single particle models for
    high-rate operation of graded lithium-ion electrodes: Systematic derivation
    and validation." Electrochemica Acta 339 (2020): 135862

    Parameters
    ----------
    c_e: :class:`pybamm.Symbol`
        Dimensional electrolyte concentration
    T: :class:`pybamm.Symbol`
        Dimensional temperature

    Returns
    -------
    :class:`pybamm.Symbol`
        Solid diffusivity
    """

    # The diffusivity epends on the electrolyte conductivity
    inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
    sigma_e = pybamm.FunctionParameter("Electrolyte conductivity [S.m-1]",
                                       inputs)

    D_c_e = (constants.k_b / (constants.F * constants.q_e)) * sigma_e * T / c_e

    return D_c_e
Example #10
0
def D_e_dimensional(c_e, T):
    "Dimensional diffusivity in electrolyte"
    return pybamm.FunctionParameter("Electrolyte diffusivity [m2.s-1]", c_e)
Example #11
0
 def T_amb_dim(self, t):
     "Dimensional ambient temperature"
     return pybamm.FunctionParameter("Ambient temperature [K]",
                                     {"Times [s]": t})
def j0_p_Ox_dimensional(c_e, T):
    "Dimensional oxygen positive electrode exchange-current density [A.m-2]"
    inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
    return pybamm.FunctionParameter(
        "Positive electrode oxygen exchange-current density [A.m-2]", inputs)
def U_p_dimensional(c_e, T):
    "Dimensional open-circuit voltage in the positive electrode [V]"
    inputs = {"Electrolyte molar mass [mol.kg-1]": m_dimensional(c_e)}
    return pybamm.FunctionParameter(
        "Positive electrode open-circuit potential [V]", inputs)
def chi_dimensional(c_e):
    inputs = {"Electrolyte concentration [mol.m-3]": c_e}
    return pybamm.FunctionParameter("Darken thermodynamic factor", inputs)
def kappa_e_dimensional(c_e, T):
    "Dimensional electrolyte conductivity"
    inputs = {"Electrolyte concentration [mol.m-3]": c_e}
    return pybamm.FunctionParameter("Electrolyte conductivity [S.m-1]", inputs)
Example #16
0
def chi_dimensional(c_e):
    return pybamm.FunctionParameter("Darken thermodynamic factor", c_e)
def t_plus(c_e):
    "Dimensionless transference number (i.e. c_e is dimensionless)"
    inputs = {"Electrolyte concentration [mol.m-3]": c_e * c_e_typ}
    return pybamm.FunctionParameter("Cation transference number", inputs)
Example #18
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)
Example #19
0
    def test_process_function_parameter(self):
        parameter_values = pybamm.ParameterValues(
            {
                "a": 3,
                "func": pybamm.load_function(
                    os.path.join(
                        "tests",
                        "unit",
                        "test_parameters",
                        "data",
                        "process_symbol_test_function.py",
                    )
                ),
                "const": 254,
                "float_func": lambda x: 42,
                "mult": pybamm.InputParameter("b") * 5,
                "bad type": np.array([1, 2, 3]),
            }
        )
        a = pybamm.InputParameter("a")

        # process function
        func = pybamm.FunctionParameter("func", {"a": a})
        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(inputs={"a": 3}), 369)

        # process constant function
        const = pybamm.FunctionParameter("const", {"a": a})
        processed_const = parameter_values.process_symbol(const)
        self.assertIsInstance(processed_const, pybamm.Scalar)
        self.assertEqual(processed_const.evaluate(), 254)

        # process case where parameter provided is a pybamm symbol
        # (e.g. a multiplication)
        mult = pybamm.FunctionParameter("mult", {"a": a})
        processed_mult = parameter_values.process_symbol(mult)
        self.assertEqual(processed_mult.evaluate(inputs={"a": 14, "b": 63}), 63 * 5)

        # process differentiated function parameter
        diff_func = func.diff(a)
        processed_diff_func = parameter_values.process_symbol(diff_func)
        self.assertEqual(processed_diff_func.evaluate(inputs={"a": 3}), 123)

        # make sure diff works, despite simplifications, when the child is constant
        a_const = pybamm.Scalar(3)
        func_const = pybamm.FunctionParameter("func", {"a": a_const})
        diff_func_const = func_const.diff(a_const)
        processed_diff_func_const = parameter_values.process_symbol(diff_func_const)
        self.assertEqual(processed_diff_func_const.evaluate(), 123)

        # function parameter that returns a python float
        func = pybamm.FunctionParameter("float_func", {"a": a})
        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(), 42)

        # weird type raises error
        func = pybamm.FunctionParameter("bad type", {"a": a})
        with self.assertRaisesRegex(TypeError, "Parameter provided for"):
            parameter_values.process_symbol(func)

        # function itself as input (different to the variable being an input)
        parameter_values = pybamm.ParameterValues(
            {"func": "[input]", "vector func": pybamm.InputParameter("vec", "test")}
        )
        a = pybamm.Scalar(3)
        func = pybamm.FunctionParameter("func", {"a": a})
        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(inputs={"func": 13}), 13)

        func = pybamm.FunctionParameter("vector func", {"a": a})
        processed_func = parameter_values.process_symbol(func)
        self.assertEqual(processed_func.evaluate(inputs={"vec": 13}), 13)

        # make sure function keeps the domain of the original function

        def my_func(x):
            return 2 * x

        x = pybamm.standard_spatial_vars.x_n
        func = pybamm.FunctionParameter("func", {"x": x})

        parameter_values = pybamm.ParameterValues({"func": my_func})
        func1 = parameter_values.process_symbol(func)

        parameter_values = pybamm.ParameterValues({"func": pybamm.InputParameter("a")})
        func2 = parameter_values.process_symbol(func)

        parameter_values = pybamm.ParameterValues(
            {"func": pybamm.InputParameter("a", "negative electrode")}
        )
        func3 = parameter_values.process_symbol(func)

        self.assertEqual(func1.domains, func2.domains)
        self.assertEqual(func1.domains, func3.domains)
Example #20
0
    def _get_standard_active_material_variables(self, eps_solid):
        param = self.param
        eps_solid_av = pybamm.x_average(eps_solid)

        variables = {
            self.domain + " electrode active material volume fraction":
            eps_solid,
            "X-averaged " + self.domain.lower() + " electrode active material volume fraction":
            eps_solid_av,
        }

        # Update other microstructure variables
        # some models (e.g. lead-acid) do not have particles
        if self.options["particle shape"] == "no particles":
            if self.domain == "Negative":
                x = pybamm.standard_spatial_vars.x_n
                a = self.param.a_n(x)
                a_typ = self.param.a_n_typ
            elif self.domain == "Positive":
                x = pybamm.standard_spatial_vars.x_p
                a = self.param.a_p(x)
                a_typ = self.param.a_p_typ
            variables.update({
                self.domain + " electrode surface area to volume ratio":
                a,
                self.domain + " electrode surface area to volume ratio [m-1]":
                a * a_typ,
            })
            return variables

        else:
            # Update electrode capacity variables
            if self.domain == "Negative":
                L = param.L_n
                c_s_max = param.c_n_max
            elif self.domain == "Positive":
                L = param.L_p
                c_s_max = param.c_p_max

            C = eps_solid_av * L * param.A_cc * c_s_max * param.F / 3600
            variables.update({self.domain + " electrode capacity [A.h]": C})

            if self.domain == "Negative":
                x = pybamm.standard_spatial_vars.x_n
                R = self.param.R_n(x)
                R_dim = self.param.R_n_dimensional(x * self.param.L_x)
                a_typ = self.param.a_n_typ
            elif self.domain == "Positive":
                x = pybamm.standard_spatial_vars.x_p
                R = self.param.R_p(x)
                R_dim = self.param.R_p_dimensional(x * self.param.L_x)
                a_typ = self.param.a_p_typ
            R_dim_av = pybamm.x_average(R_dim)

            # Compute dimensional particle shape
            if self.options["particle shape"] == "spherical":
                a_dim = 3 * eps_solid / R_dim
                a_dim_av = 3 * eps_solid_av / R_dim_av
            elif self.options["particle shape"] == "user":
                if self.domain == "Negative":
                    # give dimensional x as an input
                    inputs = {
                        "Through-cell distance (x_n) [m]": x * self.param.L_x
                    }
                    a_dim = pybamm.FunctionParameter(
                        "Negative electrode surface area to volume ratio [m-1]",
                        inputs)
                if self.domain == "Positive":
                    # give dimensional x as an input
                    inputs = {
                        "Through-cell distance (x_p) [m]": x * self.param.L_x
                    }
                    a_dim = pybamm.FunctionParameter(
                        "Positive electrode surface area to volume ratio [m-1]",
                        inputs)
                a_dim_av = pybamm.x_average(a_dim)

            # Surface area to volume ratio is scaled with a_typ, so that it is equal to
            # 1 when eps_solid and R are uniform in space and time
            a = a_dim / a_typ
            a_av = a_dim_av / a_typ
            variables.update({
                self.domain + " particle radius":
                R,
                self.domain + " particle radius [m]":
                R_dim,
                self.domain + " electrode surface area to volume ratio":
                a,
                self.domain + " electrode surface area to volume ratio [m-1]":
                a_dim,
                "X-averaged " + self.domain.lower() + " electrode surface area to volume ratio":
                a_av,
                "X-averaged " + self.domain.lower() + " electrode surface area to volume ratio [m-1]":
                a_dim_av,
            })

            return variables
Example #21
0
def U_p_dimensional(c_e, T):
    "Dimensional open-circuit voltage in the positive electrode [V]"
    return pybamm.FunctionParameter(
        "Positive electrode open-circuit potential [V]", m_dimensional(c_e))
Example #22
0
def mu_dimensional(c_e):
    """
    Dimensional viscosity of electrolyte [kg.m-1.s-1].
    """
    return pybamm.FunctionParameter("Electrolyte viscosity [kg.m-1.s-1]", c_e)
    def test_process_symbol(self):
        parameter_values = pybamm.ParameterValues({"a": 4, "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, 4)

        # process binary operation
        var = pybamm.Variable("var")
        add = a + var
        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.Variable)
        self.assertEqual(processed_add.children[0].value, 4)

        b = pybamm.Parameter("b")
        add = a + b
        processed_add = parameter_values.process_symbol(add)
        self.assertIsInstance(processed_add, pybamm.Scalar)
        self.assertEqual(processed_add.value, 6)

        scal = pybamm.Scalar(34)
        mul = a * scal
        processed_mul = parameter_values.process_symbol(mul)
        self.assertIsInstance(processed_mul, pybamm.Scalar)
        self.assertEqual(processed_mul.value, 136)

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

        # process unary operation
        v = pybamm.Variable("v", domain="test")
        grad = pybamm.Gradient(v)
        processed_grad = parameter_values.process_symbol(grad)
        self.assertIsInstance(processed_grad, pybamm.Gradient)
        self.assertIsInstance(processed_grad.children[0], pybamm.Variable)

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

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

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

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

        # not implemented
        sym = pybamm.Symbol("sym")
        with self.assertRaises(NotImplementedError):
            parameter_values.process_symbol(sym)

        # not found
        with self.assertRaises(KeyError):
            x = pybamm.Parameter("x")
            parameter_values.process_symbol(x)

        parameter_values = pybamm.ParameterValues({"x": np.nan})
        with self.assertRaisesRegex(ValueError, "Parameter 'x' not found"):
            x = pybamm.Parameter("x")
            parameter_values.process_symbol(x)
        with self.assertRaisesRegex(ValueError, "possibly a function"):
            x = pybamm.FunctionParameter("x", {})
            parameter_values.process_symbol(x)
def D_e_dimensional(c_e, T):
    "Dimensional diffusivity in electrolyte"
    inputs = {"Electrolyte concentration [mol.m-3]": c_e}
    return pybamm.FunctionParameter("Electrolyte diffusivity [m2.s-1]", inputs)
Example #25
0
 def test_function_parameter_diff(self):
     var = pybamm.Variable("var")
     func = pybamm.FunctionParameter("a", var).diff(var)
     self.assertEqual(func.diff_variable, var)
Example #26
0
def kappa_e_dimensional(c_e, T):
    "Dimensional electrolyte conductivity"
    return pybamm.FunctionParameter("Electrolyte conductivity [S.m-1]", c_e)
Example #27
0
 def external_circuit_function(variables):
     I = variables["Current [A]"]
     V = variables["Terminal voltage [V]"]
     return V + I - pybamm.FunctionParameter("Function",
                                             {"Time [s]": pybamm.t})
Example #28
0
 def test_evaluate_for_shape(self):
     a = pybamm.Parameter("a")
     func = pybamm.FunctionParameter("func", 2 * a)
     self.assertIsInstance(func.evaluate_for_shape(), numbers.Number)
Example #29
0
    def test_process_integral_broadcast(self):
        # Test that the x-average of a broadcast, created outside of x-average, gets
        # processed correctly
        var = pybamm.Variable("var", domain="test")
        func = pybamm.x_average(pybamm.FunctionParameter("func", {"var": var}))

        param = pybamm.ParameterValues({"func": 2})
        func_proc = param.process_symbol(func)

        self.assertEqual(func_proc.id, pybamm.Scalar(2, name="func").id)

        # test with auxiliary domains
        var = pybamm.Variable(
            "var", domain="test", auxiliary_domains={"secondary": "test sec"}
        )
        func = pybamm.x_average(pybamm.FunctionParameter("func", {"var": var}))

        param = pybamm.ParameterValues({"func": 2})
        func_proc = param.process_symbol(func)

        self.assertEqual(
            func_proc.id,
            pybamm.PrimaryBroadcast(pybamm.Scalar(2, name="func"), "test sec").id,
        )

        var = pybamm.Variable(
            "var",
            domain="test",
            auxiliary_domains={"secondary": "test sec", "tertiary": "test tert"},
        )
        func = pybamm.x_average(pybamm.FunctionParameter("func", {"var": var}))

        param = pybamm.ParameterValues({"func": 2})
        func_proc = param.process_symbol(func)

        self.assertEqual(
            func_proc.id,
            pybamm.FullBroadcast(
                pybamm.Scalar(2, name="func"), "test sec", "test tert"
            ).id,
        )

        # this should be the case even if the domain is one of the special domains
        var = pybamm.Variable("var", domain="negative electrode")
        func = pybamm.x_average(pybamm.FunctionParameter("func", {"var": var}))

        param = pybamm.ParameterValues({"func": 2})
        func_proc = param.process_symbol(func)

        self.assertEqual(func_proc.id, pybamm.Scalar(2, name="func").id)

        # special case for integral of concatenations of broadcasts
        var_n = pybamm.Variable("var_n", domain="negative electrode")
        var_s = pybamm.Variable("var_s", domain="separator")
        var_p = pybamm.Variable("var_p", domain="positive electrode")
        func_n = pybamm.FunctionParameter("func_n", {"var_n": var_n})
        func_s = pybamm.FunctionParameter("func_s", {"var_s": var_s})
        func_p = pybamm.FunctionParameter("func_p", {"var_p": var_p})

        func = pybamm.x_average(pybamm.concatenation(func_n, func_s, func_p))
        param = pybamm.ParameterValues(
            {
                "func_n": 2,
                "func_s": 3,
                "func_p": 4,
                "Negative electrode thickness [m]": 1,
                "Separator thickness [m]": 1,
                "Positive electrode thickness [m]": 1,
            }
        )
        func_proc = param.process_symbol(func)

        self.assertEqual(func_proc.id, pybamm.Scalar(3).id)

        # with auxiliary domains
        var_n = pybamm.Variable(
            "var_n",
            domain="negative electrode",
            auxiliary_domains={"secondary": "current collector"},
        )
        var_s = pybamm.Variable(
            "var_s",
            domain="separator",
            auxiliary_domains={"secondary": "current collector"},
        )
        var_p = pybamm.Variable(
            "var_p",
            domain="positive electrode",
            auxiliary_domains={"secondary": "current collector"},
        )
        func_n = pybamm.FunctionParameter("func_n", {"var_n": var_n})
        func_s = pybamm.FunctionParameter("func_s", {"var_s": var_s})
        func_p = pybamm.FunctionParameter("func_p", {"var_p": var_p})

        func = pybamm.x_average(pybamm.concatenation(func_n, func_s, func_p))
        param = pybamm.ParameterValues(
            {
                "func_n": 2,
                "func_s": 3,
                "func_p": 4,
                "Negative electrode thickness [m]": 1,
                "Separator thickness [m]": 1,
                "Positive electrode thickness [m]": 1,
            }
        )
        func_proc = param.process_symbol(func)

        self.assertEqual(
            func_proc.id,
            pybamm.PrimaryBroadcast(pybamm.Scalar(3), "current collector").id,
        )
        "Positive electrode exchange-current density [A.m-2]", inputs)


def j0_p_Ox_dimensional(c_e, T):
    "Dimensional oxygen positive electrode exchange-current density [A.m-2]"
    inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
    return pybamm.FunctionParameter(
        "Positive electrode oxygen exchange-current density [A.m-2]", inputs)


D_e_typ = D_e_dimensional(c_e_typ, T_ref)
rho_typ = rho_dimensional(c_e_typ)
mu_typ = mu_dimensional(c_e_typ)

inputs = {"Electrolyte concentration [mol.m-3]": pybamm.Scalar(1)}
U_n_ref = pybamm.FunctionParameter(
    "Negative electrode open-circuit potential [V]", inputs)
inputs = {"Electrolyte concentration [mol.m-3]": pybamm.Scalar(1)}
U_p_ref = pybamm.FunctionParameter(
    "Positive electrode open-circuit potential [V]", inputs)

# --------------------------------------------------------------------------------------
"3. Scales"

# concentrations
electrolyte_concentration_scale = c_e_typ

# electrical
potential_scale = R * T_ref / F
current_scale = i_typ
interfacial_current_scale_n = i_typ / (a_n_dim * L_x)
interfacial_current_scale_p = i_typ / (a_p_dim * L_x)