Skip to content

Commit

Permalink
Merge pull request #1969 from pybamm-team/issue-1575-discharge-energy
Browse files Browse the repository at this point in the history
Issue 1575 discharge energy
  • Loading branch information
valentinsulzer authored Mar 10, 2022
2 parents abba68e + 7d28451 commit 7cca539
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 60 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Features

- Added "Discharge energy [W.h]", which is the integral of the power in Watts, as an optional output. Set the option "calculate discharge energy" to "true" to get this output ("false" by default, since it can slow down some of the simple models) ([#1969](https://github.com/pybamm-team/PyBaMM/pull/1969)))
- Added an option "calculate heat source for isothermal models" to choose whether or not the heat generation terms are computed when running models with the option `thermal="isothermal"` ([#1958](https://github.com/pybamm-team/PyBaMM/pull/1958))

## Bug fixes
Expand Down
2 changes: 1 addition & 1 deletion examples/notebooks/models/using-submodels.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@
"metadata": {},
"outputs": [],
"source": [
"model.submodels[\"external circuit\"] = pybamm.external_circuit.ExplicitCurrentControl(model.param)"
"model.submodels[\"external circuit\"] = pybamm.external_circuit.ExplicitCurrentControl(model.param, model.options)"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion examples/scripts/custom_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

# set choice of submodels
model.submodels["external circuit"] = pybamm.external_circuit.ExplicitCurrentControl(
model.param
model.param, model.options
)
model.submodels["current collector"] = pybamm.current_collector.Uniform(model.param)
model.submodels["thermal"] = pybamm.thermal.isothermal.Isothermal(model.param)
Expand Down
35 changes: 25 additions & 10 deletions pybamm/models/full_battery_models/base_battery_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class BatteryModelOptions(pybamm.FuzzyDict):
where a 2-tuple of strings can be provided instead to indicate a different
option for the negative and positive electrodes.
* "calculate discharge energy": str
Whether to calculate the discharge energy. Must be one of "true" or
"false". "false" is the default, since calculating the discharge
energy can be computationally expensive for simple models like SPM.
* "cell geometry" : str
Sets the geometry of the cell. Can be "pouch" (default) or
"arbitrary". The arbitrary geometry option solves a 1D electrochemical
Expand Down Expand Up @@ -168,6 +172,7 @@ class BatteryModelOptions(pybamm.FuzzyDict):

def __init__(self, extra_options):
self.possible_options = {
"calculate discharge energy": ["false", "true"],
"cell geometry": ["arbitrary", "pouch"],
"calculate heat source for isothermal models": ["false", "true"],
"convection": ["none", "uniform transverse", "full transverse"],
Expand Down Expand Up @@ -922,34 +927,44 @@ def set_external_circuit_submodel(self):
e.g. (not necessarily constant-) current, voltage, etc
"""
if self.options["operating mode"] == "current":
model = pybamm.external_circuit.ExplicitCurrentControl(self.param)
model = pybamm.external_circuit.ExplicitCurrentControl(
self.param, self.options
)
elif self.options["operating mode"] == "voltage":
model = pybamm.external_circuit.VoltageFunctionControl(self.param)
model = pybamm.external_circuit.VoltageFunctionControl(
self.param, self.options
)
elif self.options["operating mode"] == "power":
model = pybamm.external_circuit.PowerFunctionControl(
self.param, "algebraic"
self.param, self.options, "algebraic"
)
elif self.options["operating mode"] == "differential power":
model = pybamm.external_circuit.PowerFunctionControl(
self.param, "differential without max"
self.param, self.options, "differential without max"
)
elif self.options["operating mode"] == "explicit power":
model = pybamm.external_circuit.ExplicitPowerControl(self.param)
model = pybamm.external_circuit.ExplicitPowerControl(
self.param, self.options
)
elif self.options["operating mode"] == "resistance":
model = pybamm.external_circuit.ResistanceFunctionControl(
self.param, "algebraic"
self.param, self.options, "algebraic"
)
elif self.options["operating mode"] == "differential resistance":
model = pybamm.external_circuit.ResistanceFunctionControl(
self.param, "differential without max"
self.param, self.options, "differential without max"
)
elif self.options["operating mode"] == "explicit resistance":
model = pybamm.external_circuit.ExplicitResistanceControl(self.param)
model = pybamm.external_circuit.ExplicitResistanceControl(
self.param, self.options
)
elif self.options["operating mode"] == "CCCV":
model = pybamm.external_circuit.CCCVFunctionControl(self.param)
model = pybamm.external_circuit.CCCVFunctionControl(
self.param, self.options
)
elif callable(self.options["operating mode"]):
model = pybamm.external_circuit.FunctionControl(
self.param, self.options["operating mode"]
self.param, self.options["operating mode"], self.options
)
self.submodels["external circuit"] = model

Expand Down
14 changes: 10 additions & 4 deletions pybamm/models/full_battery_models/lead_acid/loqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,26 @@ def set_external_circuit_submodel(self):
if self.options["operating mode"] == "current":
self.submodels[
"leading order external circuit"
] = pybamm.external_circuit.LeadingOrderExplicitCurrentControl(self.param)
] = pybamm.external_circuit.LeadingOrderExplicitCurrentControl(
self.param, self.options
)
elif self.options["operating mode"] == "voltage":
self.submodels[
"leading order external circuit"
] = pybamm.external_circuit.LeadingOrderVoltageFunctionControl(self.param)
] = pybamm.external_circuit.LeadingOrderVoltageFunctionControl(
self.param, self.options
)
elif self.options["operating mode"] == "power":
self.submodels[
"leading order external circuit"
] = pybamm.external_circuit.LeadingOrderPowerFunctionControl(self.param)
] = pybamm.external_circuit.LeadingOrderPowerFunctionControl(
self.param, self.options
)
elif callable(self.options["operating mode"]):
self.submodels[
"leading order external circuit"
] = pybamm.external_circuit.LeadingOrderFunctionControl(
self.param, self.options["operating mode"]
self.param, self.options["operating mode"], self.options
)

def set_current_collector_submodel(self):
Expand Down
5 changes: 3 additions & 2 deletions pybamm/models/standard_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

class StandardVariables:
def __init__(self):
# Discharge capacity
self.Q = pybamm.Variable("Discharge capacity [A.h]")
# Discharge capacity and energy
self.Q_Ah = pybamm.Variable("Discharge capacity [A.h]")
self.Q_Wh = pybamm.Variable("Discharge energy [W.h]")

# Electrolyte concentration
self.c_e_n = pybamm.Variable(
Expand Down
38 changes: 26 additions & 12 deletions pybamm/models/submodels/external_circuit/base_external_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,46 @@
class BaseModel(pybamm.BaseSubModel):
"""Model to represent the behaviour of the external circuit."""

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

def get_fundamental_variables(self):
Q = pybamm.standard_variables.Q
variables = {"Discharge capacity [A.h]": Q}
Q_Ah = pybamm.standard_variables.Q_Ah
variables = {"Discharge capacity [A.h]": Q_Ah}
if self.options["calculate discharge energy"] == "true":
Q_Wh = pybamm.standard_variables.Q_Wh
variables.update({"Discharge energy [W.h]": Q_Wh})
return variables

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

def set_rhs(self, variables):
# ODE for discharge capacity
Q = variables["Discharge capacity [A.h]"]
Q_Ah = variables["Discharge capacity [A.h]"]
I = variables["Current [A]"]
self.rhs[Q] = I * self.param.timescale / 3600

self.rhs[Q_Ah] = I * self.param.timescale / 3600
if self.options["calculate discharge energy"] == "true":
Q_Wh = variables["Discharge energy [W.h]"]
V = variables["Terminal voltage [V]"]
self.rhs[Q_Wh] = I * V * self.param.timescale / 3600


class LeadingOrderBaseModel(BaseModel):
"""Model to represent the behaviour of the external circuit, at leading order."""

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

def get_fundamental_variables(self):
Q = pybamm.Variable("Leading-order discharge capacity [A.h]")
variables = {"Discharge capacity [A.h]": Q}
Q_Ah = pybamm.Variable("Leading-order discharge capacity [A.h]")
variables = {"Discharge capacity [A.h]": Q_Ah}
if self.options["calculate discharge energy"] == "true":
Q_Wh = pybamm.Variable("Leading-order discharge energy [W.h]")
variables.update({"Discharge energy [W.h]": Q_Wh})
return variables
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
class ExplicitCurrentControl(BaseModel):
"""External circuit with current control."""

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

def get_fundamental_variables(self):
# Current is given as a function of time
Expand All @@ -34,8 +34,8 @@ def get_fundamental_variables(self):
class ExplicitPowerControl(BaseModel):
"""External circuit with current set explicitly to hit target power."""

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

def get_coupled_variables(self, variables):
param = self.param
Expand Down Expand Up @@ -64,8 +64,8 @@ def get_coupled_variables(self, variables):
class ExplicitResistanceControl(BaseModel):
"""External circuit with current set explicitly to hit target resistance."""

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

def get_coupled_variables(self, variables):
param = self.param
Expand Down Expand Up @@ -94,5 +94,5 @@ def get_coupled_variables(self, variables):
class LeadingOrderExplicitCurrentControl(ExplicitCurrentControl, LeadingOrderBaseModel):
"""External circuit with current control, for leading order models."""

def __init__(self, param):
super().__init__(param)
def __init__(self, param, options):
super().__init__(param, options)
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ class FunctionControl(BaseModel):
The parameters to use for this submodel
external_circuit_function : callable
The function that controls the current
options : dict
Dictionary of options to use for the submodel
control : str, optional
The type of control to use. Must be one of 'algebraic' (default)
or 'differential'.
"""

def __init__(self, param, external_circuit_function, control="algebraic"):
super().__init__(param)
def __init__(self, param, external_circuit_function, options, control="algebraic"):
super().__init__(param, options)
self.external_circuit_function = external_circuit_function
self.control = control

Expand Down Expand Up @@ -81,8 +83,8 @@ class VoltageFunctionControl(FunctionControl):
External circuit with voltage control, implemented as an extra algebraic equation.
"""

def __init__(self, param):
super().__init__(param, self.constant_voltage, control="algebraic")
def __init__(self, param, options):
super().__init__(param, self.constant_voltage, options, control="algebraic")

def constant_voltage(self, variables):
V = variables["Terminal voltage [V]"]
Expand All @@ -94,8 +96,8 @@ def constant_voltage(self, variables):
class PowerFunctionControl(FunctionControl):
"""External circuit with power control."""

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

def constant_power(self, variables):
I = variables["Current [A]"]
Expand All @@ -115,8 +117,8 @@ def constant_power(self, variables):
class ResistanceFunctionControl(FunctionControl):
"""External circuit with resistance control."""

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

def constant_resistance(self, variables):
I = variables["Current [A]"]
Expand Down Expand Up @@ -146,8 +148,8 @@ class CCCVFunctionControl(FunctionControl):
"""

def __init__(self, param):
super().__init__(param, self.cccv, control="differential with max")
def __init__(self, param, options):
super().__init__(param, self.cccv, options, control="differential with max")
pybamm.citations.register("Mohtat2021")

def cccv(self, variables):
Expand All @@ -165,8 +167,8 @@ def cccv(self, variables):
class LeadingOrderFunctionControl(FunctionControl, LeadingOrderBaseModel):
"""External circuit with an arbitrary function, at leading order."""

def __init__(self, param, external_circuit_class, control="algebraic"):
super().__init__(param, external_circuit_class, control=control)
def __init__(self, param, external_circuit_function, options, control="algebraic"):
super().__init__(param, external_circuit_function, options, control=control)

def _get_current_variable(self):
return pybamm.Variable("Leading-order total current density")
Expand All @@ -178,8 +180,8 @@ class LeadingOrderVoltageFunctionControl(LeadingOrderFunctionControl):
at leading order.
"""

def __init__(self, param):
super().__init__(param, self.constant_voltage, control="algebraic")
def __init__(self, param, options):
super().__init__(param, self.constant_voltage, options, control="algebraic")

def constant_voltage(self, variables):
V = variables["Terminal voltage [V]"]
Expand All @@ -191,8 +193,8 @@ def constant_voltage(self, variables):
class LeadingOrderPowerFunctionControl(LeadingOrderFunctionControl):
"""External circuit with power control, at leading order."""

def __init__(self, param):
super().__init__(param, self.constant_power, control="algebraic")
def __init__(self, param, options):
super().__init__(param, self.constant_power, options, control="algebraic")

def constant_power(self, variables):
I = variables["Current [A]"]
Expand Down
10 changes: 5 additions & 5 deletions pybamm/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ def set_up_model_for_experiment_old(self, model):
# FunctionControl submodel
# create the FunctionControl submodel and extract variables
external_circuit_variables = pybamm.external_circuit.FunctionControl(
model.param, None
model.param, None, model.options
).get_fundamental_variables()

# Perform the replacement
Expand Down Expand Up @@ -396,7 +396,7 @@ def set_up_model_for_experiment_new(self, model):
# create the FunctionControl submodel and extract variables
external_circuit_variables = (
pybamm.external_circuit.FunctionControl(
model.param, None, control=control
model.param, None, model.options, control=control
).get_fundamental_variables()
)

Expand Down Expand Up @@ -470,23 +470,23 @@ def set_up_model_for_experiment_new(self, model):
new_model.algebraic[
i_cell
] = pybamm.external_circuit.VoltageFunctionControl(
new_model.param
new_model.param, model.options
).constant_voltage(
new_model.variables
)
elif op_inputs["Power switch"] == 1:
new_model.algebraic[
i_cell
] = pybamm.external_circuit.PowerFunctionControl(
new_model.param, control="algebraic"
new_model.param, new_model.options, control="algebraic"
).constant_power(
new_model.variables
)
elif op_inputs["CCCV switch"] == 1:
new_model.rhs[
i_cell
] = pybamm.external_circuit.CCCVFunctionControl(
new_model.param
new_model.param, new_model.options
).cccv(
new_model.variables
)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_citations.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def test_mohtat_2021(self):

citations._reset()
self.assertNotIn("Mohtat2021", citations._papers_to_cite)
pybamm.external_circuit.CCCVFunctionControl(None)
pybamm.external_circuit.CCCVFunctionControl(None, None)
self.assertIn("Mohtat2021", citations._papers_to_cite)

def test_sripad_2020(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
}

PRINT_OPTIONS_OUTPUT = """\
'calculate discharge energy': 'false' (possible: ['false', 'true'])
'cell geometry': 'pouch' (possible: ['arbitrary', 'pouch'])
'calculate heat source for isothermal models': 'false' (possible: ['false', 'true'])
'convection': 'none' (possible: ['none', 'uniform transverse', 'full transverse'])
Expand Down
Loading

0 comments on commit 7cca539

Please sign in to comment.