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

Composite model for particle mechanics #4516

Closed
Closed
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0e70d3e
Started modifying porosity change submodel to work with phases
DrSOKane Aug 27, 2024
b8dd013
Porosity now works on composite electrode
DrSOKane Aug 27, 2024
e8fc8f4
Now works for non-composite electrode as well!
DrSOKane Aug 27, 2024
b2825de
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
DrSOKane Sep 5, 2024
b76a2ca
style: pre-commit fixes
pre-commit-ci[bot] Sep 5, 2024
6b87041
changelog
DrSOKane Sep 5, 2024
cd4aa54
Merge branch 'composite-porosity' of https://github.com/DrSOKane/PyBa…
DrSOKane Sep 5, 2024
4758ab8
style fix
DrSOKane Sep 5, 2024
adcb652
Updated tests
DrSOKane Sep 5, 2024
1985fb1
Changed how pref is handled
DrSOKane Sep 7, 2024
9352297
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
DrSOKane Sep 7, 2024
709d634
Added comments to the new if statements
DrSOKane Sep 7, 2024
96d960d
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
DrSOKane Sep 9, 2024
f0a5a79
Why did I not think of this before?!
DrSOKane Sep 9, 2024
3937c54
Merge branch 'develop' of https://github.com/pybamm-team/PyBaMM into …
DrSOKane Sep 10, 2024
7e87880
Merge branch 'develop' into composite-porosity
brosaplanella Sep 11, 2024
47949e7
changelog
DrSOKane Sep 24, 2024
b1b225a
Merge branch 'composite-porosity' of https://github.com/DrSOKane/PyBa…
DrSOKane Sep 24, 2024
04d0d7a
Merge branch 'develop' into composite-porosity
kratman Sep 30, 2024
029cdee
mechanics for composite electrode
mohammedasher Oct 11, 2024
b9a02bb
Fix style issues: remove duplicate function, fix indentation, and rem…
mohammedasher Oct 15, 2024
1056b7c
style: pre-commit fixes
pre-commit-ci[bot] Oct 15, 2024
fd177eb
Merge branch 'develop' into composite_mechanics
brosaplanella Oct 16, 2024
35df164
changelog
DrSOKane Oct 22, 2024
69b366d
changelog
DrSOKane Oct 22, 2024
a218f06
Merge remote-tracking branch 'OKane_composite_porosity/composite-poro…
mohammedasher Oct 23, 2024
c781d00
Merge branch 'composite_mechanics' of https://github.com/mohammedashe…
mohammedasher Oct 23, 2024
dce8d03
Fixed indentation and syntax errors in reaction_driven_porosity.py
mohammedasher Oct 23, 2024
3996799
style: pre-commit fixes
pre-commit-ci[bot] Oct 23, 2024
7576847
phase_name to self.phase_name in reaction_driven_porosity.py
mohammedasher Oct 23, 2024
ee73d55
phase_name to self.phase_name in reaction_driven_porosity.py
mohammedasher Oct 23, 2024
7b18328
style: pre-commit fixes
pre-commit-ci[bot] Oct 23, 2024
07ac6fa
Applied pre-commit fixes after removing ghost files
mohammedasher Oct 23, 2024
460d2ef
Merge branch 'composite_mechanics' of https://github.com/mohammedashe…
mohammedasher Oct 23, 2024
375570a
Merge branch 'develop' into composite_mechanics
brosaplanella Oct 30, 2024
3a2dda5
Merge branch 'develop' into composite_mechanics
mohammedasher Nov 6, 2024
d8d2b6c
Update lithium_ion_parameters.py
mohammedasher Nov 15, 2024
0aefd43
Merge branch 'develop' into composite_mechanics
mohammedasher Dec 18, 2024
3adba7e
style: pre-commit fixes
pre-commit-ci[bot] Dec 18, 2024
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,5 @@ results/

# tests
test_callback.log
PublicPyBaMM_Composite/
PyBaMM/
Comment on lines +140 to +141
Copy link
Member

Choose a reason for hiding this comment

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

These two are repository specific, I would suggest to remove them

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added `BasicDFN` model for sodium-ion batteries ([#4451](https://github.com/pybamm-team/PyBaMM/pull/4451))
- Added sensitivity calculation support for `pybamm.Simulation` and `pybamm.Experiment` ([#4415](https://github.com/pybamm-team/PyBaMM/pull/4415))
- Added OpenMP parallelization to IDAKLU solver for lists of input parameters ([#4449](https://github.com/pybamm-team/PyBaMM/pull/4449))
- Porosity change now works for composite electrode ([#4417](https://github.com/pybamm-team/PyBaMM/pull/4417))
- Added phase-dependent particle options to LAM
([#4369](https://github.com/pybamm-team/PyBaMM/pull/4369))
- Added a lithium ion equivalent circuit model with split open circuit voltages for each electrode (`SplitOCVR`). ([#4330](https://github.com/pybamm-team/PyBaMM/pull/4330))
Expand Down
348 changes: 301 additions & 47 deletions src/pybamm/input/parameters/lithium_ion/Chen2020_composite.py

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions src/pybamm/models/full_battery_models/base_battery_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,13 @@ def __init__(self, extra_options):
if isinstance(options["stress-induced diffusion"], str):
if (
options["stress-induced diffusion"] == "true"
and options["particle mechanics"] == "none"
# and options["particle mechanics"] == "none"
):
raise pybamm.OptionError(
"cannot have stress-induced diffusion without a particle "
"mechanics model"
)
pass
# raise pybamm.OptionError(
# "cannot have stress-induced diffusion without a particle "
# "mechanics model"
# )

if options["working electrode"] != "both":
if options["thermal"] == "x-full":
Expand Down
9 changes: 7 additions & 2 deletions src/pybamm/models/submodels/interface/base_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,14 @@ def _get_standard_volumetric_current_density_variables(self, variables):
a_j_av = pybamm.x_average(a_j)

if reaction_name == "SEI on cracks ":
roughness = variables[f"{Domain} electrode roughness ratio"] - 1
roughness = (
variables[f"{Domain} electrode {self.phase_name}roughness ratio"] - 1
)
roughness_av = (
variables[f"X-averaged {domain} electrode roughness ratio"] - 1
variables[
f"X-averaged {domain} electrode {self.phase_name}roughness ratio"
]
- 1
)
else:
roughness = 1
Expand Down
4 changes: 3 additions & 1 deletion src/pybamm/models/submodels/interface/sei/base_sei.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ def _get_standard_concentration_variables(self, variables):
elif self.reaction == "SEI on cracks":
L_inner_cr = variables[f"{Domain} inner {reaction_name}thickness [m]"]
L_outer_cr = variables[f"{Domain} outer {reaction_name}thickness [m]"]
roughness = variables[f"{Domain} electrode roughness ratio"]
roughness = variables[
f"{Domain} electrode {self.phase_name}roughness ratio"
]

n_inner_cr = L_inner_cr * L_to_n_inner * (roughness - 1)
n_outer_cr = L_outer_cr * L_to_n_outer * (roughness - 1)
Expand Down
3 changes: 1 addition & 2 deletions src/pybamm/models/submodels/particle/base_particle.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def __init__(self, param, domain, options, phase="primary"):

def _get_effective_diffusivity(self, c, T, current):
domain, Domain = self.domain_Domain
domain_param = self.domain_param
phase_param = self.phase_param
domain_options = getattr(self.options, domain)

Expand Down Expand Up @@ -60,7 +59,7 @@ def _get_effective_diffusivity(self, c, T, current):
E = pybamm.r_average(phase_param.E(sto, T))
nu = phase_param.nu
theta_M = Omega / (self.param.R * T) * (2 * Omega * E) / (9 * (1 - nu))
stress_factor = 1 + theta_M * (c - domain_param.c_0)
stress_factor = 1 + theta_M * (c - phase_param.c_0)
else:
stress_factor = 1

Expand Down
20 changes: 10 additions & 10 deletions src/pybamm/models/submodels/particle_mechanics/base_mechanics.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ class BaseMechanics(pybamm.BaseSubModel):

"""

def __init__(self, param, domain, options, phase="primary"):
def __init__(self, param, domain, options, phase):
super().__init__(param, domain, options=options, phase=phase)

def _get_standard_variables(self, l_cr):
domain, Domain = self.domain_Domain
l_cr_av = pybamm.x_average(l_cr)
variables = {
f"{Domain} particle crack length [m]": l_cr,
f"X-averaged {domain} particle crack length [m]": l_cr_av,
f"{Domain} {self.phase_name}particle crack length [m]": l_cr,
f"X-averaged {domain} {self.phase_name}particle crack length [m]": l_cr_av,
}
return variables

Expand Down Expand Up @@ -61,7 +61,7 @@ def _get_mechanical_results(self, variables):
sto = variables[f"{Domain} {phase_name}particle concentration"]
Omega = pybamm.r_average(phase_param.Omega(sto, T))
R0 = phase_param.R
c_0 = domain_param.c_0
c_0 = phase_param.c_0
E0 = pybamm.r_average(phase_param.E(sto, T))
nu = phase_param.nu
L0 = domain_param.L
Expand Down Expand Up @@ -129,19 +129,19 @@ def _get_standard_surface_variables(self, variables):
domain, Domain = self.domain_Domain
phase_name = self.phase_name

l_cr = variables[f"{Domain} particle crack length [m]"]
l_cr = variables[f"{Domain} {self.phase_name}particle crack length [m]"]
a = variables[
f"{Domain} electrode {phase_name}surface area to volume ratio [m-1]"
]
rho_cr = self.domain_param.rho_cr
w_cr = self.domain_param.w_cr
rho_cr = self.phase_param.rho_cr
w_cr = self.phase_param.w_cr
roughness = 1 + 2 * l_cr * rho_cr * w_cr # ratio of cracks to normal surface
a_cr = (roughness - 1) * a # crack surface area to volume ratio

roughness_xavg = pybamm.x_average(roughness)
variables = {
f"{Domain} crack surface to volume ratio [m-1]": a_cr,
f"{Domain} electrode roughness ratio": roughness,
f"X-averaged {domain} electrode roughness ratio": roughness_xavg,
f"{Domain} {self.phase_name}crack surface to volume ratio [m-1]": a_cr,
f"{Domain} electrode {self.phase_name}roughness ratio": roughness,
f"X-averaged {domain} electrode {self.phase_name}roughness ratio": roughness_xavg,
}
return variables
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class CrackPropagation(BaseMechanics):

"""

def __init__(self, param, domain, x_average, options, phase="primary"):
def __init__(self, param, domain, x_average, options, phase):
super().__init__(param, domain, options, phase)
self.x_average = x_average

Expand All @@ -39,17 +39,17 @@ def get_fundamental_variables(self):

if self.x_average is True:
l_cr_av = pybamm.Variable(
f"X-averaged {domain} particle crack length [m]",
f"X-averaged {domain} {self.phase_name}particle crack length [m]",
domain="current collector",
scale=self.domain_param.l_cr_0,
scale=self.phase_param.l_cr_0,
)
l_cr = pybamm.PrimaryBroadcast(l_cr_av, f"{domain} electrode")
else:
l_cr = pybamm.Variable(
f"{Domain} particle crack length [m]",
f"{Domain} {self.phase_name}particle crack length [m]",
domain=f"{domain} electrode",
auxiliary_domains={"secondary": "current collector"},
scale=self.domain_param.l_cr_0,
scale=self.phase_param.l_cr_0,
)

variables = self._get_standard_variables(l_cr)
Expand All @@ -62,18 +62,20 @@ def get_coupled_variables(self, variables):
variables.update(self._get_standard_surface_variables(variables))
variables.update(self._get_mechanical_results(variables))
T = variables[f"{Domain} electrode temperature [K]"]
k_cr = self.domain_param.k_cr(T)
m_cr = self.domain_param.m_cr
b_cr = self.domain_param.b_cr
stress_t_surf = variables[f"{Domain} particle surface tangential stress [Pa]"]
l_cr = variables[f"{Domain} particle crack length [m]"]
k_cr = self.phase_param.k_cr(T)
m_cr = self.phase_param.m_cr
b_cr = self.phase_param.b_cr
stress_t_surf = variables[
f"{Domain} {self.phase_name}particle surface tangential stress [Pa]"
]
l_cr = variables[f"{Domain} {self.phase_name}particle crack length [m]"]
# # compressive stress will not lead to crack propagation
dK_SIF = stress_t_surf * b_cr * pybamm.sqrt(np.pi * l_cr) * (stress_t_surf >= 0)
dl_cr = k_cr * (dK_SIF**m_cr) / 3600 # divide by 3600 to replace t0_cr
variables.update(
{
f"{Domain} particle cracking rate [m.s-1]": dl_cr,
f"X-averaged {domain} particle cracking rate [m.s-1]": pybamm.x_average(
f"{Domain} {self.phase_name}particle cracking rate [m.s-1]": dl_cr,
f"X-averaged {domain} {self.phase_name}particle cracking rate [m.s-1]": pybamm.x_average(
dl_cr
),
}
Expand All @@ -84,21 +86,29 @@ def set_rhs(self, variables):
domain, Domain = self.domain_Domain

if self.x_average is True:
l_cr = variables[f"X-averaged {domain} particle crack length [m]"]
dl_cr = variables[f"X-averaged {domain} particle cracking rate [m.s-1]"]
l_cr = variables[
f"X-averaged {domain} {self.phase_name}particle crack length [m]"
]
dl_cr = variables[
f"X-averaged {domain} {self.phase_name}particle cracking rate [m.s-1]"
]
else:
l_cr = variables[f"{Domain} particle crack length [m]"]
dl_cr = variables[f"{Domain} particle cracking rate [m.s-1]"]
l_cr = variables[f"{Domain} {self.phase_name}particle crack length [m]"]
dl_cr = variables[
f"{Domain} {self.phase_name}particle cracking rate [m.s-1]"
]
self.rhs = {l_cr: dl_cr}

def set_initial_conditions(self, variables):
domain, Domain = self.domain_Domain

l_cr_0 = self.domain_param.l_cr_0
l_cr_0 = self.phase_param.l_cr_0
if self.x_average is True:
l_cr = variables[f"X-averaged {domain} particle crack length [m]"]
else:
l_cr = variables[f"{Domain} particle crack length [m]"]
l_cr = variables[
f"X-averaged {domain} {self.phase_name}particle crack length [m]"
]
l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} electrode")
self.initial_conditions = {l_cr: l_cr_0}

Expand All @@ -108,10 +118,12 @@ def add_events_from(self, variables):
if self.x_average is True:
l_cr = variables[f"X-averaged {domain} particle crack length [m]"]
else:
l_cr = variables[f"{Domain} particle crack length [m]"]
l_cr = variables[
f"X-averaged {domain} {self.phase_name}particle crack length [m]"
]
self.events.append(
pybamm.Event(
f"{domain} particle crack length larger than particle radius",
1 - pybamm.max(l_cr) / self.domain_param.prim.R_typ,
f"{domain} {self.phase_name}particle crack length larger than particle radius",
1 - pybamm.max(l_cr) / self.phase_param.R_typ,
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class NoMechanics(BaseMechanics):
Phase of the particle (default is "primary")
"""

def __init__(self, param, domain, options, phase="primary"):
def __init__(self, param, domain, options, phase):
super().__init__(param, domain, options, phase)

def get_fundamental_variables(self):
Expand All @@ -35,8 +35,8 @@ def get_fundamental_variables(self):
variables = self._get_standard_variables(zero)
variables.update(
{
f"{Domain} particle cracking rate [m.s-1]": zero,
f"X-averaged {domain} particle cracking rate [m.s-1]": zero_av,
f"{Domain} {self.phase_name}particle cracking rate [m.s-1]": zero,
f"X-averaged {domain} {self.phase_name}particle cracking rate [m.s-1]": zero_av,
}
)
return variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SwellingOnly(BaseMechanics):

"""

def __init__(self, param, domain, options, phase="primary"):
def __init__(self, param, domain, options, phase):
super().__init__(param, domain, options, phase)

pybamm.citations.register("Ai2019")
Expand All @@ -39,8 +39,8 @@ def get_fundamental_variables(self):
variables = self._get_standard_variables(zero)
variables.update(
{
f"{Domain} particle cracking rate [m.s-1]": zero,
f"X-averaged {domain} particle cracking rate [m.s-1]": zero_av,
f"{Domain} {self.phase_name}particle cracking rate [m.s-1]": zero,
f"X-averaged {domain} {self.phase_name}particle cracking rate [m.s-1]": zero_av,
}
)
return variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ def __init__(self, param, options, x_average):
def get_coupled_variables(self, variables):
eps_dict = {}
for domain in self.options.whole_cell_domains:
delta_eps_k = 0
if domain == "separator":
delta_eps_k = 0 # separator porosity does not change
pass # separator porosity does not change
else:
Domain = domain.split()[0].capitalize()
L_sei_k = variables[f"{Domain} total SEI thickness [m]"]
Expand All @@ -37,7 +38,9 @@ def get_coupled_variables(self, variables):
L_pl_k = variables[f"{Domain} lithium plating thickness [m]"]
L_dead_k = variables[f"{Domain} dead lithium thickness [m]"]
L_sei_cr_k = variables[f"{Domain} total SEI on cracks thickness [m]"]
roughness_k = variables[f"{Domain} electrode roughness ratio"]
roughness_k = variables[
f"{Domain} electrode {self.phase_name}roughness ratio"
Copy link
Member

Choose a reason for hiding this comment

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

The issue with the phase_name is that this class does not take a phase as argument (see for example how loss_active_material.py does it. However, I don't understand how this model works: you have different values for different phases for the roughness, but the SEI on cracks thickness is only one. Shouldn't you just have one roughness ratio overall?

Copy link
Author

Choose a reason for hiding this comment

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

@DrSOKane could you please advise on how I can go about with introducing phases in the reaction-driven-porosity model? Most of the remaining errors are stemming from this file. Thank you.

Copy link
Contributor

@DrSOKane DrSOKane Dec 19, 2024

Choose a reason for hiding this comment

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

Hi @mohammedasher, you need to move the roughness ratio inside the loop for phase in phases:. Something like this should work:

roughness_k = variables[f"{Domain} total {phase_name}SEI on cracks thickness [m]"]

Then, delete the reference to roughness_k outside the loop (line 36 in my version). phase_name is defined at the start of the loop for phase in phases: so that gets around the problems Ferran rightly pointed out.

Copy link
Author

@mohammedasher mohammedasher Dec 20, 2024

Choose a reason for hiding this comment

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

Hi @DrSOKane....I will define a new for phase in phases: loop; apart from the roughness_k variable, L_sei_k = variables[f"{Domain} total SEI thickness [m]"] also runs into error when the domain is negative (negative electrode). I tried L_sei_k = variables[f"{Phase}: {Domain} total SEI thickness [m]"]', but it did not help.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mohammedasher the code you need is here. Uncomment lines 63-65 and deleted line 36, and it should work.

]

L_tot = (
(L_sei_k - L_sei_0)
Expand All @@ -47,14 +50,15 @@ def get_coupled_variables(self, variables):
)

a_k = variables[
f"{Domain} electrode surface area to volume ratio [m-1]"
f"{Domain} electrode {self.phase_name}"
"surface area to volume ratio [m-1]"
]

# This assumes a thin film so curvature effects are neglected.
# They could be included (e.g. for a sphere it is
# a_n * (L_tot + L_tot ** 2 / R_n + L_tot ** # 3 / (3 * R_n ** 2)))
# but it is not clear if it is relevant or not.
delta_eps_k = -a_k * L_tot
delta_eps_k += -a_k * L_tot

domain_param = self.param.domain_params[domain.split()[0]]
eps_k = domain_param.epsilon_init + delta_eps_k
Expand Down
Loading
Loading