def test_loqs_spm_base(self): t_eval = np.linspace(0, 0.01, 2) # SPM for model in [pybamm.lithium_ion.SPM(), pybamm.lead_acid.LOQS()]: 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 = model.default_solver solution = solver.solve(model, t_eval) pybamm.QuickPlot(model, mesh, solution) # test quick plot of particle for spm if model.name == "Single Particle Model": output_variables = [ "X-averaged negative particle concentration [mol.m-3]", "X-averaged positive particle concentration [mol.m-3]", ] pybamm.QuickPlot(model, mesh, solution, output_variables)
def test_plot_2plus1D_spm(self): spm = pybamm.lithium_ion.SPM({ "current collector": "potential pair", "dimensionality": 2 }) geometry = spm.default_geometry param = spm.default_parameter_values param.process_model(spm) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = { var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5, var.y: 5, var.z: 5, } mesh = pybamm.Mesh(geometry, spm.default_submesh_types, var_pts) disc_spm = pybamm.Discretisation(mesh, spm.default_spatial_methods) disc_spm.process_model(spm) t_eval = np.linspace(0, 100, 10) solution = spm.default_solver.solve(spm, t_eval) quick_plot = pybamm.QuickPlot( solution, [ "Negative current collector potential [V]", "Positive current collector potential [V]", "Terminal voltage [V]", ], ) quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(1) # check 2D (y,z space) variables update properly for different time units phi_n = solution["Negative current collector potential [V]"].entries for unit, scale in zip(["seconds", "minutes", "hours"], [1, 60, 3600]): quick_plot = pybamm.QuickPlot( solution, ["Negative current collector potential [V]"], time_unit=unit) quick_plot.plot(0) qp_data = quick_plot.plots[( "Negative current collector potential [V]", )][0][1] np.testing.assert_array_almost_equal(qp_data, phi_n[:, :, 0]) quick_plot.slider_update(t_eval[-1] / scale) qp_data = quick_plot.plots[( "Negative current collector potential [V]", )][0][1] np.testing.assert_array_almost_equal(qp_data, phi_n[:, :, -1]) with self.assertRaisesRegex(NotImplementedError, "Shape not recognized for"): pybamm.QuickPlot(solution, ["Negative particle concentration [mol.m-3]"]) pybamm.close_plots()
def test_plot_lithium_ion(self): spm = pybamm.lithium_ion.SPM() spme = pybamm.lithium_ion.SPMe() geometry = spm.default_geometry param = spm.default_parameter_values param.process_model(spm) param.process_model(spme) param.process_geometry(geometry) mesh = pybamm.Mesh(geometry, spme.default_submesh_types, spme.default_var_pts) disc_spm = pybamm.Discretisation(mesh, spm.default_spatial_methods) disc_spme = pybamm.Discretisation(mesh, spme.default_spatial_methods) disc_spm.process_model(spm) disc_spme.process_model(spme) t_eval = np.linspace(0, 3600, 100) solution_spm = spm.default_solver.solve(spm, t_eval) solution_spme = spme.default_solver.solve(spme, t_eval) quick_plot = pybamm.QuickPlot([solution_spm, solution_spme]) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] quick_plot.axis.update({("Electrolyte concentration",): new_axis}) self.assertEqual(quick_plot.axis[("Electrolyte concentration",)], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis[("Electrolyte concentration",)], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.update(0.01) # Test with different output variables output_vars = [ "Negative particle surface concentration", "Electrolyte concentration", "Positive particle surface concentration", ] quick_plot = pybamm.QuickPlot(solution_spm, output_vars) self.assertEqual(len(quick_plot.axis), 3) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] quick_plot.axis.update({("Electrolyte concentration",): new_axis}) self.assertEqual(quick_plot.axis[("Electrolyte concentration",)], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis[("Electrolyte concentration",)], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.update(0.01)
def test_plot_1plus1D_spme(self): spm = pybamm.lithium_ion.SPMe( {"current collector": "potential pair", "dimensionality": 1} ) geometry = spm.default_geometry param = spm.default_parameter_values param.process_model(spm) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5, var.z: 5} mesh = pybamm.Mesh(geometry, spm.default_submesh_types, var_pts) disc_spm = pybamm.Discretisation(mesh, spm.default_spatial_methods) disc_spm.process_model(spm) t_eval = np.linspace(0, 100, 10) solution = spm.default_solver.solve(spm, t_eval) # check 2D (x,z space) variables update properly for different time units # Note: these should be the transpose of the entries in the processed variable c_e = solution["Electrolyte concentration [mol.m-3]"] for unit, scale in zip(["seconds", "minutes", "hours"], [1, 60, 3600]): quick_plot = pybamm.QuickPlot( solution, ["Electrolyte concentration [mol.m-3]"], time_unit=unit ) quick_plot.plot(0) qp_data = quick_plot.plots[("Electrolyte concentration [mol.m-3]",)][0][1] c_e_eval = c_e(t_eval[0], x=c_e.first_dim_pts, z=c_e.second_dim_pts) np.testing.assert_array_almost_equal(qp_data.T, c_e_eval) quick_plot.slider_update(t_eval[-1] / scale) qp_data = quick_plot.plots[("Electrolyte concentration [mol.m-3]",)][0][1] c_e_eval = c_e(t_eval[-1], x=c_e.first_dim_pts, z=c_e.second_dim_pts) np.testing.assert_array_almost_equal(qp_data.T, c_e_eval) pybamm.close_plots()
def plot(self, quick_plot_vars=None, testing=False): """ A method to quickly plot the outputs of the simulation. Parameters ---------- quick_plot_vars: list, optional A list of the variables to plot. testing, bool, optional If False the plot will not be displayed """ if self._solution is None: raise ValueError( "Model has not been solved, please solve the model before plotting." ) if quick_plot_vars is None: quick_plot_vars = self.quick_plot_vars plot = pybamm.QuickPlot(self._solution, output_variables=quick_plot_vars) if isnotebook(): import ipywidgets as widgets widgets.interact( plot.plot, t=widgets.FloatSlider(min=0, max=plot.max_t, step=0.05, value=0), ) else: plot.dynamic_plot(testing=testing)
def test_model_with_inputs(self): chemistry = pybamm.parameter_sets.Chen2020 parameter_values = pybamm.ParameterValues(chemistry=chemistry) model = pybamm.lithium_ion.SPMe() parameter_values.update({"Electrode height [m]": "[input]"}) solver = pybamm.CasadiSolver(mode="safe") sim1 = pybamm.Simulation(model, parameter_values=parameter_values, solver=solver) inputs1 = {"Electrode height [m]": 1.00} sol1 = sim1.solve(t_eval=np.linspace(0, 1000, 101), inputs=inputs1) sim2 = pybamm.Simulation(model, parameter_values=parameter_values, solver=solver) inputs2 = {"Electrode height [m]": 2.00} sol2 = sim2.solve(t_eval=np.linspace(0, 1000, 101), inputs=inputs2) output_variables = [ "Terminal voltage [V]", "Current [A]", "Negative electrode potential [V]", "Positive electrode potential [V]", "Electrolyte potential [V]", "Electrolyte concentration", "Negative particle surface concentration", "Positive particle surface concentration", ] quick_plot = pybamm.QuickPlot(solutions=[sol1, sol2], output_variables=output_variables) quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(1) pybamm.close_plots()
def setUp(self): self.model = pybamm.lithium_ion.DFN() self.parameter_values = self.model.default_parameter_values self.sim = pybamm.Simulation( self.model, parameter_values=self.parameter_values ) self.sim.solve([0, 3700]) self.solution = self.sim.solution self.t = self.solution["Time [s]"] self.final_time = int(self.t.entries[len(self.t.entries) - 1]) self.time_array = np.linspace(0, self.final_time, num=3) self.images = [] self.image_files = [] for val in self.time_array: self.plot = pybamm.QuickPlot(self.sim, time_unit="seconds") self.plot.plot(val) self.images.append("plot" + str(val) + ".png") self.plot.fig.savefig("plot" + str(val) + ".png", dpi=200) plt.close() for image in self.images: self.image_files.append(imageio.imread(image)) imageio.mimsave('plot.gif', self.image_files, duration=0.1) for image in self.images: os.remove(image)
def test_plot_2plus1D_spm(self): spm = pybamm.lithium_ion.SPM({ "current collector": "potential pair", "dimensionality": 2 }) geometry = spm.default_geometry param = spm.default_parameter_values param.process_model(spm) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = { var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5, var.y: 5, var.z: 5, } mesh = pybamm.Mesh(geometry, spm.default_submesh_types, var_pts) disc_spm = pybamm.Discretisation(mesh, spm.default_spatial_methods) disc_spm.process_model(spm) t_eval = np.linspace(0, 3600, 100) solution_spm = spm.default_solver.solve(spm, t_eval) quick_plot = pybamm.QuickPlot( solution_spm, [ "Negative current collector potential [V]", "Positive current collector potential [V]", "Terminal voltage [V]", ], ) quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(1) with self.assertRaisesRegex(NotImplementedError, "Shape not recognized for"): pybamm.QuickPlot( solution_spm, ["Negative particle concentration [mol.m-3]"], )
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, "")], )
def test_spm_simulation(self): # SPM model = pybamm.lithium_ion.SPM() sim = pybamm.Simulation(model) t_eval = np.linspace(0, 10, 2) sim.solve(t_eval) # mixed simulation and solution input # solution should be extracted from the simulation quick_plot = pybamm.QuickPlot([sim, sim.solution]) quick_plot.plot(0)
def test_plot_lead_acid(self): loqs = pybamm.lead_acid.LOQS() geometry = loqs.default_geometry param = loqs.default_parameter_values param.process_model(loqs) param.process_geometry(geometry) mesh = pybamm.Mesh(geometry, loqs.default_submesh_types, loqs.default_var_pts) disc_loqs = pybamm.Discretisation(mesh, loqs.default_spatial_methods) disc_loqs.process_model(loqs) t_eval = np.linspace(0, 3600, 100) solution_loqs = loqs.default_solver.solve(loqs, t_eval) pybamm.QuickPlot(solution_loqs)
def dynamic_plot(*args, **kwargs): """ Creates a :class:`pybamm.QuickPlot` object (with arguments 'args' and keyword arguments 'kwargs') and then calls :meth:`pybamm.QuickPlot.dynamic_plot`. The key-word argument 'testing' is passed to the 'dynamic_plot' method, not the `QuickPlot` class. Returns ------- plot : :class:`pybamm.QuickPlot` The 'QuickPlot' object that was created """ kwargs_for_class = {k: v for k, v in kwargs.items() if k != "testing"} plot = pybamm.QuickPlot(*args, **kwargs_for_class) plot.dynamic_plot(kwargs.get("testing", False)) return plot
def plot_graph(solution, sim, t=None, reply=False, comparing=False): if t == None and not comparing: t = solution["Time [s]"] final_time = int(t.entries[len(t.entries) - 1]) # plot_type = random.randint(0, 1) time = random.randint(0, final_time) print(time) # if plot_type == 0: plot = pybamm.QuickPlot(sim, time_unit="seconds") plot.plot(time) if not reply: plot.fig.savefig("foo.png", dpi=300) elif reply: plot.fig.savefig("replyFoo.png", dpi=300) # if comparing: # print(solution[0]) # t = solution[0]["Time [s]"] # final_time = int(t.entries[len(t.entries) - 1]) # time = random.randint(0, final_time) # plot = pybamm.QuickPlot(sim) # plot.plot(time) # plot.fig.savefig("foo.png", dpi=300) # Below was the code to plot random output variables (not needed right now) # else: # while True: # lower_limit = random.randint(0, len(output_variables)) # upper_limit = random.randint(0, len(output_variables)) # if upper_limit - lower_limit < 9 and upper_limit - lower_limit > 2: # plot = pybamm.QuickPlot( # sim, # output_variables=output_variables[lower_limit:upper_limit], # time_unit="seconds", # ) # plot.plot(time) # if not reply: # plot.fig.savefig("foo.png", dpi=300) # elif reply: # plot.fig.savefig("replyFoo.png", dpi=300) # # foo1.pdf_to_png('foo.pdf') # break return time
def test_loqs_spme(self): t_eval = np.linspace(0, 10, 2) for model in [pybamm.lithium_ion.SPMe(), pybamm.lead_acid.LOQS()]: geometry = model.default_geometry param = model.default_parameter_values param.process_model(model) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = { var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5 } mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) solver = model.default_solver solution = solver.solve(model, t_eval) pybamm.QuickPlot(solution) # check 1D (space) variables update properly for different time units t = solution["Time [s]"].entries c_e_var = solution["Electrolyte concentration [mol.m-3]"] # 1D variables should be evaluated on edges L_x = param.evaluate(model.param.L_x) c_e = c_e_var(t=t, x=mesh.combine_submeshes(*c_e_var.domain).edges * L_x) for unit, scale in zip(["seconds", "minutes", "hours"], [1, 60, 3600]): quick_plot = pybamm.QuickPlot( solution, ["Electrolyte concentration [mol.m-3]"], time_unit=unit) quick_plot.plot(0) qp_data = ( quick_plot.plots[("Electrolyte concentration [mol.m-3]", )][0][0].get_ydata(), )[0] np.testing.assert_array_almost_equal(qp_data, c_e[:, 0]) quick_plot.slider_update(t_eval[-1] / scale) qp_data = ( quick_plot.plots[("Electrolyte concentration [mol.m-3]", )][0][0].get_ydata(), )[0][:, 0] np.testing.assert_array_almost_equal(qp_data, c_e[:, 1]) # test quick plot of particle for spme if model.name == "Single Particle Model with electrolyte": output_variables = [ "X-averaged negative particle concentration [mol.m-3]", "X-averaged positive particle concentration [mol.m-3]", "Negative particle concentration [mol.m-3]", "Positive particle concentration [mol.m-3]", ] pybamm.QuickPlot(solution, output_variables) # check 2D (space) variables update properly for different time units c_n = solution["Negative particle concentration [mol.m-3]"] for unit, scale in zip(["seconds", "minutes", "hours"], [1, 60, 3600]): quick_plot = pybamm.QuickPlot( solution, ["Negative particle concentration [mol.m-3]"], time_unit=unit, ) quick_plot.plot(0) qp_data = quick_plot.plots[( "Negative particle concentration [mol.m-3]", )][0][1] c_n_eval = c_n(t_eval[0], r=c_n.first_dim_pts, x=c_n.second_dim_pts) np.testing.assert_array_almost_equal(qp_data, c_n_eval) quick_plot.slider_update(t_eval[-1] / scale) qp_data = quick_plot.plots[( "Negative particle concentration [mol.m-3]", )][0][1] c_n_eval = c_n(t_eval[-1], r=c_n.first_dim_pts, x=c_n.second_dim_pts) np.testing.assert_array_almost_equal(qp_data, c_n_eval) pybamm.close_plots()
"Positive electrode potential [V]": comsol_phi_p, "Terminal voltage [V]": comsol_voltage, # Add spatial variables for use in QuickPlot "x": pybamm_model.variables["x"], "x [m]": pybamm_model.variables["x [m]"], } # Make new solution with same t and y comsol_solution = pybamm.Solution(pybamm_solution.t, pybamm_solution.y) # Update model timescale to match the pybamm model comsol_model.timescale = pybamm_model.timescale comsol_solution.model = comsol_model # plot output_variables = [ "Negative particle surface concentration [mol.m-3]", "Electrolyte concentration [mol.m-3]", "Positive particle surface concentration [mol.m-3]", "Current [A]", "Negative electrode potential [V]", "Electrolyte potential [V]", "Positive electrode potential [V]", "Terminal voltage [V]", ] plot = pybamm.QuickPlot( [pybamm_solution, comsol_solution], output_variables=output_variables, labels=["PyBaMM", "Comsol"], ) plot.dynamic_plot()
def test_simple_ode_model(self): model = pybamm.BaseBatteryModel(name="Simple ODE Model") whole_cell = ["negative electrode", "separator", "positive electrode"] # Create variables: domain is explicitly empty since these variables are only # functions of time a = pybamm.Variable("a", domain=[]) b = pybamm.Variable("b", domain=[]) c = pybamm.Variable("c", domain=[]) # Simple ODEs model.rhs = {a: pybamm.Scalar(2), b: pybamm.Scalar(0), c: -c} # Simple initial conditions model.initial_conditions = { a: pybamm.Scalar(0), b: pybamm.Scalar(1), c: pybamm.Scalar(1), } # no boundary conditions for an ODE model # Broadcast some of the variables model.variables = { "a": a, "b broadcasted": pybamm.FullBroadcast(b, whole_cell, "current collector"), "c broadcasted": pybamm.FullBroadcast( c, ["negative electrode", "separator"], "current collector" ), } # ODEs only (don't use jacobian) model.use_jacobian = False # Process and solve 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 = model.default_solver t_eval = np.linspace(0, 2, 100) solution = solver.solve(model, t_eval) quick_plot = pybamm.QuickPlot(model, mesh, solution) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] quick_plot.axis.update({("a",): new_axis}) self.assertEqual(quick_plot.axis[("a",)], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis[("a",)], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.update(0.01) # Test with different output variables quick_plot = pybamm.QuickPlot(model, mesh, solution, ["b broadcasted"]) self.assertEqual(len(quick_plot.axis), 1) quick_plot.plot(0) quick_plot = pybamm.QuickPlot( model, mesh, solution, [["a", "a"], ["b broadcasted", "b broadcasted"], "c broadcasted"], ) self.assertEqual(len(quick_plot.axis), 3) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] var_key = ("c broadcasted",) quick_plot.axis.update({var_key: new_axis}) self.assertEqual(quick_plot.axis[var_key], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis[var_key], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.update(0.01) # Test longer name model.variables["Variable with a very long name"] = model.variables["a"] quick_plot = pybamm.QuickPlot(model, mesh, solution) quick_plot.plot(0) # Test errors with self.assertRaisesRegex(ValueError, "mismatching variable domains"): pybamm.QuickPlot(model, mesh, solution, [["a", "b broadcasted"]]) model.variables["3D variable"] = disc.process_symbol( pybamm.Broadcast(1, ["negative particle"]) ) with self.assertRaisesRegex(NotImplementedError, "cannot plot 3D variables"): pybamm.QuickPlot(model, mesh, solution, ["3D variable"])
def ambient_temperature(t): return 300 + t * 100 / 3600 param = model.default_parameter_values param.update({"Ambient temperature [K]": ambient_temperature}, check_already_exists=False) param.process_model(model) param.process_geometry(geometry) # set mesh var = pybamm.standard_spatial_vars var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} 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 / 2, 100) solver = pybamm.CasadiSolver(mode="fast") solver.rtol = 1e-3 solver.atol = 1e-6 solution = solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot( solution, ["X-averaged cell temperature [K]", "Ambient temperature [K]"]) plot.dynamic_plot()
fill_value="extrapolate", bounds_error=False, ), pybamm.t, ) comsol_voltage.mesh = None comsol_voltage.secondary_mesh = None # Create comsol model with dictionary of Matrix variables comsol_model = pybamm.BaseModel() comsol_model.variables = { "Negative particle surface concentration [mol.m-3]": comsol_c_n_surf, "Electrolyte concentration [mol.m-3]": comsol_c_e, "Positive particle surface concentration [mol.m-3]": comsol_c_p_surf, "Current [A]": pybamm_model.variables["Current [A]"], "Negative electrode potential [V]": comsol_phi_n, "Electrolyte potential [V]": comsol_phi_e, "Positive electrode potential [V]": comsol_phi_p, "Terminal voltage [V]": comsol_voltage, } # Make new solution with same t and y comsol_solution = pybamm.Solution(pybamm_solution.t, pybamm_solution.y) comsol_solution.model = comsol_model # plot plot = pybamm.QuickPlot( [pybamm_solution, comsol_solution], output_variables=comsol_model.variables.keys(), labels=["PyBaMM", "Comsol"], ) plot.dynamic_plot()
# load parameter values and process models and geometry param = models[0].default_parameter_values param["Current function [A]"] = 1 for model in models: param.process_model(model) # set mesh var = pybamm.standard_spatial_vars var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 5, var.r_p: 5} # discretise models for model in models: # create geometry geometry = model.default_geometry param.process_geometry(geometry) mesh = pybamm.Mesh(geometry, models[-1].default_submesh_types, var_pts) disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # solve model solutions = [None] * len(models) t_eval = np.linspace(0, 3600, 100) for i, model in enumerate(models): solutions[i] = model.default_solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot(solutions, linestyles=[":", "--", "-"]) plot.dynamic_plot()
# process geometry and discretise models for model in models: geometry = model.default_geometry param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = { var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5, var.y: 5, var.z: 5, } mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # solve model solutions = [None] * len(models) t_eval = np.linspace(0, 1, 1000) for i, model in enumerate(models): solution = model.default_solver.solve(model, t_eval) solutions[i] = solution # plot # TO DO: plotting 3D variables output_variables = ["Terminal voltage [V]"] plot = pybamm.QuickPlot(models, mesh, solutions, output_variables) plot.dynamic_plot()
return grading * R_p_0 params[1]["Negative particle radius [m]"] = negative_radius params[1]["Positive particle radius [m]"] = positive_radius # set up and solve simulations t_eval = np.linspace(0, 3600, 100) sols = [] for model, param in zip(models, params): sim = pybamm.Simulation(model, parameter_values=param) sol = sim.solve(t_eval) sols.append(sol) output_variables = [ "Negative particle surface concentration", "Electrolyte concentration", "Positive particle surface concentration", "Current [A]", "Negative electrode potential [V]", "Electrolyte potential [V]", "Positive electrode potential [V]", "Terminal voltage [V]", "Negative particle radius", "Positive particle radius", ] # plot plot = pybamm.QuickPlot(sols, output_variables=output_variables) plot.dynamic_plot()
param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = { var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10, var.y: 10, var.z: 10, } mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # solve model solutions = [None] * len(models) t_eval = np.linspace(0, 3600, 1000) for i, model in enumerate(models): solution = model.default_solver.solve(model, t_eval) solutions[i] = solution # plot output_variables = [ "Terminal voltage [V]", "Negative current collector potential [V]", "Positive current collector potential [V]", ] plot = pybamm.QuickPlot(solutions, output_variables) plot.dynamic_plot()
var = pybamm.standard_spatial_vars var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} 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) solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-3) solution = solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot( solution, [ "Negative particle concentration [mol.m-3]", "Electrolyte concentration [mol.m-3]", "Positive particle concentration [mol.m-3]", "Current [A]", "Negative electrode potential [V]", "Electrolyte potential [V]", "Positive electrode potential [V]", "Terminal voltage [V]", ], time_unit="seconds", spatial_unit="um", ) plot.dynamic_plot()
def test_simple_ode_model(self): model = pybamm.BaseBatteryModel(name="Simple ODE Model") whole_cell = ["negative electrode", "separator", "positive electrode"] # Create variables: domain is explicitly empty since these variables are only # functions of time a = pybamm.Variable("a", domain=[]) b = pybamm.Variable("b", domain=[]) c = pybamm.Variable("c", domain=[]) # Simple ODEs model.rhs = {a: pybamm.Scalar(2), b: pybamm.Scalar(0), c: -c} # Simple initial conditions model.initial_conditions = { a: pybamm.Scalar(0), b: pybamm.Scalar(1), c: pybamm.Scalar(1), } # no boundary conditions for an ODE model # Broadcast some of the variables model.variables = { "a": a, "b broadcasted": pybamm.FullBroadcast(b, whole_cell, "current collector"), "c broadcasted": pybamm.FullBroadcast(c, ["negative electrode", "separator"], "current collector"), "b broadcasted negative electrode": pybamm.PrimaryBroadcast(b, "negative particle"), "c broadcasted positive electrode": pybamm.PrimaryBroadcast(c, "positive particle"), "x [m]": pybamm.standard_spatial_vars.x, "x": pybamm.standard_spatial_vars.x, "r_n [m]": pybamm.standard_spatial_vars.r_n, "r_n": pybamm.standard_spatial_vars.r_n, "r_p [m]": pybamm.standard_spatial_vars.r_p, "r_p": pybamm.standard_spatial_vars.r_p, } # ODEs only (don't use jacobian) model.use_jacobian = False # Process and solve 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 = model.default_solver t_eval = np.linspace(0, 2, 100) solution = solver.solve(model, t_eval) quick_plot = pybamm.QuickPlot( solution, [ "a", "b broadcasted", "c broadcasted", "b broadcasted negative electrode", "c broadcasted positive electrode", ], ) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] quick_plot.axis_limits.update({("a", ): new_axis}) self.assertEqual(quick_plot.axis_limits[("a", )], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis_limits[("a", )], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(0.01) # Test with different output variables quick_plot = pybamm.QuickPlot(solution, ["b broadcasted"]) self.assertEqual(len(quick_plot.axis_limits), 1) quick_plot.plot(0) quick_plot = pybamm.QuickPlot( solution, [ ["a", "a"], ["b broadcasted", "b broadcasted"], "c broadcasted", "b broadcasted negative electrode", "c broadcasted positive electrode", ], ) self.assertEqual(len(quick_plot.axis_limits), 5) quick_plot.plot(0) # update the axis new_axis = [0, 0.5, 0, 1] var_key = ("c broadcasted", ) quick_plot.axis_limits.update({var_key: new_axis}) self.assertEqual(quick_plot.axis_limits[var_key], new_axis) # and now reset them quick_plot.reset_axis() self.assertNotEqual(quick_plot.axis_limits[var_key], new_axis) # check dynamic plot loads quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(0.01) # Test longer name model.variables["Variable with a very long name"] = model.variables[ "a"] quick_plot = pybamm.QuickPlot(solution, ["Variable with a very long name"]) quick_plot.plot(0) # Test different inputs quick_plot = pybamm.QuickPlot( [solution, solution], ["a"], colors=["r", "g", "b"], linestyles=["-", "--"], figsize=(1, 2), labels=["sol 1", "sol 2"], ) self.assertEqual(quick_plot.colors, ["r", "g", "b"]) self.assertEqual(quick_plot.linestyles, ["-", "--"]) self.assertEqual(quick_plot.figsize, (1, 2)) self.assertEqual(quick_plot.labels, ["sol 1", "sol 2"]) # Test different time units quick_plot = pybamm.QuickPlot(solution, ["a"]) self.assertEqual(quick_plot.time_scaling_factor, 1) quick_plot = pybamm.QuickPlot(solution, ["a"], time_unit="seconds") quick_plot.plot(0) self.assertEqual(quick_plot.time_scaling_factor, 1) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_xdata(), t_eval) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_ydata(), 2 * t_eval) quick_plot = pybamm.QuickPlot(solution, ["a"], time_unit="minutes") quick_plot.plot(0) self.assertEqual(quick_plot.time_scaling_factor, 60) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_xdata(), t_eval / 60) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_ydata(), 2 * t_eval) quick_plot = pybamm.QuickPlot(solution, ["a"], time_unit="hours") quick_plot.plot(0) self.assertEqual(quick_plot.time_scaling_factor, 3600) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_xdata(), t_eval / 3600) np.testing.assert_array_almost_equal( quick_plot.plots[("a", )][0][0].get_ydata(), 2 * t_eval) with self.assertRaisesRegex(ValueError, "time unit"): pybamm.QuickPlot(solution, ["a"], time_unit="bad unit") # long solution defaults to hours instead of seconds solution_long = solver.solve(model, np.linspace(0, 1e5)) quick_plot = pybamm.QuickPlot(solution_long, ["a"]) self.assertEqual(quick_plot.time_scaling_factor, 3600) # Test different spatial units quick_plot = pybamm.QuickPlot(solution, ["a"]) self.assertEqual(quick_plot.spatial_unit, "$\mu m$") quick_plot = pybamm.QuickPlot(solution, ["a"], spatial_unit="m") self.assertEqual(quick_plot.spatial_unit, "m") quick_plot = pybamm.QuickPlot(solution, ["a"], spatial_unit="mm") self.assertEqual(quick_plot.spatial_unit, "mm") quick_plot = pybamm.QuickPlot(solution, ["a"], spatial_unit="um") self.assertEqual(quick_plot.spatial_unit, "$\mu m$") with self.assertRaisesRegex(ValueError, "spatial unit"): pybamm.QuickPlot(solution, ["a"], spatial_unit="bad unit") # Test 2D variables model.variables["2D variable"] = disc.process_symbol( pybamm.FullBroadcast(1, "negative particle", {"secondary": "negative electrode"})) quick_plot = pybamm.QuickPlot(solution, ["2D variable"]) quick_plot.plot(0) quick_plot.dynamic_plot(testing=True) quick_plot.slider_update(0.01) with self.assertRaisesRegex(NotImplementedError, "Cannot plot 2D variables"): pybamm.QuickPlot([solution, solution], ["2D variable"]) # Test different variable limits quick_plot = pybamm.QuickPlot( solution, ["a", ["c broadcasted", "c broadcasted"]], variable_limits="tight") self.assertEqual(quick_plot.axis_limits[("a", )][2:], [None, None]) self.assertEqual( quick_plot.axis_limits[("c broadcasted", "c broadcasted")][2:], [None, None]) quick_plot.plot(0) quick_plot.slider_update(1) quick_plot = pybamm.QuickPlot(solution, ["2D variable"], variable_limits="tight") self.assertEqual(quick_plot.variable_limits[("2D variable", )], (None, None)) quick_plot.plot(0) quick_plot.slider_update(1) quick_plot = pybamm.QuickPlot( solution, ["a", ["c broadcasted", "c broadcasted"]], variable_limits={ "a": [1, 2], ("c broadcasted", "c broadcasted"): [3, 4] }, ) self.assertEqual(quick_plot.axis_limits[("a", )][2:], [1, 2]) self.assertEqual( quick_plot.axis_limits[("c broadcasted", "c broadcasted")][2:], [3, 4]) quick_plot.plot(0) quick_plot.slider_update(1) quick_plot = pybamm.QuickPlot(solution, ["a", "b broadcasted"], variable_limits={"a": "tight"}) self.assertEqual(quick_plot.axis_limits[("a", )][2:], [None, None]) self.assertNotEqual(quick_plot.axis_limits[("b broadcasted", )][2:], [None, None]) quick_plot.plot(0) quick_plot.slider_update(1) with self.assertRaisesRegex( TypeError, "variable_limits must be 'fixed', 'tight', or a dict"): pybamm.QuickPlot(solution, ["a", "b broadcasted"], variable_limits="bad variable limits") # Test errors with self.assertRaisesRegex(ValueError, "Mismatching variable domains"): pybamm.QuickPlot(solution, [["a", "b broadcasted"]]) with self.assertRaisesRegex(ValueError, "labels"): pybamm.QuickPlot([solution, solution], ["a"], labels=["sol 1", "sol 2", "sol 3"]) # Remove 'x [m]' from the variables and make sure a key error is raise del solution.model.variables["x [m]"] with self.assertRaisesRegex( KeyError, "Can't find spatial scale for 'negative electrode'"): pybamm.QuickPlot(solution, ["b broadcasted"]) # No variable can be NaN model.variables["NaN variable"] = disc.process_symbol( pybamm.Scalar(np.nan)) with self.assertRaisesRegex( ValueError, "All-NaN variable 'NaN variable' provided"): pybamm.QuickPlot(solution, ["NaN variable"])
def test_failure(self): with self.assertRaisesRegex(TypeError, "solutions must be"): pybamm.QuickPlot(1)
def US06_experiment(reply=False): model = pybamm.lithium_ion.DFN() # import drive cycle from file if reply: drive_cycle = pd.read_csv("drive_cycle.csv", comment="#", header=None).to_numpy() elif not reply: drive_cycle = pd.read_csv("US06.csv", comment="#", header=None).to_numpy() # create interpolant param = model.default_parameter_values timescale = param.evaluate(model.timescale) current_interpolant = pybamm.Interpolant( drive_cycle[:, 0], drive_cycle[:, 1], timescale * pybamm.t ) # set drive cycle param["Current function [A]"] = current_interpolant sim_US06_1 = pybamm.Simulation( model, parameter_values=param, solver=pybamm.CasadiSolver(mode="fast") ) sol_US06_1 = sim_US06_1.solve() if reply: time = foo1.plot_graph(sol_US06_1, sim_US06_1, reply=reply) return time solved = False print("REACHED") while not solved: try: cycle = US06_experiment_cycle() # cycle = ["Charge at 1 A until 4.1 V", "Hold at 4.1 V until 50 mA"] experiment = pybamm.Experiment(cycle) sim_cccv = pybamm.Simulation(model, experiment=experiment) sol_cccv = sim_cccv.solve() new_model = model.set_initial_conditions_from(sol_cccv, inplace=False) sim_US06_2 = pybamm.Simulation( new_model, parameter_values=param, solver=pybamm.CasadiSolver(mode="fast"), ) sol_US06_2 = sim_US06_2.solve() # pybamm.dynamic_plot( # [sol_US06_1, sol_US06_2], # labels=["Default initial conditions", "Fully charged"], # ) solution = [sol_US06_1, sol_US06_2] sim = [sim_US06_1, sim_US06_2] t = solution[0]["Time [s]"] final_time = int(t.entries[len(t.entries) - 1]) time = random.randint(0, final_time) plot = pybamm.QuickPlot( sim, labels=["Default initial conditions", "Fully charged"], time_unit="seconds", ) plot.plot(time) plot.fig.savefig("foo.png", dpi=300) print(sol_US06_1) solved = True except: pass # print("Exception") return time, cycle
geometry = model.default_geometry param.process_geometry(geometry) mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # solve model solutions = [None] * len(models) t_eval = np.linspace(0, 3600 * 2, 1000) for i, model in enumerate(models): solution = model.default_solver.solve(model, t_eval) solutions[i] = solution # plot output_variables = [ "Interfacial current density [A.m-2]", "Electrolyte concentration [mol.m-3]", "Current [A]", "Porosity", "Electrolyte potential [V]", "Terminal voltage [V]", "Negative electrode reaction overpotential", "Positive electrode reaction overpotential", "Sum of interfacial current densities", "Sum of electrolyte reaction source terms", ] plot = pybamm.QuickPlot(solutions, output_variables, linestyles=[":", "--", "-"]) plot.dynamic_plot()
# load model pybamm.set_logging_level("INFO") model = pybamm.lithium_ion.SPMe() # create geometry geometry = model.default_geometry # load parameter values and process model and geometry param = model.default_parameter_values param["Current function"] = pybamm.GetUserCurrent(car_current) param.process_model(model) param.process_geometry(geometry) # set mesh mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # simulate car current for 30 minutes tau = param.process_symbol( pybamm.standard_parameters_lithium_ion.tau_discharge).evaluate(0) t_eval = np.linspace(0, 1800 / tau, 600) solution = model.default_solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot(model, mesh, solution) plot.dynamic_plot()
# build model model.build_model() # create geometry geometry = pybamm.Geometry("1D macro", "1D micro") # process model and geometry param = model.default_parameter_values param.process_model(model) param.process_geometry(geometry) # set mesh # Note: li-ion base model has defaults for mesh and var_pts mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) # discretise model # Note: li-ion base model has default spatial methods disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) # solve model t_eval = np.linspace(0, 3600, 100) solver = pybamm.ScipySolver() solution = solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot(solution) plot.dynamic_plot()
var_pts = model.default_var_pts 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, 7200, 1000) solver = pybamm.CasadiSolver(mode="safe", atol=1e-6, rtol=1e-3) solution = solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot( solution, [ "Working particle concentration [mol.m-3]", "Electrolyte concentration [mol.m-3]", "Current [A]", "Working electrode potential [V]", "Electrolyte potential [V]", "Total electrolyte concentration", "Total lithium in working electrode [mol]", "Working electrode open circuit potential [V]", ["Terminal voltage [V]", "Voltage drop in the cell [V]"], ], time_unit="seconds", spatial_unit="um", ) plot.dynamic_plot()