Skip to content

Simulation inaccuracy induced by model processing #4976

@DundalekJan

Description

@DundalekJan

PyBaMM version: 24.5
Python version: 3.9.13

Description

I have encountered simulation inaccuracy when solving the diffusion equation having diffusion coefficient defined by function or interpolant. The issue can be observed for specific combination of parameter values and is linked to model processing, which introduces "magic number" of 1e-16 into the model equation.

Is there a possibility to programmatically influence the value of "magic number" during the model processing?

Example

Spherical diffusion implemented according to A step towards the Single Particle Model parametrized to provide constant value of "Diffusion coefficient [m2.s-1]" = 3.9e-15 by pybamm.Interpolant class.

  • Simulation result comparison:
    Image
  • Model rhs comparison:
    Image

Note: The simulation inaccuracy of example can be mitigated by decreasing of the order of magnitude of "magic number" after the model processing.

Steps to Reproduce Example

import pybamm
import numpy as np
import matplotlib.pyplot as plt

model_scalar = pybamm.BaseModel()
c = pybamm.Variable("Concentration [mol.m-3]", domain="negative particle")
R = pybamm.Parameter("Particle radius [m]")
D = pybamm.Parameter("Diffusion coefficient [m2.s-1]")
j = pybamm.Parameter("Interfacial current density [A.m-2]")
F = pybamm.Parameter("Faraday constant [C.mol-1]")
c0 = pybamm.Parameter("Initial concentration [mol.m-3]")
N = -D * pybamm.grad(c)
dcdt = -pybamm.div(N)
model_scalar.rhs = {c: dcdt}
lbc = pybamm.Scalar(0)
rbc = -j / F / D
model_scalar.boundary_conditions = {c: {"left": (lbc, "Neumann"), "right": (rbc, "Neumann")}}
model_scalar.initial_conditions = {c: c0}
model_scalar.variables = {
    "Concentration [mol.m-3]": c,
    "Surface concentration [mol.m-3]": pybamm.surf(c),
    "Flux [mol.m-2.s-1]": N,
}
param_scalar = pybamm.ParameterValues(
    {
        "Particle radius [m]": 10e-6,
        "Diffusion coefficient [m2.s-1]": 3.9e-15,
        "Interfacial current density [A.m-2]": 1.4,
        "Faraday constant [C.mol-1]": 96485,
        "Initial concentration [mol.m-3]": 2.5e4,
    }
)
r = pybamm.SpatialVariable(
    "r", domain=["negative particle"], coord_sys="spherical polar"
)
geometry_scalar = {"negative particle": {r: {"min": pybamm.Scalar(0), "max": R}}}
param_scalar.process_model(model_scalar)
param_scalar.process_geometry(geometry_scalar)
submesh_types = {"negative particle": pybamm.Uniform1DSubMesh}
var_pts = {r: 20}
mesh_scalar = pybamm.Mesh(geometry_scalar, submesh_types, var_pts)
spatial_methods = {"negative particle": pybamm.FiniteVolume()}
disc_scalar = pybamm.Discretisation(mesh_scalar, spatial_methods)
disc_scalar.process_model(model_scalar);
model_scalar.rhs[c].render()

model_LUT = pybamm.BaseModel()
inputs = {"Concentration [mol.m-3]": c}
D = pybamm.FunctionParameter("Diffusion coefficient [m2.s-1]", inputs)
N = -D * pybamm.grad(c)
dcdt = -pybamm.div(N)
model_LUT.rhs = {c: dcdt}
rbc = -j / F / pybamm.surf(D)
model_LUT.boundary_conditions = {c: {"left": (lbc, "Neumann"), "right": (rbc, "Neumann")}}
model_LUT.initial_conditions = {c: c0}
model_LUT.variables = {
    "Concentration [mol.m-3]": c,
    "Surface concentration [mol.m-3]": pybamm.surf(c),
    "Flux [mol.m-2.s-1]": N,
}
param_LUT = pybamm.ParameterValues(
    {
        "Particle radius [m]": param_scalar["Particle radius [m]"],
        "Diffusion coefficient [m2.s-1]": pybamm.Interpolant(np.array([0,2*param_scalar["Initial concentration [mol.m-3]"]]),np.array([param_scalar["Diffusion coefficient [m2.s-1]"],param_scalar["Diffusion coefficient [m2.s-1]"]]),c),
        "Interfacial current density [A.m-2]": param_scalar["Interfacial current density [A.m-2]"],
        "Faraday constant [C.mol-1]": param_scalar["Faraday constant [C.mol-1]"],
        "Initial concentration [mol.m-3]": param_scalar["Initial concentration [mol.m-3]"],
    }
)
geometry_LUT = {"negative particle": {r: {"min": pybamm.Scalar(0), "max": R}}}
param_LUT.process_model(model_LUT)
param_LUT.process_geometry(geometry_LUT)
mesh_LUT = pybamm.Mesh(geometry_LUT, submesh_types, var_pts)
disc_LUT = pybamm.Discretisation(mesh_LUT, spatial_methods)
disc_LUT.process_model(model_LUT);
# Uncomment the following line to mitigate simulation inaccuracy of model that uses diffusion coefficient defined by interpolant
# model_LUT.rhs[c].children[1].children[1].children[0].children[1].children[1].children[1].children[0]=pybamm.Scalar(1e-20)
model_LUT.rhs[c].render()

t = [0, 3600]
models=[model_scalar,model_LUT]
solutions = []
for model in models:
    solver = pybamm.ScipySolver()
    solutions.append(solver.solve(model, t))

time=solutions[0].t
c_surf_scalar = solutions[0]["Surface concentration [mol.m-3]"](time)
c_surf_LUT = solutions[1]["Surface concentration [mol.m-3]"](time)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 4))
ax1.plot(time, c_surf_scalar,color="tab:green")
ax1.plot(time, c_surf_LUT,color="tab:red")
ax1.set_xlabel("Time [s]")
ax1.set_ylabel("Surface concentration [mol.m-3]")
ax1.legend(['scalar', 'LUT'])
ax2.plot(time, c_surf_LUT-c_surf_scalar,color="tab:blue")
ax2.set_xlabel("Time [s]")
ax2.set_ylabel("Error of surface concentration [mol.m-3]",color="tab:blue")
ax2_right = ax2.twinx()
ax2_right.plot(time, (c_surf_LUT-c_surf_scalar)/c_surf_scalar*100,color="tab:orange")
ax2_right.set_ylabel("Relative error of surface concentration [%]",color="tab:orange")
fig.tight_layout()
plt.show()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions