Skip to content

Commit a24543c

Browse files
#492 trying to get charging strategies working
1 parent db3ebbb commit a24543c

File tree

3 files changed

+78
-54
lines changed

3 files changed

+78
-54
lines changed

examples/scripts/charging_strategies.py

+61-34
Original file line numberDiff line numberDiff line change
@@ -19,67 +19,94 @@
1919
else:
2020
pybamm.set_logging_level("INFO")
2121

22+
23+
class CCCV:
24+
num_switches = 1
25+
26+
def __call__(self, variables):
27+
# switch controls 1A charge vs 4.2V charge
28+
# charging current is negative
29+
a = variables["Switch 1"]
30+
I = variables["Current [A]"]
31+
V = variables["Terminal voltage [V]"]
32+
return (a < 0.5) * (I + 1) + (a > 0.5) * (I)
33+
34+
35+
class CCCP:
36+
num_switches = 1
37+
38+
def __call__(self, variables):
39+
# switch controls 4W charge vs 4.2V charge
40+
# charging current (and hence power) is negative
41+
a = variables["Switch 1"]
42+
I = variables["Current [A]"]
43+
V = variables["Terminal voltage [V]"]
44+
return (a * (V > 0) <= 0) * (I * V + 4) + (a * (V > 0) > 0) * (V - 4.2)
45+
46+
2247
# load models
2348
models = [
24-
pybamm.lithium_ion.DFN({"operating mode": "custom"}),
25-
pybamm.lithium_ion.DFN({"operating mode": "voltage"}),
26-
pybamm.lithium_ion.DFN({"operating mode": "custom"}),
49+
pybamm.lithium_ion.SPM({"operating mode": CCCV}, name="CCCV SPM"),
50+
# pybamm.lithium_ion.DFN({"operating mode": "voltage"}, name="CV DFN"),
51+
# pybamm.lithium_ion.DFN({"operating mode": CCCP}, name="CCCP DFN"),
2752
]
2853

2954

3055
# load parameter values and process models and geometry
31-
params = [models[0].default_parameter_values] * 3
56+
params = [model.default_parameter_values for model in models]
3257

3358
# 1. CC-CV: Charge at 1C ( A) to 4.2V then 4.2V hold
34-
a = pybamm.Parameter("CCCV switch")
59+
params[0]["Switch 1"] = 0
60+
params[0]["Upper voltage cut-off [V]"] = 4.15
3561

62+
# # 2. CV: Charge at 4.1V
63+
# params[1]["Voltage function"] = 4.1
3664

37-
def cccv(I, V):
38-
# switch a controls 1A charge vs 4.2V charge
39-
# charging current is negative
40-
return a * (I + 1) + (1 - a) * (V - 4.2)
65+
# # 3. CP-CV: Charge at 4W to 4.2V then 4.2V hold
66+
# b = pybamm.Parameter("CCCP switch")
4167

4268

43-
params[0]["CCCV switch"] = 1 # start with CC
44-
params[0]["External circuit function"] = cccv
69+
# params[2]["CCCP switch"] = 1 # start with CP
70+
# params[2]["External circuit function"] = cccp
4571

46-
# 2. CV: Charge at 4.1V
47-
params[1]["Voltage function"] = 4.1
4872
for model, param in zip(models, params):
4973
param.process_model(model)
5074

51-
# 3. CP-CV: Charge at 4W to 4.2V then 4.2V hold
52-
b = pybamm.Parameter("CCCP switch")
53-
54-
55-
def cccp(I, V):
56-
# switch a controls 1A charge vs 4.2V charge
57-
# charging current is negative
58-
return b * (I * V + 4) + (1 - b) * (V - 4.2)
59-
60-
61-
params[0]["CCCP switch"] = 1 # start with CP
62-
params[0]["External circuit function"] = cccp
63-
6475
# set mesh
6576
var = pybamm.standard_spatial_vars
6677
var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 5, var.r_p: 5}
6778

6879
# discretise models
80+
discs = {}
6981
for model in models:
7082
# create geometry
83+
model.convert_to_format = "python"
7184
geometry = model.default_geometry
7285
param.process_geometry(geometry)
7386
mesh = pybamm.Mesh(geometry, models[-1].default_submesh_types, var_pts)
7487
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
7588
disc.process_model(model)
76-
77-
# solve model
78-
solutions = [None] * len(models)
79-
t_eval = np.linspace(0, 0.3, 100)
80-
for i, model in enumerate(models):
81-
solutions[i] = model.default_solver.solve(model, t_eval)
82-
89+
discs[model] = disc
90+
91+
# solve models
92+
solver0 = model.default_solver
93+
solution0 = solver0.step(model, 1, npts=1000)
94+
params[0]["Switch 1"] = 1
95+
params[0]["Upper voltage cut-off [V]"] = 4.16
96+
params[0].update_model(models[0], discs[models[0]])
97+
solution0.append(solver0.step(model, 1 - solution0.t[-1], npts=1000))
98+
solutions = [solution0]
99+
# # Step
100+
# solution0 = models[0].default_solver.step(models[0], t_eval)
101+
# # Switch to CV
102+
# params[0].update({"CCCV switch": 0})
103+
# params[0].update_model(models[0], discs[models[0]])
104+
# # Step
105+
# solution0.append(models[0].default_solver.step(models[0], t_eval))
106+
107+
# solution1 = models[1].default_solver.solve(models[1], t_eval)
108+
109+
# solutions = [solution0, solution1]
83110
# plot
84111
output_variables = [
85112
"Negative particle surface concentration",
@@ -88,7 +115,7 @@ def cccp(I, V):
88115
"Current [A]",
89116
"Negative electrode potential [V]",
90117
"Electrolyte potential [V]",
91-
"Terminal power [W]",
118+
"Switch 1",
92119
"Terminal voltage [V]",
93120
]
94121
plot = pybamm.QuickPlot(models, mesh, solutions, output_variables)

pybamm/models/full_battery_models/base_battery_model.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def options(self, extra_options):
157157
"particle": "Fickian diffusion",
158158
"thermal": "isothermal",
159159
"thermal current collector": False,
160-
"external submodels": []
160+
"external submodels": [],
161161
}
162162
options = default_options
163163
# any extra options overwrite the default options
@@ -169,12 +169,10 @@ def options(self, extra_options):
169169
raise pybamm.OptionError("option {} not recognised".format(name))
170170

171171
# Some standard checks to make sure options are compatible
172-
if options["operating mode"] not in [
173-
"current",
174-
"voltage",
175-
"power",
176-
"custom",
177-
]:
172+
if not (
173+
options["operating mode"] in ["current", "voltage", "power"]
174+
or callable(options["operating mode"])
175+
):
178176
raise pybamm.OptionError(
179177
"operating mode '{}' not recognised".format(options["operating mode"])
180178
)
@@ -543,10 +541,12 @@ def set_external_circuit_submodel(self):
543541
self.submodels["external circuit"] = pybamm.external_circuit.PowerControl(
544542
self.param
545543
)
546-
elif self.options["operating mode"] == "custom":
544+
elif callable(self.options["operating mode"]):
547545
self.submodels[
548546
"external circuit"
549-
] = pybamm.external_circuit.FunctionControl(self.param)
547+
] = pybamm.external_circuit.FunctionControl(
548+
self.param, self.options["operating mode"]
549+
)
550550

551551
def set_tortuosity_submodels(self):
552552
self.submodels["electrolyte tortuosity"] = pybamm.tortuosity.Bruggeman(

pybamm/models/submodels/external_circuit/function_control_external_circuit.py

+8-11
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,9 @@
88
class FunctionControl(BaseModel):
99
"""External circuit with an arbitrary function. """
1010

11-
def __init__(self, param):
11+
def __init__(self, param, ExternalCircuitClass):
1212
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)
13+
self.external_circuit_class = ExternalCircuitClass()
2014

2115
def get_fundamental_variables(self):
2216
# Current is a variable
@@ -31,6 +25,11 @@ def get_fundamental_variables(self):
3125
"Current [A]": I,
3226
}
3327

28+
# Add switches
29+
for i in range(self.external_circuit_class.num_switches):
30+
s = pybamm.Parameter("Switch {}".format(i + 1))
31+
variables["Switch {}".format(i + 1)] = s
32+
3433
return variables
3534

3635
def set_initial_conditions(self, variables):
@@ -43,6 +42,4 @@ def set_algebraic(self, variables):
4342
# The external circuit function should fix either the current, or the voltage,
4443
# or a combination (e.g. I*V for power control)
4544
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)
45+
self.algebraic[i_cell] = self.external_circuit_class(variables)

0 commit comments

Comments
 (0)