Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lfp parameters #1209

Merged
merged 27 commits into from
Oct 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
976c66f
This is a test commit, please ignore it
dalbamont Apr 8, 2020
f47d630
Added parameters for LFP cathod - based on Prada 2013, Peyman, and La…
dalbamont May 2, 2020
7a5f151
Merging before adding LFP and A123 parameters
dalbamont May 2, 2020
7c5dc4c
Removed incorrect file
dalbamont May 2, 2020
be13aa9
Adjusted formating to agree with flake8
dalbamont May 2, 2020
eff587b
Merge pull request #1036 from pybamm-team/develop
rtimms Jun 1, 2020
66dc659
Merge pull request #1043 from pybamm-team/develop
tlestang Jun 9, 2020
ee2a54f
Merge pull request #1047 from pybamm-team/develop
rtimms Jun 12, 2020
dd26cc7
Merge pull request #1054 from pybamm-team/develop
tlestang Jun 12, 2020
09a3c08
Merge pull request #1095 from pybamm-team/develop
valentinsulzer Jul 1, 2020
b7da2cd
The state used to create the parameter evolution figures included in …
dalbamont Jul 8, 2020
23b2927
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
dalbamont Jul 8, 2020
0e20e51
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
dalbamont Jul 13, 2020
f00b8d1
Merge pull request #1139 from pybamm-team/develop
valentinsulzer Sep 7, 2020
f5b6479
Cleaning code charges, updating input files
dalbamont Sep 11, 2020
a56f477
Merge remote-tracking branch 'upstream/master' into cleaned
dalbamont Sep 11, 2020
803ba50
change to reaction rate
dalbamont Sep 11, 2020
cedd3d6
updating files to comply with PEP8
dalbamont Sep 16, 2020
c61f292
merge develop
valentinsulzer Oct 19, 2020
0efbcb7
Merge branch 'develop' into lfp-parameters
valentinsulzer Oct 22, 2020
20a9b92
add refs for parameters
valentinsulzer Oct 22, 2020
5c26f30
some cleaning up
valentinsulzer Oct 22, 2020
1b0c370
fix test
valentinsulzer Oct 22, 2020
b4e1325
ferran comments
valentinsulzer Oct 23, 2020
79b914f
Merge branch 'develop' of github.com:pybamm-team/PyBaMM into lfp-para…
valentinsulzer Oct 23, 2020
54844e5
changelog
valentinsulzer Oct 23, 2020
90250c4
codacy
valentinsulzer Oct 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 parameter set for an A123 LFP cell ([#1209](https://github.com/pybamm-team/PyBaMM/pull/1209))
- Added variables related to equivalent circuit models ([#1204](https://github.com/pybamm-team/PyBaMM/pull/1204))
- Added an example script to check conservation of lithium ([#1186](https://github.com/pybamm-team/PyBaMM/pull/1186))
- Added `erf` and `erfc` functions ([#1184](https://github.com/pybamm-team/PyBaMM/pull/1184))
Expand Down
61 changes: 31 additions & 30 deletions examples/scripts/compare_spectral_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

# load model
# don't use new_copy
models = [pybamm.lithium_ion.DFN(name="Finite Volume"),
pybamm.lithium_ion.DFN(name="Spectral Volume")]
models = [
pybamm.lithium_ion.DFN(name="Finite Volume"),
pybamm.lithium_ion.DFN(name="Spectral Volume"),
]

# create geometry
geometries = [m.default_geometry for m in models]
Expand All @@ -24,32 +26,31 @@
var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 1, var.x_s: 1, var.x_p: 1, var.r_n: 1, var.r_p: 1}
# the Finite Volume method also works on spectral meshes
meshes = [pybamm.Mesh(
geometry,
{
"negative particle": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh,
{"order": order}
),
"positive particle": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh,
{"order": order}
),
"negative electrode": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh,
{"order": order}
),
"separator": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh,
{"order": order}
),
"positive electrode": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh,
{"order": order}
),
"current collector": pybamm.SubMesh0D,
},
var_pts) for geometry in geometries]
meshes = [
pybamm.Mesh(
geometry,
{
"negative particle": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh, {"order": order}
),
"positive particle": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh, {"order": order}
),
"negative electrode": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh, {"order": order}
),
"separator": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh, {"order": order}
),
"positive electrode": pybamm.MeshGenerator(
pybamm.SpectralVolume1DSubMesh, {"order": order}
),
"current collector": pybamm.SubMesh0D,
},
var_pts,
)
for geometry in geometries
]

# discretise model
disc_fv = pybamm.Discretisation(meshes[0], models[0].default_spatial_methods)
Expand All @@ -61,8 +62,8 @@
"negative electrode": pybamm.SpectralVolume(order=order),
"separator": pybamm.SpectralVolume(order=order),
"positive electrode": pybamm.SpectralVolume(order=order),
"current collector": pybamm.ZeroDimensionalSpatialMethod()
}
"current collector": pybamm.ZeroDimensionalSpatialMethod(),
},
)

disc_fv.process_model(models[0])
Expand Down
37 changes: 31 additions & 6 deletions pybamm/CITATIONS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,15 @@ year={2019},
publisher={The Electrochemical Society}
}

@article{Mohtat2020,
author = {Mohtat, Peyman and Siegel, Jason B and Stefanopoulou, Anna G},
title = {{High C-rate Differential Expansion and Voltage Model for Li-ion Batteries}},
journal = {Submitted for publication},
year = {2019},
publisher={ECSarXiv}
@article{mohtat2020differential,
title={Differential Expansion and Voltage Model for Li-ion Batteries at Practical Charging Rates},
author={Mohtat, Peyman and Lee, Suhak and Sulzer, Valentin and Siegel, Jason B and Stefanopoulou, Anna G},
journal={Journal of The Electrochemical Society},
volume={167},
number={11},
pages={110561},
year={2020},
publisher={IOP Publishing}
}

@article{scikits-odes,
Expand Down Expand Up @@ -204,3 +207,25 @@ primaryClass={physics.app-ph},
year={2005},
publisher={IOP Publishing}
}

@article{lain2019design,
title={Design Strategies for High Power vs. High Energy Lithium Ion Cells},
author={Lain, Michael J and Brandon, James and Kendrick, Emma},
journal={Batteries},
volume={5},
number={4},
pages={64},
year={2019},
publisher={Multidisciplinary Digital Publishing Institute}
}

@article{prada2013simplified,
title={A simplified electrochemical and thermal aging model of LiFePO4-graphite Li-ion batteries: power and capacity fade simulations},
author={Prada, Eric and Di Domenico, D and Creff, Y and Bernard, J and Sauvant-Moynot, Val{\'e}rie and Huet, Fran{\c{c}}ois},
journal={Journal of The Electrochemical Society},
volume={160},
number={4},
pages={A616},
year={2013},
publisher={IOP Publishing}
}
75 changes: 40 additions & 35 deletions pybamm/expression_tree/operations/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

import numbers
from platform import system

if system() != "Windows":
import jax

from jax.config import config

config.update("jax_enable_x64", True)


Expand Down Expand Up @@ -95,30 +97,35 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False):
dummy_eval_left = symbol.children[0].evaluate_for_shape()
dummy_eval_right = symbol.children[1].evaluate_for_shape()
if not to_dense and scipy.sparse.issparse(dummy_eval_left):
symbol_str = "{0}.multiply({1})"\
.format(children_vars[0], children_vars[1])
symbol_str = "{0}.multiply({1})".format(
children_vars[0], children_vars[1]
)
elif not to_dense and scipy.sparse.issparse(dummy_eval_right):
symbol_str = "{1}.multiply({0})"\
.format(children_vars[0], children_vars[1])
symbol_str = "{1}.multiply({0})".format(
children_vars[0], children_vars[1]
)
else:
symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1])
elif isinstance(symbol, pybamm.Division):
dummy_eval_left = symbol.children[0].evaluate_for_shape()
if not to_dense and scipy.sparse.issparse(dummy_eval_left):
symbol_str = "{0}.multiply(1/{1})"\
.format(children_vars[0], children_vars[1])
symbol_str = "{0}.multiply(1/{1})".format(
children_vars[0], children_vars[1]
)
else:
symbol_str = "{0} / {1}".format(children_vars[0], children_vars[1])

elif isinstance(symbol, pybamm.Inner):
dummy_eval_left = symbol.children[0].evaluate_for_shape()
dummy_eval_right = symbol.children[1].evaluate_for_shape()
if not to_dense and scipy.sparse.issparse(dummy_eval_left):
symbol_str = "{0}.multiply({1})"\
.format(children_vars[0], children_vars[1])
symbol_str = "{0}.multiply({1})".format(
children_vars[0], children_vars[1]
)
elif not to_dense and scipy.sparse.issparse(dummy_eval_right):
symbol_str = "{1}.multiply({0})"\
.format(children_vars[0], children_vars[1])
symbol_str = "{1}.multiply({0})".format(
children_vars[0], children_vars[1]
)
else:
symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1])

Expand Down Expand Up @@ -294,18 +301,20 @@ def __init__(self, symbol):
# extract constants in generated function
for i, symbol_id in enumerate(constants.keys()):
const_name = id_to_python_variable(symbol_id, True)
python_str = '{} = constants[{}]\n'.format(const_name, i) + python_str
python_str = "{} = constants[{}]\n".format(const_name, i) + python_str

# constants passed in as an ordered dict, convert to list
self._constants = list(constants.values())

# indent code
python_str = ' ' + python_str
python_str = python_str.replace('\n', '\n ')
python_str = " " + python_str
python_str = python_str.replace("\n", "\n ")

# add function def to first line
python_str = 'def evaluate(constants, t=None, y=None, '\
'y_dot=None, inputs=None, known_evals=None):\n' + python_str
python_str = (
"def evaluate(constants, t=None, y=None, "
"y_dot=None, inputs=None, known_evals=None):\n" + python_str
)

# calculate the final variable that will output the result of calling `evaluate`
# on `symbol`
Expand All @@ -315,21 +324,18 @@ def __init__(self, symbol):

# add return line
if symbol.is_constant() and isinstance(result_value, numbers.Number):
python_str = python_str + '\n return ' + str(result_value)
python_str = python_str + "\n return " + str(result_value)
else:
python_str = python_str + '\n return ' + result_var
python_str = python_str + "\n return " + result_var

# store a copy of examine_jaxpr
python_str = python_str + \
'\nself._evaluate = evaluate'
python_str = python_str + "\nself._evaluate = evaluate"

self._python_str = python_str
self._symbol = symbol

# compile and run the generated python code,
compiled_function = compile(
python_str, result_var, "exec"
)
compiled_function = compile(python_str, result_var, "exec")
exec(compiled_function)

def evaluate(self, t=None, y=None, y_dot=None, inputs=None, known_evals=None):
Expand Down Expand Up @@ -377,7 +383,7 @@ def __init__(self, symbol):
constants, python_str = pybamm.to_python(symbol, debug=False, to_dense=True)

# replace numpy function calls to jax numpy calls
python_str = python_str.replace('np.', 'jax.numpy.')
python_str = python_str.replace("np.", "jax.numpy.")

# convert all numpy constants to device vectors
for symbol_id in constants:
Expand All @@ -387,18 +393,20 @@ def __init__(self, symbol):
# extract constants in generated function
for i, symbol_id in enumerate(constants.keys()):
const_name = id_to_python_variable(symbol_id, True)
python_str = '{} = constants[{}]\n'.format(const_name, i) + python_str
python_str = "{} = constants[{}]\n".format(const_name, i) + python_str

# constants passed in as an ordered dict, convert to list
self._constants = list(constants.values())

# indent code
python_str = ' ' + python_str
python_str = python_str.replace('\n', '\n ')
python_str = " " + python_str
python_str = python_str.replace("\n", "\n ")

# add function def to first line
python_str = 'def evaluate_jax(constants, t=None, y=None, '\
'y_dot=None, inputs=None, known_evals=None):\n' + python_str
python_str = (
"def evaluate_jax(constants, t=None, y=None, "
"y_dot=None, inputs=None, known_evals=None):\n" + python_str
)

# calculate the final variable that will output the result of calling `evaluate`
# on `symbol`
Expand All @@ -408,18 +416,15 @@ def __init__(self, symbol):

# add return line
if symbol.is_constant() and isinstance(result_value, numbers.Number):
python_str = python_str + '\n return ' + str(result_value)
python_str = python_str + "\n return " + str(result_value)
else:
python_str = python_str + '\n return ' + result_var
python_str = python_str + "\n return " + result_var

# store a copy of examine_jaxpr
python_str = python_str + \
'\nself._evaluate_jax = evaluate_jax'
python_str = python_str + "\nself._evaluate_jax = evaluate_jax"

# compile and run the generated python code,
compiled_function = compile(
python_str, result_var, "exec"
)
compiled_function = compile(python_str, result_var, "exec")
exec(compiled_function)

self._jit_evaluate = jax.jit(self._evaluate_jax, static_argnums=(0, 4, 5))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from pybamm import exp, constants, Parameter
valentinsulzer marked this conversation as resolved.
Show resolved Hide resolved


def LFP_electrolyte_exchange_current_density_kashkooli2017(c_e, c_s_surf, T): # , 1
"""
Exchange-current density for Butler-Volmer reactions between LFP and electrolyte

References
----------
.. [1] Kashkooli, A. G., Amirfazli, A., Farhad, S., Lee, D. U., Felicelli, S., Park,
H. W., ... & Chen, Z. (2017). Representative volume element model of lithium-ion
battery electrodes based on X-ray nano-tomography. Journal of Applied
Electrochemistry, 47(3), 281-293.

Parameters
----------
c_e : :class:`pybamm.Symbol`
Electrolyte concentration [mol.m-3]
c_s_surf : :class:`pybamm.Symbol`
Particle concentration [mol.m-3]
T : :class:`pybamm.Symbol`
Temperature [K]

Returns
-------
:class:`pybamm.Symbol`
Exchange-current density [A.m-2]
"""

m_ref = 6 * 10 ** (-7) # (A/m2)(mol/m3)**1.5 - includes ref concentrations
E_r = 39570
arrhenius = exp(E_r / constants.R * (1 / 298.15 - 1 / T))
c_p_max = Parameter("Maximum concentration in positive electrode [mol.m-3]")

return (
m_ref * arrhenius * c_e ** 0.5 * c_s_surf ** 0.5 * (c_p_max - c_s_surf) ** 0.5
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pybamm import exp


def LFP_ocp_ashfar2017(sto):
"""
Open-circuit potential for LFP

References
----------
.. [1] Afshar, S., Morris, K., & Khajepour, A. (2017). Efficient electrochemical
model for lithium-ion cells. arXiv preprint arXiv:1709.03970.

Parameters
----------
sto : :class:`pybamm.Symbol`
Stochiometry of material (li-fraction)

"""

c1 = -150 * sto
c2 = -30 * (1 - sto)
k = 3.4077 - 0.020269 * sto + 0.5 * exp(c1) - 0.9 * exp(c2)

return k
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Lithium Cobalt Oxide cathode parameters
valentinsulzer marked this conversation as resolved.
Show resolved Hide resolved

Parameters for an LFP cathode, from the paper

> Prada, E., Di Domenico, D., Creff, Y., Bernard, J., Sauvant-Moynot, V., & Huet, F. (2013). A simplified electrochemical and thermal aging model of LiFePO4-graphite Li-ion batteries: power and capacity fade simulations. [Journal of The Electrochemical Society](https://doi.org/10.1149/2.053304jes), 160(4), A616.

and references therein. The functions used for OCP and exchange-current density are from separate references (documented within the functions), to provide better fit to data
Loading