Skip to content

Commit

Permalink
Merge pull request pybamm-team#3995 from pybamm-team/basic-experiments
Browse files Browse the repository at this point in the history
Make basic models compatible with experiments
  • Loading branch information
valentinsulzer authored May 9, 2024
2 parents fadf094 + f214f3c commit fd7d1fd
Show file tree
Hide file tree
Showing 23 changed files with 212 additions and 219 deletions.
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 @@ def __init__(self, name="Composite graphite/silicon Doyle-Fuller-Newman model"):
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 @@ def __init__(self, name="Composite graphite/silicon Doyle-Fuller-Newman model"):
"[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 @@ def __init__(self, name="Composite graphite/silicon Doyle-Fuller-Newman model"):
"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")
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
55 changes: 0 additions & 55 deletions pybamm/models/submodels/external_circuit/base_external_circuit.py
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
64 changes: 64 additions & 0 deletions pybamm/models/submodels/external_circuit/discharge_throughput.py
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
Loading

0 comments on commit fd7d1fd

Please sign in to comment.