Skip to content

Commit

Permalink
Merge pull request #1257 from pybamm-team/issue-1207-composite-surface
Browse files Browse the repository at this point in the history
#1207 add composite surface form
  • Loading branch information
rtimms committed Nov 26, 2020
2 parents 834be0c + 07dffe2 commit 0d34872
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 31 deletions.
13 changes: 12 additions & 1 deletion CHANGELOG.md
@@ -1,3 +1,14 @@
# [Unreleased](https://github.com/pybamm-team/PyBaMM)

## Features
- Added composite surface form electrolyte models: `CompositeDifferential` and `CompositeAlgebraic` ([#1207](https://github.com/pybamm-team/PyBaMM/issues/1207))

## Optimizations

## Bug fixes

## Breaking changes

# [v0.3.0](https://github.com/pybamm-team/PyBaMM) - 2020-11-22

This release introduces a new aging model for particle swelling and cracking, a new reduced-order model (TSPMe), and a parameter set for A123 LFP cells. Additionally, there have been several backend optimizations to speed up model creation and solving, and other minor features and bug fixes.
Expand Down Expand Up @@ -36,7 +47,7 @@ This release introduces a new aging model for particle swelling and cracking, a
## Breaking changes

- Operations such as `1*x` and `0+x` now directly return `x`. This can be bypassed by explicitly creating the binary operators, e.g. `pybamm.Multiplication(1, x)` ([#1252](https://github.com/pybamm-team/PyBaMM/pull/1252))
- The parameters "Positive/Negative particle distribution in x" and "Positive/Negative surface area per unit volume distribution in x" have been deprecated. Instead, users can provide "Positive/Negative particle radius [m]" and "Positive/Negative surface area per unit volume [m-1]" directly as functions of through-cell position (x [m]) ([#1237](https://github.com/pybamm-team/PyBaMM/pull/1237))
- The parameters "Positive/Negative particle distribution in x" and "Positive/Negative surface area per unit volume distribution in x" have been deprecated. Instead, users can provide "Positive/Negative particle radius [m]" and "Positive/Negative surface area per unit volume [m-1]" directly as functions of through-cell position (x [m]) ([#1237](https://github.com/pybamm-team/PyBaMM/pull/1237))

# [v0.2.4](https://github.com/pybamm-team/PyBaMM/tree/v0.2.4) - 2020-09-07

Expand Down
4 changes: 4 additions & 0 deletions examples/scripts/calendar_ageing.py
Expand Up @@ -5,9 +5,13 @@

models = [
pb.lithium_ion.SPM({"sei": "reaction limited"}),
pb.lithium_ion.SPMe({"sei": "reaction limited"}),
pb.lithium_ion.SPM(
{"sei": "reaction limited", "surface form": "algebraic"}, name="Algebraic SPM"
),
pb.lithium_ion.SPMe(
{"sei": "reaction limited", "surface form": "algebraic"}, name="Algebraic SPMe"
),
pb.lithium_ion.DFN({"sei": "reaction limited"}),
]

Expand Down
61 changes: 35 additions & 26 deletions pybamm/models/full_battery_models/lithium_ion/spme.py
Expand Up @@ -81,22 +81,31 @@ def set_tortuosity_submodels(self):

def set_interfacial_submodel(self):

self.submodels["negative interface"] = pybamm.interface.InverseButlerVolmer(
self.param, "Negative", "lithium-ion main", self.options
)
self.submodels["positive interface"] = pybamm.interface.InverseButlerVolmer(
self.param, "Positive", "lithium-ion main", self.options
)
self.submodels[
"negative interface current"
] = pybamm.interface.CurrentForInverseButlerVolmer(
self.param, "Negative", "lithium-ion main"
)
self.submodels[
"positive interface current"
] = pybamm.interface.CurrentForInverseButlerVolmer(
self.param, "Positive", "lithium-ion main"
)
if self.options["surface form"] is False:
self.submodels["negative interface"] = pybamm.interface.InverseButlerVolmer(
self.param, "Negative", "lithium-ion main", self.options
)
self.submodels["positive interface"] = pybamm.interface.InverseButlerVolmer(
self.param, "Positive", "lithium-ion main", self.options
)
self.submodels[
"negative interface current"
] = pybamm.interface.CurrentForInverseButlerVolmer(
self.param, "Negative", "lithium-ion main"
)
self.submodels[
"positive interface current"
] = pybamm.interface.CurrentForInverseButlerVolmer(
self.param, "Positive", "lithium-ion main"
)
else:
self.submodels["negative interface"] = pybamm.interface.ButlerVolmer(
self.param, "Negative", "lithium-ion main", self.options
)

self.submodels["positive interface"] = pybamm.interface.ButlerVolmer(
self.param, "Positive", "lithium-ion main", self.options
)

def set_particle_submodel(self):

Expand Down Expand Up @@ -137,6 +146,8 @@ def set_positive_electrode_submodel(self):

def set_electrolyte_submodel(self):

surf_form = pybamm.electrolyte_conductivity.surface_potential_form

if self.options["electrolyte conductivity"] not in [
"default",
"composite",
Expand All @@ -158,17 +169,15 @@ def set_electrolyte_submodel(self):
"electrolyte conductivity"
] = pybamm.electrolyte_conductivity.Integrated(self.param)
elif self.options["surface form"] == "differential":
raise NotImplementedError(
"surface form '{}' has not been implemented for SPMe yet".format(
self.options["surface form"]
)
)
for domain in ["Negative", "Separator", "Positive"]:
self.submodels[
domain.lower() + " electrolyte conductivity"
] = surf_form.CompositeDifferential(self.param, domain)
elif self.options["surface form"] == "algebraic":
raise NotImplementedError(
"surface form '{}' has not been implemented for SPMe yet".format(
self.options["surface form"]
)
)
for domain in ["Negative", "Separator", "Positive"]:
self.submodels[
domain.lower() + " electrolyte conductivity"
] = surf_form.CompositeAlgebraic(self.param, domain)

self.submodels["electrolyte diffusion"] = pybamm.electrolyte_diffusion.Full(
self.param
Expand Down
@@ -1,6 +1,12 @@
# Full order models
from .full_surface_form_conductivity import FullAlgebraic, FullDifferential

# Composite models
from .composite_surface_form_conductivity import (
CompositeDifferential,
CompositeAlgebraic,
)

# Leading-order models
from .leading_surface_form_conductivity import (
LeadingOrderDifferential,
Expand Down
@@ -0,0 +1,158 @@
#
# Class for composite surface form electrolyte conductivity employing stefan-maxwell
#
import pybamm

from ..composite_conductivity import Composite


class BaseModel(Composite):
"""
Base class for composite conservation of charge in the electrolyte employing
the Stefan-Maxwell constitutive equations employing the surface potential difference
formulation.
Parameters
----------
param : parameter class
The parameters to use for this submodel
domain : str
The domain in which the model holds
reactions : dict
Dictionary of reaction terms
**Extends:** :class:`pybamm.electrolyte_conductivity.Composite`
"""

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

def get_fundamental_variables(self):

if self.domain == "Negative":
delta_phi = pybamm.standard_variables.delta_phi_n_av
elif self.domain == "Separator":
return {}
elif self.domain == "Positive":
delta_phi = pybamm.standard_variables.delta_phi_p_av

variables = self._get_standard_surface_potential_difference_variables(delta_phi)
return variables

def set_initial_conditions(self, variables):

if self.domain == "Separator":
return

delta_phi = variables[
"X-averaged "
+ self.domain.lower()
+ " electrode surface potential difference"
]
if self.domain == "Negative":
delta_phi_init = self.param.U_n(self.param.c_n_init(0), self.param.T_init)
elif self.domain == "Positive":
delta_phi_init = self.param.U_p(self.param.c_p_init(1), self.param.T_init)

self.initial_conditions = {delta_phi: delta_phi_init}

def set_boundary_conditions(self, variables):
if self.domain == "Negative":
phi_e = variables["Electrolyte potential"]
self.boundary_conditions = {
phi_e: {
"left": (pybamm.Scalar(0), "Neumann"),
"right": (pybamm.Scalar(0), "Neumann"),
}
}


class CompositeDifferential(BaseModel):
"""
Composite model for conservation of charge in the electrolyte employing the
Stefan-Maxwell constitutive equations employing the surface potential difference
formulation and where capacitance is present.
Parameters
----------
param : parameter class
The parameters to use for this submodel
**Extends:** :class:`BaseModel`
"""

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

def set_rhs(self, variables):
if self.domain == "Separator":
return

param = self.param

sum_j = variables[
"Sum of x-averaged "
+ self.domain.lower()
+ " electrode interfacial current densities"
]

sum_j_av = variables[
"X-averaged "
+ self.domain.lower()
+ " electrode total interfacial current density"
]
delta_phi = variables[
"X-averaged "
+ self.domain.lower()
+ " electrode surface potential difference"
]

if self.domain == "Negative":
C_dl = param.C_dl_n
elif self.domain == "Positive":
C_dl = param.C_dl_p

self.rhs[delta_phi] = 1 / C_dl * (sum_j_av - sum_j)


class CompositeAlgebraic(BaseModel):
"""
Composite model for conservation of charge in the electrolyte employing the
Stefan-Maxwell constitutive equations employing the surface potential difference
formulation.
Parameters
----------
param : parameter class
The parameters to use for this submodel
**Extends:** :class:`BaseModel`
"""

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

def set_algebraic(self, variables):
if self.domain == "Separator":
return

sum_j = variables[
"Sum of x-averaged "
+ self.domain.lower()
+ " electrode interfacial current densities"
]

sum_j_av = variables[
"X-averaged "
+ self.domain.lower()
+ " electrode total interfacial current density"
]
delta_phi = variables[
"X-averaged "
+ self.domain.lower()
+ " electrode surface potential difference"
]

self.algebraic[delta_phi] = sum_j_av - sum_j
Expand Up @@ -110,13 +110,13 @@ def test_particle_shape_user(self):

def test_surface_form_differential(self):
options = {"surface form": "differential"}
with self.assertRaises(NotImplementedError):
pybamm.lithium_ion.SPMe(options)
model = pybamm.lithium_ion.SPMe(options)
model.check_well_posedness()

def test_surface_form_algebraic(self):
options = {"surface form": "algebraic"}
with self.assertRaises(NotImplementedError):
pybamm.lithium_ion.SPMe(options)
model = pybamm.lithium_ion.SPMe(options)
model.check_well_posedness()

def test_integrated_conductivity(self):
options = {"electrolyte conductivity": "integrated"}
Expand Down
@@ -0,0 +1,76 @@
#
# Test leading surface form stefan maxwell electrolyte conductivity submodel
#

import pybamm
import tests
import unittest


class TestCompositeModel(unittest.TestCase):
def test_public_functions(self):
param = pybamm.LithiumIonParameters()
a = pybamm.PrimaryBroadcast(0, "current collector")
a_n = pybamm.FullBroadcast(
pybamm.Scalar(0), ["negative electrode"], "current collector"
)
a_s = pybamm.FullBroadcast(pybamm.Scalar(0), ["separator"], "current collector")
a_p = pybamm.FullBroadcast(
pybamm.Scalar(0), ["positive electrode"], "current collector"
)
c_e_n = pybamm.standard_variables.c_e_n
c_e_s = pybamm.standard_variables.c_e_s
c_e_p = pybamm.standard_variables.c_e_p
variables = {
"Leading-order current collector current density": a,
"Negative electrolyte concentration": c_e_n,
"Separator electrolyte concentration": c_e_s,
"Positive electrolyte concentration": c_e_p,
"X-averaged electrolyte concentration": a,
"X-averaged negative electrode potential": a,
"X-averaged negative electrode surface potential difference": a,
"Leading-order x-averaged negative electrode porosity": a,
"Leading-order x-averaged separator porosity": a,
"Leading-order x-averaged positive electrode porosity": a,
"Leading-order x-averaged negative electrolyte tortuosity": a,
"Leading-order x-averaged separator tortuosity": a,
"Leading-order x-averaged positive electrolyte tortuosity": a,
"X-averaged cell temperature": a,
"Current collector current density": a,
"Negative electrode porosity": a_n,
"Sum of x-averaged negative electrode interfacial current densities": a,
"X-averaged negative electrode total interfacial current density": a,
"Current collector current density": a,
"Negative electrolyte potential": a_n,
"Negative electrolyte current density": a_n,
"Separator electrolyte potential": a_s,
"Separator electrolyte current density": a_s,
"Positive electrode porosity": a_p,
"Sum of x-averaged positive electrode interfacial current densities": a,
"X-averaged positive electrode total interfacial current density": a,
}

spf = pybamm.electrolyte_conductivity.surface_potential_form
submodel = spf.CompositeAlgebraic(param, "Negative")
std_tests = tests.StandardSubModelTests(submodel, variables)
std_tests.test_all()
submodel = spf.CompositeDifferential(param, "Negative")
std_tests = tests.StandardSubModelTests(submodel, variables)
std_tests.test_all()

submodel = spf.CompositeAlgebraic(param, "Positive")
std_tests = tests.StandardSubModelTests(submodel, variables)
std_tests.test_all()
submodel = spf.CompositeDifferential(param, "Positive")
std_tests = tests.StandardSubModelTests(submodel, variables)
std_tests.test_all()


if __name__ == "__main__":
print("Add -v for more debug output")
import sys

if "-v" in sys.argv:
debug = True
pybamm.settings.debug_mode = True
unittest.main()

0 comments on commit 0d34872

Please sign in to comment.