Пример #1
0
    def test_ode_integrate_with_event(self):
        # Constant
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def constant_decay(t, y):
            return -2 * np.ones_like(y)

        def y_equal_0(t, y):
            return y[0]

        y0 = np.array([1])
        t_eval = np.linspace(0, 1, 100)
        solution = solver.integrate(constant_decay,
                                    y0,
                                    t_eval,
                                    events=[y_equal_0])
        np.testing.assert_allclose(1 - 2 * solution.t, solution.y[0])
        self.assertLess(len(solution.t), len(t_eval))
        np.testing.assert_array_less(0, solution.y[0])
        np.testing.assert_array_less(solution.t, 0.5)
        np.testing.assert_allclose(solution.t_event, 0.5)
        np.testing.assert_allclose(solution.y_event, 0)
        self.assertEqual(solution.termination, "event")

        # Expnonential growth
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def exponential_growth(t, y):
            return y

        def y_eq_9(t, y):
            return y - 9

        def ysq_eq_7(t, y):
            return y**2 - 7

        y0 = np.array([1])
        t_eval = np.linspace(0, 3, 100)
        solution = solver.integrate(exponential_growth,
                                    y0,
                                    t_eval,
                                    events=[ysq_eq_7, y_eq_9])
        self.assertLess(len(solution.t), len(t_eval))
        np.testing.assert_allclose(np.exp(solution.t),
                                   solution.y[0],
                                   rtol=1e-4)
        np.testing.assert_array_less(solution.y, 9)
        np.testing.assert_array_less(solution.y**2, 7)
        np.testing.assert_allclose(solution.t_event, np.log(7) / 2, rtol=1e-4)
        np.testing.assert_allclose(solution.y_event**2, 7, rtol=1e-4)
        self.assertEqual(solution.termination, "event")
Пример #2
0
    def test_solver_citations(self):
        # Test that solving each solver adds the right citations
        citations = pybamm.citations

        citations._reset()
        self.assertNotIn("virtanen2020scipy", citations._papers_to_cite)
        pybamm.ScipySolver()
        self.assertIn("virtanen2020scipy", citations._papers_to_cite)

        citations._reset()
        self.assertNotIn("virtanen2020scipy", citations._papers_to_cite)
        pybamm.AlgebraicSolver()
        self.assertIn("virtanen2020scipy", citations._papers_to_cite)

        if pybamm.have_scikits_odes():
            citations._reset()
            self.assertNotIn("scikits-odes", citations._papers_to_cite)
            pybamm.ScikitsOdeSolver()
            self.assertIn("scikits-odes", citations._papers_to_cite)

            citations._reset()
            self.assertNotIn("scikits-odes", citations._papers_to_cite)
            pybamm.ScikitsDaeSolver()
            self.assertIn("scikits-odes", citations._papers_to_cite)

        if pybamm.have_idaklu():
            citations._reset()
            self.assertNotIn("hindmarsh2005sundials",
                             citations._papers_to_cite)
            pybamm.IDAKLUSolver()
            self.assertIn("hindmarsh2005sundials", citations._papers_to_cite)
Пример #3
0
    def test_model_step_ode_python(self):
        model = pybamm.BaseModel()
        model.convert_to_format = "python"
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=whole_cell)
        model.rhs = {var: -0.1 * var}
        model.initial_conditions = {var: 1}
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)

        # Step once
        dt = 1
        step_sol = solver.step(None, model, dt)
        np.testing.assert_array_equal(step_sol.t, [0, dt])
        np.testing.assert_allclose(step_sol.y[0], np.exp(-0.1 * step_sol.t))

        # Step again (return 5 points)
        step_sol_2 = solver.step(step_sol, model, dt, npts=5)
        np.testing.assert_array_equal(
            step_sol_2.t,
            np.concatenate([np.array([0]),
                            np.linspace(dt, 2 * dt, 5)]))
        np.testing.assert_allclose(step_sol_2.y[0],
                                   np.exp(-0.1 * step_sol_2.t))

        # Check steps give same solution as solve
        t_eval = step_sol.t
        solution = solver.solve(model, t_eval)
        np.testing.assert_allclose(solution.y[0], step_sol.y[0])
Пример #4
0
    def test_model_solver_ode_events_casadi(self):
        # Create model
        model = pybamm.BaseModel()
        model.convert_to_format = "casadi"
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=whole_cell)
        model.rhs = {var: 0.1 * var}
        model.initial_conditions = {var: 1}
        model.events = [
            pybamm.Event("2 * var = 2.5", pybamm.min(2 * var - 2.5)),
            pybamm.Event("var = 1.5", pybamm.min(var - 1.5)),
        ]
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve
        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)
        t_eval = np.linspace(0, 10, 100)
        solution = solver.solve(model, t_eval)
        np.testing.assert_allclose(solution.y[0], np.exp(0.1 * solution.t))
        np.testing.assert_array_less(solution.y[0:, -1], 1.5)
        np.testing.assert_array_less(solution.y[0:, -1], 1.25 + 1e-6)
        np.testing.assert_equal(solution.t_event[0], solution.t[-1])
        np.testing.assert_array_equal(solution.y_event[:, 0], solution.y[:,
                                                                         -1])
Пример #5
0
    def test_model_step_ode(self):
        # Create model
        model = pybamm.BaseModel()
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=whole_cell)
        model.rhs = {var: 0.1 * var}
        model.initial_conditions = {var: 1}
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)

        # Step once
        dt = 0.1
        step_sol = solver.step(model, dt)
        np.testing.assert_array_equal(step_sol.t, [0, dt])
        np.testing.assert_allclose(step_sol.y[0], np.exp(0.1 * step_sol.t))

        # Step again (return 5 points)
        step_sol_2 = solver.step(model, dt, npts=5)
        np.testing.assert_array_equal(step_sol_2.t, np.linspace(dt, 2 * dt, 5))
        np.testing.assert_allclose(step_sol_2.y[0], np.exp(0.1 * step_sol_2.t))

        # Check steps give same solution as solve
        t_eval = np.concatenate((step_sol.t, step_sol_2.t[1:]))
        solution = solver.solve(model, t_eval)
        concatenated_steps = np.concatenate((step_sol.y[0], step_sol_2.y[0,
                                                                         1:]))
        np.testing.assert_allclose(solution.y[0], concatenated_steps)
Пример #6
0
    def test_model_solver_ode_jacobian_python(self):
        model = pybamm.BaseModel()
        model.convert_to_format = "python"
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var1 = pybamm.Variable("var1", domain=whole_cell)
        var2 = pybamm.Variable("var2", domain=whole_cell)
        model.rhs = {var1: var1, var2: 1 - var1}
        model.initial_conditions = {var1: 1.0, var2: -1.0}
        model.variables = {"var1": var1, "var2": var2}

        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Add user-supplied Jacobian to model
        mesh = get_mesh_for_testing()
        combined_submesh = mesh.combine_submeshes(
            "negative electrode", "separator", "positive electrode"
        )
        N = combined_submesh[0].npts

        # Solve
        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)
        t_eval = np.linspace(0, 1, 100)
        solution = solver.solve(model, t_eval)
        np.testing.assert_array_equal(solution.t, t_eval)

        T, Y = solution.t, solution.y
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(T, Y),
            np.ones((N, T.size)) * np.exp(T[np.newaxis, :]),
        )
        np.testing.assert_array_almost_equal(
            model.variables["var2"].evaluate(T, Y),
            np.ones((N, T.size)) * (T[np.newaxis, :] - np.exp(T[np.newaxis, :])),
        )
Пример #7
0
 def test_ode_solver_fail_with_dae(self):
     model = pybamm.BaseModel()
     a = pybamm.Scalar(1)
     model.algebraic = {a: a}
     model.concatenated_initial_conditions = a
     solver = pybamm.ScikitsOdeSolver()
     with self.assertRaisesRegex(pybamm.SolverError, "Cannot use ODE solver"):
         solver.set_up(model)
Пример #8
0
    def test_model_solver_ode_jacobian(self):
        # Create model
        model = pybamm.BaseModel()
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var1 = pybamm.Variable("var1", domain=whole_cell)
        var2 = pybamm.Variable("var2", domain=whole_cell)
        model.rhs = {var1: var1, var2: 1 - var1}
        model.initial_conditions = {var1: 1.0, var2: -1.0}
        model.variables = {"var1": var1, "var2": var2}

        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Add user-supplied Jacobian to model
        mesh = get_mesh_for_testing()
        combined_submesh = mesh.combine_submeshes("negative electrode",
                                                  "separator",
                                                  "positive electrode")
        N = combined_submesh[0].npts

        # construct jacobian in order of model.rhs
        J = []
        for var in model.rhs.keys():
            if var.id == var1.id:
                J.append([np.eye(N), np.zeros((N, N))])
            else:
                J.append([-1.0 * np.eye(N), np.zeros((N, N))])

        J = np.block(J)

        def jacobian(t, y):
            return J

        model.jacobian = jacobian

        # Solve
        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)
        t_eval = np.linspace(0, 1, 100)
        solution = solver.solve(model, t_eval)
        np.testing.assert_array_equal(solution.t, t_eval)

        T, Y = solution.t, solution.y
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(T, Y),
            np.ones((N, T.size)) * np.exp(T[np.newaxis, :]),
        )
        np.testing.assert_array_almost_equal(
            model.variables["var2"].evaluate(T, Y),
            np.ones(
                (N, T.size)) * (T[np.newaxis, :] - np.exp(T[np.newaxis, :])),
        )
Пример #9
0
    def test_ode_integrate(self):
        # Constant
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def constant_growth(t, y):
            return 0.5 * np.ones_like(y)

        y0 = np.array([0])
        t_eval = np.linspace(0, 1, 100)
        solution = solver.integrate(constant_growth, y0, t_eval)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(0.5 * solution.t, solution.y[0])

        # Exponential decay
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def exponential_decay(t, y):
            return -0.1 * y

        y0 = np.array([1])
        t_eval = np.linspace(0, 1, 100)
        solution = solver.integrate(exponential_decay, y0, t_eval)
        np.testing.assert_allclose(solution.y[0], np.exp(-0.1 * solution.t))
        self.assertEqual(solution.termination, "final time")
Пример #10
0
    def test_model_solver_ode_python(self):
        model = pybamm.BaseModel()
        model.convert_to_format = "python"
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=whole_cell)
        model.rhs = {var: 0.1 * var}
        model.initial_conditions = {var: 1}
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve
        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)
        t_eval = np.linspace(0, 1, 100)
        solution = solver.solve(model, t_eval)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(solution.y[0], np.exp(0.1 * solution.t))
Пример #11
0
    def test_ode_integrate_failure(self):
        # Turn off warnings to ignore sqrt error
        warnings.simplefilter("ignore")

        def sqrt_decay(t, y):
            return -np.sqrt(y)

        y0 = np.array([1])
        t_eval = np.linspace(0, 3, 100)
        solver = pybamm.ScikitsOdeSolver()
        # Expect solver to fail when y goes negative
        with self.assertRaises(pybamm.SolverError):
            solver.integrate(sqrt_decay, y0, t_eval)

        # Turn warnings back on
        warnings.simplefilter("default")
Пример #12
0
    def test_model_ode_integrate_failure(self):
        # Turn off warnings to ignore sqrt error
        warnings.simplefilter("ignore")

        model = pybamm.BaseModel()
        var = pybamm.Variable("var")
        model.rhs = {var: -pybamm.sqrt(var)}
        model.initial_conditions = {var: 1}
        disc = pybamm.Discretisation()
        disc.process_model(model)

        t_eval = np.linspace(0, 3, 100)
        solver = pybamm.ScikitsOdeSolver()
        # Expect solver to fail when y goes negative
        with self.assertRaises(pybamm.SolverError):
            solver.solve(model, t_eval)

        # Turn warnings back on
        warnings.simplefilter("default")
Пример #13
0
    def test_model_solver_ode_events(self):
        # Create model
        model = pybamm.BaseModel()
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var = pybamm.Variable("var", domain=whole_cell)
        model.rhs = {var: 0.1 * var}
        model.initial_conditions = {var: 1}
        model.events = {
            "2 * var = 2.5": pybamm.min(2 * var - 2.5),
            "var = 1.5": pybamm.min(var - 1.5),
        }
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve
        solver = pybamm.ScikitsOdeSolver(rtol=1e-9, atol=1e-9)
        t_eval = np.linspace(0, 10, 100)
        solution = solver.solve(model, t_eval)
        np.testing.assert_allclose(solution.y[0], np.exp(0.1 * solution.t))
        np.testing.assert_array_less(solution.y[0], 1.5)
        np.testing.assert_array_less(solution.y[0], 1.25)
Пример #14
0
 def test_init(self):
     # linsolver deprecated
     with self.assertRaisesRegex(ValueError,
                                 "linsolver has been deprecated"):
         pybamm.ScikitsOdeSolver(linsolver="lapackdense")
Пример #15
0
    def test_ode_integrate_with_jacobian(self):
        # Linear
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def linear_ode(t, y):
            return np.array([0.5, 2 - y[0]])

        J = np.array([[0.0, 0.0], [-1.0, 0.0]])
        sJ = sparse.csr_matrix(J)

        def jacobian(t, y):
            return J

        def sparse_jacobian(t, y):
            return sJ

        y0 = np.array([0.0, 0.0])
        t_eval = np.linspace(0, 1, 100)
        solution = solver.integrate(linear_ode, y0, t_eval, jacobian=jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(0.5 * solution.t, solution.y[0])
        np.testing.assert_allclose(2.0 * solution.t - 0.25 * solution.t**2,
                                   solution.y[1],
                                   rtol=1e-4)

        y0 = np.array([0.0, 0.0])
        t_eval = np.linspace(0, 1, 100)
        solution = solver.integrate(linear_ode,
                                    y0,
                                    t_eval,
                                    jacobian=sparse_jacobian)

        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(2.0 * solution.t - 0.25 * solution.t**2,
                                   solution.y[1],
                                   rtol=1e-4)
        np.testing.assert_allclose(0.5 * solution.t, solution.y[0])

        solver = pybamm.ScikitsOdeSolver(rtol=1e-8,
                                         atol=1e-8,
                                         linsolver="spgmr")

        solution = solver.integrate(linear_ode, y0, t_eval, jacobian=jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(0.5 * solution.t, solution.y[0])
        np.testing.assert_allclose(2.0 * solution.t - 0.25 * solution.t**2,
                                   solution.y[1],
                                   rtol=1e-4)

        solution = solver.integrate(linear_ode,
                                    y0,
                                    t_eval,
                                    jacobian=sparse_jacobian)

        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(2.0 * solution.t - 0.25 * solution.t**2,
                                   solution.y[1],
                                   rtol=1e-4)
        np.testing.assert_allclose(0.5 * solution.t, solution.y[0])

        # Nonlinear exponential grwoth
        solver = pybamm.ScikitsOdeSolver(rtol=1e-8, atol=1e-8)

        def exponential_growth(t, y):
            return np.array([y[0], (1.0 - y[0]) * y[1]])

        def jacobian(t, y):
            return np.array([[1.0, 0.0], [-y[1], 1 - y[0]]])

        def sparse_jacobian(t, y):
            return sparse.csr_matrix(jacobian(t, y))

        y0 = np.array([1.0, 1.0])
        t_eval = np.linspace(0, 1, 100)

        solution = solver.integrate(exponential_growth,
                                    y0,
                                    t_eval,
                                    jacobian=jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(np.exp(solution.t),
                                   solution.y[0],
                                   rtol=1e-4)
        np.testing.assert_allclose(np.exp(1 + solution.t - np.exp(solution.t)),
                                   solution.y[1],
                                   rtol=1e-4)

        solution = solver.integrate(exponential_growth,
                                    y0,
                                    t_eval,
                                    jacobian=sparse_jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(np.exp(solution.t),
                                   solution.y[0],
                                   rtol=1e-4)
        np.testing.assert_allclose(np.exp(1 + solution.t - np.exp(solution.t)),
                                   solution.y[1],
                                   rtol=1e-4)

        solver = pybamm.ScikitsOdeSolver(rtol=1e-8,
                                         atol=1e-8,
                                         linsolver="spgmr")

        solution = solver.integrate(exponential_growth,
                                    y0,
                                    t_eval,
                                    jacobian=jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(np.exp(solution.t),
                                   solution.y[0],
                                   rtol=1e-4)
        np.testing.assert_allclose(np.exp(1 + solution.t - np.exp(solution.t)),
                                   solution.y[1],
                                   rtol=1e-4)

        solution = solver.integrate(exponential_growth,
                                    y0,
                                    t_eval,
                                    jacobian=sparse_jacobian)
        np.testing.assert_array_equal(solution.t, t_eval)
        np.testing.assert_allclose(np.exp(solution.t),
                                   solution.y[0],
                                   rtol=1e-4)
        np.testing.assert_allclose(np.exp(1 + solution.t - np.exp(solution.t)),
                                   solution.y[1],
                                   rtol=1e-4)
Пример #16
0
 def default_solver(self):
     """
     Create and return the default solver for this model
     """
     return pybamm.ScikitsOdeSolver()