Skip to content

Commit

Permalink
Merge pull request #4330 from parkec3/ocvr_ecm
Browse files Browse the repository at this point in the history
ECM with split OCV
  • Loading branch information
valentinsulzer authored Sep 19, 2024
2 parents 48dbb68 + 5bb146f commit 4cda488
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 2 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
# [Unreleased](https://github.com/pybamm-team/PyBaMM/)

## Features

- 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))
- 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))

## Optimizations

- Removed the `start_step_offset` setting and disabled minimum `dt` warnings for drive cycles with the (`IDAKLUSolver`). ([#4416](https://github.com/pybamm-team/PyBaMM/pull/4416))

## Features

- Added phase-dependent particle options to LAM #4369

## Breaking changes

- The parameters "... electrode OCP entropic change [V.K-1]" and "... electrode volume change" are now expected to be functions of stoichiometry only instead of functions of both stoichiometry and maximum concentration ([#4427](https://github.com/pybamm-team/PyBaMM/pull/4427))
- Renamed `set_events` function to `add_events_from` to better reflect its purpose. ([#4421](https://github.com/pybamm-team/PyBaMM/pull/4421))


# [v24.9.0](https://github.com/pybamm-team/PyBaMM/tree/v24.9.0) - 2024-09-03

## Features
Expand Down
7 changes: 7 additions & 0 deletions docs/source/api/models/lithium_ion/ecm_split_ocv.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Equivalent Circuit Model with Split OCV (SplitOCVR)
=====================================================

.. autoclass:: pybamm.lithium_ion.SplitOCVR
:members:

.. footbibliography::
1 change: 1 addition & 0 deletions docs/source/api/models/lithium_ion/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Lithium-ion Models
msmr
yang2017
electrode_soh
ecm_split_ocv
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
from .Yang2017 import Yang2017
from .mpm import MPM
from .msmr import MSMR
from .basic_splitOCVR import SplitOCVR

__all__ = ['Yang2017', 'base_lithium_ion_model', 'basic_dfn',
'basic_dfn_composite', 'basic_dfn_half_cell', 'basic_spm', 'dfn',
'electrode_soh', 'electrode_soh_half_cell', 'mpm', 'msmr',
'newman_tobias', 'spm', 'spme']
'newman_tobias', 'spm', 'spme', 'basic_splitOCVR']
100 changes: 100 additions & 0 deletions src/pybamm/models/full_battery_models/lithium_ion/basic_splitOCVR.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#
# Equivalent Circuit Model with split OCV
#
import pybamm


class SplitOCVR(pybamm.BaseModel):
"""Basic Equivalent Circuit Model that uses two OCV functions
for each electrode. This model is easily parameterizable with minimal parameters.
This class differs from the :class: pybamm.equivalent_circuit.Thevenin() due
to dual OCV functions to make up the voltage from each electrode.
Parameters
----------
name: str, optional
The name of the model.
"""

def __init__(self, name="ECM with split OCV"):
super().__init__(name)

######################
# Variables
######################
# All variables are only time-dependent
# No domain definition needed

theta_n = pybamm.Variable("Negative particle stoichiometry")
theta_p = pybamm.Variable("Positive particle stoichiometry")
Q = pybamm.Variable("Discharge capacity [A.h]")
V = pybamm.Variable("Voltage [V]")

# model is isothermal
I = pybamm.FunctionParameter("Current function [A]", {"Time [s]": pybamm.t})

# Capacity equation
self.rhs[Q] = I / 3600
self.initial_conditions[Q] = pybamm.Scalar(0)

# Capacity in each electrode
Q_n = pybamm.Parameter("Negative electrode capacity [A.h]")
Q_p = pybamm.Parameter("Positive electrode capacity [A.h]")

# State of charge electrode equations
theta_n_0 = pybamm.Parameter("Negative electrode initial stoichiometry")
theta_p_0 = pybamm.Parameter("Positive electrode initial stoichiometry")
self.rhs[theta_n] = -I / Q_n / 3600
self.rhs[theta_p] = I / Q_p / 3600
self.initial_conditions[theta_n] = theta_n_0
self.initial_conditions[theta_p] = theta_p_0

# Resistance for IR expression
R = pybamm.Parameter("Ohmic resistance [Ohm]")

# Open-circuit potential for each electrode
Un = pybamm.FunctionParameter(
"Negative electrode OCP [V]", {"Negative particle stoichiometry": theta_n}
)
Up = pybamm.FunctionParameter(
"Positive electrode OCP [V]", {"Positive particle stoichiometry": theta_p}
)

# Voltage expression
V = Up - Un - I * R

# Parameters for Voltage cutoff
voltage_high_cut = pybamm.Parameter("Upper voltage cut-off [V]")
voltage_low_cut = pybamm.Parameter("Lower voltage cut-off [V]")

self.variables = {
"Negative particle stoichiometry": theta_n,
"Positive particle stoichiometry": theta_p,
"Current [A]": I,
"Discharge capacity [A.h]": Q,
"Voltage [V]": V,
"Times [s]": pybamm.t,
"Positive electrode OCP [V]": Up,
"Negative electrode OCP [V]": Un,
"Current function [A]": I,
}

# Events specify points at which a solution should terminate
self.events += [
pybamm.Event("Minimum voltage [V]", V - voltage_low_cut),
pybamm.Event("Maximum voltage [V]", voltage_high_cut - V),
pybamm.Event("Maximum Negative Electrode stoichiometry", 0.999 - theta_n),
pybamm.Event("Maximum Positive Electrode stoichiometry", 0.999 - theta_p),
pybamm.Event("Minimum Negative Electrode stoichiometry", theta_n - 0.0001),
pybamm.Event("Minimum Positive Electrode stoichiometry", theta_p - 0.0001),
]

@property
def default_quick_plot_variables(self):
return [
"Voltage [V]",
["Negative particle stoichiometry", "Positive particle stoichiometry"],
"Negative electrode OCP [V]",
"Positive electrode OCP [V]",
"Current [A]",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#
# Test that the model works with an example parameter set
#
import pybamm
import numpy as np
import tests


class TestSplitOCVR:
def test_basic_processing(self):
# example parameters
qp0 = 8.73231852
qn0 = 5.82761507
theta0_n = 0.9013973983641687 * 0.9
theta0_p = 0.5142305254580026 * 0.83

# OCV functions
def Un(theta_n):
Un = (
0.1493
+ 0.8493 * np.exp(-61.79 * theta_n)
+ 0.3824 * np.exp(-665.8 * theta_n)
- np.exp(39.42 * theta_n - 41.92)
- 0.03131 * np.arctan(25.59 * theta_n - 4.099)
- 0.009434 * np.arctan(32.49 * theta_n - 15.74)
)
return Un

def Up(theta_p):
Up = (
-10.72 * theta_p**4
+ 23.88 * theta_p**3
- 16.77 * theta_p**2
+ 2.595 * theta_p
+ 4.563
)
return Up

pars = pybamm.ParameterValues(
{
"Positive electrode capacity [A.h]": qp0,
"Ohmic resistance [Ohm]": 0.001,
"Negative electrode initial stoichiometry": theta0_n,
"Lower voltage cut-off [V]": 2.8,
"Positive electrode initial stoichiometry": theta0_p,
"Upper voltage cut-off [V]": 4.2,
"Negative electrode capacity [A.h]": qn0,
"Current function [A]": 5,
"Positive electrode OCP [V]": Up,
"Negative electrode OCP [V]": Un,
"Nominal cell capacity [A.h]": 5,
}
)
model = pybamm.lithium_ion.SplitOCVR()
modeltest = tests.StandardModelTest(model)
modeltest.test_all(param=pars)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# Test for the ecm split-OCV model
#
import pybamm


class TestSplitOCVR:
def test_ecmsplitocv_well_posed(self):
model = pybamm.lithium_ion.SplitOCVR()
model.check_well_posedness()

def test_get_default_quick_plot_variables(self):
model = pybamm.lithium_ion.SplitOCVR()
variables = model.default_quick_plot_variables
assert "Current [A]" in variables

0 comments on commit 4cda488

Please sign in to comment.