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

BPX example #4635

Merged
merged 21 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
335 changes: 335 additions & 0 deletions docs/source/examples/notebooks/parameterization/bpx.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should this be moved to pybamm-data? how do you actually add things there?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a pretty small file, so there is not a major issue with putting it in the repo. Having the data on pybamm-data will probably make it more compatible with the google-colab functionality in the documentation

Copy link
Member

@agriyakhetarpal agriyakhetarpal Dec 3, 2024

Choose a reason for hiding this comment

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

should this be moved to pybamm-data?

This is a pretty small file, so there is not a major issue with putting it in the repo. Having the data on pybamm-data will probably make it more compatible with the google-colab functionality in the documentation

Yes, I think we should centralise everything under pybamm-data, so it would be nice to add this file there regardless of its small size (we do have a user-facing DataLoader class, after all, so it makes sense to showcase it more through more example notebooks). And usage with Google Colab is also improved indeed.

how do you actually add things there?

The procedure for adding things there is to first create a new v1.0.1 release and add all of the files from the previous release, add this file, and then bump the version in pybamm_data.py. We do this for reproducibility, such that the next PyBaMM release will retrieve the files from a different release URL (and this gives us the added benefit of better-segregated download analytics/usage stats from the GitHub API). If the changes to this file are final, I can do this later today if you'd like, @rtimms, or step back in case you may wish to do this yourself; please let me know!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done, thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

@agriyakhetarpal Can you add documentation to the pybamm-data repo for how that is done?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, @kratman, on it already but haven't pushed the changes yet. I'll ask you to review when done

"Header": {
"BPX": 0.1,
"Title": "Parameterisation example of an NMC111|graphite 12.5 Ah pouch cell",
"Description": "NMC111|graphite 12.5 Ah pouch cell. Parameterisation by About:Energy Limited (aboutenergy.io), December 2022, based on cell cycling data, and electrode data gathered after cell teardown. Electrolyte properties from Nyman et al. 2008 (doi:10.1016/j.electacta.2008.04.023). Negative electrode entropic coefficient data are from O'Regan et al. 2022 (doi:10.1016/j.electacta.2022.140700). Positive electrode entropic coefficient data are from Viswanathan et al. 2010 (doi:10.1016/j.jpowsour.2009.11.103). Other thermal properties are estimated.",
"Model": "DFN"
},
"Parameterisation": {
"Cell": {
"Ambient temperature [K]": 298.15,
"Initial temperature [K]": 298.15,
"Reference temperature [K]": 298.15,
"Lower voltage cut-off [V]": 2.7,
"Upper voltage cut-off [V]": 4.2,
"Nominal cell capacity [A.h]": 12.5,
"Specific heat capacity [J.K-1.kg-1]": 913,
"Thermal conductivity [W.m-1.K-1]": 2.04,
"Density [kg.m-3]": 1847,
"Electrode area [m2]": 0.016808,
"Number of electrode pairs connected in parallel to make a cell": 34,
"External surface area [m2]": 0.0379,
"Volume [m3]": 0.000128
},
"Electrolyte": {
"Initial concentration [mol.m-3]": 1000,
"Cation transference number": 0.2594,
"Conductivity [S.m-1]": "0.1297 * (x / 1000) ** 3 - 2.51 * (x / 1000) ** 1.5 + 3.329 * (x / 1000)",
"Diffusivity [m2.s-1]": "8.794e-11 * (x / 1000) ** 2 - 3.972e-10 * (x / 1000) + 4.862e-10",
"Conductivity activation energy [J.mol-1]": 17100,
"Diffusivity activation energy [J.mol-1]": 17100
},
"Negative electrode": {
"Particle radius [m]": 4.12e-06,
"Thickness [m]": 5.62e-05,
"Diffusivity [m2.s-1]": 2.728e-14,
"OCP [V]": "9.47057878e-01 * exp(-1.59418743e+02 * x) - 3.50928033e+04 + 1.64230269e-01 * tanh(-4.55509094e+01 * (x - 3.24116012e-02 )) + 3.69968491e-02 * tanh(-1.96718868e+01 * (x - 1.68334476e-01)) + 1.91517003e+04 * tanh(3.19648312e+00 * (x - 1.85139824e+00)) + 5.42448511e+04 * tanh(-3.19009848e+00 * (x - 2.01660395e+00))",
"Entropic change coefficient [V.K-1]": "(-0.1112 * x + 0.02914 + 0.3561 * exp(-((x - 0.08309) ** 2) / 0.004616)) / 1000",
"Conductivity [S.m-1]": 0.222,
"Surface area per unit volume [m-1]": 499522,
"Porosity": 0.253991,
"Transport efficiency": 0.128,
"Reaction rate constant [mol.m-2.s-1]": 5.199e-06,
"Minimum stoichiometry": 0.005504,
"Maximum stoichiometry": 0.75668,
"Maximum concentration [mol.m-3]": 29730,
"Diffusivity activation energy [J.mol-1]": 30000,
"Reaction rate constant activation energy [J.mol-1]": 55000
},
"Positive electrode": {
"Particle radius [m]": 4.6e-06,
"Thickness [m]": 5.23e-05,
"Diffusivity [m2.s-1]": 3.2e-14,
"OCP [V]": "-3.04420906 * x + 10.04892207 - 0.65637536 * tanh(-4.02134095 * (x - 0.80063948)) + 4.24678547 * tanh(12.17805062 * (x - 7.57659337)) - 0.3757068 * tanh(59.33067782 * (x - 0.99784492))",
"Entropic change coefficient [V.K-1]": -1e-4,
"Conductivity [S.m-1]": 0.789,
"Surface area per unit volume [m-1]": 432072,
"Porosity": 0.277493,
"Transport efficiency": 0.1462,
"Reaction rate constant [mol.m-2.s-1]": 2.305e-05,
"Minimum stoichiometry": 0.42424,
"Maximum stoichiometry": 0.96210,
"Maximum concentration [mol.m-3]": 46200,
"Diffusivity activation energy [J.mol-1]": 15000,
"Reaction rate constant activation energy [J.mol-1]": 35000
},
"Separator": {
"Thickness [m]": 2e-05,
"Porosity": 0.47,
"Transport efficiency": 0.3222
}
},
"Validation": {
"C/20 discharge": {
"Time [s]": [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 21000, 22000, 23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 40000, 41000, 42000, 43000, 44000, 45000, 46000, 47000, 48000, 49000, 50000, 51000, 52000, 53000, 54000, 55000, 56000, 57000, 58000, 59000, 60000, 61000, 62000, 63000, 64000, 65000, 66000, 67000, 68000, 69000, 70000, 71000, 72000, 73000, 74000, 75000],
"Current [A]": [-0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625],
"Voltage [V]": [4.19367569, 4.1677888, 4.14976386, 4.13250593, 4.11582327, 4.09952412, 4.08360848, 4.06788459, 4.05254422, 4.03720384, 4.02186346, 4.00690659, 3.99194973, 3.97699286, 3.96222774, 3.94727088, 3.93250576, 3.9173572, 3.90240027, 3.8874434, 3.87191127, 3.85637914, 3.8404635, 3.82493136, 3.80978274, 3.79482587, 3.78082778, 3.76740495, 3.75455738, 3.74286035, 3.73173857, 3.72176733, 3.71237135, 3.70393414, 3.69607219, 3.68859376, 3.68169059, 3.67517093, 3.66922653, 3.66309038, 3.65752958, 3.65235212, 3.64717474, 3.64257263, 3.637587, 3.63298489, 3.62819102, 3.62339716, 3.61879504, 3.61380942, 3.6088238, 3.60345467, 3.59770202, 3.59175763, 3.58542972, 3.57891014, 3.57200689, 3.56472021, 3.55685827, 3.54822931, 3.53864157, 3.52828682, 3.5173568, 3.5071938, 3.49894834, 3.49204517, 3.48590902, 3.47938936, 3.47152742, 3.4605974, 3.44218895, 3.39981122, 3.33749094, 3.25407757, 3.13308034, 2.89472934],
"Temperature [K]": [298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15]
},
"1C discharge": {
"Time [s]": [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700],
"Current [A]": [-12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5, -12.5],
"Voltage [V]": [4.1936757, 4.0487091, 4.0107418, 3.9762259, 3.9426688, 3.9094952, 3.8763218, 3.8433398, 3.8113168, 3.7802525, 3.7505305, 3.7221509, 3.695497, 3.6703771, 3.6467912, 3.6247394, 3.6042217, 3.5858132, 3.5685555, 3.5532149, 3.5382581, 3.5238765, 3.5102619, 3.4974143, 3.4849502, 3.4728697, 3.4609809, 3.4485169, 3.4352858, 3.4216712, 3.4070979, 3.3907987, 3.3720067, 3.3474621, 3.3121793, 3.2569541, 3.1589672, 2.9047014],
"Temperature [K]": [298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15, 298.15]
}
}
}
34 changes: 23 additions & 11 deletions src/pybamm/parameters/bpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def _get_phase_names(domain):
)


def _bpx_to_param_dict(bpx: BPX) -> dict:
def bpx_to_param_dict(bpx: BPX) -> dict:
"""
Turns a BPX object in to a dictionary of parameters for PyBaMM
"""
Expand Down Expand Up @@ -225,6 +225,9 @@ def _bpx_to_param_dict(bpx: BPX) -> dict:
# define functional forms for pybamm parameters that depend on more than one
# variable

def _get_activation_energy(name):
return pybamm_dict.get(name) or 0.0

def _arrhenius(Ea, T):
return exp(Ea / constants.R * (1 / T_ref - 1 / T))

Expand Down Expand Up @@ -294,11 +297,15 @@ def _conductivity(c_e, T, Ea, sigma_ref, constant=False):
k_norm = pybamm_dict[
phase_domain_pre_name + "reaction rate constant [mol.m-2.s-1]"
]
Ea_k = pybamm_dict.get(
Ea_k = _get_activation_energy(
phase_domain_pre_name
+ "reaction rate constant activation energy [J.mol-1]",
0.0,
+ "reaction rate constant activation energy [J.mol-1]"
)
pybamm_dict[
phase_domain_pre_name
+ "reaction rate constant activation energy [J.mol-1]"
] = Ea_k

# Note that in BPX j = 2*F*k_norm*sqrt((ce/ce0)*(c/c_max)*(1-c/c_max))...
# *sinh(),
# and in PyBaMM j = 2*k*sqrt(ce*c*(c_max - c))*sinh()
Expand All @@ -308,9 +315,8 @@ def _conductivity(c_e, T, Ea, sigma_ref, constant=False):
)

# diffusivity
Ea_D = pybamm_dict.get(
phase_domain_pre_name + "diffusivity activation energy [J.mol-1]",
0.0,
Ea_D = _get_activation_energy(
phase_domain_pre_name + "diffusivity activation energy [J.mol-1]"
)
pybamm_dict[
phase_domain_pre_name + "diffusivity activation energy [J.mol-1]"
Expand All @@ -335,8 +341,11 @@ def _conductivity(c_e, T, Ea, sigma_ref, constant=False):
)

# electrolyte
Ea_D_e = pybamm_dict.get(
electrolyte.pre_name + "diffusivity activation energy [J.mol-1]", 0.0
Ea_D_e = _get_activation_energy(
electrolyte.pre_name + "diffusivity activation energy [J.mol-1]"
)
pybamm_dict[electrolyte.pre_name + "diffusivity activation energy [J.mol-1]"] = (
Ea_D_e
)
D_e_ref = pybamm_dict[electrolyte.pre_name + "diffusivity [m2.s-1]"]

Expand All @@ -358,8 +367,11 @@ def _conductivity(c_e, T, Ea, sigma_ref, constant=False):
)

# conductivity
Ea_sigma_e = pybamm_dict.get(
electrolyte.pre_name + "conductivity activation energy [J.mol-1]", 0.0
Ea_sigma_e = _get_activation_energy(
electrolyte.pre_name + "conductivity activation energy [J.mol-1]"
)
pybamm_dict[electrolyte.pre_name + "conductivity activation energy [J.mol-1]"] = (
Ea_sigma_e
)
sigma_e_ref = pybamm_dict[electrolyte.pre_name + "conductivity [S.m-1]"]

Expand Down
89 changes: 63 additions & 26 deletions src/pybamm/parameters/parameter_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,42 +67,31 @@ def __init__(self, values):
for citation in self._dict_items["citations"]:
pybamm.citations.register(citation)

@staticmethod
def create_from_bpx(filename, target_soc: float = 1):
"""
Parameters
----------
filename: str
The filename of the bpx file
target_soc : float, optional
Target state of charge. Must be between 0 and 1. Default is 1.

Returns
-------
ParameterValues
A parameter values object with the parameters in the bpx file

"""
if target_soc < 0 or target_soc > 1:
raise ValueError("Target SOC should be between 0 and 1")

from bpx import parse_bpx_file, get_electrode_concentrations
def _create_from_bpx(bpx, target_soc):
from bpx import get_electrode_concentrations
from bpx.schema import ElectrodeBlended, ElectrodeBlendedSPM
from .bpx import _bpx_to_param_dict
from .bpx import bpx_to_param_dict

# parse bpx
bpx = parse_bpx_file(filename)
pybamm_dict = _bpx_to_param_dict(bpx)
pybamm_dict = bpx_to_param_dict(bpx)

if "Open-circuit voltage at 0% SOC [V]" not in pybamm_dict:
pybamm_dict["Open-circuit voltage at 0% SOC [V]"] = pybamm_dict[
"Lower voltage cut-off [V]"
]
warn(
"'Open-circuit voltage at 0% SOC [V]' not found in BPX file. Using "
"'Lower voltage cut-off [V]'.",
stacklevel=2,
)
if "Open-circuit voltage at 100% SOC [V]" not in pybamm_dict:
pybamm_dict["Open-circuit voltage at 100% SOC [V]"] = pybamm_dict[
"Upper voltage cut-off [V]"
]
# probably should put a warning here to indicate we are going
# ahead with the low voltage limit.
warn(
"'Open-circuit voltage at 100% SOC [V]' not found in BPX file. Using "
"'Upper voltage cut-off [V]'.",
stacklevel=2,
)

# get initial concentrations based on SOC
# Note: we cannot set SOC for blended electrodes,
Expand All @@ -127,6 +116,54 @@ def create_from_bpx(filename, target_soc: float = 1):

return pybamm.ParameterValues(pybamm_dict)

@staticmethod
def create_from_bpx_obj(bpx_obj, target_soc: float = 1):
"""
Parameters
----------
bpx_obj: dict
A dictionary containing the parameters in the `BPX <https://bpxstandard.com/>`_ format
target_soc : float, optional
Target state of charge. Must be between 0 and 1. Default is 1.

Returns
-------
ParameterValues
A parameter values object with the parameters in the bpx file

"""
from bpx import parse_bpx_obj

if target_soc < 0 or target_soc > 1:
raise ValueError("Target SOC should be between 0 and 1")

bpx = parse_bpx_obj(bpx_obj)
return ParameterValues._create_from_bpx(bpx, target_soc)

@staticmethod
def create_from_bpx(filename, target_soc: float = 1):
"""
Parameters
----------
filename: str
The filename of the `BPX <https://bpxstandard.com/>`_ file
target_soc : float, optional
Target state of charge. Must be between 0 and 1. Default is 1.

Returns
-------
ParameterValues
A parameter values object with the parameters in the bpx file

"""
from bpx import parse_bpx_file

if target_soc < 0 or target_soc > 1:
raise ValueError("Target SOC should be between 0 and 1")

bpx = parse_bpx_file(filename)
return ParameterValues._create_from_bpx(bpx, target_soc)

def __getitem__(self, key):
try:
return self._dict_items[key]
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/test_parameters/test_bpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,24 @@ def test_bpx_user_defined(self):
assert isinstance(
param["User-defined parameter data function"](var), pybamm.Power
)

def test_bpx_activation_energy_default(self):
bpx_obj = copy.copy(self.base)
bpx_obj["Parameterisation"]["Negative electrode"][
"Diffusivity activation energy [J.mol-1]"
] = None
with tempfile.NamedTemporaryFile(
suffix="test.json", delete=False, mode="w"
) as test_file:
json.dump(copy.copy(bpx_obj), test_file)
test_file.flush()
param = pybamm.ParameterValues.create_from_bpx(test_file.name)
assert (
param["Negative electrode diffusivity activation energy [J.mol-1]"]
== 0.0
)

def test_bpx_from_obj(self):
bpx_obj = copy.copy(self.base)
param = pybamm.ParameterValues.create_from_bpx_obj(bpx_obj)
assert isinstance(param, pybamm.ParameterValues)
Loading