Esempio n. 1
0
    def test_model_solver_dae_inputs_in_initial_conditions(self):
        # Create model
        model = pybamm.BaseModel()
        var1 = pybamm.Variable("var1")
        var2 = pybamm.Variable("var2")
        model.rhs = {var1: pybamm.InputParameter("rate") * var1}
        model.algebraic = {var2: var1 - var2}
        model.initial_conditions = {
            var1: pybamm.InputParameter("ic 1"),
            var2: pybamm.InputParameter("ic 2"),
        }

        # Solve
        solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8)
        t_eval = np.linspace(0, 5, 100)
        solution = solver.solve(model,
                                t_eval,
                                inputs={
                                    "rate": -1,
                                    "ic 1": 0.1,
                                    "ic 2": 2
                                })
        np.testing.assert_array_almost_equal(solution.y[0],
                                             0.1 * np.exp(-solution.t),
                                             decimal=5)
        np.testing.assert_array_almost_equal(solution.y[-1],
                                             0.1 * np.exp(-solution.t),
                                             decimal=5)

        # Solve again with different initial conditions
        solution = solver.solve(model,
                                t_eval,
                                inputs={
                                    "rate": -0.1,
                                    "ic 1": 1,
                                    "ic 2": 3
                                })
        np.testing.assert_array_almost_equal(solution.y[0],
                                             1 * np.exp(-0.1 * solution.t),
                                             decimal=5)
        np.testing.assert_array_almost_equal(solution.y[-1],
                                             1 * np.exp(-0.1 * solution.t),
                                             decimal=5)
Esempio n. 2
0
    def test_diff_c_e_lead_acid(self):

        # With intercalation
        param = pybamm.standard_parameters_lead_acid
        model_n = pybamm.interface.ButlerVolmer(param, "Negative",
                                                "lead-acid main")
        model_p = pybamm.interface.ButlerVolmer(param, "Positive",
                                                "lead-acid main")
        parameter_values = pybamm.lead_acid.BaseModel(
        ).default_parameter_values

        def j_n(c_e):
            variables = {
                **self.variables,
                "Negative electrode surface potential difference":
                1,
                "Negative electrolyte concentration":
                c_e,
            }
            return model_n.get_coupled_variables(variables)[
                "Negative electrode interfacial current density"].orphans[0]

        def j_p(c_e):
            variables = {
                **self.variables,
                "Positive electrode surface potential difference":
                1,
                "Positive electrolyte concentration":
                c_e,
            }
            return model_p.get_coupled_variables(variables)[
                "Positive electrode interfacial current density"].orphans[0]

        c_e = pybamm.InputParameter("c_e")
        h = pybamm.Scalar(0.00001)

        # Analytical
        j_n_diff = parameter_values.process_symbol(j_n(c_e).diff(c_e))
        j_p_diff = parameter_values.process_symbol(j_p(c_e).diff(c_e))

        # Numerical
        j_n_FD = parameter_values.process_symbol(
            (j_n(c_e + h) - j_n(c_e - h)) / (2 * h))
        self.assertAlmostEqual(
            j_n_diff.evaluate(inputs={"c_e": 0.5}),
            j_n_FD.evaluate(inputs={"c_e": 0.5}),
            places=5,
        )
        j_p_FD = parameter_values.process_symbol(
            (j_p(c_e + h) - j_p(c_e - h)) / (2 * h))
        self.assertAlmostEqual(
            j_p_diff.evaluate(inputs={"c_e": 0.5}),
            j_p_FD.evaluate(inputs={"c_e": 0.5}),
            places=5,
        )
    def __init__(self, working_electrode, name="Electrode-specific SOH model"):
        self.working_electrode = working_electrode
        pybamm.citations.register("Mohtat2019")
        super().__init__(name)
        param = pybamm.LithiumIonParameters(
            {"working electrode": working_electrode})

        x_100 = pybamm.Variable("x_100", bounds=(0, 1))
        C = pybamm.Variable("C", bounds=(0, np.inf))
        Cw = pybamm.InputParameter("C_w")
        T_ref = param.T_ref
        if working_electrode == "negative":  # pragma: no cover
            raise NotImplementedError
        elif working_electrode == "positive":
            Uw = param.U_p_dimensional
            x_0 = x_100 + C / Cw

        V_max = pybamm.InputParameter("V_max")
        V_min = pybamm.InputParameter("V_min")

        self.algebraic = {
            x_100: Uw(x_100, T_ref) - V_max,
            C: Uw(x_0, T_ref) - V_min,
        }

        # initial guess must be chosen such that 0 < x_0, x_100 < 1
        # First guess for x_100
        x_100_init = 0.85
        # Make sure x_0 = x_100 - C/C_w > 0
        C_init = param.Q
        C_init = pybamm.minimum(Cw * x_100_init - 0.1, C_init)
        self.initial_conditions = {x_100: x_100_init, C: C_init}

        self.variables = {
            "x_100": x_100,
            "C": C,
            "x_0": x_0,
            "Uw(x_100)": Uw(x_100, T_ref),
            "Uw(x_0)": Uw(x_0, T_ref),
            "C_w": Cw,
            "C_w * (x_100 - x_0)": Cw * (x_100 - x_0),
        }
Esempio n. 4
0
    def test_generate_casadi(self):
        model = pybamm.BaseModel()
        t = pybamm.t
        a = pybamm.Variable("a")
        b = pybamm.Variable("b")
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        model.rhs = {a: -a * p}
        model.algebraic = {b: a - b}
        model.initial_conditions = {a: q, b: 1}
        model.variables = {"a+b": a + b - t}

        # Generate C code
        model.generate("test.c", ["a+b"])

        # Compile
        subprocess.run(["gcc", "-fPIC", "-shared", "-o", "test.so",
                        "test.c"])  # nosec

        # Read the generated functions
        x0_fn = casadi.external("x0", "./test.so")
        z0_fn = casadi.external("z0", "./test.so")
        rhs_fn = casadi.external("rhs_", "./test.so")
        alg_fn = casadi.external("alg_", "./test.so")
        jac_rhs_fn = casadi.external("jac_rhs", "./test.so")
        jac_alg_fn = casadi.external("jac_alg", "./test.so")
        var_fn = casadi.external("variables", "./test.so")

        # Test that function values are as expected
        self.assertEqual(x0_fn([0, 5]), 5)
        self.assertEqual(z0_fn([0, 0]), 1)
        self.assertEqual(rhs_fn(0, 3, 2, [7, 2]), -21)
        self.assertEqual(alg_fn(0, 3, 2, [7, 2]), 1)
        np.testing.assert_array_equal(np.array(jac_rhs_fn(5, 6, 7, [8, 9])),
                                      [[-8, 0]])
        np.testing.assert_array_equal(np.array(jac_alg_fn(5, 6, 7, [8, 9])),
                                      [[1, -1]])
        self.assertEqual(var_fn(6, 3, 2, [7, 2]), -1)

        # Remove generated files.
        os.remove("test.c")
        os.remove("test.so")
Esempio n. 5
0
 def test_block_symbolic_inputs(self):
     solver = pybamm.BaseSolver(rtol=1e-2, atol=1e-4)
     model = pybamm.BaseModel()
     a = pybamm.Scalar(0)
     p = pybamm.InputParameter("p")
     model.rhs = {a: a * p}
     with self.assertRaisesRegex(
             pybamm.SolverError,
             "Only CasadiSolver and CasadiAlgebraicSolver can have symbolic inputs",
     ):
         solver.solve(model, np.array([1, 2, 3]))
Esempio n. 6
0
 def test_tanh(self):
     a = pybamm.InputParameter("a")
     fun = pybamm.tanh(a)
     self.assertEqual(fun.evaluate(inputs={"a": 3}), np.tanh(3))
     h = 0.0000001
     self.assertAlmostEqual(
         fun.diff(a).evaluate(inputs={"a": 3}),
         (pybamm.tanh(pybamm.Scalar(3 + h)).evaluate() -
          fun.evaluate(inputs={"a": 3})) / h,
         places=5,
     )
Esempio n. 7
0
 def test_timescale_input_fail(self):
     # Make sure timescale can't depend on inputs
     model = pybamm.BaseModel()
     v = pybamm.Variable("v")
     model.rhs = {v: -1}
     model.initial_conditions = {v: 1}
     a = pybamm.InputParameter("a")
     model.timescale = a
     solver = pybamm.BaseSolver()
     with self.assertRaisesRegex(pybamm.SolverError, "The model timescale"):
         solver.set_up(model, inputs={"a": 10})
Esempio n. 8
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)
Esempio n. 9
0
    def test_model_solver_dae_inputs_events(self):
        # Create model
        for form in ["python", "casadi"]:
            model = pybamm.BaseModel()
            model.convert_to_format = form
            whole_cell = [
                "negative electrode", "separator", "positive electrode"
            ]
            var1 = pybamm.Variable("var1", domain=whole_cell)
            var2 = pybamm.Variable("var2", domain=whole_cell)
            model.rhs = {var1: pybamm.InputParameter("rate 1") * var1}
            model.algebraic = {
                var2: pybamm.InputParameter("rate 2") * var1 - var2
            }
            model.initial_conditions = {var1: 1, var2: 2}
            model.events = [
                pybamm.Event("var1 = 1.5", pybamm.min(var1 - 1.5)),
                pybamm.Event("var2 = 2.5", pybamm.min(var2 - 2.5)),
            ]
            disc = get_discretisation_for_testing()
            disc.process_model(model)

            # Solve
            if form == "python":
                solver = pybamm.ScikitsDaeSolver(rtol=1e-8,
                                                 atol=1e-8,
                                                 root_method="lm")
            else:
                solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8)
            t_eval = np.linspace(0, 5, 100)
            solution = solver.solve(model,
                                    t_eval,
                                    inputs={
                                        "rate 1": 0.1,
                                        "rate 2": 2
                                    })
            np.testing.assert_array_less(solution.y[0], 1.5)
            np.testing.assert_array_less(solution.y[-1], 2.5)
            np.testing.assert_allclose(solution.y[0], np.exp(0.1 * solution.t))
            np.testing.assert_allclose(solution.y[-1],
                                       2 * np.exp(0.1 * solution.t))
Esempio n. 10
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)
Esempio n. 11
0
 def set_events(self, variables):
     # add current and voltage events to the model
     # current events both negative and positive to catch specification
     n_cells = self.param.n_cells
     self.events.extend([
         pybamm.Event(
             "Current cut-off (positive) [A] [experiment]",
             variables["Current [A]"] -
             abs(pybamm.InputParameter("Current cut-off [A]")),
         ),
         pybamm.Event(
             "Current cut-off (negative) [A] [experiment]",
             variables["Current [A]"] +
             abs(pybamm.InputParameter("Current cut-off [A]")),
         ),
         pybamm.Event(
             "Voltage cut-off [V] [experiment]",
             variables["Terminal voltage [V]"] -
             pybamm.InputParameter("Voltage cut-off [V]") / n_cells,
         ),
     ])
Esempio n. 12
0
 def test_sqrt(self):
     a = pybamm.InputParameter("a")
     fun = pybamm.sqrt(a)
     self.assertIsInstance(fun, pybamm.Sqrt)
     self.assertEqual(fun.evaluate(inputs={"a": 3}), np.sqrt(3))
     h = 0.0000001
     self.assertAlmostEqual(
         fun.diff(a).evaluate(inputs={"a": 3}),
         (pybamm.sqrt(pybamm.Scalar(3 + h)).evaluate() -
          fun.evaluate(inputs={"a": 3})) / h,
         places=5,
     )
    def test_processed_variable_0D_some_inputs(self):
        # with some symbolic inputs and some non-symbolic inputs
        y = pybamm.StateVector(slice(0, 1))
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        var = p * y - q
        var.mesh = None

        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        solution = pybamm.Solution(t_sol, y_sol)
        solution.inputs = {"p": casadi.MX.sym("p"), "q": 2}
        processed_var = pybamm.ProcessedSymbolicVariable(var, solution)
        np.testing.assert_array_equal(
            processed_var.value({
                "p": 3
            }).full(), 3 * y_sol - 2)
        np.testing.assert_array_equal(
            processed_var.sensitivity({
                "p": 3
            }).full(), y_sol.T)
Esempio n. 14
0
 def test_set_expected_size(self):
     a = pybamm.InputParameter("a")
     a.set_expected_size(10)
     self.assertEqual(a._expected_size, 10)
     y = np.linspace(0, 1, 10)
     np.testing.assert_array_equal(a.evaluate(inputs={"a": y}), y)
     with self.assertRaisesRegex(
             ValueError,
             "Input parameter 'a' was given an object of size '1' but was expecting an "
             "object of size '10'",
     ):
         a.evaluate(inputs={"a": 5})
    def test_processed_variable_0D_with_inputs(self):
        # with symbolic inputs
        y = pybamm.StateVector(slice(0, 1))
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        var = p * y + q
        var.mesh = None

        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        solution = pybamm.Solution(t_sol, y_sol)
        solution.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_var = pybamm.ProcessedSymbolicVariable(var, solution)
        np.testing.assert_array_equal(
            processed_var.value({
                "p": 3,
                "q": 4
            }).full(), 3 * y_sol + 4)
        np.testing.assert_array_equal(
            processed_var.sensitivity({
                "p": 3,
                "q": 4
            }).full(),
            np.c_[y_sol.T, np.ones_like(y_sol).T],
        )

        # via value_and_sensitivity
        val, sens = processed_var.value_and_sensitivity({"p": 3, "q": 4})
        np.testing.assert_array_equal(val.full(), 3 * y_sol + 4)
        np.testing.assert_array_equal(sens.full(),
                                      np.c_[y_sol.T,
                                            np.ones_like(y_sol).T])

        # Test bad inputs
        with self.assertRaisesRegex(TypeError, "inputs should be 'dict'"):
            processed_var.value(1)
        with self.assertRaisesRegex(ValueError, "Inconsistent input keys"):
            processed_var.value({"not p": 3})
        with self.assertRaisesRegex(ValueError, "Inconsistent input keys"):
            processed_var.value({"q": 3, "p": 2})
Esempio n. 16
0
    def test_read_input_parameters(self):
        # Read input parameters from different parts of the model
        model = pybamm.BaseModel()
        a = pybamm.InputParameter("a")
        b = pybamm.InputParameter("b")
        c = pybamm.InputParameter("c")
        d = pybamm.InputParameter("d")
        e = pybamm.InputParameter("e")
        f = pybamm.InputParameter("f")

        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": v + f}

        self.assertEqual(
            set([x.name for x in model.input_parameters]),
            set([x.name for x in [a, b, c, d, e, f]]),
        )
        self.assertTrue(
            all(
                isinstance(x, pybamm.InputParameter)
                for x in model.input_parameters))
Esempio n. 17
0
 def test_erfc(self):
     a = pybamm.InputParameter("a")
     fun = pybamm.erfc(a)
     self.assertAlmostEqual(fun.evaluate(inputs={"a": 3}),
                            special.erfc(3),
                            places=15)
     h = 0.0000001
     self.assertAlmostEqual(
         fun.diff(a).evaluate(inputs={"a": 3}),
         (pybamm.erfc(pybamm.Scalar(3 + h)).evaluate() -
          fun.evaluate(inputs={"a": 3})) / h,
         places=5,
     )
Esempio n. 18
0
 def test_sinh(self):
     a = pybamm.InputParameter("a")
     fun = pybamm.sinh(a)
     self.assertIsInstance(fun, pybamm.Sinh)
     self.assertEqual(fun.children[0].id, a.id)
     self.assertEqual(fun.evaluate(inputs={"a": 3}), np.sinh(3))
     h = 0.0000001
     self.assertAlmostEqual(
         fun.diff(a).evaluate(inputs={"a": 3}),
         (pybamm.sinh(pybamm.Scalar(3 + h)).evaluate() -
          fun.evaluate(inputs={"a": 3})) / h,
         places=5,
     )
Esempio n. 19
0
    def test_solve_with_input(self):
        # Simple system: a single algebraic equation
        var = pybamm.Variable("var")
        model = pybamm.BaseModel()
        model.algebraic = {var: var + pybamm.InputParameter("value")}
        model.initial_conditions = {var: 2}

        # create discretisation
        disc = pybamm.Discretisation()
        disc.process_model(model)

        # Solve
        solver = pybamm.AlgebraicSolver()
        solution = solver.solve(model, np.linspace(0, 1, 10), inputs={"value": 7})
        np.testing.assert_array_equal(solution.y, -7)
Esempio n. 20
0
    def test_model_solver_multiple_inputs_initial_conditions_error(self):
        # Create model
        model = pybamm.BaseModel()
        model.convert_to_format = "casadi"
        domain = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=domain)
        model.rhs = {var: -pybamm.InputParameter("rate") * var}
        model.initial_conditions = {var: 2 * pybamm.InputParameter("rate")}
        # create discretisation
        mesh = get_mesh_for_testing()
        spatial_methods = {"macroscale": pybamm.FiniteVolume()}
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        solver = pybamm.ScipySolver(rtol=1e-8, atol=1e-8, method="RK45")
        t_eval = np.linspace(0, 10, 100)
        ninputs = 8
        inputs_list = [{"rate": 0.01 * (i + 1)} for i in range(ninputs)]

        with self.assertRaisesRegex(
            pybamm.SolverError,
            ("Input parameters cannot appear in expression " "for initial conditions."),
        ):
            solver.solve(model, t_eval, inputs=inputs_list, nproc=2)
Esempio n. 21
0
def constant_current_constant_voltage_constant_power(variables):
    I = variables["Current [A]"]
    V = variables["Terminal voltage [V]"]
    s_I = pybamm.InputParameter("Current switch")
    s_V = pybamm.InputParameter("Voltage switch")
    s_P = pybamm.InputParameter("Power switch")
    n_cells = pybamm.electrical_parameters.n_cells
    return (s_I * (I - pybamm.InputParameter("Current input [A]")) + s_V *
            (V - pybamm.InputParameter("Voltage input [V]") / n_cells) + s_P *
            (V * I - pybamm.InputParameter("Power input [W]") / n_cells))
Esempio n. 22
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)
Esempio n. 23
0
def constant_current_constant_voltage_constant_power(variables):
    I = variables["Current [A]"]
    V = variables["Terminal voltage [V]"]
    s_I = pybamm.InputParameter("Current switch")
    s_V = pybamm.InputParameter("Voltage switch")
    s_P = pybamm.InputParameter("Power switch")
    n_cells = pybamm.Parameter(
        "Number of cells connected in series to make a battery")
    return (s_I * (I - pybamm.InputParameter("Current input [A]")) + s_V *
            (V - pybamm.InputParameter("Voltage input [V]") / n_cells) + s_P *
            (V * I - pybamm.InputParameter("Power input [W]") / n_cells))
Esempio n. 24
0
    def test_solver_sensitivities(self):
        # Create model
        model = pybamm.BaseModel()
        model.convert_to_format = "jax"
        domain = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=domain)
        model.rhs = {var: -pybamm.InputParameter("rate") * var}
        model.initial_conditions = {var: 1}

        # create discretisation
        mesh = get_mesh_for_testing(xpts=10)
        spatial_methods = {"macroscale": pybamm.FiniteVolume()}
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        # Solve
        t_eval = np.linspace(0, 10, 4)
        y0 = model.concatenated_initial_conditions.evaluate().reshape(-1)
        rhs = pybamm.EvaluatorJax(model.concatenated_rhs)

        def fun(y, t, inputs):
            return rhs.evaluate(t=t, y=y, inputs=inputs).reshape(-1)

        h = 0.0001
        rate = 0.1

        # create a dummy "model" where we calculate the sum of the time series
        @jax.jit
        def solve_bdf(rate):
            return jax.numpy.sum(
                pybamm.jax_bdf_integrate(fun,
                                         y0,
                                         t_eval, {'rate': rate},
                                         rtol=1e-9,
                                         atol=1e-9))

        # check answers with finite difference
        eval_plus = solve_bdf(rate + h)
        eval_neg = solve_bdf(rate - h)
        grad_num = (eval_plus - eval_neg) / (2 * h)

        grad_solve_bdf = jax.jit(jax.grad(solve_bdf))
        grad_bdf = grad_solve_bdf(rate)

        self.assertAlmostEqual(grad_bdf, grad_num, places=3)
Esempio n. 25
0
    def test_cos(self):
        a = pybamm.InputParameter("a")
        fun = pybamm.cos(a)
        self.assertIsInstance(fun, pybamm.Cos)
        self.assertEqual(fun.children[0].id, a.id)
        self.assertEqual(fun.evaluate(inputs={"a": 3}), np.cos(3))
        h = 0.0000001
        self.assertAlmostEqual(
            fun.diff(a).evaluate(inputs={"a": 3}),
            (pybamm.cos(pybamm.Scalar(3 + h)).evaluate() -
             fun.evaluate(inputs={"a": 3})) / h,
            places=5,
        )

        # test simplify
        y = pybamm.StateVector(slice(0, 1))
        fun = pybamm.cos(y)
        self.assertEqual(fun.id, fun.simplify().id)
Esempio n. 26
0
    def test_get_solve(self):
        # Create model
        model = pybamm.BaseModel()
        model.convert_to_format = "jax"
        domain = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=domain)
        model.rhs = {var: -pybamm.InputParameter("rate") * var}
        model.initial_conditions = {var: 1}
        # No need to set parameters; can use base discretisation (no spatial
        # operators)

        # create discretisation
        mesh = get_mesh_for_testing()
        spatial_methods = {"macroscale": pybamm.FiniteVolume()}
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        # test that another method string gives error
        with self.assertRaises(ValueError):
            solver = pybamm.JaxSolver(method="not_real")

        # Solve
        solver = pybamm.JaxSolver(rtol=1e-8, atol=1e-8)
        t_eval = np.linspace(0, 5, 80)

        with self.assertRaisesRegex(RuntimeError,
                                    "Model is not set up for solving"):
            solver.get_solve(model, t_eval)

        solver.solve(model, t_eval, inputs={"rate": 0.1})
        solver = solver.get_solve(model, t_eval)
        y = solver({"rate": 0.1})

        np.testing.assert_allclose(y[0],
                                   np.exp(-0.1 * t_eval),
                                   rtol=1e-6,
                                   atol=1e-6)

        y = solver({"rate": 0.2})

        np.testing.assert_allclose(y[0],
                                   np.exp(-0.2 * t_eval),
                                   rtol=1e-6,
                                   atol=1e-6)
Esempio n. 27
0
    def test_solve_with_symbolic_input_1D_vector_input(self):
        var = pybamm.Variable("var", "negative electrode")
        model = pybamm.BaseModel()
        param = pybamm.InputParameter("param", "negative electrode")
        model.rhs = {var: -param * var}
        model.initial_conditions = {var: 2}
        model.variables = {"var": var}

        # create discretisation
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve - scalar input
        solver = pybamm.CasadiSolver()
        solution = solver.solve(model, np.linspace(0, 1))
        n = disc.mesh["negative electrode"].npts

        solver = pybamm.CasadiSolver()
        t_eval = np.linspace(0, 1)
        solution = solver.solve(model, t_eval)
        p = np.linspace(0, 1, n)[:, np.newaxis]
        np.testing.assert_array_almost_equal(
            solution["var"].value({"param": 3 * np.ones(n)}),
            np.repeat(2 * np.exp(-3 * t_eval), 40)[:, np.newaxis],
            decimal=4,
        )
        np.testing.assert_array_almost_equal(
            solution["var"].value({"param": 2 * p}),
            2 * np.exp(-2 * p * t_eval).T.reshape(-1, 1),
            decimal=4,
        )
        np.testing.assert_array_almost_equal(
            solution["var"].sensitivity({"param": 3 * np.ones(n)}),
            np.kron(-2 * t_eval * np.exp(-3 * t_eval), np.eye(40)).T,
            decimal=4,
        )

        sens = solution["var"].sensitivity({"param": p}).full()
        for idx, t in enumerate(t_eval):
            np.testing.assert_array_almost_equal(
                sens[40 * idx:40 * (idx + 1), :],
                -2 * t * np.exp(-p * t) * np.eye(40),
                decimal=4,
            )
Esempio n. 28
0
 def __init__(self, e_class):
     self.dim_dict=e_class.dim_dict
     self.nd_dict=e_class.nd_param.nd_param_dict
     self.model=pybamm.BaseModel()
     self.parameter_dict={}
     self.pybam_val_dict={}
     self.simulation_options=e_class.simulation_options
     self.dim_keys=self.nd_dict.keys()
     self.time=e_class.time_vec
     for key in self.dim_keys:
         self.parameter_dict[key]=pybamm.InputParameter(key)
         self.pybam_val_dict[key]=None
     self.current=pybamm.Variable("current")
     self.theta=pybamm.Variable("theta")
     if self.simulation_options["method"]=="dcv":
         Edc_forward = pybamm.t
         Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"])
         E_t = self.parameter_dict["E_start"]+ \
         (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \
         (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards
     elif self.simulation_options["method"]=="sinusoidal":
         E_t=self.parameter_dict["E_start"]+self.parameter_dict["d_E"]+(self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"]))
     elif self.simulation_options["method"]=="ramped":
         Edc_forward = pybamm.t
         Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"])
         E_t = self.parameter_dict["E_start"]+ \
         (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \
         (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards+\
         (self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"]))
     Er=E_t-(self.parameter_dict["Ru"]*self.current)
     ErE0=Er-self.parameter_dict["E_0"]
     alpha=self.parameter_dict["alpha"]
     if "Cdlinv" not in e_class.optim_list:
         Cdlp=self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3))
     else:
         Cdlp=(pybamm.t <= self.parameter_dict["tr"]) *(self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3)))+\
         (pybamm.t > self.parameter_dict["tr"]) *(self.parameter_dict["Cdlinv"]*(1+self.parameter_dict["CdlE1inv"]*Er+self.parameter_dict["CdlE2inv"]*(Er**2)+self.parameter_dict["CdlE3inv"]*(Er**3)))
     self.model.variables={"current":self.current, "theta":self.theta}
     d_thetadt=((1-self.theta)*self.parameter_dict["k_0"]*pybamm.exp((1-alpha)*ErE0))-(self.theta*self.parameter_dict["k_0"]*pybamm.exp((-alpha)*ErE0))
     dIdt=(E_t.diff(pybamm.t)-(self.current/Cdlp)+self.parameter_dict["gamma"]*d_thetadt*(1/Cdlp))/self.parameter_dict["Ru"]
     self.model.rhs={self.current:dIdt, self.theta:d_thetadt}
     self.disc=pybamm.Discretisation()
     self.model.initial_conditions={self.theta:pybamm.Scalar(1), self.current:pybamm.Scalar(0)}
     self.disc.process_model(self.model)
    def test_solve_with_symbolic_input_1D_scalar_input(self):
        var = pybamm.Variable("var", "negative electrode")
        model = pybamm.BaseModel()
        param = pybamm.InputParameter("param")
        model.algebraic = {var: var + param}
        model.initial_conditions = {var: 2}
        model.variables = {"var": var}

        # create discretisation
        disc = tests.get_discretisation_for_testing()
        disc.process_model(model)

        # Solve - scalar input
        solver = pybamm.CasadiAlgebraicSolver()
        solution = solver.solve(model, [0])
        np.testing.assert_array_equal(solution["var"].value({"param": 7}), -7)
        np.testing.assert_array_equal(solution["var"].value({"param": 3}), -3)
        np.testing.assert_array_equal(
            solution["var"].sensitivity({"param": 3}), -1)
    def test_solve_with_symbolic_input_in_initial_conditions(self):
        # Simple system: a single algebraic equation
        var = pybamm.Variable("var")
        model = pybamm.BaseModel()
        model.algebraic = {var: var + 2}
        model.initial_conditions = {var: pybamm.InputParameter("param")}
        model.variables = {"var": var}

        # create discretisation
        disc = pybamm.Discretisation()
        disc.process_model(model)

        # Solve
        solver = pybamm.CasadiAlgebraicSolver()
        solution = solver.solve(model, [0])
        np.testing.assert_array_equal(solution["var"].value({"param": 7}), -2)
        np.testing.assert_array_equal(solution["var"].value({"param": 3}), -2)
        np.testing.assert_array_equal(
            solution["var"].sensitivity({"param": 3}), 0)