Skip to content

Commit

Permalink
#492 more reformatting, need to figure out currents still
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinsulzer committed Nov 23, 2019
1 parent a24543c commit e14811d
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 104 deletions.
84 changes: 15 additions & 69 deletions examples/scripts/charging_strategies.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#
# Compare some charging strategies for lithium-ion batteries
#
# 1. CC-CV: Charge at 1A to 4.2V then 4.2V hold
# 1. CC: Charge at 1A
# 2. CV: Charge at 4.1V
# 3. Constant Power-CV: Charge at 4W to 4.2V then 4.2V hold
# 3. CP: Charge at 4W
#
import argparse
import numpy as np
Expand All @@ -20,93 +20,39 @@
pybamm.set_logging_level("INFO")


class CCCV:
num_switches = 1

def __call__(self, variables):
# switch controls 1A charge vs 4.2V charge
# charging current is negative
a = variables["Switch 1"]
I = variables["Current [A]"]
V = variables["Terminal voltage [V]"]
return (a < 0.5) * (I + 1) + (a > 0.5) * (I)


class CCCP:
num_switches = 1

def __call__(self, variables):
# switch controls 4W charge vs 4.2V charge
# charging current (and hence power) is negative
a = variables["Switch 1"]
I = variables["Current [A]"]
V = variables["Terminal voltage [V]"]
return (a * (V > 0) <= 0) * (I * V + 4) + (a * (V > 0) > 0) * (V - 4.2)


# load models
models = [
pybamm.lithium_ion.SPM({"operating mode": CCCV}, name="CCCV SPM"),
# pybamm.lithium_ion.DFN({"operating mode": "voltage"}, name="CV DFN"),
# pybamm.lithium_ion.DFN({"operating mode": CCCP}, name="CCCP DFN"),
pybamm.lithium_ion.DFN(name="CC DFN"),
pybamm.lithium_ion.DFN({"operating mode": "voltage"}, name="CV DFN"),
pybamm.lithium_ion.DFN({"operating mode": "power"}, name="CP DFN"),
]


# load parameter values and process models and geometry
params = [model.default_parameter_values for model in models]

# 1. CC-CV: Charge at 1C ( A) to 4.2V then 4.2V hold
params[0]["Switch 1"] = 0
params[0]["Upper voltage cut-off [V]"] = 4.15
# 1. Charge at 1A
params[0]["Typical current [A]"] = -0.1

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

# # 3. CP-CV: Charge at 4W to 4.2V then 4.2V hold
# b = pybamm.Parameter("CCCP switch")
# 3. CP-CV: Charge at 4W
params[2]["Power function"] = -0.4


# params[2]["CCCP switch"] = 1 # start with CP
# params[2]["External circuit function"] = cccp

solutions = []
t_eval = np.linspace(0, 1, 100)
for model, param in zip(models, params):
param.process_model(model)

# set mesh
var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 5, var.r_p: 5}

# discretise models
discs = {}
for model in models:
# create geometry
model.convert_to_format = "python"
geometry = model.default_geometry
param.process_geometry(geometry)
mesh = pybamm.Mesh(geometry, models[-1].default_submesh_types, var_pts)
mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts)
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
disc.process_model(model)
discs[model] = disc

# solve models
solver0 = model.default_solver
solution0 = solver0.step(model, 1, npts=1000)
params[0]["Switch 1"] = 1
params[0]["Upper voltage cut-off [V]"] = 4.16
params[0].update_model(models[0], discs[models[0]])
solution0.append(solver0.step(model, 1 - solution0.t[-1], npts=1000))
solutions = [solution0]
# # Step
# solution0 = models[0].default_solver.step(models[0], t_eval)
# # Switch to CV
# params[0].update({"CCCV switch": 0})
# params[0].update_model(models[0], discs[models[0]])
# # Step
# solution0.append(models[0].default_solver.step(models[0], t_eval))

# solution1 = models[1].default_solver.solve(models[1], t_eval)
solutions.append(model.default_solver.solve(model, t_eval))

# solutions = [solution0, solution1]
# plot
output_variables = [
"Negative particle surface concentration",
Expand All @@ -115,7 +61,7 @@ def __call__(self, variables):
"Current [A]",
"Negative electrode potential [V]",
"Electrolyte potential [V]",
"Switch 1",
"Terminal power [W]",
"Terminal voltage [V]",
]
plot = pybamm.QuickPlot(models, mesh, solutions, output_variables)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
class FunctionControl(BaseModel):
"""External circuit with an arbitrary function. """

def __init__(self, param, ExternalCircuitClass):
def __init__(self, param, external_circuit_class):
super().__init__(param)
self.external_circuit_class = ExternalCircuitClass()
self.external_circuit_class = external_circuit_class

def get_fundamental_variables(self):
# Current is a variable
Expand All @@ -26,6 +26,9 @@ def get_fundamental_variables(self):
}

# Add switches
# These are not implemented yet but can be used later with the Experiment class
# to simulate different external circuit conditions sequentially within a
# single model (for example Constant Current - Constant Voltage)
for i in range(self.external_circuit_class.num_switches):
s = pybamm.Parameter("Switch {}".format(i + 1))
variables["Switch {}".format(i + 1)] = s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ class PowerControl(FunctionControl):
"""External circuit with power control. """

def __init__(self, param):
super().__init__(param)
super().__init__(param, ConstantPower())

def external_circuit_function(self, I, V):
return I * V - pybamm.FunctionParameter(
"Power function", pybamm.t * self.param.timescale
)

class ConstantPower:
num_switches = 0

def __call__(self, variables):
I = variables["Current [A]"]
V = variables["Terminal voltage [V]"]
return I * V - pybamm.FunctionParameter("Power function", pybamm.t)

Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ class VoltageControl(FunctionControl):
"""External circuit with voltage control. """

def __init__(self, param):
super().__init__(param)
super().__init__(param, ConstantVoltage())

def external_circuit_function(self, I, V):
return V - pybamm.FunctionParameter(
"Voltage function", pybamm.t * self.param.timescale
)

class ConstantVoltage:
num_switches = 0

def __call__(self, variables):
V = variables["Terminal voltage [V]"]
return V - pybamm.FunctionParameter("Voltage function", pybamm.t)

Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
#
import numpy as np
import pybamm
import tests
import unittest


class TestFunctionControl(unittest.TestCase):
def test_constant_current(self):
class ConstantCurrent:
num_switches = 0

def __call__(self, variables):
I = variables["Current [A]"]
return I + 1

# load models
models = [
pybamm.lithium_ion.SPM(),
pybamm.lithium_ion.SPM({"operating mode": "custom"}),
pybamm.lithium_ion.SPM({"operating mode": ConstantCurrent()}),
]

# load parameter values and process models and geometry
Expand All @@ -21,12 +27,6 @@ def test_constant_current(self):
# First model: 1A charge
params[0]["Typical current [A]"] = -1

# Second model: 1C charge via a function
def constant_current(I, V):
return I + 1

params[1]["External circuit function"] = constant_current

# set parameters and discretise models
for i, model in enumerate(models):
# create geometry
Expand Down Expand Up @@ -57,13 +57,23 @@ def constant_current(I, V):
solutions[1].y,
mesh,
).entries
pv0 = pybamm.post_process_variables(models[0].variables, solutions[0].t, solutions[0].y, mesh)
pv1 = pybamm.post_process_variables(models[1].variables, solutions[1].t, solutions[1].y, mesh)
import ipdb; ipdb.set_trace()
np.testing.assert_array_equal(V0, V1)

def test_constant_voltage(self):
class ConstantVoltage:
num_switches = 0

def __call__(self, variables):
V = variables["Terminal voltage [V]"]
return V - 4.1

# load models
models = [
pybamm.lithium_ion.SPM({"operating mode": "voltage"}),
pybamm.lithium_ion.SPM({"operating mode": "custom"}),
pybamm.lithium_ion.SPM({"operating mode": ConstantVoltage()}),
]

# load parameter values and process models and geometry
Expand All @@ -72,12 +82,6 @@ def test_constant_voltage(self):
# First model: 4.1V charge
params[0]["Voltage function"] = 4.1

# Second model: 4.1V charge via a function
def constant_voltage(I, V):
return V - 4.1

params[1]["External circuit function"] = constant_voltage

# set parameters and discretise models
for i, model in enumerate(models):
# create geometry
Expand Down Expand Up @@ -119,10 +123,18 @@ def constant_voltage(I, V):
np.testing.assert_array_equal(I0, I1)

def test_constant_power(self):
class ConstantPower:
num_switches = 0

def __call__(self, variables):
I = variables["Current [A]"]
V = variables["Terminal voltage [V]"]
return I * V - 4

# load models
models = [
pybamm.lithium_ion.SPM({"operating mode": "power"}),
pybamm.lithium_ion.SPM({"operating mode": "custom"}),
pybamm.lithium_ion.SPM({"operating mode": ConstantPower()}),
]

# load parameter values and process models and geometry
Expand All @@ -131,12 +143,6 @@ def test_constant_power(self):
# First model: 4W charge
params[0]["Power function"] = 4

# Second model: 4W charge via a function
def constant_power(I, V):
return I * V - 4

params[1]["External circuit function"] = constant_power

# set parameters and discretise models
for i, model in enumerate(models):
# create geometry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@
import unittest


class ExternalCircuitFunction:
num_switches = 0

def __call__(self, variables):
I = variables["Current [A]"]
V = variables["Terminal voltage [V]"]
return (
V + I - pybamm.FunctionParameter("Current plus voltage function", pybamm.t)
)


class TestFunctionControl(unittest.TestCase):
def test_public_functions(self):
param = pybamm.standard_parameters_lithium_ion
submodel = pybamm.external_circuit.FunctionControl(param)
submodel = pybamm.external_circuit.FunctionControl(
param, ExternalCircuitFunction
)
variables = {"Terminal voltage [V]": pybamm.Scalar(0)}
std_tests = tests.StandardSubModelTests(submodel, variables)
std_tests.test_all()
Expand Down

0 comments on commit e14811d

Please sign in to comment.