示例#1
0
    def test_model_solver_minimize(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.algebraic = {var1: var1 - 3, var2: 2 * var1 - var2}
        model.initial_conditions = {var1: pybamm.Scalar(1), var2: pybamm.Scalar(4)}
        model.variables = {"var1": var1, "var2": var2}
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        sol = np.concatenate((np.ones(100) * 3, np.ones(100) * 6))[:, np.newaxis]

        # Solve
        solver = pybamm.AlgebraicSolver("minimize", tol=1e-8)
        solution = solver.solve(model)
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(t=None, y=solution.y), sol[:100]
        )
        np.testing.assert_array_almost_equal(
            model.variables["var2"].evaluate(t=None, y=solution.y), sol[100:]
        )

        # Test without jacobian and with a different method
        model.use_jacobian = False
        solver = pybamm.AlgebraicSolver("minimize__BFGS")
        solution_no_jac = solver.solve(model)
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(t=None, y=solution_no_jac.y), sol[:100]
        )
        np.testing.assert_array_almost_equal(
            model.variables["var2"].evaluate(t=None, y=solution_no_jac.y), sol[100:]
        )
示例#2
0
    def test_root_find_fail(self):
        class Model:
            y0 = np.array([2])
            rhs = {}
            timescale_eval = 1
            length_scales = {}
            jac_algebraic_eval = None
            convert_to_format = "casadi"

            def algebraic_eval(self, t, y, inputs):
                # algebraic equation has no real root
                return y ** 2 + 1

        model = Model()

        solver = pybamm.AlgebraicSolver(method="hybr")
        with self.assertRaisesRegex(
            pybamm.SolverError,
            "Could not find acceptable solution: The iteration is not making",
        ):
            solver._integrate(model, np.array([0]))

        solver = pybamm.AlgebraicSolver()
        with self.assertRaisesRegex(
            pybamm.SolverError, "Could not find acceptable solution: solver terminated"
        ):
            solver._integrate(model, np.array([0]))
示例#3
0
    def test_model_solver_with_time(self):
        # Create model
        model = pybamm.BaseModel()
        var1 = pybamm.Variable("var1")
        var2 = pybamm.Variable("var2")
        model.algebraic = {var1: var1 - 3 * pybamm.t, var2: 2 * var1 - var2}
        model.initial_conditions = {var1: pybamm.Scalar(1), var2: pybamm.Scalar(4)}
        model.variables = {"var1": var1, "var2": var2}

        disc = pybamm.Discretisation()
        disc.process_model(model)

        # Solve
        t_eval = np.linspace(0, 1)
        solver = pybamm.AlgebraicSolver()
        solution = solver.solve(model, t_eval)

        sol = np.vstack((3 * t_eval, 6 * t_eval))
        np.testing.assert_array_equal(solution.y, sol)
        np.testing.assert_array_equal(
            model.variables["var1"].evaluate(t=t_eval, y=solution.y).flatten(),
            sol[0, :],
        )
        np.testing.assert_array_equal(
            model.variables["var2"].evaluate(t=t_eval, y=solution.y).flatten(),
            sol[1, :],
        )
示例#4
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)
    def test_root_find_fail(self):
        def algebraic(y):
            # algebraic equation has no real root
            return y**2 + 1

        solver = pybamm.AlgebraicSolver(method="hybr")
        y0 = np.array([2])

        with self.assertRaisesRegex(
                pybamm.SolverError,
                "Could not find acceptable solution: The iteration is not making",
        ):
            solver.root(algebraic, y0)
        solver = pybamm.AlgebraicSolver()
        with self.assertRaisesRegex(
                pybamm.SolverError,
                "Could not find acceptable solution: solver terminated"):
            solver.root(algebraic, y0)
    def test_simple_root_find(self):
        # Simple system: a single algebraic equation
        def algebraic(y):
            return y + 2

        solver = pybamm.AlgebraicSolver()
        y0 = np.array([2])
        solution = solver.root(algebraic, y0)
        np.testing.assert_array_equal(solution.y, -2)
    def test_algebraic_solver_init(self):
        solver = pybamm.AlgebraicSolver(method="hybr", tol=1e-4)
        self.assertEqual(solver.method, "hybr")
        self.assertEqual(solver.tol, 1e-4)

        solver.method = "krylov"
        self.assertEqual(solver.method, "krylov")
        solver.tol = 1e-5
        self.assertEqual(solver.tol, 1e-5)
示例#8
0
 def root_method(self, method):
     if method == "casadi":
         method = pybamm.CasadiAlgebraicSolver(self.root_tol)
     elif isinstance(method, str):
         method = pybamm.AlgebraicSolver(method, self.root_tol)
     elif not (method is None or (isinstance(method, pybamm.BaseSolver)
                                  and method.algebraic_solver is True)):
         raise pybamm.SolverError("Root method must be an algebraic solver")
     self._root_method = method
示例#9
0
    def test_algebraic_solver_init(self):
        solver = pybamm.AlgebraicSolver(
            method="hybr", tol=1e-4, extra_options={"maxfev": 100}
        )
        self.assertEqual(solver.method, "hybr")
        self.assertEqual(solver.extra_options, {"maxfev": 100})
        self.assertEqual(solver.tol, 1e-4)

        solver.method = "krylov"
        self.assertEqual(solver.method, "krylov")
        solver.tol = 1e-5
        self.assertEqual(solver.tol, 1e-5)
示例#10
0
    def test_simple_root_find(self):
        # Simple system: a single algebraic equation
        class Model:
            y0 = np.array([2])
            rhs = {}
            timescale_eval = 1
            jac_algebraic_eval = None
            convert_to_format = "python"

            def algebraic_eval(self, t, y, inputs):
                return y + 2

        # Try passing extra options to solver
        solver = pybamm.AlgebraicSolver(extra_options={"maxiter": 100})
        model = Model()
        solution = solver._integrate(model, np.array([0]))
        np.testing.assert_array_equal(solution.y, -2)

        # Relax options and see worse results
        solver = pybamm.AlgebraicSolver(extra_options={"ftol": 1})
        solution = solver._integrate(model, np.array([0]))
        self.assertNotEqual(solution.y, -2)
示例#11
0
    def test_simple_root_find(self):
        # Simple system: a single algebraic equation
        class Model:
            y0 = np.array([2])
            jacobian_eval = None
            convert_to_format = "python"

            def algebraic_eval(self, t, y, inputs):
                return y + 2

        solver = pybamm.AlgebraicSolver()
        model = Model()
        solution = solver._integrate(model, np.array([0]))
        np.testing.assert_array_equal(solution.y, -2)
示例#12
0
    def test_wrong_solver(self):
        # Create model
        model = pybamm.BaseModel()
        var = pybamm.Variable("var")
        model.rhs = {var: var}
        model.algebraic = {var: var - 1}

        # test errors
        solver = pybamm.AlgebraicSolver()
        with self.assertRaisesRegex(
            pybamm.SolverError,
            "Cannot use algebraic solver to solve model with time derivatives",
        ):
            solver.solve(model)
示例#13
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)
示例#14
0
    def test_root_method_init(self):
        solver = pybamm.BaseSolver(root_method="casadi")
        self.assertIsInstance(solver.root_method, pybamm.CasadiAlgebraicSolver)

        solver = pybamm.BaseSolver(root_method="lm")
        self.assertIsInstance(solver.root_method, pybamm.AlgebraicSolver)
        self.assertEqual(solver.root_method.method, "lm")

        root_solver = pybamm.AlgebraicSolver()
        solver = pybamm.BaseSolver(root_method=root_solver)
        self.assertEqual(solver.root_method, root_solver)

        with self.assertRaisesRegex(pybamm.SolverError,
                                    "Root method must be an algebraic solver"):
            pybamm.BaseSolver(root_method=pybamm.ScipySolver())
    def test_pure_neumann_poisson(self):
        # grad^2 u = 1, du/dz = 1 at z = 1, du/dn = 0 elsewhere, u has zero average
        u = pybamm.Variable("u", domain="current collector")
        c = pybamm.Variable("c")  # lagrange multiplier
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])

        model = pybamm.BaseModel()
        # 0*c hack otherwise gives KeyError
        model.algebraic = {
            u:
            pybamm.laplacian(u) - pybamm.source(1, u) +
            c * pybamm.DefiniteIntegralVector(u, vector_type="column"),
            c:
            pybamm.Integral(u, [y, z]) + 0 * c,
        }
        model.initial_conditions = {u: pybamm.Scalar(0), c: pybamm.Scalar(0)}
        # set boundary conditions ("negative tab" = bottom of unit square,
        # "positive tab" = top of unit square, elsewhere normal derivative is zero)
        model.boundary_conditions = {
            u: {
                "negative tab": (0, "Neumann"),
                "positive tab": (1, "Neumann")
            }
        }
        model.variables = {"c": c, "u": u}
        # create discretisation
        mesh = get_unit_2p1D_mesh_for_testing(ypts=32,
                                              zpts=32,
                                              include_particles=False)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        # solve model
        solver = pybamm.AlgebraicSolver()
        solution = solver.solve(model)

        z = mesh["current collector"].coordinates[1, :][:, np.newaxis]
        u_exact = z**2 / 2 - 1 / 6
        np.testing.assert_array_almost_equal(solution.y[:-1],
                                             u_exact,
                                             decimal=1)
示例#16
0
    def test_model_solver_minimize_with_bounds(self):
        # Note: we need a better test case to test this functionality properly
        # Create model
        model = pybamm.BaseModel()
        var1 = pybamm.Variable("var1", bounds=(0, 10))
        model.algebraic = {var1: pybamm.sin(var1) + 1}
        model.initial_conditions = {var1: pybamm.Scalar(3)}
        model.variables = {"var1": var1}

        # Solve
        solver = pybamm.AlgebraicSolver("minimize", tol=1e-16)
        solution = solver.solve(model)
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(t=None, y=solution.y),
            3 * np.pi / 2,
            decimal=4,
        )
    def test_with_jacobian(self):
        A = np.array([[4, 3], [1, -1]])
        b = np.array([0, 7])

        def algebraic(y):
            return A @ y - b

        def jac(y):
            return A

        y0 = np.zeros(2)
        sol = np.array([3, -4])[:, np.newaxis]

        solver = pybamm.AlgebraicSolver()

        solution_no_jac = solver.root(algebraic, y0)
        solution_with_jac = solver.root(algebraic, y0, jacobian=jac)

        np.testing.assert_array_almost_equal(solution_no_jac.y, sol)
        np.testing.assert_array_almost_equal(solution_with_jac.y, sol)
示例#18
0
    def test_with_jacobian(self):
        A = np.array([[4, 3], [1, -1]])
        b = np.array([0, 7])

        class Model:
            y0 = np.zeros(2)
            convert_to_format = "python"

            def algebraic_eval(self, t, y, inputs):
                return A @ y - b

            def jacobian_eval(self, t, y, inputs):
                return A

        model = Model()
        sol = np.array([3, -4])[:, np.newaxis]

        solver = pybamm.AlgebraicSolver()
        solution = solver._integrate(model, np.array([0]))
        np.testing.assert_array_almost_equal(solution.y, sol)
    def test_dirichlet_bcs(self):
        # manufactured solution u = a*z^2 + b*z + c
        model = pybamm.BaseModel()
        a = 3
        b = 4
        c = 5
        u = pybamm.Variable("variable", domain="current collector")
        model.algebraic = {u: -pybamm.laplacian(u) + pybamm.source(2 * a, u)}
        # set boundary conditions ("negative tab" = bottom of unit square,
        # "positive tab" = top of unit square, elsewhere normal derivative is zero)
        model.boundary_conditions = {
            u: {
                "negative tab": (pybamm.Scalar(c), "Dirichlet"),
                "positive tab": (pybamm.Scalar(a + b + c), "Dirichlet"),
            }
        }
        # bad initial guess (on purpose)
        model.initial_conditions = {u: pybamm.Scalar(1)}
        model.variables = {"u": u}
        # create discretisation
        mesh = get_unit_2p1D_mesh_for_testing(ypts=8,
                                              zpts=32,
                                              include_particles=False)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        # solve model
        solver = pybamm.AlgebraicSolver()
        solution = solver.solve(model)

        # indepedent of y, so just check values for one y
        z = mesh["current collector"].edges["z"][:, np.newaxis]
        u_exact = a * z**2 + b * z + c
        np.testing.assert_array_almost_equal(solution.y[0:len(z)], u_exact)
 def default_solver(self):
     return pybamm.AlgebraicSolver()
示例#21
0
 def default_solver(self):
     # Use AlgebraicSolver as CasadiAlgebraicSolver gives unnecessary warnings
     return pybamm.AlgebraicSolver()
    }
    mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts)
    cc_mesh = pybamm.Mesh(cc_geometry, cc_model.default_submesh_types, var_pts)
    disc = pybamm.Discretisation(mesh, models[0].default_spatial_methods)
    cc_disc = pybamm.Discretisation(cc_mesh, cc_models[0].default_spatial_methods)
    disc.process_model(model, check_model=False)
    cc_disc.process_model(cc_model, check_model=False)

    # solve
    tau = param.evaluate(pybamm.standard_parameters_lithium_ion.tau_discharge)
    time = comsol_t / tau
    solver = pybamm.CasadiSolver(
        atol=1e-6, rtol=1e-6, root_tol=1e-3, root_method="hybr", mode="fast"
    )
    solution = solver.solve(model, time)
    cc_solver = pybamm.AlgebraicSolver(tol=1e-6)
    cc_solution = cc_solver.solve(cc_model)
    sol_times[i] = solution.solve_time + cc_solution.solve_time

    # create comsol vars interpolated onto pybamm mesh to compare errors
    comsol_model = shared.make_comsol_model(
        comsol_variables, cc_mesh, param, thermal=True
    )

    # compute "error" using times up to voltage cut off
    t = solution.t
    # Note: casadi doesnt support events so we find this time after the solve
    if isinstance(solver, pybamm.CasadiSolver):
        V_cutoff = param.evaluate(
            pybamm.standard_parameters_lithium_ion.voltage_low_cut_dimensional
        )