Esempio n. 1
0
    def test_processed_variable_1D(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        eqn = var + x

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        eqn_sol = disc.process_symbol(eqn)

        # With scalar t_sol
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)
        np.testing.assert_array_equal(
            processed_eqn.value(), y_sol + x_sol[:, np.newaxis]
        )

        # With vector t_sol
        t_sol = np.linspace(0, 1)
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5)
        sol = pybamm.Solution(t_sol, y_sol)
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)
        np.testing.assert_array_equal(
            processed_eqn.value(), (y_sol + x_sol[:, np.newaxis]).T.reshape(-1, 1)
        )
Esempio n. 2
0
    def test_processed_var_0D_interpolation(self):
        # without spatial dependence
        t = pybamm.t
        y = pybamm.StateVector(slice(0, 1))
        var = y
        eqn = t * y
        var.mesh = None
        eqn.mesh = None

        t_sol = np.linspace(0, 1, 1000)
        y_sol = np.array([np.linspace(0, 5, 1000)])
        processed_var = pybamm.ProcessedVariable(var,
                                                 pybamm.Solution(t_sol, y_sol))
        # vector
        np.testing.assert_array_equal(processed_var(t_sol), y_sol[0])
        # scalar
        np.testing.assert_array_equal(processed_var(0.5), 2.5)
        np.testing.assert_array_equal(processed_var(0.7), 3.5)

        processed_eqn = pybamm.ProcessedVariable(eqn,
                                                 pybamm.Solution(t_sol, y_sol))
        np.testing.assert_array_equal(processed_eqn(t_sol), t_sol * y_sol[0])
        np.testing.assert_array_almost_equal(processed_eqn(0.5), 0.5 * 2.5)

        # Suppress warning for this test
        pybamm.set_logging_level("ERROR")
        np.testing.assert_array_equal(processed_eqn(2), np.nan)
        pybamm.set_logging_level("WARNING")
    def test_processed_variable_0D(self):
        # without space
        t = pybamm.t
        y = pybamm.StateVector(slice(0, 1))
        var = t * y
        var.mesh = None
        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        var_casadi = to_casadi(var, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [var],
            [var_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        np.testing.assert_array_equal(processed_var.entries, t_sol * y_sol[0])

        # scalar value
        var = y
        var.mesh = None
        t_sol = np.array([0])
        y_sol = np.array([1])[:, np.newaxis]
        var_casadi = to_casadi(var, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [var],
            [var_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        np.testing.assert_array_equal(processed_var.entries, y_sol[0])
Esempio n. 4
0
    def test_call_failure(self):
        # x domain
        var = pybamm.Variable("var x",
                              domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x",
                                   domain=["negative electrode", "separator"])
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)
        t_sol = np.linspace(0, 1)
        y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(var_sol,
                                                 pybamm.Solution(t_sol, y_sol))
        with self.assertRaisesRegex(ValueError, "x cannot be None"):
            processed_var(0)

        # r domain
        var = pybamm.Variable("var r", domain=["negative particle"])
        r = pybamm.SpatialVariable("r", domain=["negative particle"])
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(var)
        y_sol = r_sol[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(var_sol,
                                                 pybamm.Solution(t_sol, y_sol))
        with self.assertRaisesRegex(ValueError, "r cannot be None"):
            processed_var(0)
        with self.assertRaisesRegex(ValueError, "r cannot be None"):
            processed_var(0, 1)
    def test_processed_var_1D_interpolation(self):
        t = pybamm.t
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        eqn = t * var + x

        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)
        eqn_sol = disc.process_symbol(eqn)
        t_sol = np.linspace(0, 1)
        y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(
            var_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        # 2 vectors
        np.testing.assert_array_almost_equal(processed_var(t_sol, x_sol), y_sol)
        # 1 vector, 1 scalar
        np.testing.assert_array_almost_equal(
            processed_var(0.5, x_sol)[:, 0], 2.5 * x_sol
        )
        np.testing.assert_array_equal(
            processed_var(t_sol, x_sol[-1]), x_sol[-1] * np.linspace(0, 5)
        )
        # 2 scalars
        np.testing.assert_array_almost_equal(
            processed_var(0.5, x_sol[-1]), 2.5 * x_sol[-1]
        )
        processed_eqn = pybamm.ProcessedVariable(
            eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        # 2 vectors
        np.testing.assert_array_almost_equal(
            processed_eqn(t_sol, x_sol), t_sol * y_sol + x_sol[:, np.newaxis]
        )
        # 1 vector, 1 scalar
        self.assertEqual(processed_eqn(0.5, x_sol[10:30]).shape, (20, 1))
        self.assertEqual(processed_eqn(t_sol[4:9], x_sol[-1]).shape, (5,))
        # 2 scalars
        self.assertEqual(processed_eqn(0.5, x_sol[-1]).shape, (1,))

        # test x
        processed_x = pybamm.ProcessedVariable(
            disc.process_symbol(x), pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_almost_equal(processed_x(x=x_sol), x_sol[:, np.newaxis])

        # On microscale
        r_n = pybamm.Matrix(
            disc.mesh["negative particle"].nodes, domain="negative particle"
        )
        r_n.mesh = disc.mesh["negative particle"]
        processed_r_n = pybamm.ProcessedVariable(
            r_n, pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_equal(r_n.entries[:, 0], processed_r_n.entries[:, 0])
Esempio n. 6
0
    def test_add_solutions(self):
        # Set up first solution
        t1 = np.linspace(0, 1)
        y1 = np.tile(t1, (20, 1))
        sol1 = pybamm.Solution(t1, y1, pybamm.BaseModel(), {"a": 1})
        sol1.solve_time = 1.5
        sol1.integration_time = 0.3

        # Set up second solution
        t2 = np.linspace(1, 2)
        y2 = np.tile(t2, (20, 1))
        sol2 = pybamm.Solution(t2, y2, pybamm.BaseModel(), {"a": 2})
        sol2.solve_time = 1
        sol2.integration_time = 0.5
        sol_sum = sol1 + sol2

        # Test
        self.assertEqual(sol_sum.solve_time, 2.5)
        self.assertEqual(sol_sum.integration_time, 0.8)
        np.testing.assert_array_equal(sol_sum.t, np.concatenate([t1, t2[1:]]))
        np.testing.assert_array_equal(sol_sum.y,
                                      np.concatenate([y1, y2[:, 1:]], axis=1))
        np.testing.assert_array_equal(sol_sum.all_inputs, [{"a": 1}, {"a": 2}])

        # Test sub-solutions
        self.assertEqual(len(sol_sum.sub_solutions), 2)
        np.testing.assert_array_equal(sol_sum.sub_solutions[0].t, t1)
        np.testing.assert_array_equal(sol_sum.sub_solutions[1].t, t2)
        self.assertEqual(sol_sum.sub_solutions[0].all_models[0],
                         sol_sum.all_models[0])
        np.testing.assert_array_equal(
            sol_sum.sub_solutions[0].all_inputs[0]["a"], 1)
        self.assertEqual(sol_sum.sub_solutions[1].all_models[0],
                         sol2.all_models[0])
        self.assertEqual(sol_sum.all_models[1], sol2.all_models[0])
        np.testing.assert_array_equal(
            sol_sum.sub_solutions[1].all_inputs[0]["a"], 2)

        # Add solution already contained in existing solution
        t3 = np.array([2])
        y3 = np.ones((20, 1))
        sol3 = pybamm.Solution(t3, y3, pybamm.BaseModel(), {"a": 3})
        self.assertEqual((sol_sum + sol3).all_ts, sol_sum.copy().all_ts)

        # radd
        sol4 = None + sol3
        self.assertEqual(sol3.all_ys, sol4.all_ys)

        # radd failure
        with self.assertRaisesRegex(
                pybamm.SolverError,
                "Only a Solution or None can be added to a Solution"):
            sol3 + 2
        with self.assertRaisesRegex(
                pybamm.SolverError,
                "Only a Solution or None can be added to a Solution"):
            2 + sol3
    def test_processed_var_2D_secondary_broadcast(self):
        var = pybamm.Variable("var", domain=["negative particle"])
        broad_var = pybamm.SecondaryBroadcast(var, "negative electrode")
        x = pybamm.SpatialVariable("x", domain=["negative electrode"])
        r = pybamm.SpatialVariable("r", domain=["negative particle"])

        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(broad_var)
        t_sol = np.linspace(0, 1)
        y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(
            var_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        # 3 vectors
        np.testing.assert_array_equal(
            processed_var(t_sol, x_sol, r_sol).shape, (10, 40, 50)
        )
        np.testing.assert_array_equal(
            processed_var(t_sol, x_sol, r_sol),
            np.reshape(y_sol, [len(r_sol), len(x_sol), len(t_sol)]),
        )
        # 2 vectors, 1 scalar
        np.testing.assert_array_equal(processed_var(0.5, x_sol, r_sol).shape, (10, 40))
        np.testing.assert_array_equal(processed_var(t_sol, 0.2, r_sol).shape, (10, 50))
        np.testing.assert_array_equal(processed_var(t_sol, x_sol, 0.5).shape, (40, 50))
        # 1 vectors, 2 scalar
        np.testing.assert_array_equal(processed_var(0.5, 0.2, r_sol).shape, (10,))
        np.testing.assert_array_equal(processed_var(0.5, x_sol, 0.5).shape, (40,))
        np.testing.assert_array_equal(processed_var(t_sol, 0.2, 0.5).shape, (50,))
        # 3 scalars
        np.testing.assert_array_equal(processed_var(0.2, 0.2, 0.2).shape, ())

        # positive particle
        var = pybamm.Variable("var", domain=["positive particle"])
        broad_var = pybamm.SecondaryBroadcast(var, "positive electrode")
        x = pybamm.SpatialVariable("x", domain=["positive electrode"])
        r = pybamm.SpatialVariable("r", domain=["positive particle"])

        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(broad_var)
        t_sol = np.linspace(0, 1)
        y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(
            var_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        # 3 vectors
        np.testing.assert_array_equal(
            processed_var(t_sol, x_sol, r_sol).shape, (10, 35, 50)
        )
    def test_processed_variable_2D_x_z(self):
        var = pybamm.Variable(
            "var",
            domain=["negative electrode", "separator"],
            auxiliary_domains={"secondary": "current collector"},
        )
        x = pybamm.SpatialVariable(
            "x",
            domain=["negative electrode", "separator"],
            auxiliary_domains={"secondary": "current collector"},
        )
        z = pybamm.SpatialVariable("z", domain=["current collector"])

        disc = tests.get_1p1d_discretisation_for_testing()
        disc.set_variable_slices([var])
        z_sol = disc.process_symbol(z).entries[:, 0]
        x_sol = disc.process_symbol(x).entries[:, 0]
        # Keep only the first iteration of entries
        x_sol = x_sol[:len(x_sol) // len(z_sol)]
        var_sol = disc.process_symbol(var)
        t_sol = np.linspace(0, 1)
        y_sol = np.ones(len(x_sol) * len(z_sol))[:, np.newaxis] * np.linspace(
            0, 5)

        var_casadi = to_casadi(var_sol, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [var_sol],
            [var_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        np.testing.assert_array_equal(
            processed_var.entries,
            np.reshape(
                y_sol,
                [len(x_sol), len(z_sol), len(t_sol)]),
        )

        # On edges
        x_s_edge = pybamm.Matrix(
            np.tile(disc.mesh["separator"].edges, len(z_sol)),
            domain="separator",
            auxiliary_domains={"secondary": "current collector"},
        )
        x_s_edge.mesh = disc.mesh["separator"]
        x_s_edge.secondary_mesh = disc.mesh["current collector"]
        x_s_casadi = to_casadi(x_s_edge, y_sol)
        processed_x_s_edge = pybamm.ProcessedVariable(
            [x_s_edge],
            [x_s_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        np.testing.assert_array_equal(
            x_s_edge.entries.flatten(),
            processed_x_s_edge.entries[:, :, 0].T.flatten())
    def test_processed_variable_1D(self):
        t = pybamm.t
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        eqn = t * var + x

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)
        eqn_sol = disc.process_symbol(eqn)
        t_sol = np.linspace(0, 1)
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5)

        processed_var = pybamm.ProcessedVariable(
            var_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_equal(processed_var.entries, y_sol)
        np.testing.assert_array_equal(processed_var(t_sol, x_sol), y_sol)
        processed_eqn = pybamm.ProcessedVariable(
            eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_equal(
            processed_eqn(t_sol, x_sol), t_sol * y_sol + x_sol[:, np.newaxis]
        )

        # Test extrapolation
        np.testing.assert_array_equal(processed_var.entries[0], 2 * y_sol[0] - y_sol[1])
        np.testing.assert_array_equal(
            processed_var.entries[1], 2 * y_sol[-1] - y_sol[-2]
        )

        # On edges
        x_s_edge = pybamm.Matrix(disc.mesh["separator"].edges, domain="separator")
        x_s_edge.mesh = disc.mesh["separator"]
        processed_x_s_edge = pybamm.ProcessedVariable(
            x_s_edge, pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_equal(
            x_s_edge.entries[:, 0], processed_x_s_edge.entries[:, 0]
        )

        # space only
        eqn = var + x
        eqn_sol = disc.process_symbol(eqn)
        t_sol = np.array([0])
        y_sol = np.ones_like(x_sol)[:, np.newaxis]
        processed_eqn2 = pybamm.ProcessedVariable(
            eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        np.testing.assert_array_equal(
            processed_eqn2.entries, y_sol + x_sol[:, np.newaxis]
        )
    def test_processed_variable_1D_with_scalar_inputs(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        eqn = var * p + 2 * q

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        eqn_sol = disc.process_symbol(eqn)

        # Scalar t
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5

        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27, "q": -42}), 27 * y_sol - 84,
        )

        # Test sensitivities
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 27, "q": -84}),
            np.c_[y_sol, 2 * np.ones_like(y_sol)],
        )

        ################################################################################
        # Vector t
        t_sol = np.linspace(0, 1)
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5)

        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27, "q": -42}),
            (27 * y_sol - 84).T.reshape(-1, 1),
        )

        # Test sensitivities
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 27, "q": -42}),
            np.c_[y_sol.T.flatten(), 2 * np.ones_like(y_sol.T.flatten())],
        )
    def test_call_failure(self):
        # x domain
        var = pybamm.Variable("var x",
                              domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x",
                                   domain=["negative electrode", "separator"])
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)
        t_sol = np.linspace(0, 1)
        y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5)

        var_casadi = to_casadi(var_sol, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [var_sol],
            [var_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        with self.assertRaisesRegex(ValueError, "x cannot be None"):
            processed_var(0)

        # r domain
        var = pybamm.Variable("var r", domain=["negative particle"])
        r = pybamm.SpatialVariable(
            "r",
            domain=["negative particle"],
            auxiliary_domains={"secondary": ["negative electrode"]},
        )
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(var)
        y_sol = r_sol[:, np.newaxis] * np.linspace(0, 5)

        var_casadi = to_casadi(var_sol, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [var_sol],
            [var_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        with self.assertRaisesRegex(ValueError, "r cannot be None"):
            processed_var(0)
        with self.assertRaisesRegex(ValueError, "r cannot be None"):
            processed_var(0, 1)

        # t is None but len(solution.t) > 1
        with self.assertRaisesRegex(ValueError, "t cannot be None"):
            processed_var()
Esempio n. 12
0
    def test_processed_variable_1D_unknown_domain(self):
        x = pybamm.SpatialVariable("x",
                                   domain="SEI layer",
                                   coord_sys="cartesian")
        geometry = pybamm.Geometry()
        geometry.add_domain(
            "SEI layer",
            {
                "primary": {
                    x: {
                        "min": pybamm.Scalar(0),
                        "max": pybamm.Scalar(1)
                    }
                }
            },
        )

        submesh_types = {"SEI layer": pybamm.Uniform1DSubMesh}
        var_pts = {x: 100}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        nt = 100

        solution = pybamm.Solution(
            np.linspace(0, 1, nt),
            np.zeros((var_pts[x], nt)),
            np.linspace(0, 1, 1),
            np.zeros((var_pts[x])),
            "test",
        )

        c = pybamm.StateVector(slice(0, var_pts[x]), domain=["SEI layer"])
        c.mesh = mesh["SEI layer"]
        pybamm.ProcessedVariable(c, solution)
Esempio n. 13
0
    def test_processed_variable_2D_x_r(self):
        var = pybamm.Variable(
            "var",
            domain=["negative particle"],
            auxiliary_domains={"secondary": ["negative electrode"]},
        )
        x = pybamm.SpatialVariable("x", domain=["negative electrode"])
        r = pybamm.SpatialVariable("r", domain=["negative particle"])

        disc = tests.get_p2d_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        r_sol = disc.process_symbol(r).entries[:, 0]
        # Keep only the first iteration of entries
        r_sol = r_sol[:len(r_sol) // len(x_sol)]
        var_sol = disc.process_symbol(var)
        t_sol = np.linspace(0, 1)
        y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace(
            0, 5)

        processed_var = pybamm.ProcessedVariable(var_sol,
                                                 pybamm.Solution(t_sol, y_sol))
        np.testing.assert_array_equal(
            processed_var.entries,
            np.reshape(
                y_sol,
                [len(r_sol), len(x_sol), len(t_sol)]),
        )
Esempio n. 14
0
    def _integrate(self, model, t_eval, inputs_dict=None):
        """
        Solve an empty model.

        Parameters
        ----------
        model : :class:`pybamm.BaseModel`
            The model whose solution to calculate.
        t_eval : :class:`numpy.array`, size (k,)
            The times at which to compute the solution
        inputs_dict : dict, optional
            Any input parameters to pass to the model when solving

        Returns
        -------
        :class:`pybamm.Solution`
            A Solution object containing the times and values of the solution,
            as well as various diagnostic messages.

        """
        y_sol = np.zeros((1, t_eval.size))
        sol = pybamm.Solution(t_eval,
                              y_sol,
                              model,
                              inputs_dict,
                              termination="final time")
        sol.integration_time = 0
        return sol
Esempio n. 15
0
    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(KeyError, "Inconsistent input keys"):
            processed_var.value({"not p": 3})
    def test_processed_var_2D_fixed_t_scikit_interpolation(self):
        var = pybamm.Variable("var", domain=["current collector"])

        disc = tests.get_2p1d_discretisation_for_testing()
        disc.set_variable_slices([var])
        y_sol = disc.mesh["current collector"].edges["y"]
        z_sol = disc.mesh["current collector"].edges["z"]
        var_sol = disc.process_symbol(var)
        var_sol.mesh = disc.mesh["current collector"]
        t_sol = np.array([0])
        u_sol = np.ones(var_sol.shape[0])[:, np.newaxis]

        var_casadi = to_casadi(var_sol, u_sol)
        processed_var = pybamm.ProcessedVariable(
            [var_sol],
            [var_casadi],
            pybamm.Solution(t_sol, u_sol, pybamm.BaseModel(), {}),
            warn=False,
        )
        # 2 vectors
        np.testing.assert_array_equal(
            processed_var(y=y_sol, z=z_sol).shape, (15, 15))
        # 1 vector, 1 scalar
        np.testing.assert_array_equal(
            processed_var(y=0.2, z=z_sol).shape, (15, ))
        np.testing.assert_array_equal(
            processed_var(y=y_sol, z=0.5).shape, (15, ))
        # 2 scalars
        np.testing.assert_array_equal(
            processed_var(t=None, y=0.2, z=0.2).shape, ())
    def test_processed_var_1D_fixed_t_interpolation(self):
        var = pybamm.Variable("var",
                              domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x",
                                   domain=["negative electrode", "separator"])
        eqn = var + x

        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        eqn_sol = disc.process_symbol(eqn)
        t_sol = np.array([1])
        y_sol = x_sol[:, np.newaxis]

        eqn_casadi = to_casadi(eqn_sol, y_sol)
        processed_var = pybamm.ProcessedVariable(
            [eqn_sol],
            [eqn_casadi],
            pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}),
            warn=False,
        )

        # vector
        np.testing.assert_array_almost_equal(processed_var(x=x_sol),
                                             2 * x_sol[:, np.newaxis])
        # scalar
        np.testing.assert_array_almost_equal(processed_var(x=0.5), 1)
Esempio n. 18
0
    def _integrate(self, model, t_eval, inputs=None):
        """
        Solve a model defined by dydt with initial conditions y0.

        Parameters
        ----------
        model : :class:`pybamm.BaseModel`
            The model whose solution to calculate.
        t_eval : :class:`numpy.array`, size (k,)
            The times at which to compute the solution
        inputs : dict, optional
            Any input parameters to pass to the model when solving

        Returns
        -------
        object
            An object containing the times and values of the solution, as well as
            various diagnostic messages.

        """
        if model not in self._cached_solves:
            self._cached_solves[model] = self.create_solve(model, t_eval)

        y = self._cached_solves[model](inputs)

        # note - the actual solve is not done until this line!
        y = onp.array(y)

        termination = "final time"
        t_event = None
        y_event = onp.array(None)
        return pybamm.Solution(t_eval, y,
                               t_event, y_event, termination)
    def test_processed_variable_1D_unknown_domain(self):
        x = pybamm.SpatialVariable("x",
                                   domain="SEI layer",
                                   coord_sys="cartesian")
        geometry = pybamm.Geometry({
            "SEI layer": {
                x: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(1)
                }
            }
        })

        submesh_types = {"SEI layer": pybamm.Uniform1DSubMesh}
        var_pts = {x: 100}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        nt = 100

        y_sol = np.zeros((var_pts[x], nt))
        solution = pybamm.Solution(
            np.linspace(0, 1, nt),
            y_sol,
            pybamm.BaseModel(),
            {},
            np.linspace(0, 1, 1),
            np.zeros((var_pts[x])),
            "test",
        )

        c = pybamm.StateVector(slice(0, var_pts[x]), domain=["SEI layer"])
        c.mesh = mesh["SEI layer"]
        c_casadi = to_casadi(c, y_sol)
        pybamm.ProcessedVariable([c], [c_casadi], solution, warn=False)
Esempio n. 20
0
    def test_processed_var_2D_fixed_t_interpolation(self):
        var = pybamm.Variable(
            "var",
            domain=["negative particle"],
            auxiliary_domains={"secondary": ["negative electrode"]},
        )
        x = pybamm.SpatialVariable("x", domain=["negative electrode"])
        r = pybamm.SpatialVariable(
            "r",
            domain=["negative particle"],
            auxiliary_domains={"secondary": ["negative electrode"]},
        )

        disc = tests.get_p2d_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        r_sol = disc.process_symbol(r).entries[:, 0]
        # Keep only the first iteration of entries
        r_sol = r_sol[: len(r_sol) // len(x_sol)]
        var_sol = disc.process_symbol(var)
        t_sol = np.array([0])
        y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis]

        processed_var = pybamm.ProcessedVariable(
            var_sol, pybamm.Solution(t_sol, y_sol), warn=False
        )
        # 2 vectors
        np.testing.assert_array_equal(processed_var(x=x_sol, r=r_sol).shape, (10, 40))
        # 1 vector, 1 scalar
        np.testing.assert_array_equal(processed_var(x=0.2, r=r_sol).shape, (10,))
        np.testing.assert_array_equal(processed_var(x=x_sol, r=0.5).shape, (40,))
        # 2 scalars
        np.testing.assert_array_equal(processed_var(x=0.2, r=0.2).shape, ())
Esempio n. 21
0
    def _integrate(self, model, t_eval, inputs=None):
        """
        Solve a model defined by dydt with initial conditions y0.

        Parameters
        ----------
        model : :class:`pybamm.BaseModel`
            The model whose solution to calculate.
        t_eval : :class:`numpy.array`, size (k,)
            The times at which to compute the solution
        inputs : dict, optional
            Any input parameters to pass to the model when solving

        Returns
        -------
        object
            An object containing the times and values of the solution, as well as
            various diagnostic messages.

        """
        extra_options = {"rtol": self.rtol, "atol": self.atol}

        # check for user-supplied Jacobian
        implicit_methods = ["Radau", "BDF", "LSODA"]
        if np.any([self.method in implicit_methods]):
            if model.jacobian_eval:
                extra_options.update({"jac": model.jacobian_eval})

        # make events terminal so that the solver stops when they are reached
        if model.terminate_events_eval:
            for event in model.terminate_events_eval:
                event.terminal = True
            extra_options.update({"events": model.terminate_events_eval})

        sol = it.solve_ivp(model.rhs_eval, (t_eval[0], t_eval[-1]),
                           model.y0,
                           t_eval=t_eval,
                           method=self.method,
                           dense_output=True,
                           **extra_options)

        if sol.success:
            # Set the reason for termination
            if sol.message == "A termination event occurred.":
                termination = "event"
                t_event = []
                for time in sol.t_events:
                    if time.size > 0:
                        t_event = np.append(t_event, np.max(time))
                t_event = np.array([np.max(t_event)])
                y_event = sol.sol(t_event)
            elif sol.message.startswith(
                    "The solver successfully reached the end"):
                termination = "final time"
                t_event = None
                y_event = np.array(None)
            return pybamm.Solution(sol.t, sol.y, t_event, y_event, termination)
        else:
            raise pybamm.SolverError(sol.message)
Esempio n. 22
0
 def test_errors(self):
     bad_ts = [np.array([1, 2, 3]), np.array([3, 4, 5])]
     sol = pybamm.Solution(bad_ts, [np.ones(
         (1, 3)), np.ones((1, 3))], pybamm.BaseModel(), {})
     with self.assertRaisesRegex(
             ValueError,
             "Solution time vector must be strictly increasing"):
         sol.set_t()
Esempio n. 23
0
    def test_append(self):
        # Set up first solution
        t1 = np.linspace(0, 1)
        y1 = np.tile(t1, (20, 1))
        sol1 = pybamm.Solution(t1, y1)
        sol1.solve_time = 1.5
        sol1.integration_time = 0.3
        sol1.model = pybamm.BaseModel()
        sol1.inputs = {"a": 1}

        # Set up second solution
        t2 = np.linspace(1, 2)
        y2 = np.tile(t2, (20, 1))
        sol2 = pybamm.Solution(t2, y2)
        sol2.solve_time = 1
        sol2.integration_time = 0.5
        sol2.inputs = {"a": 2}
        sol1.append(sol2, create_sub_solutions=True)

        # Test
        self.assertEqual(sol1.solve_time, 2.5)
        self.assertEqual(sol1.integration_time, 0.8)
        np.testing.assert_array_equal(sol1.t, np.concatenate([t1, t2[1:]]))
        np.testing.assert_array_equal(sol1.y, np.concatenate([y1, y2[:, 1:]], axis=1))
        np.testing.assert_array_equal(
            sol1.inputs["a"],
            np.concatenate([1 * np.ones_like(t1), 2 * np.ones_like(t2[1:])])[
                np.newaxis, :
            ],
        )

        # Test sub-solutions
        self.assertEqual(len(sol1.sub_solutions), 2)
        np.testing.assert_array_equal(sol1.sub_solutions[0].t, t1)
        np.testing.assert_array_equal(sol1.sub_solutions[1].t, t2)
        self.assertEqual(sol1.sub_solutions[0].model, sol1.model)
        np.testing.assert_array_equal(
            sol1.sub_solutions[0].inputs["a"], 1 * np.ones_like(t1)[np.newaxis, :]
        )
        self.assertEqual(sol1.sub_solutions[1].model, sol2.model)
        np.testing.assert_array_equal(
            sol1.sub_solutions[1].inputs["a"], 2 * np.ones_like(t2)[np.newaxis, :]
        )
Esempio n. 24
0
 def _run_integrator(self, model, y0, inputs, t_eval):
     integrator, use_grid = self.integrators[model]
     len_rhs = model.concatenated_rhs.size
     y0_diff = y0[:len_rhs]
     y0_alg = y0[len_rhs:]
     try:
         # Try solving
         if use_grid is True:
             # Call the integrator once, with the grid
             sol = integrator(x0=y0_diff,
                              z0=y0_alg,
                              p=inputs,
                              **self.extra_options_call)
             y_sol = np.concatenate([sol["xf"].full(), sol["zf"].full()])
             return pybamm.Solution(t_eval, y_sol)
         else:
             # Repeated calls to the integrator
             x = y0_diff
             z = y0_alg
             y_diff = x
             y_alg = z
             for i in range(len(t_eval) - 1):
                 t_min = t_eval[i]
                 t_max = t_eval[i + 1]
                 inputs_with_tlims = casadi.vertcat(inputs, t_min, t_max)
                 sol = integrator(x0=x,
                                  z0=z,
                                  p=inputs_with_tlims,
                                  **self.extra_options_call)
                 x = sol["xf"]
                 z = sol["zf"]
                 y_diff = casadi.horzcat(y_diff, x)
                 if not z.is_empty():
                     y_alg = casadi.horzcat(y_alg, z)
             if z.is_empty():
                 return pybamm.Solution(t_eval, y_diff)
             else:
                 y_sol = casadi.vertcat(y_diff, y_alg)
                 return pybamm.Solution(t_eval, y_sol)
     except RuntimeError as e:
         # If it doesn't work raise error
         raise pybamm.SolverError(e.args[0])
Esempio n. 25
0
 def test_init(self):
     t = np.linspace(0, 1)
     y = np.tile(t, (20, 1))
     sol = pybamm.Solution(t, y, pybamm.BaseModel(), {})
     np.testing.assert_array_equal(sol.t, t)
     np.testing.assert_array_equal(sol.y, y)
     self.assertEqual(sol.t_event, None)
     self.assertEqual(sol.y_event, None)
     self.assertEqual(sol.termination, "final time")
     self.assertEqual(sol.all_inputs, [{}])
     self.assertIsInstance(sol.all_models[0], pybamm.BaseModel)
Esempio n. 26
0
 def test_processed_variable_0D(self):
     # without space
     t = pybamm.t
     y = pybamm.StateVector(slice(0, 1))
     var = t * y
     var.mesh = None
     t_sol = np.linspace(0, 1)
     y_sol = np.array([np.linspace(0, 5)])
     processed_var = pybamm.ProcessedVariable(var,
                                              pybamm.Solution(t_sol, y_sol))
     np.testing.assert_array_equal(processed_var.entries, t_sol * y_sol[0])
Esempio n. 27
0
 def test_solution_too_short(self):
     t = pybamm.t
     y = pybamm.StateVector(slice(0, 1))
     var = t * y
     var.mesh = None
     t_sol = np.array([1])
     y_sol = np.array([np.linspace(0, 5)])
     with self.assertRaisesRegex(
             pybamm.SolverError,
             "Solution time vector must have length > 1"):
         pybamm.ProcessedVariable(var, pybamm.Solution(t_sol, y_sol))
Esempio n. 28
0
 def test_solution_too_short(self):
     t = pybamm.t
     y = pybamm.StateVector(slice(0, 3))
     var = t * y
     disc = tests.get_2p1d_discretisation_for_testing()
     var.mesh = disc.mesh["current collector"]
     t_sol = np.array([1])
     y_sol = np.linspace(0, 5)[:, np.newaxis]
     with self.assertRaisesRegex(
             pybamm.SolverError,
             "Solution time vector must have length > 1"):
         pybamm.ProcessedVariable(var, pybamm.Solution(t_sol, y_sol))
Esempio n. 29
0
 def test_failure(self):
     with self.assertRaisesRegex(TypeError, "'models' must be"):
         pybamm.QuickPlot(1, None, None)
     with self.assertRaisesRegex(TypeError, "'meshes' must be"):
         model = pybamm.lithium_ion.SPM()
         pybamm.QuickPlot(model, 1, None)
     with self.assertRaisesRegex(TypeError, "'solutions' must be"):
         geometry = model.default_geometry
         param = model.default_parameter_values
         param.process_model(model)
         param.process_geometry(geometry)
         mesh = pybamm.Mesh(
             geometry, model.default_submesh_types, model.default_var_pts
         )
         pybamm.QuickPlot(model, mesh, 1)
     with self.assertRaisesRegex(ValueError, "must provide the same"):
         pybamm.QuickPlot(
             model,
             mesh,
             [pybamm.Solution(0, 0, 0, 0, ""), pybamm.Solution(0, 0, 0, 0, "")],
         )
Esempio n. 30
0
    def test_processed_variable_1D_with_vector_inputs(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        p = pybamm.InputParameter("p", domain=["negative electrode", "separator"])
        p.set_expected_size(65)
        q = pybamm.InputParameter("q")
        eqn = (var * p) ** 2 + 2 * q

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        n = x_sol.size
        eqn_sol = disc.process_symbol(eqn)

        # Scalar t
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p", n), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values - constant p
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27 * np.ones(n), "q": -42}),
            (27 * y_sol) ** 2 - 84,
        )
        # Test values - varying p
        p = np.linspace(0, 1, n)
        np.testing.assert_array_equal(
            processed_eqn.value({"p": p, "q": 3}), (p[:, np.newaxis] * y_sol) ** 2 + 6
        )

        # Test sensitivities - constant p
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 2 * np.ones(n), "q": -84}),
            np.c_[100 * np.eye(y_sol.size), 2 * np.ones(n)],
        )
        # Test sensitivities - varying p
        # d/dy((py)**2) = (2*p*y) * y
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": p, "q": -84}),
            np.c_[
                np.diag((2 * p[:, np.newaxis] * y_sol ** 2).flatten()), 2 * np.ones(n)
            ],
        )

        # Bad shape
        with self.assertRaisesRegex(
            ValueError, "Wrong shape for input 'p': expected 65, actual 5"
        ):
            processed_eqn.value({"p": casadi.MX.sym("p", 5), "q": 1})