Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make basic models compatible with experiments #3995

Merged
merged 17 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Added `plot_thermal_components` to plot the contributions to the total heat generation in a battery ([#4021](https://github.com/pybamm-team/PyBaMM/pull/4021))
- Added functions for normal probability density function (`pybamm.normal_pdf`) and cumulative distribution function (`pybamm.normal_cdf`) ([#3999](https://github.com/pybamm-team/PyBaMM/pull/3999))
- "Basic" models are now compatible with experiments ([#3995](https://github.com/pybamm-team/PyBaMM/pull/3995))
- Updates multiprocess `Pool` in `BaseSolver.solve()` to be constructed with context `fork`. Adds small example for multiprocess inputs. ([#3974](https://github.com/pybamm-team/PyBaMM/pull/3974))
- Lithium plating now works on composite electrodes ([#3919](https://github.com/pybamm-team/PyBaMM/pull/3919))
- Added lithium plating parameters to `Ecker2015` and `Ecker2015_graphite_halfcell` parameter sets ([#3919](https://github.com/pybamm-team/PyBaMM/pull/3919))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Discharge and throughput variables
==================================

Calculates the discharge and throughput variables (capacity and power) for the battery.

.. autoclass:: pybamm.external_circuit.DischargeThroughput
:members:
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ variable to be constant.
.. toctree::
:maxdepth: 1

discharge_throughput
explicit_control_external_circuit
function_control_external_circuit
1 change: 1 addition & 0 deletions pybamm/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def __init__(self, name="Unnamed model"):
self._boundary_conditions = {}
self._variables_by_submodel = {}
self._variables = pybamm.FuzzyDict({})
self._summary_variables = []
self._events = []
self._concatenated_rhs = None
self._concatenated_algebraic = None
Expand Down
3 changes: 3 additions & 0 deletions pybamm/models/full_battery_models/base_battery_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,9 @@ def set_external_circuit_submodel(self):
self.param, self.options["operating mode"], self.options
)
self.submodels["external circuit"] = model
self.submodels["discharge and throughput variables"] = (
pybamm.external_circuit.DischargeThroughput(self.param, self.options)
)

def set_transport_efficiency_submodels(self):
self.submodels["electrolyte transport efficiency"] = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def set_degradation_variables(self):
}
)

def set_summary_variables(self):
def set_default_summary_variables(self):
"""
Sets the default summary variables.
"""
Expand Down
15 changes: 15 additions & 0 deletions pybamm/models/full_battery_models/lithium_ion/basic_dfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__(self, name="Doyle-Fuller-Newman model"):
######################
# Variables that depend on time only are created without a domain
Q = pybamm.Variable("Discharge capacity [A.h]")

# Variables that vary spatially are created with a domain
c_e_n = pybamm.Variable(
"Negative electrolyte concentration [mol.m-3]",
Expand Down Expand Up @@ -240,18 +241,32 @@ def __init__(self, name="Doyle-Fuller-Newman model"):
# (Some) variables
######################
voltage = pybamm.boundary_value(phi_s_p, "right")
num_cells = pybamm.Parameter(
"Number of cells connected in series to make a battery"
)
# The `variables` dictionary contains all variables that might be useful for
# visualising the solution of the model
self.variables = {
"Negative particle concentration [mol.m-3]": c_s_n,
"Negative particle surface concentration [mol.m-3]": c_s_surf_n,
"Electrolyte concentration [mol.m-3]": c_e,
"Negative electrolyte concentration [mol.m-3]": c_e_n,
"Separator electrolyte concentration [mol.m-3]": c_e_s,
"Positive electrolyte concentration [mol.m-3]": c_e_p,
"Positive particle concentration [mol.m-3]": c_s_p,
"Positive particle surface concentration [mol.m-3]": c_s_surf_p,
"Current [A]": I,
"Current variable [A]": I, # for compatibility with pybamm.Experiment
"Negative electrode potential [V]": phi_s_n,
"Electrolyte potential [V]": phi_e,
"Negative electrolyte potential [V]": phi_e_n,
"Separator electrolyte potential [V]": phi_e_s,
"Positive electrolyte potential [V]": phi_e_p,
"Positive electrode potential [V]": phi_s_p,
"Voltage [V]": voltage,
"Battery voltage [V]": voltage * num_cells,
"Time [s]": pybamm.t,
"Discharge capacity [A.h]": Q,
}
# Events specify points at which a solution should terminate
self.events += [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,18 +341,40 @@
ocp_av_p = pybamm.x_average(ocp_p)
a_j_n_p1_av = pybamm.x_average(a_j_n_p1)
a_j_n_p2_av = pybamm.x_average(a_j_n_p2)
num_cells = pybamm.Parameter(
"Number of cells connected in series to make a battery"
)
# The `variables` dictionary contains all variables that might be useful for
# visualising the solution of the model
self.variables = {
"Negative primary particle concentration [mol.m-3]": c_s_n_p1,
"Negative secondary particle concentration [mol.m-3]": c_s_n_p2,
"R-averaged negative primary particle concentration "
"[mol.m-3]": c_s_rav_n_p1,
"R-averaged negative secondary particle concentration "
"[mol.m-3]": c_s_rav_n_p2,
"Average negative primary particle concentration "
"[mol.m-3]": c_s_xrav_n_p1,
"Average negative secondary particle concentration "
"[mol.m-3]": c_s_xrav_n_p2,
"Positive particle concentration [mol.m-3]": c_s_p,
"Average positive particle concentration [mol.m-3]": c_s_xrav_p,
"Electrolyte concentration [mol.m-3]": c_e,
"Negative electrolyte concentration [mol.m-3]": c_e_n,
"Separator electrolyte concentration [mol.m-3]": c_e_s,
"Positive electrolyte concentration [mol.m-3]": c_e_p,
"Negative electrode potential [V]": phi_s_n,
"Electrolyte potential [V]": phi_e,
"Positive electrode potential [V]": phi_s_p,
"Electrolyte potential [V]": phi_e,
"Negative electrolyte potential [V]": phi_e_n,
"Separator electrolyte potential [V]": phi_e_s,
"Positive electrolyte potential [V]": phi_e_p,
"Current [A]": I,
"Current variable [A]": I, # for compatibility with pybamm.Experiment
"Discharge capacity [A.h]": Q,
"Time [s]": pybamm.t,
"Voltage [V]": voltage,
"Battery voltage [V]": voltage * num_cells,
"Negative electrode primary open-circuit potential [V]": ocp_n_p1,
"Negative electrode secondary open-circuit potential [V]": ocp_n_p2,
"X-averaged negative electrode primary open-circuit potential "
Expand All @@ -361,15 +383,6 @@
"[V]": ocp_av_n_p2,
"Positive electrode open-circuit potential [V]": ocp_p,
"X-averaged positive electrode open-circuit potential [V]": ocp_av_p,
"R-averaged negative primary particle concentration "
"[mol.m-3]": c_s_rav_n_p1,
"R-averaged negative secondary particle concentration "
"[mol.m-3]": c_s_rav_n_p2,
"Average negative primary particle concentration "
"[mol.m-3]": c_s_xrav_n_p1,
"Average negative secondary particle concentration "
"[mol.m-3]": c_s_xrav_n_p2,
"Average positive particle concentration [mol.m-3]": c_s_xrav_p,
"Negative electrode primary interfacial current density [A.m-2]": j_n_p1,
"Negative electrode secondary interfacial current density [A.m-2]": j_n_p2,
"X-averaged negative electrode primary interfacial current density "
Expand All @@ -385,7 +398,12 @@
"X-averaged negative electrode secondary volumetric "
"interfacial current density [A.m-3]": a_j_n_p2_av,
}
# Events specify points at which a solution should terminate
self.events += [
pybamm.Event("Minimum voltage [V]", voltage - param.voltage_low_cut),
pybamm.Event("Maximum voltage [V]", param.voltage_high_cut - voltage),
]

@property
def default_parameter_values(self):
return pybamm.ParameterValues("Chen2020_composite")

Check warning on line 409 in pybamm/models/full_battery_models/lithium_ion/basic_dfn_composite.py

View check run for this annotation

Codecov / codecov/patch

pybamm/models/full_battery_models/lithium_ion/basic_dfn_composite.py#L409

Added line #L409 was not covered by tests
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class BasicDFNHalfCell(BaseModel):
"""

def __init__(self, options=None, name="Doyle-Fuller-Newman half cell model"):
options = {"working electrode": "positive"}
super().__init__(options, name)
pybamm.citations.register("Marquis2019")
# `param` is a class containing all the relevant parameters and functions for
Expand Down Expand Up @@ -244,6 +245,10 @@ def __init__(self, options=None, name="Doyle-Fuller-Newman half cell model"):
vdrop_cell = pybamm.boundary_value(phi_s_w, "right") - ref_potential
vdrop_Li = -eta_Li - delta_phis_Li
voltage = vdrop_cell + vdrop_Li
num_cells = pybamm.Parameter(
"Number of cells connected in series to make a battery"
)

c_e_total = pybamm.x_average(eps * c_e)
c_s_surf_w_av = pybamm.x_average(c_s_surf_w)

Expand Down Expand Up @@ -280,22 +285,29 @@ def __init__(self, options=None, name="Doyle-Fuller-Newman half cell model"):
# visualising the solution of the model
self.variables = {
"Time [s]": pybamm.t,
"Discharge capacity [A.h]": Q,
"Positive particle surface concentration [mol.m-3]": c_s_surf_w,
"X-averaged positive particle surface concentration "
"[mol.m-3]": c_s_surf_w_av,
"Positive particle concentration [mol.m-3]": c_s_w,
"Total lithium in positive electrode [mol]": c_s_vol_av * L_w * param.A_cc,
"Electrolyte concentration [mol.m-3]": c_e,
"Separator electrolyte concentration [mol.m-3]": c_e_s,
"Positive electrolyte concentration [mol.m-3]": c_e_w,
"Total lithium in electrolyte [mol]": c_e_total * param.L_x * param.A_cc,
"Current [A]": I,
"Current variable [A]": I, # for compatibility with pybamm.Experiment
"Current density [A.m-2]": i_cell,
"Positive electrode potential [V]": phi_s_w,
"Positive electrode open-circuit potential [V]": U_w(sto_surf_w, T),
"Electrolyte potential [V]": phi_e,
"Separator electrolyte potential [V]": phi_e_s,
"Positive electrolyte potential [V]": phi_e_w,
"Voltage drop in the cell [V]": vdrop_cell,
"Negative electrode exchange current density [A.m-2]": j_Li,
"Negative electrode reaction overpotential [V]": eta_Li,
"Negative electrode potential drop [V]": delta_phis_Li,
"Voltage [V]": voltage,
"Battery voltage [V]": voltage * num_cells,
"Instantaneous power [W.m-2]": i_cell * voltage,
}
9 changes: 9 additions & 0 deletions pybamm/models/full_battery_models/lithium_ion/basic_spm.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,33 @@ def __init__(self, name="Single Particle Model"):
phi_e = -eta_n - param.n.prim.U(sto_surf_n, T)
phi_s_p = eta_p + phi_e + param.p.prim.U(sto_surf_p, T)
V = phi_s_p
num_cells = pybamm.Parameter(
"Number of cells connected in series to make a battery"
)

whole_cell = ["negative electrode", "separator", "positive electrode"]
# The `variables` dictionary contains all variables that might be useful for
# visualising the solution of the model
# Primary broadcasts are used to broadcast scalar quantities across a domain
# into a vector of the right shape, for multiplying with other vectors
self.variables = {
"Time [s]": pybamm.t,
"Discharge capacity [A.h]": Q,
"X-averaged negative particle concentration [mol.m-3]": c_s_n,
"Negative particle surface "
"concentration [mol.m-3]": pybamm.PrimaryBroadcast(
c_s_surf_n, "negative electrode"
),
"Electrolyte concentration [mol.m-3]": pybamm.PrimaryBroadcast(
param.c_e_init_av, whole_cell
),
"X-averaged positive particle concentration [mol.m-3]": c_s_p,
"Positive particle surface "
"concentration [mol.m-3]": pybamm.PrimaryBroadcast(
c_s_surf_p, "positive electrode"
),
"Current [A]": I,
"Current variable [A]": I, # for compatibility with pybamm.Experiment
"Negative electrode potential [V]": pybamm.PrimaryBroadcast(
phi_s_n, "negative electrode"
),
Expand All @@ -167,7 +174,9 @@ def __init__(self, name="Single Particle Model"):
phi_s_p, "positive electrode"
),
"Voltage [V]": V,
"Battery voltage [V]": V * num_cells,
}
# Events specify points at which a solution should terminate
self.events += [
pybamm.Event("Minimum voltage [V]", V - param.voltage_low_cut),
pybamm.Event("Maximum voltage [V]", param.voltage_high_cut - V),
Expand Down
3 changes: 3 additions & 0 deletions pybamm/models/full_battery_models/lithium_ion/dfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,6 @@ def set_electrolyte_potential_submodel(self):
self.submodels[f"{domain} surface potential difference"] = surf_model(
self.param, domain, self.options
)

def set_summary_variables(self):
self.set_default_summary_variables()
3 changes: 3 additions & 0 deletions pybamm/models/full_battery_models/lithium_ion/spm.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,6 @@ def set_electrolyte_potential_submodel(self):
self.submodels[f"{domain} surface potential difference"] = surf_model(
self.param, domain, options=self.options
)

def set_summary_variables(self):
self.set_default_summary_variables()
1 change: 1 addition & 0 deletions pybamm/models/submodels/external_circuit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .base_external_circuit import BaseModel
from .discharge_throughput import DischargeThroughput
from .explicit_control_external_circuit import (
ExplicitCurrentControl,
ExplicitPowerControl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,3 @@ class BaseModel(pybamm.BaseSubModel):

def __init__(self, param, options):
super().__init__(param, options=options)

def get_fundamental_variables(self):
Q_Ah = pybamm.Variable("Discharge capacity [A.h]")
Q_Ah.print_name = "Q_Ah"
# Throughput capacity (cumulative)
Qt_Ah = pybamm.Variable("Throughput capacity [A.h]")
Qt_Ah.print_name = "Qt_Ah"

variables = {
"Discharge capacity [A.h]": Q_Ah,
"Throughput capacity [A.h]": Qt_Ah,
}
if self.options["calculate discharge energy"] == "true":
Q_Wh = pybamm.Variable("Discharge energy [W.h]")
# Throughput energy (cumulative)
Qt_Wh = pybamm.Variable("Throughput energy [W.h]")
variables.update(
{
"Discharge energy [W.h]": Q_Wh,
"Throughput energy [W.h]": Qt_Wh,
}
)
else:
variables.update(
{
"Discharge energy [W.h]": pybamm.Scalar(0),
"Throughput energy [W.h]": pybamm.Scalar(0),
}
)
return variables

def set_initial_conditions(self, variables):
Q_Ah = variables["Discharge capacity [A.h]"]
Qt_Ah = variables["Throughput capacity [A.h]"]
self.initial_conditions[Q_Ah] = pybamm.Scalar(0)
self.initial_conditions[Qt_Ah] = pybamm.Scalar(0)
if self.options["calculate discharge energy"] == "true":
Q_Wh = variables["Discharge energy [W.h]"]
Qt_Wh = variables["Throughput energy [W.h]"]
self.initial_conditions[Q_Wh] = pybamm.Scalar(0)
self.initial_conditions[Qt_Wh] = pybamm.Scalar(0)

def set_rhs(self, variables):
# ODEs for discharge capacity and throughput capacity
Q_Ah = variables["Discharge capacity [A.h]"]
Qt_Ah = variables["Throughput capacity [A.h]"]
I = variables["Current [A]"]
self.rhs[Q_Ah] = I / 3600 # Returns to zero after a complete cycle
self.rhs[Qt_Ah] = abs(I) / 3600 # Increases with each cycle
if self.options["calculate discharge energy"] == "true":
Q_Wh = variables["Discharge energy [W.h]"]
Qt_Wh = variables["Throughput energy [W.h]"]
V = variables["Voltage [V]"]
self.rhs[Q_Wh] = I * V / 3600 # Returns to zero after a complete cycle
self.rhs[Qt_Wh] = abs(I * V) / 3600 # Increases with each cycle
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#
# Variables related to discharge and throughput capacity and energy
#
import pybamm
from .base_external_circuit import BaseModel


class DischargeThroughput(BaseModel):
"""Model calculate discharge and throughput capacity and energy."""

def get_fundamental_variables(self):
Q_Ah = pybamm.Variable("Discharge capacity [A.h]")
Q_Ah.print_name = "Q_Ah"
# Throughput capacity (cumulative)
Qt_Ah = pybamm.Variable("Throughput capacity [A.h]")
Qt_Ah.print_name = "Qt_Ah"

variables = {
"Discharge capacity [A.h]": Q_Ah,
"Throughput capacity [A.h]": Qt_Ah,
}
if self.options["calculate discharge energy"] == "true":
Q_Wh = pybamm.Variable("Discharge energy [W.h]")
# Throughput energy (cumulative)
Qt_Wh = pybamm.Variable("Throughput energy [W.h]")
variables.update(
{
"Discharge energy [W.h]": Q_Wh,
"Throughput energy [W.h]": Qt_Wh,
}
)
else:
variables.update(
{
"Discharge energy [W.h]": pybamm.Scalar(0),
"Throughput energy [W.h]": pybamm.Scalar(0),
}
)
return variables

def set_initial_conditions(self, variables):
Q_Ah = variables["Discharge capacity [A.h]"]
Qt_Ah = variables["Throughput capacity [A.h]"]
self.initial_conditions[Q_Ah] = pybamm.Scalar(0)
self.initial_conditions[Qt_Ah] = pybamm.Scalar(0)
if self.options["calculate discharge energy"] == "true":
Q_Wh = variables["Discharge energy [W.h]"]
Qt_Wh = variables["Throughput energy [W.h]"]
self.initial_conditions[Q_Wh] = pybamm.Scalar(0)
self.initial_conditions[Qt_Wh] = pybamm.Scalar(0)

def set_rhs(self, variables):
# ODEs for discharge capacity and throughput capacity
Q_Ah = variables["Discharge capacity [A.h]"]
Qt_Ah = variables["Throughput capacity [A.h]"]
I = variables["Current [A]"]
self.rhs[Q_Ah] = I / 3600 # Returns to zero after a complete cycle
self.rhs[Qt_Ah] = abs(I) / 3600 # Increases with each cycle
if self.options["calculate discharge energy"] == "true":
Q_Wh = variables["Discharge energy [W.h]"]
Qt_Wh = variables["Throughput energy [W.h]"]
V = variables["Voltage [V]"]
self.rhs[Q_Wh] = I * V / 3600 # Returns to zero after a complete cycle
self.rhs[Qt_Wh] = abs(I * V) / 3600 # Increases with each cycle