Exemplo n.º 1
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)
Exemplo n.º 2
0
    def test_changing_grid(self):
        model = pybamm.lithium_ion.SPM()
        solver = pybamm.IDAKLUSolver()

        # load parameter values and geometry
        geometry = model.default_geometry
        param = model.default_parameter_values

        # Process parameters
        param.process_model(model)
        param.process_geometry(geometry)

        # Calculate time for each solver and each number of grid points
        var = pybamm.standard_spatial_vars
        t_eval = np.linspace(0, 3600, 100)
        for npts in [100, 200]:
            # discretise
            var_pts = {
                spatial_var: npts
                for spatial_var in [var.x_n, var.x_s, var.x_p, var.r_n, var.r_p]
            }
            mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts)
            disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
            model_disc = disc.process_model(model, inplace=False)

            # solve
            solver.solve(model_disc, t_eval)
Exemplo n.º 3
0
    def test_dae_external_temperature(self):

        model_options = {
            "thermal": "x-full",
            "external submodels": ["thermal"],
        }

        model = pybamm.lithium_ion.DFN(model_options)

        neg_pts = 5
        sep_pts = 3
        pos_pts = 5
        tot_pts = neg_pts + sep_pts + pos_pts

        var_pts = {
            pybamm.standard_spatial_vars.x_n: neg_pts,
            pybamm.standard_spatial_vars.x_s: sep_pts,
            pybamm.standard_spatial_vars.x_p: pos_pts,
            pybamm.standard_spatial_vars.r_n: 5,
            pybamm.standard_spatial_vars.r_p: 5,
        }

        solver = pybamm.IDAKLUSolver()
        sim = pybamm.Simulation(model, var_pts=var_pts, solver=solver)
        sim.build()

        t_eval = np.linspace(0, 100, 3)
        x = np.linspace(0, 1, tot_pts)

        for i in np.arange(1, len(t_eval) - 1):
            dt = t_eval[i + 1] - t_eval[i]
            T = (np.sin(2 * np.pi * x) *
                 np.sin(2 * np.pi * 100 * t_eval[i]))[:, np.newaxis]
            external_variables = {"Cell temperature": T}
            sim.step(dt, external_variables=external_variables)
Exemplo n.º 4
0
 def default_solver(self):
     "Return default solver based on whether model is ODE model or DAE model"
     if len(self.algebraic) == 0:
         return pybamm.ScipySolver()
     elif pybamm.have_idaklu() and self.use_jacobian is True:
         # KLU solver requires jacobian to be provided
         return pybamm.IDAKLUSolver()
     else:
         return pybamm.CasadiSolver(mode="safe")
Exemplo n.º 5
0
 def test_on_spme(self):
     model = pybamm.lithium_ion.SPMe()
     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)
     disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
     disc.process_model(model)
     t_eval = np.linspace(0, 3600, 100)
     solution = pybamm.IDAKLUSolver().solve(model, t_eval)
     np.testing.assert_array_less(1, solution.t.size)
Exemplo n.º 6
0
    def test_dae_solver_algebraic_model(self):
        model = pybamm.BaseModel()
        var = pybamm.Variable("var")
        model.algebraic = {var: var + 1}
        model.initial_conditions = {var: 0}

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

        solver = pybamm.IDAKLUSolver()
        t_eval = np.linspace(0, 1)
        solution = solver.solve(model, t_eval)
        np.testing.assert_array_equal(solution.y, -1)
Exemplo n.º 7
0
    def test_set_atol(self):
        model = pybamm.lithium_ion.SPMe()
        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)
        disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
        disc.process_model(model)
        solver = pybamm.IDAKLUSolver(root_method="lm")

        variable_tols = {"Electrolyte concentration": 1e-3}
        solver.set_atol_by_variable(variable_tols, model)
Exemplo n.º 8
0
    def test_set_tol_by_variable(self):
        model = pybamm.lithium_ion.SPMe()
        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)
        disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
        disc.process_model(model)
        t_eval = np.linspace(0, 3600, 100)
        solver = pybamm.IDAKLUSolver()

        variable_tols = {"Porosity times concentration": 1e-3}
        solver.set_atol_by_variable(variable_tols, model)

        solver.solve(model, t_eval)
Exemplo n.º 9
0
    def test_failures(self):
        # this test implements a python version of the ida Roberts
        # example provided in sundials
        # see sundials ida examples pdf
        model = pybamm.BaseModel()
        model.use_jacobian = False
        u = pybamm.Variable("u")
        model.rhs = {u: -0.1 * u}
        model.initial_conditions = {u: 1}

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

        solver = pybamm.IDAKLUSolver(root_method="lm")

        t_eval = np.linspace(0, 3, 100)
        with self.assertRaisesRegex(pybamm.SolverError, "KLU requires the Jacobian"):
            solver.solve(model, t_eval)
Exemplo n.º 10
0
    def test_2p1d(self):
        model_options = {
            "current collector": "potential pair",
            "dimensionality": 2,
            "external submodels": ["current collector"],
        }
        model = pybamm.lithium_ion.DFN(model_options)
        yz_pts = 3
        var_pts = {
            pybamm.standard_spatial_vars.x_n: 4,
            pybamm.standard_spatial_vars.x_s: 4,
            pybamm.standard_spatial_vars.x_p: 4,
            pybamm.standard_spatial_vars.r_n: 4,
            pybamm.standard_spatial_vars.r_p: 4,
            pybamm.standard_spatial_vars.y: yz_pts,
            pybamm.standard_spatial_vars.z: yz_pts,
        }
        solver = pybamm.IDAKLUSolver()
        sim = pybamm.Simulation(model, var_pts=var_pts, solver=solver)

        # Simulate 100 seconds
        t_eval = np.linspace(0, 100, 3)

        for i in np.arange(1, len(t_eval) - 1):
            dt = t_eval[i + 1] - t_eval[i]

            # provide phi_s_n and i_cc
            phi_s_n = np.zeros((yz_pts ** 2, 1))
            i_boundary_cc = np.ones((yz_pts ** 2, 1))
            external_variables = {
                "Negative current collector potential": phi_s_n,
                "Current collector current density": i_boundary_cc,
            }

            sim.step(dt, external_variables=external_variables)

            # obtain phi_s_n from the pybamm solution at the current time
            phi_s_p = sim.get_variable_array("Positive current collector potential")

        self.assertTrue(phi_s_p.shape, (yz_pts ** 2, 1))
Exemplo n.º 11
0
    def test_ida_roberts_klu(self):
        # this test implements a python version of the ida Roberts
        # example provided in sundials
        # see sundials ida examples pdf
        for form in ["python", "casadi"]:
            model = pybamm.BaseModel()
            model.convert_to_format = form
            u = pybamm.Variable("u")
            v = pybamm.Variable("v")
            model.rhs = {u: 0.1 * v}
            model.algebraic = {v: 1 - v}
            model.initial_conditions = {u: 0, v: 1}
            model.events = [
                pybamm.Event("1", u - 0.2),
                pybamm.Event("2", v),
            ]

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

            solver = pybamm.IDAKLUSolver(root_method="lm")

            t_eval = np.linspace(0, 3, 100)
            solution = solver.solve(model, t_eval)

            # test that final time is time of event
            # y = 0.1 t + y0 so y=0.2 when t=2
            np.testing.assert_array_almost_equal(solution.t[-1], 2.0)

            # test that final value is the event value
            np.testing.assert_array_almost_equal(solution.y[0, -1], 0.2)

            # test that y[1] remains constant
            np.testing.assert_array_almost_equal(
                solution.y[1, :], np.ones(solution.t.shape)
            )

            # test that y[0] = to true solution
            true_solution = 0.1 * solution.t
            np.testing.assert_array_almost_equal(solution.y[0, :], true_solution)
Exemplo n.º 12
0
    def test_ida_roberts_klu(self):
        # this test implements a python version of the ida Roberts
        # example provided in sundials
        # see sundials ida examples pdf

        # times and initial conditions
        t_eval = np.linspace(0, 3, 100)
        y0 = np.array([0.0, 1.0])

        # Standard pybamm functions
        def jac(t, y):
            J = np.zeros((2, 2))
            J[0][0] = 0.0
            J[0][1] = 1.0
            J[1][0] = 0.0
            J[1][1] = -1.0
            return sparse.csr_matrix(J)

        def event_1(t, y):
            return y[0] - 0.2

        def event_2(t, y):
            return y[1] - 0.0

        events = np.array([event_1, event_2])

        def res(t, y, yp):
            # must be of form r = f(t, y) - y'
            r = np.zeros((y.size,))
            r[0] = 0.1 * y[1]
            r[1] = 1 - y[1]
            r[0] += -yp[0]
            return r

        mass_matrix_dense = np.zeros((2, 2))
        mass_matrix_dense[0][0] = 1
        mass_matrix = sparse.csr_matrix(mass_matrix_dense)

        def rhs(t, y):
            return np.array([0.1 * y[1]])

        def alg(t, y):
            return np.array([1 - y[1]])

        solver = pybamm.IDAKLUSolver()
        solver.residuals = res
        solver.rhs = rhs
        solver.algebraic = alg

        solution = solver.integrate(res, y0, t_eval, events, mass_matrix, jac)

        # test that final time is time of event
        # y = 0.1 t + y0 so y=0.2 when t=2
        np.testing.assert_array_almost_equal(solution.t[-1], 2.0)

        # test that final value is the event value
        np.testing.assert_array_almost_equal(solution.y[0, -1], 0.2)

        # test that y[1] remains constant
        np.testing.assert_array_almost_equal(
            solution.y[1, :], np.ones(solution.t.shape)
        )

        # test that y[0] = to true solution
        true_solution = 0.1 * solution.t
        np.testing.assert_array_almost_equal(solution.y[0, :], true_solution)
Exemplo n.º 13
0
    var.z: 5,
}
# depnding on number of points in y-z plane may need to increase recursion depth...
sys.setrecursionlimit(10000)
mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts)

# discretise model
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
disc.process_model(model)

# solve model -- simulate one hour discharge
tau = param.process_symbol(
    pybamm.standard_parameters_lithium_ion.tau_discharge)
t_end = 3600 / tau.evaluate(0)
t_eval = np.linspace(0, t_end, 120)
solution = pybamm.IDAKLUSolver().solve(model, t_eval)

# TO DO: 2+1D automated plotting
phi_s_cn = pybamm.ProcessedVariable(
    model.variables["Negative current collector potential [V]"],
    solution.t,
    solution.y,
    mesh=mesh,
)
phi_s_cp = pybamm.ProcessedVariable(
    model.variables["Positive current collector potential [V]"],
    solution.t,
    solution.y,
    mesh=mesh,
)
T = pybamm.ProcessedVariable(
Exemplo n.º 14
0
var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 50, var.x_s: 50, var.x_p: 50, var.r_n: 20, var.r_p: 20}
mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts)

# discretise model
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
disc.process_model(model)

# solve model
t_eval = np.linspace(0, 3600, 100)

casadi_sol = pybamm.CasadiSolver(atol=1e-8, rtol=1e-8).solve(model, t_eval)
solutions = [casadi_sol]

if pybamm.have_idaklu():
    klu_sol = pybamm.IDAKLUSolver(atol=1e-8, rtol=1e-8).solve(model, t_eval)
    solutions.append(klu_sol)
else:
    pybamm.logger.error(
        """
        Cannot solve model with IDA KLU solver as solver is not installed.
        Please consult installation instructions on GitHub.
        """
    )
if pybamm.have_scikits_odes():
    scikits_sol = pybamm.ScikitsDaeSolver(atol=1e-8, rtol=1e-8).solve(model, t_eval)
    solutions.append(scikits_sol)
else:
    pybamm.logger.error(
        """
        Cannot solve model with Scikits DAE solver as solver is not installed.
Exemplo n.º 15
0
                   model.default_var_pts)
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
disc.process_model(model)

# tolerances (rtol, atol)
tols = [[1e-8, 1e-8], [1e-6, 1e-6], [1e-3, 1e-6], [1e-3, 1e-3]]

# solve model
solutions = [None] * len(tols)
voltages = [None] * len(tols)
voltage_rmse = [None] * len(tols)
labels = [None] * len(tols)
t_eval = np.linspace(0, 3000, 100)
for i, tol in enumerate(tols):
    if pybamm.have_idaklu():
        solver = pybamm.IDAKLUSolver(rtol=tol[0], atol=tol[1])
    else:
        solver = pybamm.CasadiSolver(rtol=tol[0], atol=tol[1])
    solutions[i] = solver.solve(model, t_eval)
    voltages[i] = solutions[i]["Terminal voltage [V]"](solutions[i].t)
    voltage_rmse[i] = pybamm.rmse(voltages[0], voltages[i])
    labels[i] = "rtol = {}, atol = {}".format(tol[0], tol[1])

# print RMSE voltage errors vs tighest tolerance
for i, tol in enumerate(tols):
    print("rtol = {}, atol = {}, solve time = {} s, Voltage RMSE = {}".format(
        tol[0], tol[1], solutions[i].solve_time, voltage_rmse[i]))
# plot
plot = pybamm.QuickPlot(solutions, labels=labels)
plot.dynamic_plot()