Source code for pybamm.plotting.plot_voltage_components

#
# Method for plotting voltage components
#
import numpy as np

from pybamm.util import import_optional_dependency
from pybamm.simulation import Simulation
from pybamm.solvers.solution import Solution


[docs] def plot_voltage_components( input_data, ax=None, show_legend=True, split_by_electrode=False, show_plot=True, **kwargs_fill, ): """ Generate a plot showing the component overpotentials that make up the voltage Parameters ---------- input_data : :class:`pybamm.Solution` or :class:`pybamm.Simulation` Solution or Simulation object from which to extract voltage components. ax : matplotlib Axis, optional The axis on which to put the plot. If None, a new figure and axis is created. show_legend : bool, optional Whether to display the legend. Default is True split_by_electrode : bool, optional Whether to show the overpotentials for the negative and positive electrodes separately. Default is False. show_plot : bool, optional Whether to show the plots. Default is True. Set to False if you want to only display the plot after plt.show() has been called. kwargs_fill Keyword arguments: :obj:`matplotlib.axes.Axes.fill_between` """ # Check if the input is a Simulation and extract Solution if isinstance(input_data, Simulation): solution = input_data.solution elif isinstance(input_data, Solution): solution = input_data plt = import_optional_dependency("matplotlib.pyplot") # Set a default value for alpha, the opacity kwargs_fill = {"alpha": 0.6, **kwargs_fill} if ax is not None: fig = None show_plot = False else: fig, ax = plt.subplots(figsize=(8, 4)) if split_by_electrode is False: overpotentials = [ "Battery particle concentration overpotential [V]", "X-averaged battery reaction overpotential [V]", "X-averaged battery concentration overpotential [V]", "X-averaged battery electrolyte ohmic losses [V]", "X-averaged battery solid phase ohmic losses [V]", ] labels = [ "Particle concentration overpotential", "Reaction overpotential", "Electrolyte concentration overpotential", "Ohmic electrolyte overpotential", "Ohmic electrode overpotential", ] else: overpotentials = [ "Battery negative particle concentration overpotential [V]", "Battery positive particle concentration overpotential [V]", "X-averaged battery negative reaction overpotential [V]", "X-averaged battery positive reaction overpotential [V]", "X-averaged battery concentration overpotential [V]", "X-averaged battery electrolyte ohmic losses [V]", "X-averaged battery negative solid phase ohmic losses [V]", "X-averaged battery positive solid phase ohmic losses [V]", ] labels = [ "Negative particle concentration overpotential", "Positive particle concentration overpotential", "Negative reaction overpotential", "Positive reaction overpotential", "Electrolyte concentration overpotential", "Ohmic electrolyte overpotential", "Ohmic negative electrode overpotential", "Ohmic positive electrode overpotential", ] # Plot # Initialise time = solution["Time [h]"].entries if split_by_electrode is False: ocv = solution["Battery open-circuit voltage [V]"] initial_ocv = ocv(time[0]) ocv = ocv.entries ax.fill_between( time, ocv, initial_ocv, **kwargs_fill, label="Open-circuit voltage" ) else: ocp_n = solution["Battery negative electrode bulk open-circuit potential [V]"] ocp_p = solution["Battery positive electrode bulk open-circuit potential [V]"] initial_ocp_n = ocp_n(time[0]) initial_ocp_p = ocp_p(time[0]) initial_ocv = initial_ocp_p - initial_ocp_n delta_ocp_n = ocp_n.entries - initial_ocp_n delta_ocp_p = ocp_p.entries - initial_ocp_p ax.fill_between( time, initial_ocv - delta_ocp_n, initial_ocv, **kwargs_fill, label="Negative open-circuit potential", ) ax.fill_between( time, initial_ocv - delta_ocp_n + delta_ocp_p, initial_ocv - delta_ocp_n, **kwargs_fill, label="Positive open-circuit potential", ) ocv = initial_ocv - delta_ocp_n + delta_ocp_p top = ocv # Plot components for overpotential, label in zip(overpotentials, labels): # negative overpotentials are positive for a discharge and negative for a charge # so we have to multiply by -1 to show them correctly sgn = -1 if "negative" in overpotential else 1 bottom = top + sgn * solution[overpotential].entries ax.fill_between(time, bottom, top, **kwargs_fill, label=label) top = bottom V = solution["Battery voltage [V]"].entries ax.plot(time, V, "k--", label="Voltage") if show_legend: leg = ax.legend(loc="center left", bbox_to_anchor=(1.05, 0.5), frameon=True) leg.get_frame().set_edgecolor("k") if fig is not None: fig.tight_layout() # Labels ax.set_xlim([time[0], time[-1]]) ax.set_xlabel("Time [h]") y_min, y_max = ( 0.98 * min(np.nanmin(V), np.nanmin(ocv)), 1.02 * (max(np.nanmax(V), np.nanmax(ocv))), ) ax.set_ylim([y_min, y_max]) if show_plot: # pragma: no cover plt.show() return fig, ax