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

Lithium plating #1287

Merged
merged 24 commits into from
Feb 3, 2021
Merged

Lithium plating #1287

merged 24 commits into from
Feb 3, 2021

Conversation

DrSOKane
Copy link
Contributor

@DrSOKane DrSOKane commented Dec 9, 2020

Description

  • The reversible Li plating model of O'Kane et al. (2020) is included as a new submodel
  • An irreversible plating model with similar physics is also included
  • New parameters that are used by these submodels are defined
  • A new variant of the existing Chen 2020 parameter set that includes these new parameters has been added
  • The new parameter set also has temperature-dependent diffusivity in the anode
  • The submodel accounts for SEI layer resistance
  • The submodel does NOT account for temperature variation at this time, but this should be easy to fix

Fixes # 836

Type of change

Please add a line in the relevant section of CHANGELOG.md to document the change (include PR #) - note reverse order of PR #s. If necessary, also add to the list of breaking changes.

  • New feature (non-breaking change which adds functionality)
  • Optimization (back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)

Key checklist:

  • No style issues: $ flake8
  • All tests pass: $ python run-tests.py --unit
  • The documentation builds: $ cd docs and then $ make clean; make html

You can run all three at once, using $ python run-tests.py --quick.

Further checks:

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

Copy link
Member

@valentinsulzer valentinsulzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @DrSOKane , this looks almost ready already!
Just a few minor comments. I'd also like to double-check the non-dimensionalization.

Am I right in reading that the "irreversible" and "reversible" plating models are identical except for the form of j_stripping? If so, we could remove some repeated code by passing options to the submodel and then using the reversible or irreversible form based on that.

Also, the plating options should be added to BaseModel.options and there should be a corresponding set_li_plating_models function

if f"{self.domain} electrode sei film overpotential" in variables:
eta_sei = variables[f"{self.domain} electrode sei film overpotential"]
else:
eta_sei = pybamm.Scalar(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the sei film overpotential should always be defined, sometimes to zero. Otherwise, if the submodels are called in the wrong order, the sei film overpotential might be non-zero but this would miss it


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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

register citation for the model

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still needs to be done (unless you don't want to of course)

"""

def __init__(self, param, domain):
super().__init__(param, domain)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

register citation for the model

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still needs to be done

def set_rhs(self, variables):
c_plated_Li = variables[f"{self.domain} electrode Li plating concentration"]
j_stripping = variables[
f"{self.domain} electrode Li plating " f"interfacial current density"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

second f string not needed

"\n",
"# add plating submodels\n",
"model1.submodels[\"Negative Li plating\"] = pybamm.li_plating.ReversiblePlating(model1.param, \"Negative\")\n",
"model1.submodels[\"Positive Li plating\"] = pybamm.li_plating.NoPlating(model1.param, \"Positive\")\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add these to the model options, etc

@codecov
Copy link

codecov bot commented Dec 9, 2020

Codecov Report

Merging #1287 (c3c3d69) into develop (ee3d67c) will decrease coverage by 0.03%.
The diff coverage is 94.73%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1287      +/-   ##
===========================================
- Coverage    98.15%   98.12%   -0.04%     
===========================================
  Files          272      277       +5     
  Lines        15600    15750     +150     
===========================================
+ Hits         15312    15454     +142     
- Misses         288      296       +8     
Impacted Files Coverage Δ
...m/models/full_battery_models/base_battery_model.py 99.04% <50.00%> (-0.64%) ⬇️
...ttery_models/lithium_ion/base_lithium_ion_model.py 92.72% <50.00%> (-7.28%) ⬇️
.../interface/lithium_plating/irreversible_plating.py 96.87% <96.87%> (ø)
...ls/interface/lithium_plating/reversible_plating.py 96.96% <96.96%> (ø)
...l_battery_models/lead_acid/base_lead_acid_model.py 100.00% <100.00%> (ø)
...ybamm/models/full_battery_models/lead_acid/full.py 100.00% <100.00%> (ø)
...dels/full_battery_models/lead_acid/higher_order.py 98.11% <100.00%> (+0.01%) ⬆️
...ybamm/models/full_battery_models/lead_acid/loqs.py 100.00% <100.00%> (ø)
...bamm/models/full_battery_models/lithium_ion/dfn.py 100.00% <100.00%> (ø)
...bamm/models/full_battery_models/lithium_ion/spm.py 100.00% <100.00%> (ø)
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ee3d67c...145d9a0. Read the comment docs.

Copy link
Sponsor Member

@brosaplanella brosaplanella left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Simon, that looks very nice! 😃 Just some minor comments.

Apart from the inline comments, you should also add tests for no_plating.py and base_plating.py to improve the coverage.

"electrolyte": "lipf6_Nyman2008",
"experiment": "1C_discharge_from_full_Chen2020",
"sei": "example",
"citation": "Chen2020",
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from Chen2020 you should also add the reference for the plating parameters.


> Chang-Hui Chen, Ferran Brosa Planella, Kieran O’Regan, Dominika Gastol, W. Dhammika Widanage, and Emma Kendrick. ["Development of Experimental Techniques for Parameterization of Multi-scale Lithium-ion Battery Models."](https://iopscience.iop.org/article/10.1149/1945-7111/ab9050) Journal of the Electrochemical Society 167 (2020): 080534

and references therein.
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the reference you got the plating parameters from

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment (doesn't apply to this PR only): we might need to reconsider how we structure the parameters as the way it is now we repeat ourselves which makes it easier for inconsistencies to appear.

I would say for the moment is fine, but now that we have several different types of models (SEI, plating, mechanics...) it would be good to think if we can improve. Maybe that is a topic for the new Discussion channel?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just append the SEI parameters to the existing set and update the references? or do some of the other parameters change? For the functions that change can they just live in the Chen folder with a new name, and then users manually update that parameter?

Negative electrode OCP entropic change [V.K-1],0,,
,,,
# Li plating parameters,,,
Li metal partial molar volume [m3.mol-1],1.3E-5,,
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the plating parameters, add the reference where you got them from in the third column (like in the Negative electrode charge transfer coefficient, for example).

import unittest


class TestReversiblePlating(unittest.TestCase):
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you have a typo here and you want to change all the ReversiblePlating by IrreversiblePlating. This would explain why the coverage of irreversible plating is so poor even with these tests.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be done (minor fix)

import unittest


class TestReversiblePlating(unittest.TestCase):
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To get the coverage of reversible plating to 100% you need to add a couple of tests that cover:

lines 44-45:

else:
    eta_sei = pybamm.Scalar(0)

lines 56-63:

if (
    "Negative electrode Li plating interfacial current density" in variables
    and "Positive electrode Li plating interfacial current density" in variables
    and "Li plating interfacial current density" not in variables
 ):
    variables.update(
        self._get_standard_whole_cell_interfacial_current_variables(variables)
    )

You might need to do the same for the irreversible tests.

@DrSOKane
Copy link
Contributor Author

DrSOKane commented Dec 10, 2020

Hi all, thanks for your suggestions. I agree the submodel needs more tests, more citations and to merge the reversible and irreversible submodels since they are mostly the same.

I've also found that the Li plating model does not converge when SEI is present in large amounts. This is the case even when the code adding eta_sei is commented out. A small amount of SEI does not cause this and produce a reasonable result even after 1000 cycles.

@valentinsulzer
Copy link
Member

Is this with constant SEI or varying?

@DrSOKane
Copy link
Contributor Author

It works with constant SEI but fails with varying.

@valentinsulzer
Copy link
Member

If I understand correctly, when you have both SEI and plating, the model is basically trying to solve an equation of the form
j(phi_s - phi_e) + j_sei(phi_s - phi_e) + j_pl(phi_s - phi_e) = I
for phi_s - phi_e, where each j is an exponential or sinh. I can see this being numerically challenging. I suggest we deal with it separately from this PR.

@DrSOKane
Copy link
Contributor Author

Two points:

  1. It is true that the two models in this release are identical save for the expression for j_stripping. However, I also have an unpublished model that differs more substantially. My plan is to keep the two separate submodels but add an option to allow the user to easily pick one.
  2. I do not actually have a meaningful reference for the plating constant. It's true that my paper does provide a value for it, but that's not only for a different cell but for a more physically accurate nonlinear diffusion function, which I've been unable to implement in PyBaMM thus far.

@valentinsulzer
Copy link
Member

Ok makes sense. Would be good to just get something merged (I think coverage is all that is needed) and then we can iterate on it

Copy link
Member

@valentinsulzer valentinsulzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, just consider using the full "lithium plating" instead of "Li plating" for legibility, and do you want to register your paper for citations?

@@ -42,6 +42,9 @@ class BaseBatteryModel(pybamm.BaseModel):
* "interfacial surface area" : str, optional
Sets the model for the interfacial surface area. Can be "constant"
(default) or "varying". Not currently implemented in any of the models.
* "Li plating" : str, optional
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor: I would prefer "lithium plating" to "Li plating"

@@ -85,6 +85,29 @@ def set_sei_submodel(self):
# positive electrode
self.submodels["positive sei"] = pybamm.sei.NoSEI(self.param, "Positive")

def set_li_plating_submodel(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general I don't think anything is lost by calling all these things lithium_plating, in fact makes it easier to read


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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still needs to be done (unless you don't want to of course)

"""

def __init__(self, param, domain):
super().__init__(param, domain)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still needs to be done


# negative electrode
if self.options["Li plating"] == "none":
self.submodels["negative Li plating"] = pybamm.sei.NoPlating(
Copy link
Member

@valentinsulzer valentinsulzer Jan 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should say li_plating.NoPlating. I am surprised the tests didn't pick this up ...

Copy link
Sponsor Member

@brosaplanella brosaplanella left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @tinosulzer comments. Once this and the additional comment on test_irreversible_plating.py are fixed we can merge. Thanks @DrSOKane!

import unittest


class TestReversiblePlating(unittest.TestCase):
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be done (minor fix)

@brosaplanella
Copy link
Sponsor Member

brosaplanella commented Jan 21, 2021

Also, note that there are some conflicts with the main branch (in base_battery_model.py) that also need to be addressed before we can merge it.

@DrSOKane
Copy link
Contributor Author

I'm in the process of renaming everything to lithium_plating or "lithium plating". While I'm doing that, do you want me to add the stripping current to inverse_butler_volmer.py?

@valentinsulzer
Copy link
Member

do you want me to add the stripping current to inverse_butler_volmer.py?

What does this refer to again? In the CurrentForInverseButlerVolmer class?

@DrSOKane
Copy link
Contributor Author

I am referring to the CurrentForInverseButlerVolmer class, yes.

@valentinsulzer
Copy link
Member

Yes that would be good to update too

@DrSOKane
Copy link
Contributor Author

Added plating/stripping current density to CurrentForInverseButlerVolmer and fixed remaining conflicts. I've also added my paper to CITATIONS.txt but not sure how to use the BibTeX entry now that it's there!

@valentinsulzer
Copy link
Member

You need to add pybamm.citations.register("your_paper_bibtex_identifier") to the __init__ of any python class that uses your paper, i.e. the two plating classes. Not sure why the tests didn't start, it might be because there are still some conflicts

@DrSOKane
Copy link
Contributor Author

DrSOKane commented Feb 2, 2021

Hi all, I'm trying to test if examples/lithium-plating.ipynb still runs and I'm getting the pybtex error:


ModuleNotFoundError Traceback (most recent call last)
in
1 get_ipython().run_line_magic('pip', 'install pybamm -q # install PyBaMM if it is not installed')
----> 2 import pybamm
3 import os
4 import numpy as np
5 import matplotlib.pyplot as plt

~/PyBaMM/pybamm/init.py in
70 from .logger import logger, set_logging_level
71 from .settings import settings
---> 72 from .citations import Citations, citations, print_citations
73
74 #

~/PyBaMM/pybamm/citations.py in
6 import pybamm
7 import os
----> 8 import pybtex
9
10

ModuleNotFoundError: No module named 'pybtex'

@valentinsulzer
Copy link
Member

You need to install pybtex, just do pip install -e . and it will do it for you

@brosaplanella
Copy link
Sponsor Member

brosaplanella commented Feb 3, 2021

I think the example tests will still fail because lithium_plating.ipynb does not include pybamm.print_citations() at the end (this is a new test we added recently). You can copy the last block from another notebook (for example Tutorial 2 - Compare models.ipynb, don't copy the block in Tutorial 1 as it is slightly different).

@@ -59,6 +59,12 @@
] = pybamm.electrolyte_conductivity.LeadingOrder(model.param)
model.submodels["negative sei"] = pybamm.sei.NoSEI(model.param, "Negative")
model.submodels["positive sei"] = pybamm.sei.NoSEI(model.param, "Positive")
model.submodels[
"negative lithium plating"
] = pybamm.li_plating.NoPlating(model.param, "Negative")
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be pybamm.lithium_plating (same in the line below). I think it is what is breaking the example tests.

@brosaplanella
Copy link
Sponsor Member

@all-contributors add @DrSOKane for code, examples, documentation and tests

@allcontributors
Copy link
Contributor

@brosaplanella

I've put up a pull request to add @DrSOKane! 🎉

@brosaplanella
Copy link
Sponsor Member

Great work @DrSOKane, thank you very much!

@brosaplanella brosaplanella merged commit 7fb6040 into pybamm-team:develop Feb 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants