Skip to content

Commit c2b7e38

Browse files
#492 reorganise and add power
1 parent 7ee11c5 commit c2b7e38

10 files changed

+123
-69
lines changed

examples/scripts/compare_lithium_ion.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
pybamm.set_logging_level("INFO")
1717

1818
# load models
19-
options = {"thermal": "isothermal", "operating mode": "voltage"}
19+
options = {"thermal": "isothermal", "operating mode": "power"}
2020
models = [
2121
pybamm.lithium_ion.SPM(options),
2222
pybamm.lithium_ion.SPMe(options),
@@ -27,7 +27,7 @@
2727
# load parameter values and process models and geometry
2828
param = models[0].default_parameter_values
2929
param["Typical current [A]"] = 1.0
30-
param["Voltage function"] = 4 # voltage
30+
param["Power function"] = -1 # voltage
3131
for model in models:
3232
param.process_model(model)
3333

@@ -51,5 +51,15 @@
5151
solutions[i] = model.default_solver.solve(model, t_eval)
5252

5353
# plot
54-
plot = pybamm.QuickPlot(models, mesh, solutions)
54+
output_variables = [
55+
"Negative particle surface concentration",
56+
"Electrolyte concentration",
57+
"Positive particle surface concentration",
58+
"Current [A]",
59+
"Negative electrode potential [V]",
60+
"Electrolyte potential [V]",
61+
"Terminal power [W]",
62+
"Terminal voltage [V]",
63+
]
64+
plot = pybamm.QuickPlot(models, mesh, solutions, output_variables)
5565
plot.dynamic_plot()

pybamm/models/base_model.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,21 @@ def check_algebraic_equations(self, post_discretisation):
388388
After discretisation, there must be at least one StateVector in each algebraic
389389
equation
390390
"""
391+
vars_in_bcs = set()
392+
for var, side_eqn in self.boundary_conditions.items():
393+
for side, (eqn, typ) in side_eqn.items():
394+
vars_in_bcs.update(
395+
[x.id for x in eqn.pre_order() if isinstance(x, pybamm.Variable)]
396+
)
391397
if not post_discretisation:
392398
# After the model has been defined, each algebraic equation key should
393-
# appear in that algebraic equation
399+
# appear in that algebraic equation, or in the boundary conditions
394400
# this has been relaxed for concatenations for now
395401
for var, eqn in self.algebraic.items():
396-
if not any(x.id == var.id for x in eqn.pre_order()) and not isinstance(
397-
var, pybamm.Concatenation
402+
if not (
403+
any(x.id == var.id for x in eqn.pre_order())
404+
or var.id in vars_in_bcs
405+
or isinstance(var, pybamm.Concatenation)
398406
):
399407
raise pybamm.ModelError(
400408
"each variable in the algebraic eqn keys must appear in the eqn"

pybamm/models/full_battery_models/base_battery_model.py

+24-7
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ def options(self, extra_options):
162162
raise pybamm.OptionError("option {} not recognised".format(name))
163163

164164
# Some standard checks to make sure options are compatible
165-
if options["operating mode"] not in ["current", "voltage"]:
165+
if options["operating mode"] not in [
166+
"current",
167+
"voltage",
168+
"power",
169+
"arbitrary",
170+
]:
166171
raise pybamm.OptionError(
167172
"operating mode '{}' not recognised".format(options["operating mode"])
168173
)
@@ -491,14 +496,22 @@ def set_external_circuit_submodel(self):
491496
e.g. (not necessarily constant-) current, voltage, etc
492497
"""
493498
if self.options["operating mode"] == "current":
499+
self.submodels["external circuit"] = pybamm.external_circuit.CurrentControl(
500+
self.param
501+
)
502+
elif self.options["operating mode"] == "voltage":
503+
self.submodels["external circuit"] = pybamm.external_circuit.VoltageControl(
504+
self.param
505+
)
506+
elif self.options["operating mode"] == "power":
507+
self.submodels["external circuit"] = pybamm.external_circuit.PowerControl(
508+
self.param
509+
)
510+
elif self.options["operating mode"] == "arbitrary":
494511
self.submodels[
495512
"external circuit"
496-
] = pybamm.external_circuit.CurrentControl(self.param)
497-
if self.options["operating mode"] == "voltage":
498-
self.submodels[
499-
"external circuit"
500-
] = pybamm.external_circuit.VoltageControl(self.param)
501-
513+
] = pybamm.external_circuit.FunctionControl(self.param)
514+
502515
def set_tortuosity_submodels(self):
503516
self.submodels["electrolyte tortuosity"] = pybamm.tortuosity.Bruggeman(
504517
self.param, "Electrolyte"
@@ -732,6 +745,10 @@ def set_voltage_variables(self):
732745
self.events["Minimum voltage"] = voltage - self.param.voltage_low_cut
733746
self.events["Maximum voltage"] = voltage - self.param.voltage_high_cut
734747

748+
# Power
749+
I_dim = self.variables["Current [A]"]
750+
self.variables.update({"Terminal power [W]": I_dim * V_dim})
751+
735752
def set_soc_variables(self):
736753
"""
737754
Set variables relating to the state of charge.

pybamm/models/full_battery_models/lead_acid/base_lead_acid_model.py

-13
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,6 @@ def default_solver(self):
5353

5454
def set_standard_output_variables(self):
5555
super().set_standard_output_variables()
56-
# Current
57-
i_cell = pybamm.standard_parameters_lead_acid.current_with_time
58-
i_cell_dim = (
59-
pybamm.standard_parameters_lead_acid.dimensional_current_density_with_time
60-
)
61-
I = pybamm.standard_parameters_lead_acid.dimensional_current_with_time
62-
self.variables.update(
63-
{
64-
"Total current density": i_cell,
65-
"Total current density [A.m-2]": i_cell_dim,
66-
"Current [A]": I,
67-
}
68-
)
6956

7057
# Time
7158
time_scale = pybamm.standard_parameters_lead_acid.tau_discharge
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
from .base_external_circuit import BaseModel
22
from .current_control_external_circuit import CurrentControl
3+
from .function_control_external_circuit import FunctionControl
34
from .voltage_control_external_circuit import VoltageControl
5+
from .power_control_external_circuit import PowerControl
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#
2+
# External circuit with an arbitrary function
3+
#
4+
import pybamm
5+
from .base_external_circuit import BaseModel
6+
7+
8+
class FunctionControl(BaseModel):
9+
"""External circuit with an arbitrary function. """
10+
11+
def __init__(self, param):
12+
super().__init__(param)
13+
14+
def external_circuit_function(self, I, V):
15+
"""
16+
Function that fixes the current, I (in Amps), or voltage, V (in Volts), or a
17+
combination of the two
18+
"""
19+
return pybamm.FunctionParameter("External circuit function", I, V)
20+
21+
def get_fundamental_variables(self):
22+
# Current is a variable
23+
param = self.param
24+
i_cell = pybamm.Variable("Total current density")
25+
I = i_cell * abs(param.I_typ)
26+
i_cell_dim = I / (param.n_electrodes_parallel * param.A_cc)
27+
28+
variables = {
29+
"Total current density": i_cell,
30+
"Total current density [A.m-2]": i_cell_dim,
31+
"Current [A]": I,
32+
}
33+
34+
return variables
35+
36+
def set_initial_conditions(self, variables):
37+
# Initial condition as a guess for consistent initial conditions
38+
i_cell = variables["Total current density"]
39+
self.initial_conditions[i_cell] = self.param.current_with_time
40+
41+
def set_algebraic(self, variables):
42+
# External circuit submodels are always equations on the current
43+
# The external circuit function should fix either the current, or the voltage,
44+
# or a combination (e.g. I*V for power control)
45+
i_cell = variables["Total current density"]
46+
I = variables["Current [A]"]
47+
V = variables["Terminal voltage [V]"]
48+
self.algebraic[i_cell] = self.external_circuit_function(I, V)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# External circuit with power control
3+
#
4+
import pybamm
5+
from .function_control_external_circuit import FunctionControl
6+
7+
8+
class PowerControl(FunctionControl):
9+
"""External circuit with power control. """
10+
11+
def __init__(self, param):
12+
super().__init__(param)
13+
14+
def external_circuit_function(self, I, V):
15+
return I * V - pybamm.FunctionParameter(
16+
"Power function", pybamm.t * self.param.timescale
17+
)
18+

pybamm/models/submodels/external_circuit/voltage_control_external_circuit.py

+6-28
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,17 @@
22
# External circuit with voltage control
33
#
44
import pybamm
5-
from .base_external_circuit import BaseModel
5+
from .function_control_external_circuit import FunctionControl
66

77

8-
class VoltageControl(BaseModel):
8+
class VoltageControl(FunctionControl):
99
"""External circuit with voltage control. """
1010

1111
def __init__(self, param):
1212
super().__init__(param)
1313

14-
def get_fundamental_variables(self):
15-
# Current is a variable
16-
param = self.param
17-
i_cell = pybamm.Variable("Total current density")
18-
I = i_cell * abs(param.I_typ)
19-
i_cell_dim = I / (param.n_electrodes_parallel * param.A_cc)
14+
def external_circuit_function(self, I, V):
15+
return V - pybamm.FunctionParameter(
16+
"Voltage function", pybamm.t * self.param.timescale
17+
)
2018

21-
variables = {
22-
"Total current density": i_cell,
23-
"Total current density [A.m-2]": i_cell_dim,
24-
"Current [A]": I,
25-
}
26-
27-
return variables
28-
29-
def set_initial_conditions(self, variables):
30-
# Initial condition as a guess for consistent initial conditions
31-
i_cell = variables["Total current density"]
32-
self.initial_conditions[i_cell] = self.param.current_with_time
33-
34-
def set_algebraic(self, variables):
35-
# External circuit submodels are always equations on the current
36-
# Fix voltage to be equal to terminal voltage
37-
i_cell = variables["Total current density"]
38-
V = variables["Terminal voltage"]
39-
# TODO: find a way to get rid of 0 * i_cell
40-
self.algebraic[i_cell] = V - self.param.voltage_with_time + 0 * i_cell

pybamm/parameters/standard_parameters_lead_acid.py

-8
Original file line numberDiff line numberDiff line change
@@ -495,11 +495,3 @@ def U_p(c_e_p, T):
495495
dimensional_current_with_time / I_typ * pybamm.Function(np.sign, I_typ)
496496
)
497497

498-
# Voltage
499-
dimensional_voltage_with_time = pybamm.FunctionParameter(
500-
"Voltage function", pybamm.t * timescale
501-
)
502-
voltage_with_time = (
503-
dimensional_voltage_with_time - (U_p_ref - U_n_ref)
504-
) / potential_scale
505-

pybamm/parameters/standard_parameters_lithium_ion.py

-7
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,3 @@ def dUdT_p(c_s_p):
452452
dimensional_current_with_time / I_typ * pybamm.Function(np.sign, I_typ)
453453
)
454454

455-
# Voltage
456-
dimensional_voltage_with_time = pybamm.FunctionParameter(
457-
"Voltage function", pybamm.t * timescale
458-
)
459-
voltage_with_time = (
460-
dimensional_voltage_with_time - (U_p_ref - U_n_ref)
461-
) / potential_scale

0 commit comments

Comments
 (0)